Design changes

This commit is contained in:
Ludwig Schubert
2017-08-09 16:48:07 -07:00
parent 27fbe9a932
commit a1800ca2b3
61 changed files with 22196 additions and 1092 deletions

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 740 B

After

Width:  |  Height:  |  Size: 740 B

Before

Width:  |  Height:  |  Size: 163 B

After

Width:  |  Height:  |  Size: 163 B

+2 -1
View File
@@ -27,9 +27,10 @@ const components = [
/* Distill website specific components */
import { DistillHeader } from './distill-components/distill-header';
import { DistillAppendix } from './distill-components/distill-appendix';
import { DistillFooter } from './distill-components/distill-footer';
const distillComponents = [
DistillHeader, DistillAppendix,
DistillHeader, DistillAppendix, DistillFooter,
];
function defineComponents() {
+4 -2
View File
@@ -3,7 +3,7 @@ import { body } from '../helpers/layout';
const T = Template('d-abstract', `
<style>
d-abstract {
:host {
display: block;
font-size: 23px;
line-height: 1.7em;
@@ -11,7 +11,9 @@ const T = Template('d-abstract', `
}
${body('d-abstract')}
</style>
`, false);
<slot></slot>
`);
export class Abstract extends T(HTMLElement) {
+9 -6
View File
@@ -1,29 +1,32 @@
import { Template } from '../mixins/template';
import { page } from '../helpers/layout';
import { body } from '../helpers/layout';
const T = Template('d-appendix', `
<style>
:host {
box-sizing: border-box;
display: block;
width: 100%;
font-size: 13px;
line-height: 1.7em;
margin-bottom: 0;
border-top: 1px solid rgba(0,0,0,0.1);
color: rgba(0,0,0,0.5);
background: rgb(250, 250, 250);
background: hsl(180, 5%, 98%);
padding-top: 36px;
padding-bottom: 48px;
}
${page('.l-body')}
${body('.content')}
</style>
<div class="l-body">
<slot></slot>
<div class='content'>
<slot></slot>
</div>
`);
`, true);
export class Appendix extends T(HTMLElement) {
+20 -4
View File
@@ -5,13 +5,29 @@ const T = Template('d-article', `
<style></style>
`, false);
// export function addInferableTags(dom, frontMatter) {
// const title = frontMatter.title;
// if (title) {
// const titleTag = document.querySelector()
//
// }
// }
export class Article extends T(HTMLElement) {
// constructor() {
// super();
// }
constructor() {
super();
new MutationObserver( (mutations) => {
for (const mutation of mutations) {
for (const addedNode of mutation.addedNodes) {
if (addedNode.nodeName === 'HR') {
console.warn('Use of <hr> tags in distill articles is discouraged!');
}
}
}
}).observe(this, {childList: true});
}
connectedCallback() {
for (const [functionName, callback] of Object.entries(Controller.listeners)) {
+28 -49
View File
@@ -1,8 +1,8 @@
import { Template } from '../mixins/template';
import bibtexParse from 'bibtex-parse-js';
import { parseBibtex } from '../helpers/bibtex';
import { bibliography_cite } from '../helpers/citation';
const T = Template('d-bibliography', `
export const templateString = `
<style>
.references {
font-size: 12px;
@@ -31,28 +31,33 @@ const T = Template('d-bibliography', `
</style>
<h3>References</h3>
<ol></ol>
`);
<ol class='references' id='references-list' ></ol>
`;
const T = Template('d-bibliography', templateString);
export function parseBibtex(bibtex) {
const bibliography = new Map();
const parsedEntries = bibtexParse.toJSON(bibtex);
for (const entry of parsedEntries) {
// normalize tags; note entryTags is an object, not Map
for (const tag in entry.entryTags) {
let value = entry.entryTags[tag];
value = value.replace(/[\t\n ]+/g, ' ');
value = value.replace(/{\\["^`.'acu~Hvs]( )?([a-zA-Z])}/g,
(full, x, char) => char);
value = value.replace(/{\\([a-zA-Z])}/g,
(full, char) => char);
entry.entryTags[tag] = value;
export function parseBibliography(element) {
if (element.firstElementChild && element.firstElementChild.tagName === 'SCRIPT') {
const bibtex = element.firstElementChild.textContent;
const bibliography = parseBibtex(bibtex);
return bibliography;
}
}
export function renderBibliography(element, entries) {
if (entries.size) {
element.host.style.display = 'initial';
let list = element.querySelector('#references-list');
list.innerHTML = '';
for (const [key, entry] of entries) {
const listItem = document.createElement('li');
listItem.id = key;
listItem.innerHTML = bibliography_cite(entry);
list.appendChild(listItem);
}
entry.entryTags.type = entry.entryType;
// add to bibliography
bibliography.set(entry.citationKey, entry.entryTags);
} else {
element.host.style.display = 'none';
}
return bibliography;
}
export class Bibliography extends T(HTMLElement) {
@@ -67,6 +72,7 @@ export class Bibliography extends T(HTMLElement) {
this.parseIfPossible();
observer.observe(this, options);
});
this.parseIfPossible();
// ...and listen for changes
observer.observe(this, options);
}
@@ -82,10 +88,6 @@ export class Bibliography extends T(HTMLElement) {
}
}
connectedCallback() {
this.list = this.root.querySelector('ol');
}
notify(bibliography) {
const options = { detail: bibliography, bubbles: true };
const event = new CustomEvent('onBibliographyChanged', options);
@@ -93,30 +95,7 @@ export class Bibliography extends T(HTMLElement) {
}
set entries(newEntries) {
if (newEntries.size) {
this.root.host.style.display = 'initial';
this.list.innerHTML = '';
for (const [key, entry] of newEntries) {
const listItem = document.createElement('li');
listItem.id = key;
listItem.innerHTML = bibliography_cite(entry);
this.list.appendChild(listItem);
}
} else {
this.root.host.style.display = 'none';
}
}
renderContent() {
// compute and store bibliography
// FrontMatter.bibliography = parseBibtex(this.bibtex);
// this.notify();
// Store.set('bibliography', bibliography);
// compute and store citations
// const citations = collectCitations();
// Store.set('citations', citations);
renderBibliography(this.root, newEntries);
}
}
+14 -6
View File
@@ -3,13 +3,13 @@ import { page } from '../helpers/layout';
const T = Template('d-byline', `
<style>
d-byline {
:host {
box-sizing: border-box;
font-size: 13px;
line-height: 20px;
display: block;
/* border-top: 1px solid rgba(0, 0, 0, 0.1);*/
/* border-bottom: 1px solid rgba(0, 0, 0, 0.1);*/
border-top: 1px solid rgba(0, 0, 0, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
color: rgba(0, 0, 0, 0.6);
padding-top: 20px;
padding-bottom: 20px;
@@ -42,6 +42,7 @@ const T = Template('d-byline', `
.date {
display: block;
text-align: left;
margin-top: 8px;
}
.year, .month {
display: inline;
@@ -54,7 +55,7 @@ const T = Template('d-byline', `
display: inline;
}
@media(min-width: 1080px) {
@media screen and (min-width: 768px), print {
d-byline {
border-bottom: none;
}
@@ -87,9 +88,11 @@ const T = Template('d-byline', `
}
.date {
border-left: 1px solid rgba(0, 0, 0, 0.1);
padding-left: 15px;
margin-left: 15px;
margin-top: 0;
display: inline-block;
}
.year, .month {
@@ -97,6 +100,7 @@ const T = Template('d-byline', `
}
.citation {
align-self: flex-end;
border-left: 1px solid rgba(0, 0, 0, 0.15);
padding-left: 15px;
margin-left: 15px;
@@ -105,12 +109,16 @@ const T = Template('d-byline', `
.citation div {
display: block;
}
.byline {
display: flex;
}
}
</style>
<div class='byline'>
</div>
`, false);
`, true);
export function bylineTemplate(frontMatter) {
return `
@@ -142,7 +150,7 @@ export function bylineTemplate(frontMatter) {
export class Byline extends T(HTMLElement) {
set frontMatter(frontMatter) {
const container = this.querySelector('.byline');
const container = this.root.querySelector('.byline');
container.innerHTML = bylineTemplate(frontMatter);
}
+10 -9
View File
@@ -28,7 +28,7 @@ const T = Template('d-cite', `
}
</style>
<div style="display: none;" id="hover-box" class="dt-hover-box">
<div id="hover-box" class="dt-hover-box">
</div>
<span id="citation-" class="citation">
@@ -37,9 +37,9 @@ const T = Template('d-cite', `
</span>
`);
export function collectCitations() {
export function collectCitations(dom=document) {
const citations = new Set();
const citeTags = document.querySelectorAll('d-cite');
const citeTags = dom.querySelectorAll('d-cite');
for (const tag of citeTags) {
const keys = tag.getAttribute('key').split(',');
for (const key of keys) {
@@ -53,11 +53,11 @@ export class Cite extends T(HTMLElement) {
/* Lifecycle */
constructor() {
super();
// Cite.currentId += 1;
// this.citeId = Cite.currentId;
}
// constructor() {
// super();
// // Cite.currentId += 1;
// // this.citeId = Cite.currentId;
// }
connectedCallback() {
// this.notify();
@@ -67,7 +67,8 @@ export class Cite extends T(HTMLElement) {
this.innerSpan = this.root.querySelector('.citation-number');
// this.outerSpan.id = `citation-${this.citeId}`;
// this.hoverDiv.id = `dt-cite-hover-box-${this.citeId}`;
HoverBox.get_box(this.hoverDiv).bind(this.outerSpan);
// console.log(this, this.hoverDiv, this.outerSpan, this.innerSpan);
this.hoverbox = new HoverBox(this.hoverDiv, this.outerSpan);
}
+3 -3
View File
@@ -11,8 +11,8 @@ d-math[block] {
</style>
<div style="display: none;" class="dt-hover-box">
<slot id='slot'></slot>
<div id="hover-box" class="dt-hover-box">
<slot id="slot"></slot>
</div>
<sup><span id="fn-" data-hover-ref="" style="cursor:pointer"></span></sup>
@@ -55,7 +55,7 @@ export class Footnote extends T(HTMLElement) {
span.setAttribute('data-hover-ref', div.id);
span.textContent = IdString;
HoverBox.get_box(div).bind(span);
this.hoverbox = new HoverBox(div, span);
}
}
+13 -13
View File
@@ -1,5 +1,17 @@
import ymlParse from 'js-yaml';
export function parseFrontmatter(element) {
const scriptTag = element.querySelector('script');
if (scriptTag) {
const yml = scriptTag.textContent;
const data = ymlParse.safeLoad(yml);
return data;
} else {
console.error('You added a frontmatter tag but did not provide a script tag with front matter data in it. Please take a look at our templates.');
return {};
}
}
export class FrontMatter extends HTMLElement {
static get is() { return 'd-front-matter'; }
@@ -9,24 +21,12 @@ export class FrontMatter extends HTMLElement {
const options = {childList: true, characterData: true, subtree: true};
const observer = new MutationObserver( () => {
const data = this.parse();
const data = parseFrontmatter(this);
this.notify(data);
});
observer.observe(this, options);
}
parse(){
const scriptTag = this.querySelector('script');
if (scriptTag) {
const yml = scriptTag.textContent;
const data = ymlParse.safeLoad(yml);
return data;
} else {
console.error('You added a frontmatter tag but did not provide a script tag with front matter data in it. Please take a look at our templates.');
return {};
}
}
notify(data) {
const options = { detail: data, bubbles: true };
const event = new CustomEvent('onFrontMatterChanged', options);
-4
View File
@@ -10,8 +10,4 @@ d-references {
export class References extends T(HTMLElement) {
connectedCallback() {
super.connectedCallback();
}
}
+30 -8
View File
@@ -1,5 +1,5 @@
import { Template } from '../mixins/template';
import { page } from '../helpers/layout';
import { body } from '../helpers/layout';
const T = Template('d-title', `
<style>
@@ -8,23 +8,45 @@ const T = Template('d-title', `
box-sizing: border-box;
display: block;
width: 100%;
margin-bottom: 100px;
margin-bottom: 64px;
}
::slotted(h1) {
padding-top: 140px;
padding-bottom: 24px;
padding-top: 16px;
padding-bottom: 16px;
margin: 0;
line-height: 1em;
font-size: 48px;
font-weight: 600;
line-height: 1.3;
font-size: 32px;
font-weight: 700;
}
@media screen and (min-width: 768px), print {
::slotted(h1) {
font-size: 42px;
padding-bottom: 32px;
}
}
@media(min-width: 1024px) {
::slotted(h1) {
padding-top: 64px;
padding-bottom: 64px;
font-size: 48px;
}
}
@media(min-width: 1280px) {
::slotted(h1) {
padding-top: 96px;
padding-bottom: 64px;
font-size: 56px;
}
}
d-byline {
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
${page('::slotted(h1), ::slotted(h2)')}
${body('::slotted(h1), ::slotted(h2)')}
</style>
+8 -4
View File
@@ -1,5 +1,6 @@
import { FrontMatter } from './front-matter';
import { collectCitations } from './components/d-cite';
import { parseFrontmatter } from './components/d-front-matter';
const frontMatter = new FrontMatter();
@@ -77,8 +78,9 @@ export const Controller = {
// ensure we have citations
if (frontMatter.citations.length === 0) {
// console.debug('onBibliographyChanged, but unresolved dependency ("citations"). Enqueing.');
Controller.waitingOn.citations.push(() => Controller.listeners.onBibliographyChanged(event));
Controller.waitingOn.citations.push( function() {
Controller.listeners.onBibliographyChanged({target: event.target, detail: event.detail});
});
return;
}
@@ -103,7 +105,9 @@ export const Controller = {
frontMatter.mergeFromYMLFrontmatter(data);
const appendix = document.querySelector('distill-appendix');
appendix.frontMatter = frontMatter;
if (appendix) {
appendix.frontMatter = frontMatter;
}
const byline = document.querySelector('d-byline');
byline.frontMatter = frontMatter;
@@ -113,7 +117,7 @@ export const Controller = {
// console.debug('DOMContentLoaded.');
const frontMatterTag = document.querySelector('d-front-matter');
const data = frontMatterTag.parse();
const data = parseFrontmatter(frontMatterTag);
Controller.listeners.onFrontMatterChanged({detail: data});
// console.debug('Resolving "citations" dependency due to initial DOM load.');
+5 -7
View File
@@ -1,3 +1,5 @@
import { serializeFrontmatterToBibtex } from '../helpers/bibtex';
const styles = `
<style>
distill-appendix h3 {
@@ -27,6 +29,8 @@ const styles = `
color: rgba(150, 150, 150, 1);
overflow: hidden;
margin-top: -12px;
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
`;
@@ -45,13 +49,7 @@ export function appendixTemplate(frontMatter) {
<p>For attribution in academic contexts, please cite this work as</p>
<pre class="citation short">${frontMatter.concatenatedAuthors}, "${frontMatter.title}", Distill, ${frontMatter.publishedYear}.</pre>
<p>BibTeX citation</p>
<pre class="citation long">@article{${frontMatter.slug},
author = {${frontMatter.bibtexAuthors}},
title = {${frontMatter.title}},
journal = {Distill},
year = {${frontMatter.publishedYear}},
note = {${frontMatter.url}}
}</pre>
<pre class="citation long">${serializeFrontmatterToBibtex(frontMatter)}</pre>
`;
}
+53
View File
@@ -0,0 +1,53 @@
import { Template } from '../mixins/template';
import logo from '../assets/distill-logo.svg';
const T = Template('distill-footer', `
<style>
:host {
display: block;
color: rgba(255, 255, 255, 0.4);
font-weight: 300;
padding: 40px 0;
border-top: 1px solid rgba(0, 0, 0, 0.1);
background-color: hsl(180, 5%, 15%); /*hsl(200, 60%, 15%);*/
text-align: left;
}
.logo svg {
width: 24px;
position: relative;
top: 4px;
margin-right: 2px;
}
.logo svg path {
fill: none;
stroke: rgba(255, 255, 255, 0.8);
stroke-width: 3px;
}
.logo {
font-size: 17px;
font-weight: 200;
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
margin-right: 6px;
}
.container {
grid-column: margin-left / body;
}
</style>
<div class='container'>
<a href="/" class="logo">
${logo}
Distill
</a> is dedicated to clear explanations of machine learning
</div>
`);
export class DistillFooter extends T(HTMLElement) {
}
+38 -19
View File
@@ -1,23 +1,21 @@
import {Template} from '../mixins/template';
import { Template } from '../mixins/template';
// import logo from "./distill-logo.svg";
var logo = '';
import logo from '../assets/distill-logo.svg';
const T = Template('distill-header', `
<style>
:host {
box-sizing: border-box;
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background-color: hsl(200, 60%, 15%);
background-color: transparent;
z-index: ${1e6};
color: rgba(0, 0, 0, 0.8);
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);
/*border-bottom: 1px solid rgba(0, 0, 0, 0.08);*/
/*box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);*/
}
.content {
height: 70px;
@@ -34,11 +32,22 @@ a:hover {
color: rgba(255, 255, 255, 1);
}
svg {
background-color: hsl(0, 0%, 15%);;
padding: 8px;
border-radius: 12px;
width: 24px;
position: relative;
top: 4px;
top: 16px;
left: 16px;
margin-right: 2px;
}
@media(min-width: 768px) {
svg {
top: 40px;
left: 40px;
}
}
@media(min-width: 1080px) {
:host {
height: 70px;
@@ -52,8 +61,8 @@ svg {
}
}
svg path {
fill: none;
stroke: rgba(255, 255, 255, 0.8);
fill: white;
stroke: rgba(255, 255, 255, 1.0);
stroke-width: 3px;
}
.logo {
@@ -69,23 +78,33 @@ svg path {
margin-left: 24px;
text-transform: uppercase;
}
.name {
opacity: 0.0;
transition: opacity 0.5s
}
a:hover .name {
opacity: 1.0;
}
</style>
<div class="content l-page">
<a href="/" class="logo">
${logo}
Distill
</a>
<div class="nav">
<a href="/faq">About</a>
<a href="https://github.com/distillpub">GitHub</a>
<!-- https://twitter.com/distillpub -->
</div>
<span class='name'>
Distill
</span>
</div>
`);
// <div class="nav">
// <a href="/faq">About</a>
// <a href="https://github.com/distillpub">GitHub</a>
// <!-- https://twitter.com/distillpub -->
// </div>
export class DistillHeader extends T(HTMLElement) {
static get is() {
return 'distill-header';
}
}
@@ -0,0 +1,14 @@
export default function(dom) {
const appendixTag = dom.querySelector('d-appendix');
if (!appendixTag) {
console.warn('No appendix tag found!');
return;
}
const distillAppendixTag = appendixTag.querySelector('distill-appendix');
if (!distillAppendixTag) {
const distillAppendix = dom.createElement('distill-appendix');
appendixTag.appendChild(distillAppendix);
}
}
+8
View File
@@ -0,0 +1,8 @@
export default function(dom) {
const footerTag = dom.querySelector('distill-footer');
if(!footerTag) {
const footer = dom.createElement('distill-footer');
const body = dom.querySelector('body');
body.appendChild(footer);
}
}
+8
View File
@@ -0,0 +1,8 @@
export default function(dom) {
const headerTag = dom.querySelector('distill-header');
if (!headerTag) {
const header = dom.createElement('distill-header');
const body = dom.querySelector('body');
body.insertBefore(header, body.firstChild);
}
}
+10
View File
@@ -0,0 +1,10 @@
import { parseBibliography } from '../components/d-bibliography';
export default function(dom, data) {
const bibliographyTag = dom.querySelector('d-bibliography');
if (!bibliographyTag) {
console.warn('No bibliography tag found!');
return;
}
data.bibliography = parseBibliography(bibliographyTag);
}
+5
View File
@@ -0,0 +1,5 @@
import { collectCitations } from '../components/d-cite';
export default function(dom, data) {
data.citations = collectCitations(dom);
}
+11
View File
@@ -0,0 +1,11 @@
import { parseFrontmatter } from '../components/d-front-matter';
export default function(dom, data) {
const frontMatterTag = dom.querySelector('d-front-matter');
if (!frontMatterTag) {
console.warn('No front matter tag found!');
return;
}
const extractedData = parseFrontmatter(frontMatterTag);
Object.assign(data, extractedData);
}
+33 -6
View File
@@ -77,6 +77,7 @@ export class FrontMatter {
// }
// volume: 1,
// issue: 9,
this.publishedDate = new Date();
//
// Assigned from publishing process
@@ -104,15 +105,34 @@ export class FrontMatter {
this.description = data.description;
const zipped = data.authors.map( (author, index) => [author, data.affiliations[index]]);
this.authors = zipped.map( ([authorEntry, affiliationEntry]) => {
const name = Object.keys(authorEntry)[0];
const author = new Author(name);
if (typeof authorEntry === 'object') {
author.personalURL = authorEntry[name];
const author = new Author();
// try to get name and personal url
switch (typeof authorEntry) {
case 'object':
author.name = Object.keys(authorEntry)[0];
author.personalURL = authorEntry[author.name];
break;
case 'string':
author.name = authorEntry;
break;
default:
throw new Error('Invalid type in frontmatter author field: ' + authorEntry);
}
author.affiliation = Object.keys(affiliationEntry)[0];
if (typeof affiliationEntry === 'object') {
// try to get affiliation name and affiliation url
switch (typeof affiliationEntry) {
case 'object':
author.affiliation = Object.keys(affiliationEntry)[0];
author.affiliationURL = affiliationEntry[author.affiliation];
break;
case 'string':
author.affiliation = affiliationEntry;
break;
default:
throw new Error('Invalid type in frontmatter affiliation field: ' + affiliationEntry);
}
return author;
});
}
@@ -213,4 +233,11 @@ export class FrontMatter {
return slug || 'Untitled';
}
get bibliographyEntries() {
return new Map(this.citations.map( citationKey => {
const entry = this.bibliography.get(citationKey);
return [citationKey, entry];
}));
}
}
+33
View File
@@ -0,0 +1,33 @@
import bibtexParse from 'bibtex-parse-js';
function normalizeTag(string) {
return string
.replace(/[\t\n ]+/g, ' ')
.replace(/{\\["^`.'acu~Hvs]( )?([a-zA-Z])}/g, (full, x, char) => char)
.replace(/{\\([a-zA-Z])}/g, (full, char) => char);
}
export function parseBibtex(bibtex) {
const bibliography = new Map();
const parsedEntries = bibtexParse.toJSON(bibtex);
for (const entry of parsedEntries) {
// normalize tags; note entryTags is an object, not Map
for (const [key, value] of Object.entries(entry.entryTags)) {
entry.entryTags[key] = normalizeTag(value);
}
entry.entryTags.type = entry.entryType;
// add to bibliography
bibliography.set(entry.citationKey, entry.entryTags);
}
return bibliography;
}
export function serializeFrontmatterToBibtex(frontMatter) {
return `@article{${frontMatter.slug},
author = {${frontMatter.bibtexAuthors}},
title = {${frontMatter.title}},
journal = {${frontMatter.journal.title}},
year = {${frontMatter.publishedYear}},
note = {${frontMatter.url}}
}`;
}
+87 -91
View File
@@ -1,12 +1,12 @@
function make_hover_css(pos) {
var pretty = window.innerWidth > 600;
var padding = pretty? 18 : 12;
var outer_padding = pretty ? 18 : 0;
var bbox = document.querySelector('body').getBoundingClientRect();
var left = pos[0] - bbox.left, top = pos[1] - bbox.top;
var width = Math.min(window.innerWidth-2*outer_padding, 648);
const pretty = window.innerWidth > 600;
const padding = pretty? 18 : 12;
const outer_padding = pretty ? 18 : 0;
const bbox = document.querySelector('body').getBoundingClientRect();
let left = pos[0] - bbox.left, top = pos[1] - bbox.top;
let width = Math.min(window.innerWidth-2*outer_padding, 648);
left = Math.min(left, window.innerWidth-width-outer_padding);
width = width - 2*padding;
width = width - 2 * padding;
return (`position: absolute;
background-color: #FFF;
opacity: 0.95;
@@ -20,93 +20,89 @@ function make_hover_css(pos) {
z-index: ${1e6};`);
}
export class HoverBox {
constructor(div) {
this.div = div;
constructor(contentHTML, triggerElement) {
this.visible = false;
this.bindDivEvents(div);
HoverBox.box_map[div.id] = this;
// div hold teh contents of the box that will become visible
this.div = contentHTML;
this.bindDivEvents(this.div);
// triggerElement holds the element that needs to be hovered etc to show contents
this.triggerElement = triggerElement;
this.bindTriggerEvents(this.triggerElement);
this.hide();
}
bindDivEvents(node) {
// For mice, same behavior as hovering on links
this.div.addEventListener('mouseover', () => {
if (!this.visible) this.showAtNode(node);
this.stopTimeout();
});
this.div.addEventListener('mouseout', () => {
this.extendTimeout(250);
});
// Don't trigger body touchstart event when touching within box
this.div.addEventListener('touchstart', (event) => {
event.stopPropagation();
}, {passive: true});
// Close box when touching outside box
document.body.addEventListener('touchstart', () => {
this.hide();
}, {passive: true});
}
bindTriggerEvents(node) {
node.addEventListener('mouseover', () => {
if (!this.visible) {
this.showAtNode(node);
}
this.stopTimeout();
});
node.addEventListener('mouseout', () => {
this.extendTimeout(250);
});
node.addEventListener('touchstart', (event) => {
if (this.visible) {
this.hide();
} else {
this.showAtNode(node);
}
// Don't trigger body touchstart event when touching link
event.stopPropagation();
}, {passive: true});
}
show(position) {
this.visible = true;
const css = make_hover_css(position);
this.div.setAttribute('style', css );
}
showAtNode(node) {
const bbox = node.getBoundingClientRect();
this.show([bbox.right, bbox.bottom]);
}
hide() {
this.visible = false;
this.div.setAttribute('style', 'display:none');
this.stopTimeout();
}
stopTimeout() {
if (this.timeout) {
clearTimeout(this.timeout);
}
}
extendTimeout(time) {
this.stopTimeout();
this.timeout = setTimeout(() => {
this.hide();
}, time);
}
}
HoverBox.box_map = {};
HoverBox.get_box = function get_box(div_id) {
if (div_id in HoverBox.box_map) {
return HoverBox.box_map[div_id];
} else {
return new HoverBox(div_id);
}
};
HoverBox.prototype.show = function show(pos){
this.visible = true;
this.div.setAttribute('style', make_hover_css(pos) );
for (var box_id in HoverBox.box_map) {
var box = HoverBox.box_map[box_id];
if (box != this) box.hide();
}
};
HoverBox.prototype.showAtNode = function showAtNode(node){
var bbox = node.getBoundingClientRect();
this.show([bbox.right, bbox.bottom]);
};
HoverBox.prototype.hide = function hide(){
this.visible = false;
if (this.div) this.div.setAttribute('style', 'display:none');
if (this.timeout) clearTimeout(this.timeout);
};
HoverBox.prototype.stopTimeout = function stopTimeout() {
if (this.timeout) clearTimeout(this.timeout);
};
HoverBox.prototype.extendTimeout = function extendTimeout(T) {
//console.log("extend", T)
var this_ = this;
this.stopTimeout();
this.timeout = setTimeout(function(){this_.hide();}.bind(this), T);
};
// Bind events to a link to open this box
HoverBox.prototype.bind = function bind(node) {
if (typeof node == 'string'){
node = document.querySelector(node);
}
node.addEventListener('mouseover', function(){
if (!this.visible) this.showAtNode(node);
this.stopTimeout();
}.bind(this));
node.addEventListener('mouseout', function(){this.extendTimeout(250);}.bind(this));
node.addEventListener('touchstart', function(e) {
if (this.visible) {
this.hide();
} else {
this.showAtNode(node);
}
// Don't trigger body touchstart event when touching link
e.stopPropagation();
}.bind(this), {passive: true});
};
HoverBox.prototype.bindDivEvents = function bindDivEvents(node){
// For mice, same behavior as hovering on links
this.div.addEventListener('mouseover', function(){
if (!this.visible) this.showAtNode(node);
this.stopTimeout();
}.bind(this));
this.div.addEventListener('mouseout', function(){this.extendTimeout(250);}.bind(this));
// Don't trigger body touchstart event when touching within box
this.div.addEventListener('touchstart', function(e){e.stopPropagation();}, {passive: true});
// Close box when touching outside box
document.body.addEventListener('touchstart', function(){this.hide();}.bind(this), {passive: true});
};
+16 -51
View File
@@ -1,68 +1,33 @@
// const marginSmall = 16;
// const marginLarge = 3 * marginSmall;
// const margin = marginSmall + marginLarge;
// const gutter = marginSmall;
// const outsetAmount = margin / 2;
// const numCols = 4;
// const numGutters = numCols - 1;
// const columnWidth = (768 - 2 * marginLarge - numGutters * gutter) / numCols;
//
// const screenwidth = 768;
// const pageWidth = screenwidth - 2 * marginLarge;
// const bodyWidth = pageWidth - columnWidth - gutter;
export function body(selector) {
return `${selector} {
width: auto;
margin-left: 24px;
margin-right: 24px;
box-sizing: border-box;
}
@media(min-width: 768px) {
${selector} {
margin-left: 72px;
margin-right: 72px;
}
}
@media(min-width: 1080px) {
${selector} {
margin-left: calc(50% - 984px / 2);
width: 648px;
}
grid-column: margin-left / body;
}
`;
}
export function page(selector) {
return `${selector} {
width: auto;
margin-left: 24px;
margin-right: 24px;
box-sizing: border-box;
}
@media(min-width: 768px) {
${selector} {
margin-left: 72px;
margin-right: 72px;
}
}
@media(min-width: 1080px) {
${selector} {
width: 984px;
margin-left: auto;
margin-right: auto;
}
grid-column: margin-left / page;
}
`;
}
export function screen(selector) {
return `${selector} {
width: auto;
margin-left: 24px;
margin-right: 24px;
box-sizing: border-box;
}
@media(min-width: 768px) {
${selector} {
margin-left: 72px;
margin-right: 72px;
}
}
@media(min-width: 1080px) {
${selector} {
margin-left: auto;
margin-right: auto;
width: auto;
}
}
grid-column: start / end;
}
`;
}
+8 -7
View File
@@ -2,14 +2,15 @@
export const Template = (name, templateString, useShadow = true) => {
const template = document.createElement('template');
template.innerHTML = templateString;
if (useShadow && 'ShadyCSS' in window) {
ShadyCSS.prepareTemplate(template, name);
}
return (superclass) => {
const template = document.createElement('template');
template.innerHTML = templateString;
if (useShadow && 'ShadyCSS' in window) {
ShadyCSS.prepareTemplate(template, name);
}
return class extends superclass {
static get is() { return name; }
+12 -7
View File
@@ -1,12 +1,17 @@
d-article {
display: block;
color: rgba(0, 0, 0, 0.8);
padding-top: 36px;
padding-top: 0;
padding-bottom: 72px;
overflow: hidden;
font-size: 16px;
font-size: 14px;
line-height: 1.6em;
border-top: 1px solid rgba(0, 0, 0, 0.2);
/*border-top: 1px solid rgba(0, 0, 0, 0.2);*/
}
@media(min-width: 768px) {
d-article {
font-size: 16px;
}
}
@media(min-width: 1024px) {
d-article {
@@ -17,10 +22,10 @@ d-article {
/* H2 */
d-article h2 {
font-weight: 400;
font-weight: 600;
font-size: 26px;
line-height: 1.25em;
margin-top: 36px;
margin-top: 16px;
margin-bottom: 24px;
padding-bottom: 24px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
@@ -51,7 +56,7 @@ d-article h1 + h2 {
/* H3 */
d-article h3 {
font-weight: 400;
font-weight: 600;
font-size: 20px;
line-height: 1.4em;
margin-top: 36px;
+6 -45
View File
@@ -1,16 +1,14 @@
html {
font-size: 20px;
line-height: 1rem;
/*font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", sans-serif;*/
font-family: "Libre Franklin", "Helvetica Neue", sans-serif;
text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
body {
margin: 0;
/*background-color: hsl(223, 9%, 25%);*/
}
a {
@@ -33,53 +31,16 @@ table th {
table thead {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
table thead th {
padding-bottom: 0.5em;
}
table tbody :first-child td {
padding-top: 0.5em;
}
/*
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
pre {
overflow: auto;
max-width: 100%;
}
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}*/
+168 -77
View File
@@ -1,22 +1,97 @@
/*
Column: 60px
Gutter: 24px
@supports not (display: grid) {
d-article,
d-title,
d-byline,
d-appendix,
distill-footer {
display: block;
padding: 8px;
}
}
Body: 648px
- 8 columns
- 7 gutters
Middle: 816px
Page: 984px
- 12 columns
- 11 gutters
*/
d-article,
d-title,
d-byline,
d-appendix,
distill-footer {
display: grid;
justify-items: stretch;
grid-template-columns: [start] 8px [margin-left-outset] 8px [margin-left] 1fr [body] 0px [page] 8px [body-outset] 0px [page-outset] 8px [end];
}
@media(min-width: 768px) {
d-article,
d-title,
d-byline,
d-appendix,
distill-footer {
grid-template-columns: [start] 32px [margin-left-outset] 32px [margin-left] 3fr [body] 32px [body-outset] 1fr [page] 32px [page-outset] 32px [end];
}
}
@media(min-width: 1024px) {
d-article,
d-title,
d-byline,
d-appendix,
distill-footer {
grid-template-columns: [start] 1fr [margin-left-outset] 32px [margin-left] 672px [body] 32px [body-outset] 224px [page] 32px [page-outset] 1fr [end];
}
}
d-appendix,
d-article > d-title,
d-article > d-title > d-byline,
d-article > distill-footer {
grid-column: start / end;
}
.l-body,
.l-body-outset,
d-article > * {
grid-column: margin-left / body;
}
.l-page {
grid-column: margin-left / page;
}
.l-body-outset {
grid-column: margin-left-outset / body-outset;
}
.l-page-outset {
grid-column: margin-left-outset / page-outset;
}
.l-screen {
grid-column: start / end;
}
.l-screen-inset {
grid-column: start / end;
padding-left: 16px;
padding-left: 16px;
}
/* Aside */
aside {
grid-column: margin-left / body;
}
@media(min-width: 768px) {
aside {
grid-column: body-outset / page;
font-size: 14px;
line-height: 1.3;
}
}
/*
.l-body,
.l-page,
.l-page-outset,
.l-middle,
.l-middle-outset,
d-article > div,
d-article > p,
d-article > h1,
@@ -40,20 +115,32 @@ d-article section > ul,
d-article section > d-abstract,
d-article section > d-code,
d-article section > d-math,
d-article section > table, {
width: auto;
margin-left: 24px;
margin-right: 24px;
d-article section > table {
width: calc(100% - 32px);
margin-left: 16px;
margin-right: 16px;
box-sizing: border-box;
}
.l-body-outset,
.l-page-outset,
.l-middle-outset {
width: calc(100% - 16px);
margin-left: 8px;
margin-right: 8px;
}
.l-screen {
margin-left: 0px;
margin-right: 0px;
width: 100%;
background-color: #F8F8FC;
border-top: 1px solid #E8E8EC;
border-bottom: 1px solid #E8E8EC;
}
@media(min-width: 768px) {
.l-body,
.l-body-outset,
.l-page,
.l-page-outset,
.l-middle,
.l-middle-outset,
d-article > div,
d-article > p,
d-article > h1,
@@ -78,12 +165,42 @@ d-article section > table, {
d-article section > d-code,
d-article section > d-math,
d-article section > table {
margin-left: 72px;
margin-right: 72px;
margin-left: 64px;
width: calc((100% - 2 * 64px - 3 * 16px)/4*3 + 2*16px );
}
.l-body-outset {
margin-left: 32px;
width: calc((100% - 2 * 64px - 3 * 16px)/4*3 + 2*16px + 64px );;
}
.l-middle,
.l-middle-outset,
.l-page {
margin-left: 64px;
margin-right: 64px;
width: calc(100% - 2*64px);
}
.l-page-outset {
margin-left: 32px;
margin-right: 32px;
width: calc(100% - 64px);
}
.margin {
font-size: 14px;
line-height: normal;
clear: both;
float: right;
margin-top: 0;
margin-left: 0;
margin-right: 64px;
width: calc((100% - 2 * 64px - 3 * 16px)/4);
}
}
@media(min-width: 1080px) {
@media(min-width: 1024px) {
.l-body,
d-article > div,
d-article > p,
@@ -107,67 +224,42 @@ d-article section > table, {
d-article section > d-code,
d-article section > d-math,
d-article section > table {
margin-left: calc(50% - 984px / 2);
width: 648px;
margin-left: calc(50% - (1024px - 2*64px) / 2);
width: 668px;
}
.l-body-outset,
d-article .l-body-outset {
margin-left: calc(50% - 984px / 2 - 96px/2);
width: calc(648px + 96px);
.l-body-outset {
margin-left: calc((50% - (1024px - 2*64px) / 2) - 32px);
width: calc(668px + 64px)
}
.l-middle,
d-article .l-middle {
width: 816px;
margin-left: calc(50% - 984px / 2);
margin-right: auto;
}
.l-middle-outset,
d-article .l-middle-outset {
width: calc(816px + 96px);
margin-left: calc(50% - 984px / 2 - 48px);
margin-right: auto;
.l-page {
margin-left: calc(50% - (1024px - 2*64px) / 2);
width: calc(100% - 2* (50% - (1024px - 2*64px) / 2));
}
d-article > h1,
d-article section > h1,
.l-page,
d-article .l-page,
d-article.centered .l-page {
width: 984px;
margin-left: auto;
margin-right: auto;
.l-page-outset {
margin-left: calc((50% - (1024px - 2*64px) / 2) - 32px);
width: calc(100% - 2* (50% - (1024px - 2*64px) / 2) + 64px);
}
.l-page-outset,
d-article .l-page-outset,
d-article.centered .l-page-outset {
width: 1080px;
margin-left: auto;
margin-right: auto;
}
.l-screen,
d-article .l-screen,
d-article.centered .l-screen {
margin-left: auto;
margin-right: auto;
width: auto;
}
.l-screen-inset,
d-article .l-screen-inset,
d-article.centered .l-screen-inset {
margin-left: 24px;
margin-right: 24px;
width: auto;
}
.l-gutter,
d-article .l-gutter {
.margin {
font-size: 14px;
line-height: normal;
clear: both;
float: right;
margin-top: 0;
margin-left: 24px;
margin-right: calc((100vw - 984px) / 2 + 168px);
width: calc((984px - 648px) / 2 - 24px);
margin-left: 0;
margin-right: calc(50% - (1024px - 2*64px) / 2);
width: 206px;
}
/* Side */
/*
.side.l-body,
d-article .side.l-body {
clear: both;
@@ -217,8 +309,7 @@ d-article section > table, {
width: 624px;
margin-right: calc((100vw - 984px) / 2);
}
}
}*/
/* Rows and Columns */
+11 -1
View File
@@ -1,20 +1,30 @@
@media print {
@page {
size: 8in 11in;
@bottom-right {
content: counter(page) " of " counter(pages);
}
}
html {
/* no general margins -- CSS Grid takes care of those */
}
p, code {
page-break-inside: avoid;
}
h2, h3 {
page-break-after: avoid;
}
d-header {
visibility: hidden;
}
d-footer {
display: none!important;
}
}
+53
View File
@@ -0,0 +1,53 @@
/* eslint-env node, mocha */
/* Extractors */
import ExtractFrontmatter from './extractors/front-matter';
import ExtractBibliography from './extractors/bibliography';
import ExtractCitations from './extractors/citations';
const extractors = [
ExtractFrontmatter,
ExtractBibliography,
ExtractCitations,
];
/* Transforms */
import HTML from './transforms/html';
import Polyfills from './transforms/polyfills';
import Meta from './transforms/meta';
import Typeset from './transforms/typeset';
// import Bibliography from './transforms/bibliography';
const transforms = [
HTML, Polyfills, Meta, Typeset//, Bibliography
];
/* Distill Transforms */
import DistillHeader from './distill-transforms/distill-header';
import DistillAppendix from './distill-transforms/distill-appendix';
import DistillFooter from './distill-transforms/distill-footer';
const distillTransforms = [
DistillHeader, DistillAppendix, DistillFooter,
];
/* Exported functions */
export function render(dom, data) {
// first, we collect static data from the dom
for (const extract of extractors) {
extract(dom, data);
}
// secondly we use it to transform parts of the dom
for (const transform of transforms) {
transform(dom, data);
}
// the function calling us can now use the transformed dom and filled data object
}
export function distillify(dom, data) {
// thirdly, we optionally use these additional transforms when publishing on the Distill website
for (const transform of distillTransforms) {
transform(dom, data);
}
}
-89
View File
@@ -1,89 +0,0 @@
const html = `
<style>
dt-appendix {
display: block;
font-size: 14px;
line-height: 24px;
margin-bottom: 0;
border-top: 1px solid rgba(0,0,0,0.1);
color: rgba(0,0,0,0.5);
background: rgb(250, 250, 250);
padding-top: 36px;
padding-bottom: 60px;
}
dt-appendix h3 {
font-size: 16px;
font-weight: 500;
margin-top: 18px;
margin-bottom: 18px;
color: rgba(0,0,0,0.65);
}
dt-appendix .citation {
font-size: 11px;
line-height: 15px;
border-left: 1px solid rgba(0, 0, 0, 0.1);
padding-left: 18px;
border: 1px solid rgba(0,0,0,0.1);
background: rgba(0, 0, 0, 0.02);
padding: 10px 18px;
border-radius: 3px;
color: rgba(150, 150, 150, 1);
overflow: hidden;
margin-top: -12px;
}
dt-appendix .references {
font-size: 12px;
line-height: 20px;
}
dt-appendix a {
color: rgba(0, 0, 0, 0.6);
}
dt-appendix ol,
dt-appendix ul {
padding-left: 24px;
}
</style>
<div class="l-body">
<h3>References</h3>
<dt-bibliography></dt-bibliography>
<h3 id="citation">Errors, Reuse, and Citation</h3>
<p>If you see mistakes or want to suggest changes, please <a class="github-issue">create an issue on GitHub</a>.</p>
<p>Diagrams and text are licensed under Creative Commons Attribution <a href="https://creativecommons.org/licenses/by/2.0/">CC-BY 2.0</a>, unless noted otherwise, with the <a class="github">source available on GitHub</a>. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: “Figure from …”.</p>
<p>For attribution in academic contexts, please cite this work as</p>
<pre class="citation short"></pre>
<p>BibTeX citation</p>
<pre class="citation long"></pre>
</div>
`;
export default function(dom, data) {
let el = dom.querySelector('dt-appendix');
if (el) {
let oldHtml = el.innerHTML;
el.innerHTML = html;
let div = el.querySelector('div.l-body');
if (dom.querySelector('dt-fn')) {
div.innerHTML = '<h3>Footnotes</h3><dt-fn-list></dt-fn-list>' + div.innerHTML;
}
div.innerHTML = oldHtml + div.innerHTML;
if (data.githubCompareUpdatesUrl) {
div.innerHTML = `<h3>Updates</h3><p><a href="${data.githubCompareUpdatesUrl}">View all changes</a> to this article since it was first published.</p>` + div.innerHTML;
}
el.querySelector('a.github').setAttribute('href', data.githubUrl);
el.querySelector('a.github-issue').setAttribute('href', data.githubUrl + '/issues/new');
el.querySelector('.citation.short').textContent = data.concatenatedAuthors + ', ' + '"' + data.title + '", Distill, ' + data.publishedYear + '.';
var bibtex = '@article{' + data.slug + ',\n';
bibtex += ' author = {' + data.bibtexAuthors + '},\n';
bibtex += ' title = {' + data.title + '},\n';
bibtex += ' journal = {Distill},\n';
bibtex += ' year = {' + data.publishedYear + '},\n';
bibtex += ' note = {' + data.url + '}\n';
bibtex += '}';
el.querySelector('.citation.long').textContent = bibtex;
}
}
+23 -42
View File
@@ -1,46 +1,27 @@
import bibtexParse from 'bibtex-parse-js';
import { renderBibliography, templateString } from '../components/d-bibliography';
export default function(dom, data) {
let el = dom.querySelector('script[type="text/bibliography"]');
let citations = [];
let bibliography = {};
//TODO If we don't have a local element, make a request for the document.
if (el) {
let rawBib = el.textContent;
let parsed = bibtexParse.toJSON(rawBib);
if(parsed) {
parsed.forEach(e => {
for (var k in e.entryTags){
var val = e.entryTags[k];
val = val.replace(/[\t\n ]+/g, ' ');
val = val.replace(/{\\["^`.'acu~Hvs]( )?([a-zA-Z])}/g,
(full, x, char) => char);
val = val.replace(/{\\([a-zA-Z])}/g,
(full, char) => char);
e.entryTags[k] = val;
}
bibliography[e.citationKey] = e.entryTags;
bibliography[e.citationKey].type = e.entryType;
});
}
var citeTags = [].slice.apply(dom.querySelectorAll('dt-cite'));
citeTags.forEach(el => {
let key = el.getAttribute('key');
if (key) {
let citationKeys = key.split(',');
citationKeys.forEach(key => {
if (citations.indexOf(key) == -1){
citations.push(key);
if (!(key in bibliography)){
console.warn('No bibliography entry found for: ' + key);
}
}
});
}
});
const bibliographyTag = dom.querySelector('d-bibliography');
if (!bibliographyTag) {
console.warn('No bibliography tag found!');
return;
}
data.bibliography = bibliography;
data.citations = citations;
const bibliographyEntries = new Map(data.citations.map( citationKey => {
const entry = data.bibliography.get(citationKey);
return [citationKey, entry];
}));
const prerenderedBibliography = dom.createElement('d-bibliography-prerendered');
const template = dom.createElement('template');
template.innerHTML = templateString;
const clone = dom.importNode(template.content, true);
prerenderedBibliography.innerHTML = template.content;
renderBibliography(prerenderedBibliography, bibliographyEntries, dom);
bibliographyTag.parentElement.insertBefore(bibliographyTag, prerenderedBibliography);
bibliographyTag.parentElement.removeChild(bibliographyTag);
}
-52
View File
@@ -1,52 +0,0 @@
import logo from './distill-logo.svg';
let html = `
<style>
dt-footer {
display: block;
color: rgba(255, 255, 255, 0.4);
font-weight: 300;
padding: 40px 0;
border-top: 1px solid rgba(0, 0, 0, 0.1);
background-color: hsl(200, 60%, 15%);
text-align: center;
}
dt-footer .logo svg {
width: 24px;
position: relative;
top: 4px;
margin-right: 2px;
}
dt-footer .logo svg path {
fill: none;
stroke: rgba(255, 255, 255, 0.8);
stroke-width: 3px;
}
dt-footer .logo {
font-size: 17px;
font-weight: 200;
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
margin-right: 6px;
}
</style>
<div class="l-screen-inset">
<a href="/" class="logo">
${logo}
Distill
</a> is dedicated to clear explanations of machine learning
</div>
`;
export default function(dom, data) {
let el = dom.querySelector('dt-footer');
if(el) {
el.innerHTML = html;
} else {
let footer = dom.createElement('dt-footer');
footer.innerHTML = html;
let b = dom.querySelector('body');
b.appendChild(footer);
}
}
-92
View File
@@ -1,92 +0,0 @@
import logo from './distill-logo.svg';
const html = `
<style>
dt-header {
display: block;
position: relative;
height: 60px;
background-color: hsl(200, 60%, 15%);
width: 100%;
box-sizing: border-box;
z-index: 2;
color: rgba(0, 0, 0, 0.8);
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);
}
dt-header .content {
height: 70px;
}
dt-header a {
font-size: 16px;
height: 60px;
line-height: 60px;
text-decoration: none;
color: rgba(255, 255, 255, 0.8);
padding: 22px 0;
}
dt-header a:hover {
color: rgba(255, 255, 255, 1);
}
dt-header svg {
width: 24px;
position: relative;
top: 4px;
margin-right: 2px;
}
@media(min-width: 1080px) {
dt-header {
height: 70px;
}
dt-header a {
height: 70px;
line-height: 70px;
padding: 28px 0;
}
dt-header .logo {
}
}
dt-header svg path {
fill: none;
stroke: rgba(255, 255, 255, 0.8);
stroke-width: 3px;
}
dt-header .logo {
font-size: 17px;
font-weight: 200;
}
dt-header .nav {
float: right;
font-weight: 300;
}
dt-header .nav a {
font-size: 12px;
margin-left: 24px;
text-transform: uppercase;
}
</style>
<div class="content l-page">
<a href="/" class="logo">
${logo}
Distill
</a>
<div class="nav">
<a href="/faq">About</a>
<a href="https://github.com/distillpub">GitHub</a>
<!-- https://twitter.com/distillpub -->
</div>
</div>
`;
export default function(dom, data) {
let el = dom.querySelector('dt-header');
if(el) {
el.innerHTML = html;
} else {
let header = dom.createElement('dt-header');
header.innerHTML = html;
let b = dom.querySelector('body');
b.insertBefore(header, b.firstChild);
}
}
+9 -4
View File
@@ -1,17 +1,22 @@
export default function(dom) {
const head = dom.querySelector('head');
// set language to 'en'
if (!dom.querySelector('html').getAttribute('lang')) {
dom.querySelector('html').setAttribute('lang', 'en');
}
let head = dom.querySelector('head');
// set charset to 'utf-8'
if (!dom.querySelector('meta[charset]')) {
let meta = dom.createElement('meta');
const meta = dom.createElement('meta');
meta.setAttribute('charset', 'utf-8');
head.appendChild(meta);
}
// set viewport
if (!dom.querySelector('meta[name=viewport]')) {
let meta = dom.createElement('meta');
const meta = dom.createElement('meta');
meta.setAttribute('name', 'viewport');
meta.setAttribute('content', 'width=device-width, initial-scale=1');
head.appendChild(meta);
+1 -2
View File
@@ -1,4 +1,4 @@
import favicon from './distill-favicon.base64';
import favicon from '../assets/distill-favicon.base64';
export default function(dom, data) {
let head = dom.querySelector('head');
@@ -68,7 +68,6 @@ export default function(dom, data) {
meta('citation_publisher', journal.publisher);
if (data.publishedDate){
let zeroPad = (n) => { return n < 10 ? '0' + n : n; };
meta('citation_publication_date', `${data.publishedYear}/${data.publishedMonthPadded}/${data.publishedDayPadded}`);
}
+31
View File
@@ -0,0 +1,31 @@
const webcomponentPath = '../dist/webcomponents-lite.js';
const template = `
if ('registerElement' in document &&
'import' in document.createElement('link') &&
'content' in document.createElement('template')) {
// Platform supports webcomponents natively! :-)
} else {
// Platform does not support webcomponents--loading polyfills synchronously.
const scriptTag = document.createElement('script');
scriptTag.src = '${webcomponentPath}';
scriptTag.async = false;
document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling);
}
`;
export default function render(dom) {
// create polyfill script tag
const polyfillScriptTag = dom.createElement('script');
polyfillScriptTag.innerHTML = template;
polyfillScriptTag.id = 'polyfills';
// insert at appropriate position--before any other script tag
const head = dom.querySelector('head');
const firstScriptTag = dom.querySelector('script');
if (firstScriptTag) {
head.insertBefore(polyfillScriptTag, firstScriptTag);
} else {
head.appendChild(polyfillScriptTag);
}
}
+9 -5
View File
@@ -1,4 +1,4 @@
export default function(dom, data) {
export default function(dom) {
var textNodes = dom.createTreeWalker(
dom.body,
@@ -10,6 +10,7 @@ export default function(dom, data) {
if (text && acceptNode(n)) {
text = quotes(text);
text = punctuation(text);
text = ligatures(text);
n.nodeValue = text;
}
}
@@ -30,6 +31,9 @@ function acceptNode(node) {
parent.nodeName !== 'D-CODE' &&
parent.nodeName !== 'D-BIBLIOGRAPHY' &&
parent.nodeName !== 'D-FOOTER' &&
parent.nodeName !== 'D-APPENDIX' &&
parent.nodeName !== 'D-FRONTMATTER' &&
parent.nodeName !== 'D-TOC' &&
parent.nodeType !== 8 && //comment nodes
!isMath;
}
@@ -57,7 +61,7 @@ function punctuation(text){
// Nbsp for punc with spaces
var NBSP = '\u00a0';
var NBSP_PUNCTUATION_START = /([«¿¡]) /g;
var NBSP_PUNCTUATION_END = / ([\!\?:;\.,‽»])/g;
var NBSP_PUNCTUATION_END = / ([!?:;.,‽»])/g;
text = text.replace(NBSP_PUNCTUATION_START, '$1' + NBSP);
text = text.replace(NBSP_PUNCTUATION_END, NBSP + '$1');
@@ -68,7 +72,7 @@ function punctuation(text){
function quotes(text) {
text = text
.replace(/(\W|^)"([^\s\!\?:;\.,‽»])/g, '$1\u201c$2') // beginning "
.replace(/(\W|^)"([^\s!?:;.,‽»])/g, '$1\u201c$2') // beginning "
.replace(/(\u201c[^"]*)"([^"]*$|[^\u201c"]*\u201c)/g, '$1\u201d$2') // ending "
.replace(/([^0-9])"/g,'$1\u201d') // remaining " at end of word
.replace(/(\W|^)'(\S)/g, '$1\u2018$2') // beginning '
@@ -81,8 +85,8 @@ function quotes(text) {
.replace(/'/g, '\u2032');
// Allow escaped quotes
text = text.replace(/\\“/, '\"');
text = text.replace(/\\”/, '\"');
text = text.replace(/\\“/, '"');
text = text.replace(/\\”/, '"');
text = text.replace(/\\/, '\'');
text = text.replace(/\\/, '\'');