Project reorganization, add editorconfig and linter

This commit is contained in:
Ludwig Schubert
2017-08-09 16:47:35 -07:00
parent 07c7527734
commit 11eda0fc49
75 changed files with 1120 additions and 17117 deletions
+18
View File
@@ -0,0 +1,18 @@
import { Template } from "../mixins/template";
import { body } from "../helpers/layout";
const T = Template("d-abstract", `
<style>
d-abstract {
display: block;
font-size: 23px;
line-height: 1.7em;
margin-bottom: 140px;
}
${body("d-abstract")}
</style>
`, false);
export class Abstract extends T(HTMLElement) {
}
+23
View File
@@ -0,0 +1,23 @@
import { Template } from "../mixins/template";
const T = Template('d-acknowledgements', `
<style>
::slotted(h3) {
font-size: 15px;
font-weight: 500;
margin-top: 20px;
margin-bottom: 0;
color: rgba(0,0,0,0.65);
line-height: 1em;
}
::slotted(*) a {
color: rgba(0, 0, 0, 0.6);
}
</style>
<slot></slot>
`);
export class Acknowledgements extends T(HTMLElement) {
}
+30
View File
@@ -0,0 +1,30 @@
import { Template } from "../mixins/template";
import { page } from "../helpers/layout";
const T = Template("d-appendix", `
<style>
:host {
display: block;
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);
padding-top: 36px;
padding-bottom: 48px;
}
${page(".l-body")}
</style>
<div class="l-body">
<slot></slot>
</div>
`);
export class Appendix extends T(HTMLElement) {
}
+26
View File
@@ -0,0 +1,26 @@
import { Template } from '../mixins/template';
import { Controller } from '../controller';
const T = Template('d-article', `
<style></style>
`, false);
export class Article extends T(HTMLElement) {
// constructor() {
// super();
// }
connectedCallback() {
for (const [functionName, callback] of Object.entries(Controller.listeners)) {
if (typeof callback === 'function') {
document.addEventListener(functionName, callback);
} else {
console.error('Controller listeners need to be functions!')
}
}
}
}
+136
View File
@@ -0,0 +1,136 @@
import { Template } from "../mixins/template";
import { Mutating } from "../mixins/mutating";
import { collectCitations } from './d-cite'
import bibtexParse from "bibtex-parse-js";
import { bibliography_cite } from "../helpers/citation";
const T = Template('d-bibliography', `
<style>
.references {
font-size: 12px;
line-height: 20px;
}
.title {
font-weight: 600;
}
ol {
padding: 0 0 0 18px;
}
li {
margin-bottom: 12px;
}
h3 {
font-size: 15px;
font-weight: 500;
margin-top: 20px;
margin-bottom: 0;
color: rgba(0,0,0,0.65);
line-height: 1em;
}
a {
color: rgba(0, 0, 0, 0.6);
}
</style>
<h3>References</h3>
<ol></ol>
`);
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;
}
entry.entryTags.type = entry.entryType;
// add to bibliography
bibliography.set(entry.citationKey, entry.entryTags);
}
return bibliography;
}
export class Bibliography extends T(HTMLElement) {
constructor() {
super()
// set up mutation observer
const options = {childList: true, subtree: true};
const observer = new MutationObserver( (mutations) => {
observer.disconnect();
this.parseIfPossible();
observer.observe(this, options);
});
// ...and listen for changes
observer.observe(this, options);
}
parseIfPossible() {
if (this.firstElementChild && this.firstElementChild.tagName === 'SCRIPT') {
const newBibtex = this.firstElementChild.textContent;
if (this.bibtex !== newBibtex) {
this.bibtex = newBibtex;
const bibliography = parseBibtex(this.bibtex);
this.notify(bibliography);
}
}
};
connectedCallback() {
this.list = this.root.querySelector('ol');
// bibliography is initially hidden
this.root.host.style.display = 'none';
// this.parseIfPossible();
// Store.subscribeTo('citations', (citations) => {
// // ensure citations list is visible
// this.root.host.style.display = 'initial';
// this.list.innerHTML = '';
// for (const key of citations) {
// const bibliography = Store.get('bibliography');
// const entry = bibliography.get(key);
// // construct and append list item to show citation
// const listItem = document.createElement('li');
// listItem.id = key;
// listItem.innerHTML = bibliography_cite(entry);
// this.list.appendChild(listItem);
// }
// });
}
notify(bibliography) {
const options = { detail: bibliography, bubbles: true };
const event = new CustomEvent('onBibliographyChanged', options);
this.dispatchEvent(event);
}
set entries(newEntries) {
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);
}
}
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);
}
}
+149
View File
@@ -0,0 +1,149 @@
import { Template } from "../mixins/template";
import { page } from "../helpers/layout";
const T = Template("d-byline", `
<style>
d-byline {
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);*/
color: rgba(0, 0, 0, 0.6);
padding-top: 20px;
padding-bottom: 20px;
}
${page(".byline")}
d-article.centered {
text-align: center;
}
a,
d-article a {
color: rgba(0, 0, 0, 0.8);
text-decoration: none;
border-bottom: none;
}
d-article a:hover {
text-decoration: underline;
border-bottom: none;
}
.authors {
text-align: left;
}
.name {
font-weight: 600;
display: inline;
text-transform: uppercase;
}
.affiliation {
display: inline;
}
.date {
display: block;
text-align: left;
}
.year, .month {
display: inline;
}
.citation {
display: block;
text-align: left;
}
.citation div {
display: inline;
}
@media(min-width: 1080px) {
d-byline {
border-bottom: none;
}
a:hover {
color: rgba(0, 0, 0, 0.9);
}
.authors {
display: inline-block;
}
.author {
display: inline-block;
margin-right: 12px;
/*padding-left: 20px;*/
/*border-left: 1px solid #ddd;*/
}
.affiliation {
display: block;
}
.author:last-child {
margin-right: 0;
}
.name {
display: block;
}
.date {
border-left: 1px solid rgba(0, 0, 0, 0.1);
padding-left: 15px;
margin-left: 15px;
display: inline-block;
}
.year, .month {
display: block;
}
.citation {
border-left: 1px solid rgba(0, 0, 0, 0.15);
padding-left: 15px;
margin-left: 15px;
display: inline-block;
}
.citation div {
display: block;
}
}
</style>
<div class='byline'>
</div>
`, false);
export function bylineTemplate(frontMatter) {
return `
<div class="authors">
${frontMatter.authors.map( author => `<div class="author">
${author.personalURL ?
`<a class="name" href="${author.personalURL}">${author.name}</a>`
:
`<div class="name">${author.name}</div>`
}
${author.affiliationURL ?
`<a class="affiliation" href="${author.affiliationURL}">${author.affiliation}</a>`
:
`<div class="affiliation">${author.affiliation}</div>`
}
</div>`).join('\n')}
</div>
<div class="date">
<div class="month">${frontMatter.publishedMonth}. ${frontMatter.publishedDay}</div>
<div class="year">${frontMatter.publishedYear}</div>
</div>
<a class="citation" href="#citation">
<div>Citation:</div>
<div>${frontMatter.concatenatedAuthors}, ${frontMatter.publishedYear}</div>
</a>
`;
}
export class Byline extends T(HTMLElement) {
set frontMatter(frontMatter) {
const container = this.querySelector('.byline');
container.innerHTML = bylineTemplate(frontMatter);
}
}
+156
View File
@@ -0,0 +1,156 @@
import { Template } from "../mixins/template";
import { hover_cite } from "../helpers/citation";
import { HoverBox } from "../helpers/hover-box";
const T = Template('d-cite', `
<style>
.citation {
color: hsla(206, 90%, 20%, 0.7);
}
.citation-number {
cursor: default;
white-space: nowrap;
font-family: -apple-system, BlinkMacSystemFont, "Roboto", Helvetica, sans-serif;
font-size: 75%;
color: hsla(206, 90%, 20%, 0.7);
display: inline-block;
line-height: 1.1em;
text-align: center;
position: relative;
top: -2px;
margin: 0 2px;
}
figcaption .citation-number {
font-size: 11px;
font-weight: normal;
top: -2px;
line-height: 1em;
}
</style>
<div style="display: none;" id="hover-box" class="dt-hover-box">
</div>
<span id="citation-" class="citation">
<slot></slot>
<span class="citation-number"></span>
</span>
`);
export function collectCitations() {
const citations = new Set();
const citeTags = document.querySelectorAll('d-cite');
for (const tag of citeTags) {
const keys = tag.getAttribute('key').split(',');
for (const key of keys) {
citations.add(key);
}
}
return [...citations];
}
export class Cite extends T(HTMLElement) {
/* Lifecycle */
constructor() {
super()
// Cite.currentId += 1;
// this.citeId = Cite.currentId;
}
connectedCallback() {
// this.notify();
this.hoverDiv = this.root.querySelector('.dt-hover-box');
this.outerSpan = this.root.querySelector('#citation-');
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);
}
/* Observed Attributes */
// renderCitationNumbers(citations) {
// const numbers = this._keys.map( (key) => {
// const index = citations.indexOf(key);
// return index == -1 ? '?' : index + 1 + '';
// });
// const text = "[" + numbers.join(", ") + "]";
// this.innerSpan.textContent = text;
// }
/* observe 'key' attribute */
static get observedAttributes() {
return ['key'];
}
attributeChangedCallback(name, oldValue, newValue) {
const eventName = oldValue ? 'onCiteKeyChanged' : 'onCiteKeyCreated';
const keys = newValue.split(',');
const options = { detail: [this, keys], bubbles: true };
const event = new CustomEvent(eventName, options);
document.dispatchEvent(event);
}
set key(value) {
this.setAttribute('key', value);
}
get key() {
return this.getAttribute('key');
}
get keys() {
return this.getAttribute('key').split(',');
}
/* Setters & Rendering */
set numbers(numbers) {
const numberStrings = numbers.map( index => {
return index == -1 ? '?' : index + 1 + '';
});
const textContent = "[" + numberStrings.join(", ") + "]";
const innerSpan = this.root.querySelector('.citation-number');
innerSpan.textContent = textContent;
}
set entries(entries) {
const div = this.root.querySelector('#hover-box');
div.innerHTML = entries.map(hover_cite).join('<br><br>');
}
// renderContent() {
// const bibliography = document.querySelector('d-bibliography');
// if (bibliography && bibliography.finishedLoading) {
// customElements.whenDefined('d-bibliography').then( () => {
// const keys = this.key.split(",");
//
// // set up hidden hover box
// const div = this.root.querySelector('.dt-hover-box');
// div.innerHTML = keys.map( (key) => {
// return bibliography.getEntry(key);
// }).map(hover_cite).join('<br><br>');
// div.id ='dt-cite-hover-box-' + this.citeId;
//
// // set up visible citation marker
// const outerSpan = this.root.querySelector('#citation-');
// outerSpan.id = `citation-${this.citeId}`;
// // outerSpan.setAttribute('data-hover', dataHoverString); // directly tell HoverBox instead?
// const innerSpan = this.root.querySelector('.citation-number');
// innerSpan.textContent = inline_cite_short(keys, bibliography);
//
// HoverBox.get_box(div).bind(outerSpan);
// });
// } else {
// console.error(`You used a d-cite tag (${key}) without including a d-bibliography tag in your article. We can't lookup your citation this way.`)
// }
// }
}
+74
View File
@@ -0,0 +1,74 @@
import Prism from "prismjs";
import "prismjs/components/prism-python";
import "prismjs/components/prism-clike";
import css from "prismjs/themes/prism.css";
import { Template } from "../mixins/template.js"
import { Mutating } from "../mixins/mutating.js"
const T = Template("d-code", `
<style>
code {
white-space: nowrap;
background: rgba(0, 0, 0, 0.04);
border-radius: 2px;
padding: 4px 7px;
font-size: 15px;
color: rgba(0, 0, 0, 0.6);
}
pre code {
display: block;
background: white;
border-left: 3px solid rgba(0, 0, 0, 0.05);
padding: 0 0 0 24px;
}
${css}
</style>
<code id="code-container"></code>
`);
export class Code extends Mutating(T(HTMLElement)) {
renderContent() {
// check if language can be highlighted
this.languageName = this.getAttribute('language');
if (!this.languageName) {
console.warn(`You need to provide a language attribute to your <d-code> block to let us know how to highlight your code; e.g.:\n <d-code language="python">zeros = np.zeros(shape)</d-code>.`);
return;
}
const language = Prism.languages[this.languageName];
if (language == undefined) {
console.warn(`Distill does not yet support highlighting your code block in "${this.languageName}".`);
return;
}
let content = this.textContent;
const codeTag = this.shadowRoot.querySelector("#code-container");
if (this.hasAttribute("block")) {
// normalize the tab indents
content = content.replace(/\n/, "");
const tabs = content.match(/\s*/);
content = content.replace(new RegExp("\n" + tabs, "g"), "\n");
content = content.trim();
// wrap code block in pre tag if needed
if (codeTag.parentNode instanceof ShadowRoot) {
const preTag = document.createElement("pre");
this.shadowRoot.removeChild(codeTag)
preTag.appendChild(codeTag);
this.shadowRoot.appendChild(preTag);
}
}
codeTag.className = `language-${this.languageName}`;
codeTag.innerHTML = Prism.highlight(content, language);
}
}
+74
View File
@@ -0,0 +1,74 @@
import { Template } from '../mixins/template';
const T = Template('d-footnote-list', `
<style>
ol {
padding: 0 0 0 18px;
}
li {
margin-bottom: 12px;
}
h3 {
font-size: 15px;
font-weight: 500;
margin-top: 20px;
margin-bottom: 0;
color: rgba(0,0,0,0.65);
line-height: 1em;
}
a {
color: rgba(0, 0, 0, 0.6);
}
a.footnote-backlink {
color: rgba(0,0,0,0.3);
padding-left: 0.5em;
}
</style>
<h3>Footnotes</h3>
<ol></ol>
`);
export class FootnoteList extends T(HTMLElement) {
connectedCallback() {
this.list = this.root.querySelector('ol');
// footnotes list is initially hidden
this.root.host.style.display = 'none';
// look through document and register existing footnotes
// Store.subscribeTo('footnotes', (footnote) => {
// this.renderFootnote(footnote);
// });
}
// TODO: could optimize this to accept individual footnotes?
set footnotes(footnotes) {
this.list.innerHTML = '';
if (footnotes.length) {
// ensure footnote list is visible
this.root.host.style.display = 'initial';
for (const footnote of footnotes) {
// construct and append list item to show footnote
const listItem = document.createElement('li');
listItem.id = footnote.id + '-listing';
listItem.innerHTML = footnote.innerHTML;
const backlink = document.createElement('a');
backlink.setAttribute('class', 'footnote-backlink');
backlink.textContent = '[↩]';
backlink.href = '#' + footnote.id;
listItem.appendChild(backlink);
this.list.appendChild(listItem);
}
} else {
// ensure footnote list is invisible
this.shadowRoot.host.style.display = 'none';
}
}
}
+63
View File
@@ -0,0 +1,63 @@
import { Template } from "../mixins/template.js";
import { HoverBox } from "../helpers/hover-box";
// import { Store } from './store';
const T = Template("d-footnote", `
<style>
d-math[block] {
display: block;
}
</style>
<div style="display: none;" class="dt-hover-box">
<slot id='slot'></slot>
</div>
<sup><span id="fn-" data-hover-ref="" style="cursor:pointer"></span></sup>
`);
export class Footnote extends T(HTMLElement) {
constructor() {
super();
const options = {childList: true, characterData: true, subtree: true};
const observer = new MutationObserver(this.notify);
observer.observe(this, options);
}
notify() {
const options = { detail: this, bubbles: true };
const event = new CustomEvent('onFootnoteChanged', options);
document.dispatchEvent(event);
}
connectedCallback() {
// listen and notify about changes to slotted content
// const slot = this.shadowRoot.querySelector('#slot');
// slot.addEventListener('slotchange', this.notify);
// create numeric ID
Footnote.currentFootnoteId += 1;
const IdString = Footnote.currentFootnoteId.toString();
this.root.host.id = 'd-footnote-' + IdString;
// set up hidden hover box
const div = this.root.querySelector('.dt-hover-box');
div.id = 'dt-fn-hover-box-' + IdString;
// set up visible footnote marker
const span = this.root.querySelector('#fn-');
span.setAttribute('id', 'fn-' + IdString);
span.setAttribute('data-hover-ref', div.id);
span.textContent = IdString;
HoverBox.get_box(div).bind(span);
}
}
Footnote.currentFootnoteId = 0;
+36
View File
@@ -0,0 +1,36 @@
import ymlParse from "js-yaml";
export class FrontMatter extends HTMLElement {
static get is() { return "d-front-matter"; }
constructor() {
super();
const options = {childList: true, characterData: true, subtree: true};
const observer = new MutationObserver( (mutation) => {
const data = this.parse();
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);
document.dispatchEvent(event);
}
}
+28
View File
@@ -0,0 +1,28 @@
import katex from "katex";
import { Mutating } from "../mixins/mutating.js"
import { Template } from "../mixins/template.js"
import katexCSS from "../../node_modules/katex/dist/katex.min.css"
const T = Template("d-math", `
<style>
d-math[block] {
display: block;
}
${katexCSS}
</style>
<span id="katex-container"></span>
`);
export class DMath extends Mutating(T(HTMLElement)) {
renderContent() {
const options = { displayMode: this.hasAttribute("block") };
const container = this.root.querySelector("#katex-container");
katex.render(this.textContent, container, options);
}
}
+18
View File
@@ -0,0 +1,18 @@
import { Template } from "../mixins/template";
import { body } from "../helpers/layout";
const T = Template("d-references", `
<style>
d-references {
display: block;
}
</style>
`, false);
export class References extends T(HTMLElement) {
connectedCallback() {
super.connectedCallback();
}
}
+36
View File
@@ -0,0 +1,36 @@
import { Template } from "../mixins/template";
import { page } from "../helpers/layout";
const T = Template("d-title", `
<style>
:host {
box-sizing: border-box;
display: block;
width: 100%;
margin-bottom: 100px;
}
::slotted(h1) {
padding-top: 140px;
padding-bottom: 24px;
margin: 0;
line-height: 1em;
font-size: 48px;
font-weight: 600;
}
d-byline {
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
${page("::slotted(h1), ::slotted(h2)")}
</style>
<slot></slot>
`);
export class Title extends T(HTMLElement) {
}
+13
View File
@@ -0,0 +1,13 @@
import {Template} from "../mixins/template";
const T = Template("d-toc", `
<style>
d-toc {
display: block;
}
</style>
`, false);
export class TOC extends T(HTMLElement) {
}