mirror of
https://github.com/wassname/template.git
synced 2026-06-28 02:31:42 +08:00
Compare commits
276 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 70d8507938 | |||
| 2e6a0dda6d | |||
| 315e888810 | |||
| 4745281c2b | |||
| ebffcb4416 | |||
| ecce53f1a2 | |||
| f355ff6894 | |||
| f388c39553 | |||
| 11b00b4cee | |||
| 302370c1cf | |||
| b8d26a4dac | |||
| 00076d3123 | |||
| 94bba88924 | |||
| 4c9c387760 | |||
| 33714c9ca4 | |||
| a43db020b1 | |||
| bc68238be9 | |||
| d01e7e9317 | |||
| 19b89f39ee | |||
| ac5a18a7d4 | |||
| ed3aceef86 | |||
| d39819462a | |||
| 4089ccf98f | |||
| f046442753 | |||
| 0ff1261b81 | |||
| 9290b10c24 | |||
| c742b36be6 | |||
| 1a4cd694cd | |||
| 02563c32d6 | |||
| 194bed395f | |||
| 15858468d1 | |||
| 68a0007503 | |||
| 3e3478686e | |||
| 6007a9d7ad | |||
| 3987f71c20 | |||
| 72a47b1a73 | |||
| 95d357c308 | |||
| 5cb9b79559 | |||
| 0dd5846703 | |||
| 30ab1dde97 | |||
| d0bb7455dc | |||
| 40240bd735 | |||
| dbafa7c7b8 | |||
| 1ee5c5f310 | |||
| 16ec5a0f63 | |||
| 0e75be4272 | |||
| 44f14bffe7 | |||
| 31a3478d84 | |||
| 8027f1b13a | |||
| f0a8ba4368 | |||
| 1255afec2c | |||
| ed7cd834f9 | |||
| f5e5acbd67 | |||
| ca1096347f | |||
| 8553a6d7c3 | |||
| 198e273211 | |||
| 8c79954f2d | |||
| c28b4afe04 | |||
| 017bb45b7c | |||
| ba58e1928c | |||
| d9693db537 | |||
| 804865d0f0 | |||
| 489f070ea6 | |||
| dd38b2b908 | |||
| 7f0fb66ec5 | |||
| fe7b4748fc | |||
| 0ab27e1382 | |||
| 044acd8f03 | |||
| 75e132e77f | |||
| ba4c35e5ca | |||
| a65f546151 | |||
| 9526d99390 | |||
| ffb5eaf3f7 | |||
| 90dca7580f | |||
| 1b2d902c0e | |||
| 1c75848b12 | |||
| 75a0a8228a | |||
| defd752b6e | |||
| de4514bcf3 | |||
| c011e67c96 | |||
| a1be3babff | |||
| 67f9429860 | |||
| 44414a5a67 | |||
| db254c3366 | |||
| e6202c5442 | |||
| ab57a90b29 | |||
| c69f39e25a | |||
| 31982778f8 | |||
| 1fe29b6a32 | |||
| bd3749547b | |||
| ff7fccc79c | |||
| b8c87b1baf | |||
| d8d00e2102 | |||
| 37a714f399 | |||
| efbb6e6a92 | |||
| 65a9563d3f | |||
| 5d4f5ff530 | |||
| d01420a048 | |||
| 364dc01c3b | |||
| 3a62ccb1ba | |||
| 3b427052b8 | |||
| 08696b36fd | |||
| fd2566a430 | |||
| f66e6fd11e | |||
| b65ea8886b | |||
| 8cd7760dd2 | |||
| 80fd26b764 | |||
| 366a3da552 | |||
| bdb7aa032c | |||
| f86f1d0a91 | |||
| 9041141bf8 | |||
| 361b6940aa | |||
| a8d0e143cf | |||
| a778d30946 | |||
| daf07f1f39 | |||
| 9d180de631 | |||
| 8d23e288ae | |||
| 50a3a49fd5 | |||
| 75cca6c7cd | |||
| a15a9ba7a3 | |||
| 9993a679c1 | |||
| 08fafcf2ee | |||
| 5e237be027 | |||
| dea6f27995 | |||
| a53817cd43 | |||
| 8f4722173a | |||
| 991ed9bd11 | |||
| b4f2c4863f | |||
| a1800ca2b3 | |||
| 27fbe9a932 | |||
| 11eda0fc49 | |||
| 07c7527734 | |||
| 9fe826447b | |||
| 929b159aaa | |||
| 41764d28ba | |||
| 09d60579d2 | |||
| 7d48a5d6e8 | |||
| 291864acae | |||
| 4f3ddce184 | |||
| 031e3b52b9 | |||
| 560f8bb4bf | |||
| 38aadd3332 | |||
| f544f1ec2d | |||
| 5b2e2867f0 | |||
| feea10ed4e | |||
| 8807bb1778 | |||
| a1651d2195 | |||
| 4ba3780f88 | |||
| 23889d702e | |||
| 815758622d | |||
| b78eaf1a49 | |||
| f19e65c68c | |||
| 056c74d2dd | |||
| 174edd5973 | |||
| 8162b8ea2d | |||
| 97acdc60d6 | |||
| de7ec5fc58 | |||
| 0c49900eae | |||
| 5dac7eed8b | |||
| e8e1a353ef | |||
| 19da5e90c4 | |||
| 1995d75cb0 | |||
| 571d437fcf | |||
| 2197327ca6 | |||
| 7426809669 | |||
| 00ccea8950 | |||
| e637010296 | |||
| e95a67b236 | |||
| 354293079a | |||
| 4e3640f5d1 | |||
| 0cfdef58c1 | |||
| 8f0b24e0a1 | |||
| cde1ca1121 | |||
| 47bf2ad986 | |||
| 3c167692ae | |||
| 495804e37d | |||
| 5c20980664 | |||
| 1a30efb26f | |||
| ad87af296d | |||
| fbcedcf9d5 | |||
| 33aa934b8b | |||
| b278859a61 | |||
| f549e6e2bd | |||
| 9e76725bc6 | |||
| cc02e9aa20 | |||
| 50b73d8e35 | |||
| a411a2a3ed | |||
| e4bb6c0ba6 | |||
| 7df82584e7 | |||
| 83c6a8c161 | |||
| e40e69733a | |||
| 353f205ae7 | |||
| 122ca1d50f | |||
| 05d90a2b5b | |||
| 8f55384b9a | |||
| 347f509660 | |||
| 02a6b5f1f1 | |||
| b914701d2b | |||
| 9c31a1ae49 | |||
| 80b752ccdb | |||
| 9b74a4e43c | |||
| 02e81e2a8b | |||
| 93e95030f4 | |||
| 45a8c03dc3 | |||
| 6ef2df375c | |||
| 42fd20f2ac | |||
| 7e03641e08 | |||
| bc04e18aba | |||
| ecfe234414 | |||
| f190b3bef7 | |||
| 8627c53506 | |||
| b6140bec36 | |||
| f6c8a2a870 | |||
| d8bc87061d | |||
| e107e72cd0 | |||
| 44af921b8c | |||
| 3e61d836ea | |||
| 548037bbe2 | |||
| d7d256946d | |||
| 1844906ec4 | |||
| beb7b6e195 | |||
| e54311ee40 | |||
| febbb4fb5f | |||
| d70d9f35f9 | |||
| 3dc4f84514 | |||
| 93d61449f9 | |||
| 10c436ffb2 | |||
| 9ebc8d5ea6 | |||
| 2ab2f0ffd5 | |||
| 30b0fdd880 | |||
| a81b614e02 | |||
| 651b650d7b | |||
| b389feff21 | |||
| f4cd0a580a | |||
| 20efb33c32 | |||
| 5f837d38b4 | |||
| 712d859dad | |||
| 2010c6d6be | |||
| 9c40d08edd | |||
| 501e624d74 | |||
| 5ff2ea745f | |||
| 460a989897 | |||
| d5c70f7c19 | |||
| 66467a9e12 | |||
| 758697ab97 | |||
| 4428ad1a5f | |||
| c77fbbd18f | |||
| adcfba4627 | |||
| 6ef3847bf6 | |||
| 0b68c4ea1f | |||
| 60cf026b88 | |||
| b30d4084ef | |||
| 8aa8ef2206 | |||
| c0824c1827 | |||
| 7fe35c3b88 | |||
| b0b3265f72 | |||
| 971e90069e | |||
| c8fa1f7eaa | |||
| 05179d887e | |||
| c02748434c | |||
| bed9a09325 | |||
| 010daea5f5 | |||
| 65ca734aa3 | |||
| 12d78fed92 | |||
| 722db5947e | |||
| cec3f6ab0b | |||
| 7e510b858e | |||
| 715dbec2a1 | |||
| 953991f3f7 | |||
| 998d88a927 | |||
| fa20821af9 | |||
| 07432d89e1 | |||
| 5e44237783 | |||
| 4ca4c92c13 | |||
| 92461b41a0 | |||
| 11026d1c2e |
@@ -0,0 +1,15 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = spaces
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{json,yml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": ["warn", { "vars": "all", "args": "after-used" }],
|
||||
"no-console": ["off", { "allow": ["warn", "error"] } ],
|
||||
"no-empty": ["error", { "allowEmptyCatch": true }],
|
||||
"indent": [ "warn", 2 ],
|
||||
"linebreak-style": [ "error", "unix" ],
|
||||
"quotes": [ "warn", "single" ],
|
||||
"semi": [ "warn", "always" ],
|
||||
"no-extra-semi": [ "warn" ],
|
||||
"no-debugger": [ "warn" ]
|
||||
}
|
||||
}
|
||||
+9
-12
@@ -9,18 +9,6 @@ pids
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
@@ -29,6 +17,7 @@ build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
bower_components
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
@@ -45,3 +34,11 @@ jspm_packages
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# Copied fonts
|
||||
examples/fonts
|
||||
dist
|
||||
article-rendered.html
|
||||
|
||||
# dependency graph
|
||||
rollup-grapher.html
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
src
|
||||
build
|
||||
.editorconfig
|
||||
.eslintrc.json
|
||||
.gitignore
|
||||
.travis.yml
|
||||
rollup.config.dev.js
|
||||
rollup.config.js
|
||||
yarn-error.log
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "node" # latest version
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
script:
|
||||
- npm run build
|
||||
- npm test
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: $GITHUB_OAUTH_TOKEN
|
||||
file_glob: true
|
||||
file: dist/*
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
on:
|
||||
tags: true
|
||||
@@ -1,5 +1,25 @@
|
||||
# Distill Templates
|
||||
# Distill Template [](https://travis-ci.org/distillpub/template)
|
||||
|
||||
This is the repository for the distill web framework. If you're interesting in just using the framework to write an article for the [Distill journal](http://distill.pub), visit http://distill.pub/guide/.
|
||||
|
||||
The general process for using this framework is to hotlink the compiled code in your dev environment.
|
||||
|
||||
```html
|
||||
<script src="https://distill.pub/template.v2.js"></script>
|
||||
```
|
||||
|
||||
You can also install it as a local dependency through npm or with [yarn](https://yarnpkg.com).
|
||||
|
||||
```
|
||||
npm install --D distill-template
|
||||
```
|
||||
|
||||
If you're interested in submitting pull requests or developing on the framework itself, read on.
|
||||
|
||||
## Development
|
||||
|
||||
Run `npm run start` to start a watching build rollup server. To view the sample pages in the repo, you can run `npm run serve` as a separate process which starts a static server. `npm run build` will run a one-time build.
|
||||
|
||||
## Testing
|
||||
|
||||
Run `yarn test`. That's it.
|
||||
Run `npm test`. That's it.
|
||||
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const program = require('commander');
|
||||
const jsdom = require('jsdom');
|
||||
const { JSDOM } = jsdom;
|
||||
const transforms = require('../dist/transforms.v2.js');
|
||||
|
||||
program
|
||||
.version('1.0.0')
|
||||
.description('Pre-renders distill articles for publication.')
|
||||
.usage('-i <input_path> -o <output_path>')
|
||||
.option('-i, --input-path <path>', 'path to input HTML file.')
|
||||
.option('-o, --output-path <path>', 'path to write rendered HTML file to.')
|
||||
.parse(process.argv);
|
||||
|
||||
const virtualConsole = new jsdom.VirtualConsole();
|
||||
// omitJSDOMErrors as JSDOM routinely can't parse modern CSS
|
||||
virtualConsole.sendTo(console, { omitJSDOMErrors: true });
|
||||
|
||||
const options = { runScripts: 'outside-only', QuerySelector: true, virtualConsole: virtualConsole };
|
||||
JSDOM.fromFile(program.inputPath, options).then(dom => {
|
||||
const window = dom.window;
|
||||
const document = window.document;
|
||||
|
||||
const data = new transforms.FrontMatter;
|
||||
data.inputHTMLPath = program.inputPath; // may be needed to resolve relative links!
|
||||
data.inputDirectory = path.dirname(program.inputPath);
|
||||
transforms.render(document, data);
|
||||
transforms.distillify(document, data);
|
||||
|
||||
const transformedHtml = dom.serialize();
|
||||
fs.writeFileSync(program.outputPath, transformedHtml);
|
||||
}).catch(console.error);
|
||||
@@ -1,78 +0,0 @@
|
||||
const html = `
|
||||
<style>
|
||||
dt-appendix {
|
||||
display: block;
|
||||
font-family: "Open Sans";
|
||||
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: rgba(0,0,0,0.025);
|
||||
padding-top: 36px;
|
||||
padding-right: 24px;
|
||||
padding-bottom: 60px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
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);
|
||||
}
|
||||
</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 submit a pull request on <a class="github">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 source available on available on <a class="github">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>
|
||||
`;
|
||||
|
||||
// distill.data().then(function(data) {
|
||||
// var as = el.querySelectorAll("a.github");
|
||||
// [].forEach.call(as, function(a) {
|
||||
// a.setAttribute("href", data.github);
|
||||
// });
|
||||
// el.querySelector(".citation.short").textContent = data.concatenatedAuthors + ", " + '"' + data.title + '", Distill, ' + data.firstPublishedYear + ".";
|
||||
// var bibtex = "@article{" + data.slug + ",\n";
|
||||
// bibtex += " author = {" + data.bibtexAuthors + "},\n";
|
||||
// bibtex += " title = {" + data.title + "},\n";
|
||||
// bibtex += " journal = {Distill},\n";
|
||||
// bibtex += " year = {" + data.firstPublishedYear + "},\n";
|
||||
// bibtex += " note = {" + data.url + "}\n";
|
||||
// bibtex += "}";
|
||||
// el.querySelector(".citation.long").textContent = bibtex;
|
||||
// })
|
||||
|
||||
export default function(dom, data) {
|
||||
let el = dom.querySelector('dt-appendix')
|
||||
if (el) el.innerHTML = html;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import bibtexParse from "bibtex-parse-js";
|
||||
|
||||
export default function(dom, data) {
|
||||
let el = dom.querySelector('script[type="text/bibliography"]');
|
||||
|
||||
//TODO If we don't have a local element, make a request for the document.
|
||||
if (el) {
|
||||
let rawBib = el.textContent;
|
||||
let bibliography = {};
|
||||
bibtexParse.toJSON(rawBib).forEach(e => {
|
||||
bibliography[e.citationKey] = e.entryTags;
|
||||
bibliography[e.citationKey].type = e.entryType;
|
||||
});
|
||||
|
||||
let citations = [];
|
||||
var citeTags = [].slice.apply(dom.querySelectorAll("dt-cite"));
|
||||
citeTags.forEach(el => {
|
||||
let citationKeys = el.getAttribute("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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
data.bibliography = bibliography;
|
||||
data.citations = citations;
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
export default function(dom, data) {
|
||||
let citations = data.citations;
|
||||
/*if (data.citations) {
|
||||
citations = Object.keys(data.citations).map(c => data.citations[c]);
|
||||
citations.sort((a, b) => {
|
||||
return a.author.localeCompare(b.author);
|
||||
});
|
||||
}*/
|
||||
|
||||
var citeTags = [].slice.apply(dom.querySelectorAll("dt-cite"));
|
||||
console.log(citeTags);
|
||||
citeTags.forEach(el => {
|
||||
var keys = el.getAttribute("key").split(",");
|
||||
console.log(keys)
|
||||
var cite_string = inline_cite_short(keys);
|
||||
el.innerHTML = cite_string;
|
||||
});
|
||||
|
||||
let bibEl = dom.querySelector("dt-bibliography");
|
||||
if (bibEl) {
|
||||
let ol = dom.createElement("ol");
|
||||
citations.forEach(key => {
|
||||
let el = dom.createElement("li");
|
||||
el.textContent = bibliography_cite(data.bibliography[key]);
|
||||
ol.appendChild(el);
|
||||
})
|
||||
bibEl.appendChild(ol);
|
||||
}
|
||||
|
||||
function inline_cite_short(keys){
|
||||
function cite_string(key){
|
||||
if (key in data.bibliography){
|
||||
var n = data.citations.indexOf(key)+1;
|
||||
return ""+n;
|
||||
} else {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
return "["+keys.map(cite_string).join(", ")+"]";
|
||||
}
|
||||
|
||||
function inline_cite_long(keys){
|
||||
function cite_string(key){
|
||||
if (key in data.bibliography){
|
||||
var ent = data.bibliography[key];
|
||||
var names = ent.author.split(" and ");
|
||||
names = names.map(name => name.split(",")[0].trim())
|
||||
var year = ent.year;
|
||||
if (names.length == 1) return names[0] + ", " + year;
|
||||
if (names.length == 2) return names[0] + " & " + names[1] + ", " + year;
|
||||
if (names.length > 2) return names[0] + ", et al., " + year;
|
||||
} else {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
return keys.map(cite_string).join(", ");
|
||||
}
|
||||
|
||||
function bibliography_cite(ent){
|
||||
if (ent){
|
||||
var names = ent.author.split(" and ");
|
||||
var cite = "";
|
||||
let name_strings = names.map(name => {
|
||||
var last = name.split(",")[0].trim();
|
||||
var firsts = name.split(",")[1];
|
||||
if (firsts != undefined) {
|
||||
var initials = firsts.trim().split(" ").map(s => s.trim()[0]);
|
||||
return last + ", " + initials.join(".")+".";
|
||||
}
|
||||
return last;
|
||||
});
|
||||
if (names.length > 1) {
|
||||
cite += name_strings.slice(0, names.length-1).join(", ");
|
||||
cite += " and " + name_strings[names.length-1];
|
||||
} else {
|
||||
cite += name_strings[0]
|
||||
}
|
||||
cite += ", " + ent.year + ". "
|
||||
cite += ent.title + ". "
|
||||
cite += (ent.journal || ent.booktitle || "")
|
||||
if ("volume" in ent){
|
||||
var issue = ent.issue || ent.number;
|
||||
issue = (issue != undefined)? "("+issue+")" : "";
|
||||
cite += ", Vol " + ent.volume + issue;
|
||||
}
|
||||
if ("pages" in ent){
|
||||
cite += ", pp. " + ent.pages
|
||||
}
|
||||
cite += ". "
|
||||
return cite
|
||||
} else {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//https://scholar.google.com/scholar?q=allintitle%3ADocument+author%3Aolah
|
||||
function get_URL(ent){
|
||||
if (ent){
|
||||
var names = ent.author.split(" and ");
|
||||
names = names.map(name => name.split(",")[0].trim())
|
||||
var title = ent.title.split(" ")//.replace(/[,:]/, "")
|
||||
var url = "http://search.labs.crossref.org/dois?"//""https://scholar.google.com/scholar?"
|
||||
url += uris({q: names.join(" ") + " " + title.join(" ")})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
<svg viewBox="-607 419 64 64">
|
||||
<path style="fill: none; stroke: black;stroke-width: 2px;" d="M-573.4,478.9c-8,0-14.6-6.4-14.6-14.5s14.6-25.9,14.6-40.8c0,14.9,14.6,32.8,14.6,40.8S-565.4,478.9-573.4,478.9z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 216 B |
@@ -1,36 +0,0 @@
|
||||
export default function(dom, data) {
|
||||
|
||||
data.authors = data.authors || [];
|
||||
|
||||
// paths
|
||||
//data.distillPath = post.distillPath;
|
||||
//data.githubPath = post.githubPath;
|
||||
//data.url = "http://distill.pub/" + post.distillPath;
|
||||
//data.githubUrl = "https://github.com/" + post.githubPath;
|
||||
|
||||
// Homepage
|
||||
//data.homepage = !post.noHomepage;
|
||||
|
||||
// Dates
|
||||
// TODO: fix updated date
|
||||
if (data.published){//} && data.journal) {
|
||||
data.volume = data.published.getFullYear() - 2015;
|
||||
data.issue = data.published.getMonth() + 1;
|
||||
}
|
||||
/*
|
||||
//let RFC = d3.timeFormat("%a, %d %b %Y %H:%M:%S %Z");
|
||||
let months = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"];
|
||||
let zeroPad = (n) => { return n < 10 ? "0" + n : n; };
|
||||
//data.publishedDateRFC = RFC(data.publishedDate);
|
||||
data.publishedYear = data.publishedDate.getFullYear();
|
||||
data.publishedMonth = months[data.publishedDate.getMonth()];
|
||||
data.publishedDay = data.publishedDate.getDate();
|
||||
data.publishedMonthPadded = zeroPad(data.publishedDate.getMonth() + 1);
|
||||
data.publishedDayPadded = zeroPad(data.publishedDate.getDate());
|
||||
data.volume = data.publishedDate.getFullYear() - 2015;
|
||||
data.issue = data.publishedDate.getMonth() + 1;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,43 +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: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
dt-footer .logo svg {
|
||||
width: 24px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
dt-footer .logo svg path {
|
||||
stroke: rgba(255, 255, 255, 0.8)!important;
|
||||
stroke-width: 3px!important;
|
||||
}
|
||||
dt-footer .logo {
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
text-decoration: none;
|
||||
margin-right: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="l-body">
|
||||
<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;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import ymlParse from "js-yaml";
|
||||
|
||||
export default function(dom, data) {
|
||||
let el = dom.querySelector('script[type="text/front-matter"]');
|
||||
|
||||
//TODO If we don't have a local element, make a request for the document.
|
||||
if (el) {
|
||||
let text = el.textContent;
|
||||
let localData = ymlParse.safeLoad(text);
|
||||
|
||||
data.title = localData.title;
|
||||
data.description = localData.description;
|
||||
data.published = new Date(localData.published);
|
||||
data.updated = new Date(localData.published || localData.updated);
|
||||
|
||||
data.authors = localData.authors.map((author, i) =>{
|
||||
let a = {};
|
||||
let name = Object.keys(author)[0];
|
||||
let names = name.split(" ");
|
||||
a.firstName = names.slice(0, names.length - 1).join(" ");
|
||||
a.lastName = names[names.length -1];
|
||||
a.personalURL = author[name];
|
||||
if(localData.affiliations[i]) {
|
||||
let affiliation = Object.keys(localData.affiliations[i])[0];
|
||||
a.affiliation = affiliation;
|
||||
a.affiliationURL = localData.affiliations[i][affiliation];
|
||||
}
|
||||
return a;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import logo from "./distill-logo.svg";
|
||||
|
||||
const html = `
|
||||
<style>
|
||||
dt-header {
|
||||
display: block;
|
||||
position: relative;
|
||||
height: 60px;
|
||||
background-color: #fcfcfc;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
dt-header .content {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
|
||||
height: 60px;
|
||||
}
|
||||
dt-header a {
|
||||
font-size: 16px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
text-decoration: none;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
dt-header svg {
|
||||
width: 24px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
dt-header svg path {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
stroke-width: 1;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
dt-header .logo {
|
||||
font-size: 16px;
|
||||
font-weight: 300;
|
||||
}
|
||||
dt-header .nav {
|
||||
float: right;
|
||||
}
|
||||
dt-header .nav a {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="content l-page">
|
||||
<a href="/" class="logo">
|
||||
${logo}
|
||||
Distill
|
||||
</a>
|
||||
<div class="nav">
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
export default function(dom, data) {
|
||||
dom.querySelector('dt-header').innerHTML = html;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
export default function(dom) {
|
||||
if (!dom.querySelector("html").getAttribute("lang")) {
|
||||
dom.querySelector("html").setAttribute("lang", "en")
|
||||
}
|
||||
|
||||
let head = dom.querySelector("head");
|
||||
|
||||
if (!dom.querySelector("meta[charset]")) {
|
||||
let meta = dom.createElement("meta");
|
||||
meta.setAttribute("charset", "utf-8");
|
||||
head.appendChild(meta);
|
||||
}
|
||||
if (!dom.querySelector("meta[name=viewport]")) {
|
||||
let meta = dom.createElement("meta");
|
||||
meta.setAttribute("name", "viewport");
|
||||
meta.setAttribute("content", "width=device-width, initial-scale=1");
|
||||
head.appendChild(meta);
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
export default function(dom, data) {
|
||||
let head = dom.querySelector("head");
|
||||
let appendHead = html => appendHtml(head, html);
|
||||
|
||||
function meta(name, content) {
|
||||
if (content)
|
||||
appendHead(`<meta name="${name}" content="${content}" >`);
|
||||
}
|
||||
|
||||
appendHead(`
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<link href="/rss.xml" rel="alternate" type="application/rss+xml" title="Articles from Distill">
|
||||
<link rel="canonical" href="${data.url}">
|
||||
<title>${data.title}</title>
|
||||
`);
|
||||
|
||||
appendHead(`
|
||||
<!-- https://schema.org/Article -->
|
||||
<meta property="article:published" itemprop="datePublished" content="${data.published}" />
|
||||
<meta property="article:modified" itemprop="dateModified" content="${data.updated}" />
|
||||
`);
|
||||
data.authors.forEach((a) => {
|
||||
appendHtml(head, `
|
||||
<meta property="article:author" content="${a.firstName} ${a.lastName}" />`)
|
||||
});
|
||||
|
||||
appendHead(`
|
||||
<!-- https://developers.facebook.com/docs/sharing/webmasters#markup -->
|
||||
<meta property="og:type" content="article"/>
|
||||
<meta property="og:title" content="${data.title}"/>
|
||||
<meta property="og:description" content="${data.description}">
|
||||
<meta property="og:url" content="${data.url}"/>
|
||||
<meta property="og:image" content="${data.url}/thumbnail.png"/>
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:site_name" content="Distill" />
|
||||
`);
|
||||
|
||||
appendHead(`
|
||||
<!-- https://dev.twitter.com/cards/types/summary -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="${data.title}">
|
||||
<meta name="twitter:description" content="${data.description}">
|
||||
<meta name="twitter:url" content="${data.url}">
|
||||
<meta name="twitter:image" content="${data.url}/thumbnail.png">
|
||||
<meta name="twitter:image:width" content="560">
|
||||
<meta name="twitter:image:height" content="295">
|
||||
`);
|
||||
|
||||
appendHead(`
|
||||
<!-- https://scholar.google.com/intl/en/scholar/inclusion.html#indexing -->
|
||||
`);
|
||||
|
||||
meta("citation_title", data.title);
|
||||
meta("citation_fulltext_html_url", data.url);
|
||||
meta("citation_volume", data.volume);
|
||||
meta("citation_issue", data.issue);
|
||||
meta("citation_firstpage", data.doiSuffix? `e${data.doiSuffix}` : undefined);
|
||||
meta("citation_doi", data.doi);
|
||||
|
||||
let journal = data.journal || {};
|
||||
meta("citation_journal_title", journal.name);
|
||||
meta("citation_journal_abbrev", journal.nameAbbrev);
|
||||
meta("citation_issn", journal.issn);
|
||||
meta("citation_publisher", journal.publisher);
|
||||
|
||||
if (data.published){
|
||||
let zeroPad = (n) => { return n < 10 ? "0" + n : n; };
|
||||
let publishedYear = data.published.getFullYear();
|
||||
let publishedMonthPadded = zeroPad(data.published.getMonth() + 1);
|
||||
let publishedDayPadded = zeroPad(data.published.getDate());
|
||||
meta("citation_publication_date", `${publishedYear}/${publishedMonthPadded}/${publishedDayPadded}`);
|
||||
}
|
||||
|
||||
(data.authors || []).forEach((a) => {
|
||||
meta("citation_author", `${a.lastName}, ${a.firstName}`);
|
||||
meta("citation_author_institution", a.affiliation);
|
||||
});
|
||||
|
||||
if (data.citations) {
|
||||
data.citations.forEach(key =>
|
||||
meta("citation_reference", citation_meta_content(data.bibliography[key]) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function appendHtml(el, html) {
|
||||
el.innerHTML += html;
|
||||
}
|
||||
|
||||
function citation_meta_content(ref){
|
||||
var content = `citation_title=${ref.title};`;
|
||||
ref.author.split(" and ").forEach(author => {
|
||||
content += `citation_author=${author.trim()};`;
|
||||
});
|
||||
if ("journal" in ref){
|
||||
content += `citation_journal_title=${ref.journal};`;
|
||||
}
|
||||
if ("volume" in ref) {
|
||||
content += `citation_volume=${ref.volume};`;
|
||||
}
|
||||
if ("issue" in ref || "number" in ref){
|
||||
content += `citation_number=${ref.issue || ref.number};`;
|
||||
}
|
||||
/*content += `citation_first_page=${};`;
|
||||
content += `citation_publication_date=${};`;*/
|
||||
return content;
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
dt-article {
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
font: 15px/1.55em -apple-system, BlinkMacSystemFont, "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
dt-article {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
dt-article h1 {
|
||||
font-weight: 700;
|
||||
font-size: 32px;
|
||||
line-height: 1.1em;
|
||||
/*-webkit-font-smoothing: antialiased;*/
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
dt-article h1 {
|
||||
font-size: 50px;
|
||||
margin-bottom: 12px;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
dt-article > h1:first-of-type {
|
||||
margin-top: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
dt-article h2 {
|
||||
font-weight: 400;
|
||||
font-size: 28px;
|
||||
line-height: 1.25em;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dt-article h1 + h2 {
|
||||
padding-bottom: 48px;
|
||||
margin-bottom: 48px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
dt-article h3 {
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
line-height: 1.4em;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
dt-article h4 {
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
dt-article a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
dt-article p {
|
||||
margin-bottom: 24px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
/*font-family: Georgia, serif;*/
|
||||
}
|
||||
|
||||
dt-article p a {
|
||||
/*text-decoration: none;*/
|
||||
/*background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.25) 50%, rgba(0, 0, 0, 0) 50%);*/
|
||||
/*background-repeat: repeat-x;*/
|
||||
/*background-size: 2px 1em;*/
|
||||
/*background-position: 0 1.25em;*/
|
||||
}
|
||||
|
||||
dt-article p .link {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
dt-article ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
dt-article li {
|
||||
/*margin-bottom: 24px;*/
|
||||
}
|
||||
|
||||
dt-article pre {
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
dt-article hr {
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
dt-article section {
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
|
||||
/* Figure */
|
||||
|
||||
dt-article figure {
|
||||
position: relative;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
dt-article figure {
|
||||
margin-top: 48px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
dt-article figure img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
dt-article figure svg text,
|
||||
dt-article figure svg tspan {
|
||||
}
|
||||
|
||||
dt-article figure figcaption {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
font-size: 12px;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
@media(min-width: 1024px) {
|
||||
dt-article figure figcaption {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
dt-article figure.external img {
|
||||
background: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
|
||||
padding: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
dt-article figure figcaption a {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/*dt-article figure figcaption::before {
|
||||
position: relative;
|
||||
display: block;
|
||||
top: -20px;
|
||||
content: "";
|
||||
width: 25px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.3);
|
||||
}*/
|
||||
|
||||
dt-article span.equation-mimic {
|
||||
font-family: georgia;
|
||||
font-size: 115%;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
dt-article figure figcaption b {
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 1.0);
|
||||
}
|
||||
|
||||
dt-article > dt-code {
|
||||
display: block;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
html {
|
||||
font: 400 15px/1.55em -apple-system, BlinkMacSystemFont, "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}*/
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
|
||||
code {
|
||||
white-space:pre-wrap;
|
||||
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: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #a67f59;
|
||||
background: hsla(0, 0%, 100%, .5);
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
.l-body,
|
||||
.l-page,
|
||||
dt-article > * {
|
||||
margin-left: 24px;
|
||||
margin-right: 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
.l-body,
|
||||
.l-page,
|
||||
dt-article > * {
|
||||
margin-left: 72px;
|
||||
margin-right: 72px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1080px) {
|
||||
.l-body,
|
||||
dt-article > * {
|
||||
margin-left: calc(50% - 984px / 2);
|
||||
width: 648px;
|
||||
}
|
||||
.l-body-outset,
|
||||
dt-article .l-body-outset {
|
||||
margin-left: calc(50% - 984px / 2 - 24px);
|
||||
width: calc(648px + 48px);
|
||||
}
|
||||
.l-middle,
|
||||
dt-article .l-middle {
|
||||
width: 816px;
|
||||
margin-left: calc(50% - 984px / 2);
|
||||
}
|
||||
.l-page,
|
||||
dt-article .l-page {
|
||||
width: 984px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.l-page-outset,
|
||||
dt-article .l-page-outset {
|
||||
width: 1080px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.l-screen,
|
||||
dt-article .l-screen {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: auto;
|
||||
}
|
||||
.l-screen-inset,
|
||||
dt-article .l-screen-inset {
|
||||
margin-left: 24px;
|
||||
margin-right: 24px;
|
||||
width: auto;
|
||||
}
|
||||
.l-gutter,
|
||||
dt-article .l-gutter {
|
||||
clear: both;
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
margin-left: 24px;
|
||||
margin-right: calc((100vw - 960px) / 2);
|
||||
width: calc((984px - 648px) / 2 - 24px);
|
||||
}
|
||||
/* Side */
|
||||
.side.l-body,
|
||||
dt-article .side.l-body {
|
||||
clear: both;
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
margin-left: 48px;
|
||||
margin-right: calc((100vw - 984px + 648px) / 2);
|
||||
width: calc(648px / 2 - 24px);
|
||||
}
|
||||
.side.l-body-outset,
|
||||
dt-article .side.l-body-outset {
|
||||
clear: both;
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
margin-left: 48px;
|
||||
margin-right: calc((100vw - 984px + 648px - 48px) / 2);
|
||||
width: calc(648px / 2 - 48px + 24px);
|
||||
}
|
||||
.side.l-page,
|
||||
dt-article .side.l-page {
|
||||
clear: both;
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
margin-left: 48px;
|
||||
margin-right: calc((100vw - 984px) / 2);
|
||||
width: calc(960px / 2 - 48px);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import base from './styles-base.css';
|
||||
import layout from './styles-layout.css';
|
||||
import article from './styles-article.css';
|
||||
import code from './styles-code.css';
|
||||
|
||||
export default function(dom) {
|
||||
let s = dom.createElement("style");
|
||||
s.textContent = base + layout + article + code;
|
||||
dom.querySelector("head").appendChild(s);
|
||||
}
|
||||
Vendored
-6670
File diff suppressed because it is too large
Load Diff
Vendored
-1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,188 @@
|
||||
<!doctype html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
|
||||
<script src="../dist/components.js"></script>
|
||||
|
||||
<d-front-matter>
|
||||
<script type="text/yml">
|
||||
title: Demo Title Attention and Augmented Recurrent Neural Networks
|
||||
published: Jan 10, 2017
|
||||
authors:
|
||||
- Chris Olah:
|
||||
- Shan Carter: http://shancarter.com
|
||||
affiliations:
|
||||
- Google Brain
|
||||
- Google Brain: http://g.co/brain
|
||||
</script>
|
||||
</d-front-matter>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<d-article>
|
||||
<d-title>
|
||||
<h1>Attention and Augmented Recurrent Neural Networks</h1>
|
||||
<!-- <h2>Some people want a deck</h2> -->
|
||||
<d-byline></d-byline>
|
||||
</d-title>
|
||||
<d-abstract>
|
||||
<p>This is the first paragraph of the article. Test a long — dash -- here it is.</p>
|
||||
</d-abstract>
|
||||
<p>This is the first paragraph of the article. Test a long — dash -- here it is.</p>
|
||||
<p>Test for owner's possessive. Test for "quoting a passage." And another sentence. Or two. Some flopping fins; for diving.</p>
|
||||
<hr>
|
||||
<div style="max-width: 800px; background-color: red; height: 100px; border-radius: 50px;"></div>
|
||||
<p>Here's a test of an inline equation <d-math>c = a^2 + b^2</d-math>. And then there's a block equation:</p>
|
||||
<d-math block>
|
||||
c = \pm \sqrt{ \sum_{i=0}^{n}{a^{222} + b^2}}
|
||||
</d-math>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>First</th><th>Second</th><th>Third</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>23</td><td>654</td><td>23</td></tr>
|
||||
<tr><td>14</td><td>54</td><td>34</td></tr>
|
||||
<tr><td>234</td><td>54</td><td>23</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Displaying code snippets</h2>
|
||||
<p>Some inline javascript:<d-code language="javascript">var x = 25;</d-code></p>
|
||||
<p>Here's a javascript code block.</p>
|
||||
<d-code block language="javascript">
|
||||
var x = 25;
|
||||
function(x){
|
||||
return x * x;
|
||||
}
|
||||
</d-code>
|
||||
<p>We also support python.</p>
|
||||
<d-code block language="python">
|
||||
# Python 3: Fibonacci series up to n
|
||||
def fib(n):
|
||||
a, b = 0, 1
|
||||
while a < n:
|
||||
print(a, end=' ')
|
||||
a, b = b, a+b
|
||||
</d-code>
|
||||
<p>That's it for the example article!</p>
|
||||
<aside>Some text.</aside>
|
||||
</d-article>
|
||||
|
||||
<d-appendix>
|
||||
<d-acknowledgements>
|
||||
<h3>Contributions</h3>
|
||||
<p>Some text describing who did what.</p>
|
||||
<h4>Reviewers</h4>
|
||||
<p>Some text with links describing who reviewed the article.</p>
|
||||
</d-acknowledgements>
|
||||
|
||||
<d-footnote-list></d-footnote-list>
|
||||
|
||||
<d-bibliography><script type="text/bibtex">
|
||||
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXiv preprint arXiv:1502.04623},
|
||||
year={2015},
|
||||
url ={https://arxiv.org/pdf/1502.04623.pdf}
|
||||
}
|
||||
@article{mercier2011humans,
|
||||
title={Why do humans reason? Arguments for an argumentative theory},
|
||||
author={Mercier, Hugo and Sperber, Dan},
|
||||
journal={Behavioral and brain sciences},
|
||||
volume={34},
|
||||
number={02},
|
||||
pages={57--74},
|
||||
year={2011},
|
||||
publisher={Cambridge Univ Press},
|
||||
doi={10.1017/S0140525X10000968}
|
||||
}
|
||||
|
||||
@article{dong2014image,
|
||||
title={Image super-resolution using deep convolutional networks},
|
||||
author={Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou},
|
||||
journal={arXiv preprint arXiv:1501.00092},
|
||||
year={2014},
|
||||
url={https://arxiv.org/pdf/1501.00092.pdf}
|
||||
}
|
||||
|
||||
@article{dumoulin2016adversarially,
|
||||
title={Adversarially Learned Inference},
|
||||
author={Dumoulin, Vincent and Belghazi, Ishmael and Poole, Ben and Lamb, Alex and Arjovsky, Martin and Mastropietro, Olivier and Courville, Aaron},
|
||||
journal={arXiv preprint arXiv:1606.00704},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1606.00704.pdf}
|
||||
}
|
||||
|
||||
@article{dumoulin2016guide,
|
||||
title={A guide to convolution arithmetic for deep learning},
|
||||
author={Dumoulin, Vincent and Visin, Francesco},
|
||||
journal={arXiv preprint arXiv:1603.07285},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1603.07285.pdf}
|
||||
}
|
||||
|
||||
@article{gauthier2014conditional,
|
||||
title={Conditional generative adversarial nets for convolutional face generation},
|
||||
author={Gauthier, Jon},
|
||||
journal={Class Project for Stanford CS231N: Convolutional Neural Networks for Visual Recognition, Winter semester},
|
||||
volume={2014},
|
||||
year={2014},
|
||||
url={http://www.foldl.me/uploads/papers/tr-cgans.pdf}
|
||||
}
|
||||
|
||||
@article{johnson2016perceptual,
|
||||
title={Perceptual losses for real-time style transfer and super-resolution},
|
||||
author={Johnson, Justin and Alahi, Alexandre and Fei-Fei, Li},
|
||||
journal={arXiv preprint arXiv:1603.08155},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1603.08155.pdf}
|
||||
}
|
||||
|
||||
@article{mordvintsev2015inceptionism,
|
||||
title={Inceptionism: Going deeper into neural networks},
|
||||
author={Mordvintsev, Alexander and Olah, Christopher and Tyka, Mike},
|
||||
journal={Google Research Blog},
|
||||
year={2015},
|
||||
url={https://research.googleblog.com/2015/06/inceptionism-going-deeper-into-neural.html}
|
||||
}
|
||||
|
||||
@misc{mordvintsev2016deepdreaming,
|
||||
title={DeepDreaming with TensorFlow},
|
||||
author={Mordvintsev, Alexander},
|
||||
year={2016},
|
||||
url={https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb},
|
||||
}
|
||||
|
||||
@article{radford2015unsupervised,
|
||||
title={Unsupervised representation learning with deep convolutional generative adversarial networks},
|
||||
author={Radford, Alec and Metz, Luke and Chintala, Soumith},
|
||||
journal={arXiv preprint arXiv:1511.06434},
|
||||
year={2015},
|
||||
url={https://arxiv.org/pdf/1511.06434.pdf}
|
||||
}
|
||||
|
||||
@inproceedings{salimans2016improved,
|
||||
title={Improved techniques for training gans},
|
||||
author={Salimans, Tim and Goodfellow, Ian and Zaremba, Wojciech and Cheung, Vicki and Radford, Alec and Chen, Xi},
|
||||
booktitle={Advances in Neural Information Processing Systems},
|
||||
pages={2226--2234},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1606.03498.pdf}
|
||||
}
|
||||
|
||||
@article{shi2016deconvolution,
|
||||
title={Is the deconvolution layer the same as a convolutional layer?},
|
||||
author={Shi, Wenzhe and Caballero, Jose and Theis, Lucas and Huszar, Ferenc and Aitken, Andrew and Ledig, Christian and Wang, Zehan},
|
||||
journal={arXiv preprint arXiv:1609.07009},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1609.07009.pdf}
|
||||
}
|
||||
|
||||
</script></d-bibliography>
|
||||
|
||||
<distill-appendix> </distill-appendix>
|
||||
</d-appendix>
|
||||
</body>
|
||||
@@ -0,0 +1,232 @@
|
||||
<!DOCTYPE html><html lang="en"><head>
|
||||
<meta charset="utf8">
|
||||
|
||||
<script id="polyfills">
|
||||
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 = '../dist/webcomponents-lite.js';
|
||||
scriptTag.async = false;
|
||||
document.currentScript.parentNode.insertBefore(scriptTag, document.currentScript.nextSibling);
|
||||
}
|
||||
</script><script src="../dist/components.js"></script>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA99JREFUeNrsG4t1ozDMzQSM4A2ODUonKBucN2hugtIJ6E1AboLcBiQTkJsANiAb9OCd/OpzMWBJBl5TvaeXPiiyJetry0J8wW3D3QpjRh3GjneXDq+fSQA9s2mH9x3KDhN4foJfCb8N/Jrv+2fnDn8vLRQOplWHVYdvHZYdZsBcZP1vBmh/n8DzEmhUQDPaOuP9pFuY+JwJHwHnCLQE2tnWBGEyXozY9xCUgHMhhjE2I4heVWtgIkZ83wL6Qgxj1obfWBxymPwe+b00BCCRNPbwfb60yleAkkBHGT5AEehIYz7eJrFDMF9CvH4wwhcGHiHMneFvLDQwlwvMLQq58trRcYBWfYn0A0OgHWQUSu25mE+BnoYKnnEJoeIWAifzOv7vLWd2ZKRfWAIme3tOiUaQ3UnLkb0xj1FxRIeEGKaGIHOs9nEgLaaA9i0JRYo1Ic67wJW86KSKE/ZAM8KuVMk8ITVhmxUxJ3Cl2xlm9Vtkeju1+mpCQNxaEGNCY8bs9X2YqwNoQeGjBWut/ma0QAWy/TqAsHx9wSya3I5IRxOfTC+leG+kA/4vSeEcGBtNUN6byhu3+keEZCQJUNh8MAO7HL6H8pQLnsW/Hd4T4lv93TPjfM7A46iEEqbB5EDOvwYNW6tGNZzT/o+CZ6sqZ6wUtR/wf7mi/VL8iNciT6rHih48Y55b4nKCHJCCzb4y0nwFmin3ZEMIoLfZF8F7nncFmvnWBaBj7CGAYA/WGJsUwHdYqVDwAmNsUgAx4CGgAA7GOOxADYOFWOaIKifuVYzmOpREqA21Mo7aPsgiY1PhOMAmxtR+AUbYH3Id2wc0SAFIQTsn9IUGWR8k9jx3vtXSiAacFxTAGakBk9UudkNECd6jLe+6HrshshvIuC6IlLMRy7er+JpcKma24SlE4cFZSZJDGVVrsNvitQhQrDhW0jfiOLfFd47C42eHT56D/BK0To+58Ahj+cAT8HT1UWlfLZCCd/uKawzU0Rh2EyIX/Icqth3niG8ybNroezwe6khdCNxRN+l4XGdOLVLlOOt2hTRJlr1ETIuMAltVTMz70mJrkdGAaZLSmnBEqmAE32JCMmuTlCnRgsBENtOUpHhvvsYIL0ibnBkaC6QvKcR7738GKp0AKnim7xgUSNv1bpS8QwhBt8r+EP47v/oyRK/S34yJ9nT+AN0Tkm4OdB9E4BsmXM3SnMlRFUrtp6IDpV2eKzdYvF3etm3KhQksbOLChGkSmcBdmcEwvqkrMy5BzL00NZeu3qPYJOOuCc+5NjcWKXQxFvTa3NoXJ4d8in7fiAUuTt781dkvuHX4K8AA2Usy7yNKLy0AAAAASUVORK5CYII=
|
||||
">
|
||||
<link href="/rss.xml" rel="alternate" type="application/rss+xml" title="Articles from Distill">
|
||||
<link rel="canonical" href="undefined">
|
||||
<title>Demo Title Attention and Augmented Recurrent Neural Networks</title>
|
||||
|
||||
<!-- https://schema.org/Article -->
|
||||
<meta property="article:published" itemprop="datePublished" content="undefined-undefined-undefined">
|
||||
<meta property="article:modified" itemprop="dateModified" content="undefined">
|
||||
|
||||
<meta property="article:author" content="undefined undefined">
|
||||
<meta property="article:author" content="undefined undefined">
|
||||
<!-- https://developers.facebook.com/docs/sharing/webmasters#markup -->
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:title" content="Demo Title Attention and Augmented Recurrent Neural Networks">
|
||||
<meta property="og:description" content="undefined">
|
||||
<meta property="og:url" content="undefined">
|
||||
<meta property="og:image" content="undefined/thumbnail.jpg">
|
||||
<meta property="og:locale" content="en_US">
|
||||
<meta property="og:site_name" content="Distill">
|
||||
|
||||
<!-- https://dev.twitter.com/cards/types/summary -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Demo Title Attention and Augmented Recurrent Neural Networks">
|
||||
<meta name="twitter:description" content="undefined">
|
||||
<meta name="twitter:url" content="undefined">
|
||||
<meta name="twitter:image" content="undefined/thumbnail.jpg">
|
||||
<meta name="twitter:image:width" content="560">
|
||||
<meta name="twitter:image:height" content="295">
|
||||
</head><body><distill-header></distill-header><d-front-matter>
|
||||
<script type="text/yml">
|
||||
title: Demo Title Attention and Augmented Recurrent Neural Networks
|
||||
published: Jan 10, 2017
|
||||
authors:
|
||||
- Chris Olah:
|
||||
- Shan Carter: http://shancarter.com
|
||||
affiliations:
|
||||
- Google Brain:
|
||||
- Google Brain: http://g.co/brain
|
||||
</script>
|
||||
</d-front-matter>
|
||||
|
||||
|
||||
|
||||
<d-article>
|
||||
<d-title>
|
||||
<h1>Attention and Augmented Recurrent Neural Networks</h1>
|
||||
<!-- <h2>Some people want a deck</h2> -->
|
||||
<d-byline></d-byline>
|
||||
</d-title>
|
||||
|
||||
<d-abstract>
|
||||
<p>This is the first paragraph of the article. Test a long — dash — here it is.</p>
|
||||
</d-abstract>
|
||||
<p>This is the first paragraph of the article. Test a long — dash — here it is.</p>
|
||||
<p>Test for owner’s possessive. Test for “quoting a passage.” And another sentence. Or two. Some flopping fins; for diving.</p>
|
||||
<p>Here’s a test of an inline equation <d-math>c = a^2 + b^2</d-math>. And then there’s a block equation:</p>
|
||||
<d-math block="">
|
||||
c = \pm \sqrt{ \sum_{i=0}^{n}{a^{222} + b^2}}
|
||||
</d-math>
|
||||
<p>We can<d-cite key="mercier2011humans"></d-cite> also cite <d-cite key="gregor2015draw,mercier2011humans"></d-cite> external publications. <d-cite key="dong2014image,dumoulin2016guide,mordvintsev2015inceptionism"></d-cite></p>
|
||||
<p>We should also be testing footnotes<d-footnote>This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote.</d-footnote>. There are multiple footnotes, and they appear in the appendix<d-footnote>Given I have coded them right. Also, here’s math in a footnote: <d-math>c = \sum_0^i{x}</d-math>. Also, a citation. Box-ception<d-cite key="gregor2015draw"></d-cite>!</d-footnote> as well.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>First</th><th>Second</th><th>Third</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>23</td><td>654</td><td>23</td></tr>
|
||||
<tr><td>14</td><td>54</td><td>34</td></tr>
|
||||
<tr><td>234</td><td>54</td><td>23</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Displaying code snippets</h2>
|
||||
<p>Some inline javascript:<d-code language="javascript">var x = 25;</d-code></p>
|
||||
<p>Here’s a javascript code block.</p>
|
||||
<d-code block="" language="javascript">
|
||||
var x = 25;
|
||||
function(x){
|
||||
return x * x;
|
||||
}
|
||||
</d-code>
|
||||
<p>We also support python.</p>
|
||||
<d-code block="" language="python">
|
||||
# Python 3: Fibonacci series up to n
|
||||
def fib(n):
|
||||
a, b = 0, 1
|
||||
while a < n:
|
||||
print(a, end=' ')
|
||||
a, b = b, a+b
|
||||
</d-code>
|
||||
<p>That’s it for the example article!</p>
|
||||
</d-article>
|
||||
|
||||
<d-appendix>
|
||||
<d-acknowledgements>
|
||||
<h3>Contributions</h3>
|
||||
<p>Some text describing who did what.</p>
|
||||
<h4>Reviewers</h4>
|
||||
<p>Some text with links describing who reviewed the article.</p>
|
||||
</d-acknowledgements>
|
||||
|
||||
<d-footnote-list></d-footnote-list>
|
||||
|
||||
<d-bibliography>
|
||||
<script type="text/bibtex">
|
||||
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXiv preprint arXiv:1502.04623},
|
||||
year={2015},
|
||||
url ={https://arxiv.org/pdf/1502.04623.pdf}
|
||||
}
|
||||
@article{mercier2011humans,
|
||||
title={Why do humans reason? Arguments for an argumentative theory},
|
||||
author={Mercier, Hugo and Sperber, Dan},
|
||||
journal={Behavioral and brain sciences},
|
||||
volume={34},
|
||||
number={02},
|
||||
pages={57--74},
|
||||
year={2011},
|
||||
publisher={Cambridge Univ Press},
|
||||
doi={10.1017/S0140525X10000968}
|
||||
}
|
||||
|
||||
@article{dong2014image,
|
||||
title={Image super-resolution using deep convolutional networks},
|
||||
author={Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou},
|
||||
journal={arXiv preprint arXiv:1501.00092},
|
||||
year={2014},
|
||||
url={https://arxiv.org/pdf/1501.00092.pdf}
|
||||
}
|
||||
|
||||
@article{dumoulin2016adversarially,
|
||||
title={Adversarially Learned Inference},
|
||||
author={Dumoulin, Vincent and Belghazi, Ishmael and Poole, Ben and Lamb, Alex and Arjovsky, Martin and Mastropietro, Olivier and Courville, Aaron},
|
||||
journal={arXiv preprint arXiv:1606.00704},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1606.00704.pdf}
|
||||
}
|
||||
|
||||
@article{dumoulin2016guide,
|
||||
title={A guide to convolution arithmetic for deep learning},
|
||||
author={Dumoulin, Vincent and Visin, Francesco},
|
||||
journal={arXiv preprint arXiv:1603.07285},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1603.07285.pdf}
|
||||
}
|
||||
|
||||
@article{gauthier2014conditional,
|
||||
title={Conditional generative adversarial nets for convolutional face generation},
|
||||
author={Gauthier, Jon},
|
||||
journal={Class Project for Stanford CS231N: Convolutional Neural Networks for Visual Recognition, Winter semester},
|
||||
volume={2014},
|
||||
year={2014},
|
||||
url={http://www.foldl.me/uploads/papers/tr-cgans.pdf}
|
||||
}
|
||||
|
||||
@article{johnson2016perceptual,
|
||||
title={Perceptual losses for real-time style transfer and super-resolution},
|
||||
author={Johnson, Justin and Alahi, Alexandre and Fei-Fei, Li},
|
||||
journal={arXiv preprint arXiv:1603.08155},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1603.08155.pdf}
|
||||
}
|
||||
|
||||
@article{mordvintsev2015inceptionism,
|
||||
title={Inceptionism: Going deeper into neural networks},
|
||||
author={Mordvintsev, Alexander and Olah, Christopher and Tyka, Mike},
|
||||
journal={Google Research Blog},
|
||||
year={2015},
|
||||
url={https://research.googleblog.com/2015/06/inceptionism-going-deeper-into-neural.html}
|
||||
}
|
||||
|
||||
@misc{mordvintsev2016deepdreaming,
|
||||
title={DeepDreaming with TensorFlow},
|
||||
author={Mordvintsev, Alexander},
|
||||
year={2016},
|
||||
url={https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb},
|
||||
}
|
||||
|
||||
@article{radford2015unsupervised,
|
||||
title={Unsupervised representation learning with deep convolutional generative adversarial networks},
|
||||
author={Radford, Alec and Metz, Luke and Chintala, Soumith},
|
||||
journal={arXiv preprint arXiv:1511.06434},
|
||||
year={2015},
|
||||
url={https://arxiv.org/pdf/1511.06434.pdf}
|
||||
}
|
||||
|
||||
@inproceedings{salimans2016improved,
|
||||
title={Improved techniques for training gans},
|
||||
author={Salimans, Tim and Goodfellow, Ian and Zaremba, Wojciech and Cheung, Vicki and Radford, Alec and Chen, Xi},
|
||||
booktitle={Advances in Neural Information Processing Systems},
|
||||
pages={2226--2234},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1606.03498.pdf}
|
||||
}
|
||||
|
||||
@article{shi2016deconvolution,
|
||||
title={Is the deconvolution layer the same as a convolutional layer?},
|
||||
author={Shi, Wenzhe and Caballero, Jose and Theis, Lucas and Huszar, Ferenc and Aitken, Andrew and Ledig, Christian and Wang, Zehan},
|
||||
journal={arXiv preprint arXiv:1609.07009},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1609.07009.pdf}
|
||||
}
|
||||
|
||||
</script>
|
||||
</d-bibliography>
|
||||
|
||||
<distill-appendix> </distill-appendix>
|
||||
</d-appendix>
|
||||
|
||||
<distill-footer></distill-footer></body></html>
|
||||
+128
-34
@@ -1,39 +1,133 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf8">
|
||||
<script src="../dist/template.js"></script>
|
||||
|
||||
<script type="text/front-matter">
|
||||
title: Article Title
|
||||
description: Description of the post
|
||||
published: Jan 10, 2017
|
||||
authors:
|
||||
- Chris Olah: http://colah.github.io
|
||||
- Shan Carter: http://shancarter.com
|
||||
affiliations:
|
||||
- Google Brain: http://g.co/brain
|
||||
- Google Brain: http://g.co/brain
|
||||
</script>
|
||||
<head>
|
||||
<script src="../dist/template.v2.js"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" >
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
|
||||
<dt-header></dt-header>
|
||||
<dt-article>
|
||||
<script type="text/article"></script>
|
||||
<h1>Hello World</h1>
|
||||
<h2>A description of the article</h2>
|
||||
<dt-byline></dt-byline>
|
||||
<p>This is the first paragraph of the article.</p>
|
||||
<p>We can also cite <dt-cite key="gregor2015draw"></dt-cite> external publications.</p>
|
||||
</dt-article>
|
||||
<body>
|
||||
<distill-header></distill-header>
|
||||
<d-front-matter>
|
||||
<script id='distill-front-matter' type="text/json">{
|
||||
"title": "Why Momentum Really Works",
|
||||
"description": "Although \" extremely useful for visualizing high-dimensional data, t-SNE plots can sometimes be mysterious or misleading.",
|
||||
"published": "Jan 10, 2017",
|
||||
"authors": [
|
||||
{
|
||||
"author":"Chris Olah",
|
||||
"authorURL":"https://colah.github.io/",
|
||||
"affiliation":"Google Brain",
|
||||
"affiliationURL":"https://g.co/brain"
|
||||
},
|
||||
{
|
||||
"author":"Shan Carter",
|
||||
"authorURL":"https://shancarter.com/",
|
||||
"affiliation":"Google Brain",
|
||||
"affiliationURL":"https://g.co/brain"
|
||||
},
|
||||
{
|
||||
"author":"Ludwig Schubert",
|
||||
"authorURL":"https://shancarter.com/",
|
||||
"affiliation":"Google Brain",
|
||||
"affiliationURL":"https://g.co/brain"
|
||||
}
|
||||
],
|
||||
"katex": {
|
||||
"delimiters": [
|
||||
{"left": "$$", "right": "$$", "display": false}
|
||||
]
|
||||
}
|
||||
}</script>
|
||||
</d-front-matter>
|
||||
<d-title>
|
||||
<figure style="grid-column: page; margin: 1rem 0;"><img src="momentum.png" style="width:100%; border: 1px solid rgba(0, 0, 0, 0.2);"/></figure>
|
||||
<p>We often think of Momentum as a means of dampening oscillations and speeding up the iterations, leading to faster convergence. But it has other interesting behavior. It allows a larger range of step-sizes to be used, and creates its own oscillations. What is going on?</p>
|
||||
</d-title>
|
||||
<d-article>
|
||||
<a class="marker" href="#section-1" id="section-1"><span>1</span></a>
|
||||
<h2>A Brief Survey of Techniques</h2>
|
||||
<p>Before diving in: if you haven’t encountered t-SNE before, here’s what you need to know about the math behind it. The goal is to take a set of points in a high-dimensional space and find a faithful representation of those points in a lower-dimensional space, typically the 2D plane. The algorithm is non-linear and adapts to the underlying data, performing different transformations on different regions. Those differences can be a major source of confusion.</p>
|
||||
<p>This is the first paragraph of the article. Test a long — dash -- here it is.</p>
|
||||
<p>Test for owner's possessive. Test for "quoting a passage." And another sentence. Or two. Some flopping fins; for diving.</p>
|
||||
<aside>Some text in an aside, margin notes, etc...</aside>
|
||||
<p>Here's a test of an inline equation <d-math>c = a^2 + b^2</d-math>. Also with configurable katex standards just using inline '$' signs: $$x^2$$ And then there's a block equation:</p>
|
||||
<d-math block>
|
||||
c = \pm \sqrt{ \sum_{i=0}^{n}{a^{222} + b^2}}
|
||||
</d-math>
|
||||
<p>Math can also be quite involved:</p>
|
||||
<d-math block>
|
||||
\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots} } } }
|
||||
</d-math>
|
||||
<a class="marker" href="#section-1.1" id="section-1.1"><span>1.1</span></a>
|
||||
<h3>Citations</h3>
|
||||
<p><d-slider style="width: 200px;"></d-slider></p>
|
||||
<p>We can<d-cite key="mercier2011humans"></d-cite> also cite <d-cite key="gregor2015draw,mercier2011humans"></d-cite> external publications. <d-cite key="dong2014image,dumoulin2016guide,mordvintsev2015inceptionism"></d-cite>. We should also be testing footnotes<d-footnote>This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote. This will become a hoverable footnote.</d-footnote>. There are multiple footnotes, and they appear in the appendix<d-footnote>Given I have coded them right. Also, here's math in a footnote: <d-math>c = \sum_0^i{x}</d-math>. Also, a citation. Box-ception<d-cite key='gregor2015draw'></d-cite>!</d-footnote> as well.</p>
|
||||
<a class="marker" href="#section-2" id="section-2"><span>2</span></a>
|
||||
<h2>Displaying code snippets</h2>
|
||||
<p>Some inline javascript:<d-code language="javascript">var x = 25;</d-code>. And here's a javascript code block.</p>
|
||||
<d-code block language="javascript">
|
||||
var x = 25;
|
||||
function(x){
|
||||
return x * x;
|
||||
}
|
||||
</d-code>
|
||||
<p>We also support python.</p>
|
||||
<d-code block language="python">
|
||||
# Python 3: Fibonacci series up to n
|
||||
def fib(n):
|
||||
a, b = 0, 1
|
||||
while a < n:
|
||||
print(a, end=' ')
|
||||
a, b = b, a+b
|
||||
</d-code>
|
||||
<p>And a table</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>First</th><th>Second</th><th>Third</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>23</td><td>654</td><td>23</td></tr>
|
||||
<tr><td>14</td><td>54</td><td>34</td></tr>
|
||||
<tr><td>234</td><td>54</td><td>23</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<d-figure id="last-figure"></d-figure>
|
||||
<script>
|
||||
const figure = document.querySelector("d-figure#last-figure");
|
||||
const initTag = document.createElement("span");
|
||||
initTag.textContent = "initialized!"
|
||||
figure.appendChild(initTag);
|
||||
figure.addEventListener("ready", function() {
|
||||
const initTag = figure.querySelector("span");
|
||||
initTag.textContent = "ready"
|
||||
console.log('ready')
|
||||
});
|
||||
figure.addEventListener("onscreen", function() {
|
||||
const initTag = figure.querySelector("span");
|
||||
initTag.textContent = "onscreen"
|
||||
console.log('onscreen')
|
||||
});
|
||||
figure.addEventListener("offscreen", function() {
|
||||
const initTag = figure.querySelector("span");
|
||||
initTag.textContent = "offscreen!"
|
||||
console.log('offscreen')
|
||||
});
|
||||
</script>
|
||||
<p>That's it for the example article!</p>
|
||||
|
||||
</d-article>
|
||||
|
||||
<d-appendix>
|
||||
|
||||
<script type="text/bibliography">
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXivreprint arXiv:1502.04623},
|
||||
year={2015}
|
||||
}
|
||||
</script>
|
||||
<dt-appendix>
|
||||
<h3>Contributions</h3>
|
||||
<p>List of who did what</p>
|
||||
</dt-appendix>
|
||||
<dt-footer></dt-footer>
|
||||
<p>Some text describing who did what.</p>
|
||||
<h3>Reviewers</h3>
|
||||
<p>Some text with links describing who reviewed the article.</p>
|
||||
|
||||
<d-bibliography src="bibliography.bib"></d-bibliography>
|
||||
</d-appendix>
|
||||
|
||||
<distill-footer></distill-footer>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXivreprint arXiv:1502.04623},
|
||||
year={2015}
|
||||
journal={arXiv preprint arXiv:1502.04623},
|
||||
year={2015},
|
||||
url ={https://arxiv.org/pdf/1502.04623.pdf}
|
||||
}
|
||||
@article{mercier2011humans,
|
||||
title={Why do humans reason? Arguments for an argumentative theory},
|
||||
@@ -12,5 +13,87 @@
|
||||
number={02},
|
||||
pages={57--74},
|
||||
year={2011},
|
||||
publisher={Cambridge Univ Press}
|
||||
publisher={Cambridge Univ Press},
|
||||
doi={10.1017/S0140525X10000968}
|
||||
}
|
||||
|
||||
@article{dong2014image,
|
||||
title={Image super-resolution using deep convolutional networks},
|
||||
author={Dong, Chao and Loy, Chen Change and He, Kaiming and Tang, Xiaoou},
|
||||
journal={arXiv preprint arXiv:1501.00092},
|
||||
year={2014},
|
||||
url={https://arxiv.org/pdf/1501.00092.pdf}
|
||||
}
|
||||
|
||||
@article{dumoulin2016adversarially,
|
||||
title={Adversarially Learned Inference},
|
||||
author={Dumoulin, Vincent and Belghazi, Ishmael and Poole, Ben and Lamb, Alex and Arjovsky, Martin and Mastropietro, Olivier and Courville, Aaron},
|
||||
journal={arXiv preprint arXiv:1606.00704},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1606.00704.pdf}
|
||||
}
|
||||
|
||||
@article{dumoulin2016guide,
|
||||
title={A guide to convolution arithmetic for deep learning},
|
||||
author={Dumoulin, Vincent and Visin, Francesco},
|
||||
journal={arXiv preprint arXiv:1603.07285},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1603.07285.pdf}
|
||||
}
|
||||
|
||||
@article{gauthier2014conditional,
|
||||
title={Conditional generative adversarial nets for convolutional face generation},
|
||||
author={Gauthier, Jon},
|
||||
journal={Class Project for Stanford CS231N: Convolutional Neural Networks for Visual Recognition, Winter semester},
|
||||
volume={2014},
|
||||
year={2014},
|
||||
url={http://www.foldl.me/uploads/papers/tr-cgans.pdf}
|
||||
}
|
||||
|
||||
@article{johnson2016perceptual,
|
||||
title={Perceptual losses for real-time style transfer and super-resolution},
|
||||
author={Johnson, Justin and Alahi, Alexandre and Fei-Fei, Li},
|
||||
journal={arXiv preprint arXiv:1603.08155},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1603.08155.pdf}
|
||||
}
|
||||
|
||||
@article{mordvintsev2015inceptionism,
|
||||
title={Inceptionism: Going deeper into neural networks},
|
||||
author={Mordvintsev, Alexander and Olah, Christopher and Tyka, Mike},
|
||||
journal={Google Research Blog},
|
||||
year={2015},
|
||||
url={https://research.googleblog.com/2015/06/inceptionism-going-deeper-into-neural.html}
|
||||
}
|
||||
|
||||
@misc{mordvintsev2016deepdreaming,
|
||||
title={DeepDreaming with TensorFlow},
|
||||
author={Mordvintsev, Alexander},
|
||||
year={2016},
|
||||
url={https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb},
|
||||
}
|
||||
|
||||
@article{radford2015unsupervised,
|
||||
title={Unsupervised representation learning with deep convolutional generative adversarial networks},
|
||||
author={Radford, Alec and Metz, Luke and Chintala, Soumith},
|
||||
journal={arXiv preprint arXiv:1511.06434},
|
||||
year={2015},
|
||||
url={https://arxiv.org/pdf/1511.06434.pdf}
|
||||
}
|
||||
|
||||
@inproceedings{salimans2016improved,
|
||||
title={Improved techniques for training gans},
|
||||
author={Salimans, Tim and Goodfellow, Ian and Zaremba, Wojciech and Cheung, Vicki and Radford, Alec and Chen, Xi},
|
||||
booktitle={Advances in Neural Information Processing Systems},
|
||||
pages={2226--2234},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1606.03498.pdf}
|
||||
}
|
||||
|
||||
@article{shi2016deconvolution,
|
||||
title={Is the deconvolution layer the same as a convolutional layer?},
|
||||
author={Shi, Wenzhe and Caballero, Jose and Theis, Lucas and Huszar, Ferenc and Aitken, Andrew and Ledig, Christian and Wang, Zehan},
|
||||
journal={arXiv preprint arXiv:1609.07009},
|
||||
year={2016},
|
||||
url={https://arxiv.org/pdf/1609.07009.pdf}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
+131
-57
@@ -11,41 +11,36 @@
|
||||
.fake-img p {
|
||||
font-family: monospace;
|
||||
color: white;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
margin: 12px 0;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<dt-header></dt-header>
|
||||
<dt-article>
|
||||
<h1>How to Create a Distill Article</h1>
|
||||
<h2>A collection of examples and best practices for creating interactive explanatory articles using the Distill web framework</h2>
|
||||
<p>Distill ships with a CSS framework and a collection of custom web components that make building interactive academic articles easier than with raw HTML, CSS and JavaScript. This reference article details several examples and best practices for how to use both frameworks.</p>
|
||||
<hr>
|
||||
<h2>Getting Started</h2>
|
||||
<p>If you’re using Chrome as your development browser, here is the smallest distill post.</p>
|
||||
<p>Distill ships with a CSS framework and a collection of custom web components that make building interactive academic articles easier than with raw HTML, CSS and JavaScript. At its simplest, each distill post is just a single HTML file with one special script tag.</p>
|
||||
<dt-code block language="html">
|
||||
<script src="../dist/template.min.js"></script>
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<script src="http://distill.pub/template.js"></script>
|
||||
|
||||
<dt-article>
|
||||
<h1>Hello World</h1>
|
||||
</dt-article>
|
||||
</dt-code>
|
||||
<p>However, this omits some required html tags that might cause rendering problems during development if you’re using a browser other than Chrome. These missing tags will be added during publishing, so if the above works for you, feel free to use it. If you are having issues, try adding <dt-code>doctype</dt-code> and <dt-code>meta</dt-code> tags explicitly.</p>
|
||||
<p>This script tag will modify your post in your browser, adding the distill styling and functionality. When we publish your article, we will bake in these transformations, but during development it’s handy to be able to preview it locally (It even works without a web server).</p>
|
||||
<p>A typical distill post will be quite a bit longer than the one above. Below is a more complete example. Don’t worry if some of the tags don’t make sense, they’re all documented further in this post.</p>
|
||||
<dt-code block language="html">
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<script src="../dist/template.min.js"></script>
|
||||
<dt-article>
|
||||
<h1>Hello World</h1>
|
||||
</dt-article>
|
||||
</dt-code>
|
||||
<p>A typical distill post will be quite a bit longer than this though. Below is a more complete example. Don’t worry if some of the tags don’t make sense, they’re all documented further in this post.</p>
|
||||
<dt-code block language="html">
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<script src="../dist/template.min.js"></script>
|
||||
<dt-front-matter>
|
||||
<script src="http://distill.pub/template.js"></script>
|
||||
|
||||
<script type="text/front-matter">
|
||||
title: Article Title
|
||||
description: Description of the post
|
||||
published: Jan 10, 2017
|
||||
@@ -55,7 +50,8 @@
|
||||
affiliations:
|
||||
- Google Brain: http://g.co/brain
|
||||
- Google Brain: http://g.co/brain
|
||||
</dt-front-matter>
|
||||
</script>
|
||||
|
||||
<dt-article>
|
||||
<h1>Hello World</h1>
|
||||
<h2>A description of the article</h2>
|
||||
@@ -63,16 +59,21 @@
|
||||
<p>This is the first paragraph of the article.</p>
|
||||
<p>We can also cite <dt-cite key="gregor2015draw"></dt-cite> external publications.</p>
|
||||
</dt-article>
|
||||
<dt-bibliography>
|
||||
|
||||
<dt-appendix>
|
||||
</dt-appendix>
|
||||
|
||||
<script type="text/bibliography">
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXivreprint arXiv:1502.04623},
|
||||
year={2015}
|
||||
year={2015},
|
||||
url={https://arxiv.org/pdf/1502.04623.pdf}
|
||||
}
|
||||
</dt-bibliography>
|
||||
</script>
|
||||
</dt-code>
|
||||
<hr>
|
||||
<!-- <hr>
|
||||
<h2>Markdown</h2>
|
||||
<p>Markdown is supported as an alternative to html for the <dt-code language="html"><dt-article></dt-code> element. </p>
|
||||
<dt-code block language="html">
|
||||
@@ -86,14 +87,36 @@
|
||||
|
||||
First paragraph of the article.
|
||||
</dt-article>
|
||||
<dt-bibliography></dt-bibliography>
|
||||
<script type="text/bibliography"></script>
|
||||
</dt-code>
|
||||
<p>We use <a href="https://github.com/chjj/marked">marked</a> as the rendering engine, with <a href="https://help.github.com/articles/basic-writing-and-formatting-syntax/">github flavored markdown</a> and <a href="https://daringfireball.net/projects/smartypants/">smartypants</a> enabled. In development mode the markdown is translated in the client after the dom content has loaded, but when published, the translation is precompiled.</p>
|
||||
<p>We use <a href="https://github.com/chjj/marked">marked</a> as the rendering engine, with <a href="https://help.github.com/articles/basic-writing-and-formatting-syntax/">github flavored markdown</a> and <a href="https://daringfireball.net/projects/smartypants/">smartypants</a> enabled. In development mode the markdown is translated in the client after the dom content has loaded, but when published, the translation is precompiled.</p> -->
|
||||
|
||||
<hr>
|
||||
<h2>Project Structure</h2>
|
||||
<p>Because all the templating is delivered via a script tag, you are generally free to develop however you are most comfortable. The only requirements are that each article must be its own Github repository. The simplest setup would be a repository that contained a single HTML file, along with any additional assets, like images or javascript files. Note, in this default setup, all files in the root of the repository will be published. Note, also, in this configuration you generally will not even need to run a static local webserver. You can just open the <dt-code>index.html</dt-code> file in your browser to preview.</p>
|
||||
|
||||
<dt-code block language="html">
|
||||
image.jpg
|
||||
index.html
|
||||
script.js
|
||||
</dt-code>
|
||||
|
||||
<p>If you have a more complicated build process, or have files you don’t want published, put your output in a <dt-code>public</dt-code> folder and we will only publish its contents.</p>
|
||||
|
||||
<dt-code block language="html">
|
||||
build/
|
||||
_index.html
|
||||
package.json
|
||||
public/
|
||||
index.html
|
||||
image.jpg
|
||||
</dt-code>
|
||||
|
||||
<hr>
|
||||
<h2>Front Matter</h2>
|
||||
<p>You’ll need to describe some data about you post — title, description, authors, etc. For this use the <dt-code language="html"><dt-front-matter></dt-code> tag.</p>
|
||||
<p>You’ll need to describe some data about you post — title, description, authors, etc. For this use the <dt-code language="html"><script type="text/front-matter"></dt-code> tag.</p>
|
||||
<dt-code block language="html">
|
||||
<dt-front-matter>
|
||||
<script type="text/front-matter">
|
||||
title: Article Title
|
||||
description: Description of the post
|
||||
authors:
|
||||
@@ -102,43 +125,55 @@
|
||||
affiliations:
|
||||
- Google Brain: http://g.co/brain
|
||||
- Google Brain: http://g.co/brain
|
||||
</dt-front-matter>
|
||||
</script>
|
||||
</dt-code>
|
||||
<p>You can also use an external JSON file if you like. We will automatically make a request for a <dt-code>distill.json</dt-code> file if there is no <dt-code language="html"><dt-front-matter></dt-code> element on the page, or you can point to another file with the <dt-code>src</dt-code> attribute. In production, these files will be inlined into the document.</p>
|
||||
<!-- <p>You can also use an external JSON file if you like. We will automatically make a request for a <dt-code>distill.json</dt-code> file if there is no <dt-code language="html"><script type="text/front-matter"></dt-code> element on the page, or you can point to another file with the <dt-code>src</dt-code> attribute. In production, these files will be inlined into the document.</p>
|
||||
<dt-code block language="html">
|
||||
<dt-front-matter src="./distill.json"></dt-front-matter>
|
||||
</dt-code>
|
||||
<script type="text/front-matter" src="./distill.json"></script>
|
||||
</dt-code> -->
|
||||
<hr>
|
||||
<h2>Citations</h2>
|
||||
<p>Bibtex is the supported way of making academic citations. You first need have a global definition of all your possible citations. For this we’ll use the <dt-code language="html"><dt-bibliography></dt-code> element.</p>
|
||||
<p>Bibtex is the supported way of making academic citations. You first need have a global definition of all your possible citations. For this we’ll use the <dt-code language="html"><script type="text/bibliography"></dt-code> element.</p>
|
||||
<dt-code block language="html">
|
||||
<dt-bibliography>
|
||||
<script type="text/bibliography">
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXivreprint arXiv:1502.04623},
|
||||
year={2015}
|
||||
year={2015},
|
||||
url={https://arxiv.org/pdf/1502.04623.pdf},
|
||||
}
|
||||
@article{mercier2011humans,
|
||||
title={Why do humans reason? Arguments for an argumentative theory},
|
||||
author={Mercier, Hugo and Sperber, Dan},
|
||||
journal={Behavioral and brain sciences},
|
||||
volume={34},
|
||||
number={02},
|
||||
pages={57--74},
|
||||
year={2011},
|
||||
publisher={Cambridge Univ Press}
|
||||
}
|
||||
</dt-bibliography>
|
||||
</script>
|
||||
</dt-code>
|
||||
<p>Like with the <dt-code language="html"><dt-front-matter></dt-code> element, you can alternatively reference an external file with the <dt-code>src</dt-code> attribute. If no <dt-code language="html"><dt-bibliography></dt-code> element is found on the page, a request will automatically be made for <dt-code>bibliography.bib</dt-code>. In production, these files will be inlined into the document.</p>
|
||||
<p>(We strongly encourage you to populate the <dt-code>url</dt-code> bibtex field where possible so that we can provide links for citations.)</p>
|
||||
<!-- <p>Like with the <dt-code language="html"><script type="text/front-matter"></dt-code> element, you can alternatively reference an external file with the <dt-code>src</dt-code> attribute. If no <dt-code language="html"><script type="text/bibliography"></dt-code> element is found on the page, a request will automatically be made for <dt-code>bibliography.bib</dt-code>. In production, these files will be inlined into the document.</p>
|
||||
<dt-code block language="html">
|
||||
<dt-bibliography src="bibliography.bib"></dt-bibliography>
|
||||
</dt-code>
|
||||
<p>Citations are then used in the article body with the <dt-code language="html"><dt-cite></dt-code> tag. The <dt-code>article</dt-code> attribute is a reference to the id provided in the bibiography.</p>
|
||||
<script type="text/bibliography" src="bibliography.bib"></script>
|
||||
</dt-code> -->
|
||||
<p>Citations are then used in the article body with the <dt-code language="html"><dt-cite></dt-code> tag. The <dt-code>key</dt-code> attribute is a reference to the id provided in the bibiography. The <dt-code>key</dt-code> attribute can take multiple ids, separated by commas.</p>
|
||||
<dt-code block language="html">
|
||||
<dt-cite ket="gregor2015draw"></dt-cite>
|
||||
<dt-cite key="gregor2015draw"></dt-cite>
|
||||
</dt-code>
|
||||
<script type="text/bibliography">
|
||||
@article{gregor2015draw,
|
||||
title={DRAW: A recurrent neural network for image generation},
|
||||
author={Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan},
|
||||
journal={arXivreprint arXiv:1502.04623},
|
||||
year={2015},
|
||||
url={https://arxiv.org/pdf/1502.04623.pdf},
|
||||
}
|
||||
</script>
|
||||
<p>The citation is presented inline like this: <dt-cite key="gregor2015draw"></dt-cite> (a number that displays more information on hover). If you have an appendix, a bibliography is automatically created and populated in it.</p>
|
||||
<p>Distill chose a numerical inline citation style to improve readability of citation dense articles and because many of the benefits of longer citations are obviated by displaying more information on hover. However, we consider it good style to mention author last names if you discuss something at length and it fits into the flow well -- the authors are human and it's nice for them to have the community associate them with their work.</p>
|
||||
|
||||
|
||||
<hr>
|
||||
<h2>Footnotes</h2>
|
||||
<p>Just wrap the text you would like to show up in a footnote in a <dt-code language="html"><dt-fn></dt-code> tag. The number of the footnote will be automatically generated. <dt-fn>This text will be shown on hover.</dt-fn></p>
|
||||
<dt-code block language="html">
|
||||
<dt-fn>This will become a hoverable footnote.</dt-fn>
|
||||
</dt-code>
|
||||
<dt-footnote-body ref="blah"></dt-footnote-body>
|
||||
|
||||
<hr>
|
||||
<h2>Code Blocks</h2>
|
||||
@@ -152,30 +187,69 @@
|
||||
</dt-code>
|
||||
</dt-code>
|
||||
|
||||
<hr>
|
||||
<h2>Footnotes</h2>
|
||||
<p>This is a <dt-footnote ref="blah" /></p>
|
||||
<dt-footnote-body ref="blah"></dt-footnote-body>
|
||||
<!--
|
||||
<hr>
|
||||
<h2>Math</h2>
|
||||
-->
|
||||
<hr>
|
||||
<h2>Layouts</h2>
|
||||
<p>The main text column is referred to as the body. It is the assumed layout of any direct descendents of the <code>dt-article</code> element.</p>
|
||||
<div class="fake-img l-body"><p>.l-body</p></div>
|
||||
<p>For images you want to display a little larger, try these:</p>
|
||||
<div class="fake-img l-middle"><p>.l-middle</p></div>
|
||||
<div class="fake-img l-page"><p>.l-page</p></div>
|
||||
<p>Occasionally you’ll want to use the full browser width. For this, use screen. You can also inset the element a little from the edge of the browser by appending, you guessed it, <code>inset</code>.</p>
|
||||
<p>All of these have an <dt-code>outset</dt-code> variant if you want to poke out from the body text a little bit. For instance:</p>
|
||||
<div class="fake-img l-body-outset"><p>.l-body-outset</p></div>
|
||||
<div class="fake-img l-middle-outset"><p>.l-middle-outset</p></div>
|
||||
<div class="fake-img l-page-outset"><p>.l-page-outset</p></div>
|
||||
<p>Occasionally you’ll want to use the full browser width. For this, use <dt-code>.l-screen</dt-code>. You can also inset the element a little from the edge of the browser by using the inset variant.</p>
|
||||
<div class="fake-img l-screen"><p>.l-screen</p></div>
|
||||
<div class="fake-img l-screen-inset"><p>.l-screen-inset</p></div>
|
||||
<p>Often you want to position smaller images so as not to completely interrupt the flow of your text. Or perhaps you want to put some text in the margin as an aside or to signal that it’s optional content. For these cases we’ll use the float-based <code>.side</code> layouts.</p>
|
||||
<p>Often you want to position smaller images so as not to completely interrupt the flow of your text. Or perhaps you want to put some text in the margin as an aside or to signal that it’s optional content. For these cases we’ll use the float-based layouts.</p>
|
||||
<div class="fake-img l-body side"><p>.l-body.side</p></div>
|
||||
<div class="fake-img l-middle side"><p>.l-middle.side</p></div>
|
||||
<div class="fake-img l-page side"><p>.l-page.side</p></div>
|
||||
<p>They are all floated to the right and anchored to the right-hand edge of the position you specify. By default, each will take up approximately half of the width of the standard layout position, but you can override the width with a more specific selector. </p>
|
||||
<div class="fake-img l-gutter"><p>.l-gutter</p></div>
|
||||
<p>The final layout is for marginalia, asides, and footnotes. It does not interrupt the normal flow of <code>.l-body</code> sized text except on mobile screen sizes.</p>
|
||||
<p>You can also use an alternate centered layout by adding a <dt-code>centered</dt-code> class to the <dt-code>dt-article</dt-code> element.</p>
|
||||
<dt-code block language="html">
|
||||
<dt-article class="centered">
|
||||
<h1>Hello World</h1>
|
||||
</dt-article>
|
||||
</dt-code>
|
||||
<p>You can toggle it on this article by <a onclick="document.querySelector('dt-article').classList.toggle('centered');">clicking here</a></p>
|
||||
<section class="centered">
|
||||
|
||||
</section>
|
||||
|
||||
<hr>
|
||||
<h2>Including External Files</h2>
|
||||
<h2>Appendix</h2>
|
||||
|
||||
<p>An appendix can be added after your article, using the <dt-code language="html"><dt-appendix></dt-code> tag.</p>
|
||||
|
||||
<dt-code block language="html">
|
||||
<dt-article>
|
||||
...
|
||||
</dt-article>
|
||||
|
||||
<dt-appendix>
|
||||
<h3>Appendix Section Title</h3>
|
||||
<p>section content<p>
|
||||
</dt-appendix>
|
||||
</dt-code>
|
||||
|
||||
<p>You may wish to include the following sections in your appendix:</p>
|
||||
<ul>
|
||||
<li><b>Acknowledgments</b>: This is a place to recognize people and institutions. It may also be a good place to acknowledge and cite software that makes your work possible (eg. TensorFlow, OpenAI Gym).</li>
|
||||
<li><b>Author Contributions</b>: We strongly encourage you to include an author contributions statement briefly describing what each author did.</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
<h2>And You’re Off</h2>
|
||||
<p>That should do it. If you have any questions or bugs to file, feel free to <a href="https://github.com/distillpub/template/issues/new">open an issue on GitHub</a>.</p>
|
||||
<!--
|
||||
<hr>
|
||||
<h2>Including External Files</h2> -->
|
||||
|
||||
</dt-article>
|
||||
<dt-footer></dt-footer>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import html from "./components/html";
|
||||
import styles from "./components/styles";
|
||||
import frontMatter from "./components/front-matter";
|
||||
import bibliography from "./components/bibliography";
|
||||
import expandData from "./components/expand-data";
|
||||
import meta from "./components/meta";
|
||||
import header from "./components/header";
|
||||
import appendix from "./components/appendix";
|
||||
import footer from "./components/footer";
|
||||
import citation from "./components/citation";
|
||||
import markdown from "./components/markdown";
|
||||
import code from "./components/code";
|
||||
|
||||
function render(dom, data) {
|
||||
data = data || {};
|
||||
html(dom);
|
||||
styles(dom);
|
||||
dom.addEventListener("DOMContentLoaded", function(event) {
|
||||
frontMatter(dom, data);
|
||||
bibliography(dom, data);
|
||||
expandData(dom, data);
|
||||
meta(dom, data);
|
||||
header(dom, data);
|
||||
appendix(dom, data);
|
||||
footer(dom, data);
|
||||
markdown(dom, data);
|
||||
code(dom, data);
|
||||
citation(dom, data);
|
||||
console.log("final data:")
|
||||
for (var k in data) {console.log(" ", k, ": ", data[k])}
|
||||
});
|
||||
}
|
||||
|
||||
// If we are in a browser, run render automatically.
|
||||
if(window && window.document) {
|
||||
render(window.document);
|
||||
}
|
||||
|
||||
export {render as render};
|
||||
export {html as html};
|
||||
export {styles as styles};
|
||||
export {frontMatter as frontMatter};
|
||||
export {bibliography as bibliography};
|
||||
export {meta as meta};
|
||||
export {header as header};
|
||||
export {appendix as appendix};
|
||||
export {footer as footer};
|
||||
export {citation as citation};
|
||||
export {markdown as markdown};
|
||||
export {code as code};
|
||||
Generated
+6309
File diff suppressed because it is too large
Load Diff
+44
-16
@@ -1,38 +1,66 @@
|
||||
{
|
||||
"name": "distill-template",
|
||||
"version": "0.0.2",
|
||||
"version": "2.2.7",
|
||||
"description": "Template for creating Distill articles.",
|
||||
"main": "dist/distill.js",
|
||||
"scripts": {
|
||||
"start": "rollup -c -w",
|
||||
"build": "rollup -c",
|
||||
"test": "mocha"
|
||||
"main": "dist/template.v2.js",
|
||||
"bin": {
|
||||
"distill-render": "./bin/render.js"
|
||||
},
|
||||
"author": "Shan Carter",
|
||||
"homepage": "https://github.com/distillpub/distill-template#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/distillpub/distill-template/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "rollup -c rollup.config.dev.js -w",
|
||||
"serve": "python3 -m http.server --bind 127.0.0.1 8888",
|
||||
"test": "mocha",
|
||||
"lint": "eslint",
|
||||
"build": "rollup -c rollup.config.js",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"repository": {
|
||||
"url": "git+https://github.com/distillpub/distill-template.git",
|
||||
"type": "git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/distillpub/distill-template/issues"
|
||||
},
|
||||
"homepage": "https://github.com/distillpub/distill-template#readme",
|
||||
"devDependencies": {
|
||||
"bibtex-parse-js": "^0.0.23",
|
||||
"chai": "^3.5.0",
|
||||
"eslint": "^4.3.0",
|
||||
"eslint-config-google": "^0.9.1",
|
||||
"js-yaml": "^3.7.0",
|
||||
"jsdom": "^9.9.1",
|
||||
"jsdom": "11.3.0",
|
||||
"jsdom-global": "3.0.2",
|
||||
"marked": "^0.3.6",
|
||||
"mocha": "^3.2.0",
|
||||
"mocha": "^3.5.3",
|
||||
"prismjs": "^1.6.0",
|
||||
"rollup": "^0.36.4",
|
||||
"rollup-plugin-buble": "^0.14.0",
|
||||
"rollup": "^0.50.0",
|
||||
"rollup-plugin-babili": "^3.1.0",
|
||||
"rollup-plugin-buble": "^0.15.0",
|
||||
"rollup-plugin-commonjs": "^7.0.0",
|
||||
"rollup-plugin-livereload": "^0.3.1",
|
||||
"rollup-plugin-copy": "^0.2.3",
|
||||
"rollup-plugin-grapher": "^0.2.0",
|
||||
"rollup-plugin-gzip": "^1.2.0",
|
||||
"rollup-plugin-node-resolve": "^2.0.0",
|
||||
"rollup-plugin-serve": "^0.1.0",
|
||||
"rollup-plugin-string": "^2.0.2",
|
||||
"rollup-plugin-uglify": "^1.0.1",
|
||||
"rollup-watch": "^2.5.0"
|
||||
"rollup-watch": "^2.5.0",
|
||||
"should": "^13.1.2",
|
||||
"webpack": "^2.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@webcomponents/webcomponentsjs": "^1.0.7",
|
||||
"assert": "^1.4.1",
|
||||
"commander": "^2.9.0",
|
||||
"d3-array": "^1.2.1",
|
||||
"d3-drag": "^1.2.1",
|
||||
"d3-scale": "^1.0.6",
|
||||
"d3-selection": "^1.1.0",
|
||||
"d3-time-format": "^2.0.3",
|
||||
"escape-html": "^1.0.3",
|
||||
"intersection-observer": "^0.4.0",
|
||||
"jsdom-wc": "^11.0.0-alpha-1",
|
||||
"katex": "^0.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import string from 'rollup-plugin-string';
|
||||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import buble from 'rollup-plugin-buble';
|
||||
|
||||
// uncomment to show dependencies [1/2]
|
||||
// import rollupGrapher from 'rollup-plugin-grapher'
|
||||
|
||||
const componentsConfig = {
|
||||
input: 'src/components.js',
|
||||
output: [{ format: 'umd', name: 'dl', file: 'dist/template.v2.js' }],
|
||||
};
|
||||
|
||||
const transformsConfig = {
|
||||
input: 'src/transforms.js',
|
||||
output: [{ format: 'umd', name: 'dl', file: 'dist/transforms.v2.js', globals: {fs: 'fs'} }],
|
||||
external: ['fs']
|
||||
};
|
||||
|
||||
const defaultConfig = {
|
||||
sourcemap: true,
|
||||
plugins: [
|
||||
resolve({
|
||||
jsnext: true,
|
||||
browser: true,
|
||||
}),
|
||||
string({
|
||||
include: ['**/*.txt', '**/*.svg', '**/*.html', '**/*.css', '**/*.base64']
|
||||
}),
|
||||
commonjs(),
|
||||
|
||||
]
|
||||
};
|
||||
|
||||
Object.assign(componentsConfig, defaultConfig);
|
||||
Object.assign(transformsConfig, defaultConfig);
|
||||
|
||||
// transpile transforms so the node render script works…
|
||||
transformsConfig.plugins.push(
|
||||
buble({
|
||||
target: { 'node': 6 }
|
||||
})
|
||||
);
|
||||
|
||||
// uncomment to show dependencies [2/2]
|
||||
// transformsConfig.plugins.push(
|
||||
// rollupGrapher({
|
||||
// dest: '/dev/null',
|
||||
// verbose: true
|
||||
// })
|
||||
// );
|
||||
|
||||
export default [
|
||||
componentsConfig,
|
||||
transformsConfig,
|
||||
];
|
||||
+11
-36
@@ -1,39 +1,14 @@
|
||||
import buble from 'rollup-plugin-buble';
|
||||
import resolve from 'rollup-plugin-node-resolve';
|
||||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import liveReload from 'rollup-plugin-livereload';
|
||||
import serve from 'rollup-plugin-serve';
|
||||
import uglify from 'rollup-plugin-uglify';
|
||||
import string from 'rollup-plugin-string';
|
||||
import configs from './rollup.config.dev';
|
||||
import babili from 'rollup-plugin-babili';
|
||||
|
||||
const PORT = 8080;
|
||||
console.log(`open http://localhost:${PORT}/`);
|
||||
const [componentsConfig, transformsConfig] = configs;
|
||||
|
||||
export default {
|
||||
entry: 'index.js',
|
||||
componentsConfig.plugins.push(babili({
|
||||
comments: false, // means: *remove* comments
|
||||
sourceMap: true,
|
||||
targets: [
|
||||
{
|
||||
format: 'umd',
|
||||
moduleName: 'dl',
|
||||
dest: `dist/template.js`,
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
resolve({
|
||||
jsnext: true,
|
||||
browser: true,
|
||||
}),
|
||||
string({
|
||||
include: ["**/*.svg", "**/*.html", "**/*.css"]
|
||||
}),
|
||||
buble({
|
||||
exclude: 'node_modules',
|
||||
target: { chrome: 52, safari: 8, edge: 13, firefox: 48, }
|
||||
}),
|
||||
commonjs(),
|
||||
// uglify(),
|
||||
// liveReload(),
|
||||
serve({port: PORT}),
|
||||
]
|
||||
};
|
||||
}));
|
||||
|
||||
export default [
|
||||
componentsConfig,
|
||||
transformsConfig,
|
||||
];
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA99JREFUeNrsG4t1ozDMzQSM4A2ODUonKBucN2hugtIJ6E1AboLcBiQTkJsANiAb9OCd/OpzMWBJBl5TvaeXPiiyJetry0J8wW3D3QpjRh3GjneXDq+fSQA9s2mH9x3KDhN4foJfCb8N/Jrv+2fnDn8vLRQOplWHVYdvHZYdZsBcZP1vBmh/n8DzEmhUQDPaOuP9pFuY+JwJHwHnCLQE2tnWBGEyXozY9xCUgHMhhjE2I4heVWtgIkZ83wL6Qgxj1obfWBxymPwe+b00BCCRNPbwfb60yleAkkBHGT5AEehIYz7eJrFDMF9CvH4wwhcGHiHMneFvLDQwlwvMLQq58trRcYBWfYn0A0OgHWQUSu25mE+BnoYKnnEJoeIWAifzOv7vLWd2ZKRfWAIme3tOiUaQ3UnLkb0xj1FxRIeEGKaGIHOs9nEgLaaA9i0JRYo1Ic67wJW86KSKE/ZAM8KuVMk8ITVhmxUxJ3Cl2xlm9Vtkeju1+mpCQNxaEGNCY8bs9X2YqwNoQeGjBWut/ma0QAWy/TqAsHx9wSya3I5IRxOfTC+leG+kA/4vSeEcGBtNUN6byhu3+keEZCQJUNh8MAO7HL6H8pQLnsW/Hd4T4lv93TPjfM7A46iEEqbB5EDOvwYNW6tGNZzT/o+CZ6sqZ6wUtR/wf7mi/VL8iNciT6rHih48Y55b4nKCHJCCzb4y0nwFmin3ZEMIoLfZF8F7nncFmvnWBaBj7CGAYA/WGJsUwHdYqVDwAmNsUgAx4CGgAA7GOOxADYOFWOaIKifuVYzmOpREqA21Mo7aPsgiY1PhOMAmxtR+AUbYH3Id2wc0SAFIQTsn9IUGWR8k9jx3vtXSiAacFxTAGakBk9UudkNECd6jLe+6HrshshvIuC6IlLMRy7er+JpcKma24SlE4cFZSZJDGVVrsNvitQhQrDhW0jfiOLfFd47C42eHT56D/BK0To+58Ahj+cAT8HT1UWlfLZCCd/uKawzU0Rh2EyIX/Icqth3niG8ybNroezwe6khdCNxRN+l4XGdOLVLlOOt2hTRJlr1ETIuMAltVTMz70mJrkdGAaZLSmnBEqmAE32JCMmuTlCnRgsBENtOUpHhvvsYIL0ibnBkaC6QvKcR7738GKp0AKnim7xgUSNv1bpS8QwhBt8r+EP47v/oyRK/S34yJ9nT+AN0Tkm4OdB9E4BsmXM3SnMlRFUrtp6IDpV2eKzdYvF3etm3KhQksbOLChGkSmcBdmcEwvqkrMy5BzL00NZeu3qPYJOOuCc+5NjcWKXQxFvTa3NoXJ4d8in7fiAUuTt781dkvuHX4K8AA2Usy7yNKLy0AAAAASUVORK5CYII=
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="64px" height="64px" viewBox="-1214 838 64 64" style="enable-background:new -1214 838 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:none;stroke:#000000;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M-1182,841.2c-15.9,0-28.8,12.9-28.8,28.8s12.9,28.8,28.8,28.8s28.8-12.9,28.8-28.8S-1166.1,841.2-1182,841.2
|
||||
z M-1182,891.2c-7.7,0-13.9-6.1-13.9-13.8s13.9-22.2,13.9-36.3c0,14.2,13.9,28.7,13.9,36.3S-1174.3,891.2-1182,891.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 740 B |
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="-607 419 64 64">
|
||||
<path d="M-573.4,478.9c-8,0-14.6-6.4-14.6-14.5s14.6-25.9,14.6-40.8c0,14.9,14.6,32.8,14.6,40.8S-565.4,478.9-573.4,478.9z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 163 B |
@@ -0,0 +1,92 @@
|
||||
import { Controller } from './controller';
|
||||
|
||||
/* Transforms */
|
||||
import { makeStyleTag } from './styles/styles';
|
||||
import { Polyfills, polyfills } from './helpers/polyfills';
|
||||
|
||||
/* Components */
|
||||
import { Abstract } from './components/d-abstract';
|
||||
import { Appendix } from './components/d-appendix';
|
||||
import { Article } from './components/d-article';
|
||||
import { Bibliography } from './components/d-bibliography';
|
||||
import { Byline } from './components/d-byline';
|
||||
import { Cite } from './components/d-cite';
|
||||
import { CitationList } from './components/d-citation-list';
|
||||
import { Code } from './components/d-code';
|
||||
import { Footnote } from './components/d-footnote';
|
||||
import { FootnoteList } from './components/d-footnote-list';
|
||||
import { FrontMatter } from './components/d-front-matter';
|
||||
import { HoverBox } from './components/d-hover-box';
|
||||
import { Title } from './components/d-title';
|
||||
import { DMath } from './components/d-math';
|
||||
import { References } from './components/d-references';
|
||||
import { TOC } from './components/d-toc';
|
||||
import { Figure } from './components/d-figure';
|
||||
import { Interstitial } from './components/d-interstitial';
|
||||
import { Slider } from './ui/d-slider';
|
||||
|
||||
/* 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 distillMain = function() {
|
||||
|
||||
if (window.distillRunlevel < 1) {
|
||||
throw new Error('Insufficient Runlevel for Distill Template!');
|
||||
}
|
||||
|
||||
/* 1. Flag that we're being loaded */
|
||||
if ('distillTemplateIsLoading' in window && window.distillTemplateIsLoading) {
|
||||
throw new Error('Runlevel 1: Distill Template is getting loaded more than once, aborting!');
|
||||
} else {
|
||||
window.distillTemplateIsLoading = true;
|
||||
console.info('Runlevel 1: Distill Template has started loading.');
|
||||
}
|
||||
|
||||
/* 2. Add styles if they weren't added during prerendering */
|
||||
makeStyleTag(document);
|
||||
console.info('Runlevel 1: Static Distill styles have been added.');
|
||||
console.info('Runlevel 1->2.');
|
||||
window.distillRunlevel = 2;
|
||||
|
||||
/* 3. Register components */
|
||||
/* Article will register controller which takes control from there */
|
||||
const components = [
|
||||
Abstract, Appendix, Article, Bibliography, Byline, Cite, CitationList, Code,
|
||||
Footnote, FootnoteList, FrontMatter, HoverBox, Title, DMath, References, TOC, Figure,
|
||||
Slider, Interstitial
|
||||
];
|
||||
|
||||
const distillComponents = [
|
||||
DistillHeader, DistillAppendix, DistillFooter,
|
||||
];
|
||||
|
||||
if (window.distillRunlevel < 2) {
|
||||
throw new Error('Insufficient Runlevel for adding custom elements!');
|
||||
}
|
||||
const allComponents = components.concat(distillComponents);
|
||||
for (const component of allComponents) {
|
||||
console.info('Runlevel 2: Registering custom element: ' + component.is);
|
||||
customElements.define(component.is, component);
|
||||
}
|
||||
|
||||
console.info('Runlevel 2: Distill Template finished registering custom elements.');
|
||||
console.info('Runlevel 2->3.');
|
||||
window.distillRunlevel = 3;
|
||||
console.info('Distill Template initialisation complete.');
|
||||
Controller.listeners.DOMContentLoaded();
|
||||
|
||||
};
|
||||
|
||||
window.distillRunlevel = 0;
|
||||
/* 0. Check browser feature support; synchronously polyfill if needed */
|
||||
if (Polyfills.browserSupportsAllFeatures()) {
|
||||
console.info('Runlevel 0: No need for polyfills.');
|
||||
console.info('Runlevel 0->1.');
|
||||
window.distillRunlevel = 1;
|
||||
distillMain();
|
||||
} else {
|
||||
console.info('Runlevel 0: Distill Template is loading polyfills.');
|
||||
Polyfills.load(distillMain);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Template } from '../mixins/template';
|
||||
import { body } from '../helpers/layout';
|
||||
|
||||
const T = Template('d-abstract', `
|
||||
<style>
|
||||
:host {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.6em;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
::slotted(p) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
grid-column: text-start / middle-end;
|
||||
}
|
||||
${body('d-abstract')}
|
||||
</style>
|
||||
|
||||
<slot></slot>
|
||||
`);
|
||||
|
||||
export class Abstract extends T(HTMLElement) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Template } from '../mixins/template';
|
||||
import { body } from '../helpers/layout';
|
||||
|
||||
const T = Template('d-appendix', `
|
||||
<style>
|
||||
|
||||
d-appendix {
|
||||
contain: content;
|
||||
font-size: 0.8em;
|
||||
line-height: 1.7em;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 0;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
color: rgba(0,0,0,0.5);
|
||||
padding-top: 60px;
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
|
||||
d-appendix h3 {
|
||||
grid-column: page-start / text-start;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0;
|
||||
color: rgba(0,0,0,0.65);
|
||||
}
|
||||
|
||||
d-appendix h3 + * {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
d-appendix ol {
|
||||
padding: 0 0 0 15px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
d-appendix ol {
|
||||
padding: 0 0 0 30px;
|
||||
margin-left: -30px;
|
||||
}
|
||||
}
|
||||
|
||||
d-appendix li {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
d-appendix a {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
d-appendix > * {
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
d-appendix > d-footnote-list,
|
||||
d-appendix > d-citation-list,
|
||||
d-appendix > distill-appendix {
|
||||
grid-column: screen;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
`, false);
|
||||
|
||||
export class Appendix extends T(HTMLElement) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// import { Template } from '../mixins/template';
|
||||
import { Controller } from '../controller';
|
||||
|
||||
const isOnlyWhitespace = /^\s*$/;
|
||||
|
||||
export class Article extends HTMLElement {
|
||||
static get is() { return 'd-article'; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
new MutationObserver( (mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
for (const addedNode of mutation.addedNodes) {
|
||||
switch (addedNode.nodeName) {
|
||||
case '#text': { // usually text nodes are only linebreaks.
|
||||
const text = addedNode.nodeValue;
|
||||
if (!isOnlyWhitespace.test(text)) {
|
||||
console.warn('Use of unwrapped text in distill articles is discouraged as it breaks layout! Please wrap any text in a <span> or <p> tag. We found the following text: ' + text);
|
||||
const wrapper = document.createElement('span');
|
||||
wrapper.innerHTML = addedNode.nodeValue;
|
||||
addedNode.parentNode.insertBefore(wrapper, addedNode);
|
||||
addedNode.parentNode.removeChild(addedNode);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).observe(this, {childList: true});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
document.onreadystatechange = function () {
|
||||
console.log('onreadystatechange:');
|
||||
console.log(document.readyState);
|
||||
};
|
||||
console.info('Article tag connected, we can now listen to controller events.');
|
||||
console.info('Runlevel 3->4.');
|
||||
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!');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { parseBibtex } from '../helpers/bibtex';
|
||||
|
||||
export function parseBibliography(element) {
|
||||
const scriptTag = element.firstElementChild;
|
||||
if (scriptTag && scriptTag.tagName === 'SCRIPT') {
|
||||
if (scriptTag.type == 'text/bibtex') {
|
||||
const bibtex = element.firstElementChild.textContent;
|
||||
return parseBibtex(bibtex);
|
||||
} else if (scriptTag.type == 'text/json') {
|
||||
return new Map(JSON.parse(scriptTag.textContent));
|
||||
} else {
|
||||
console.warn('Unsupported bibliography script tag type: ' + scriptTag.type);
|
||||
}
|
||||
} else {
|
||||
console.warn('Bibliography did not have any script tag.');
|
||||
}
|
||||
}
|
||||
|
||||
export class Bibliography extends HTMLElement {
|
||||
|
||||
static get is() { return 'd-bibliography'; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// set up mutation observer
|
||||
const options = {childList: true, characterData: true, subtree: true};
|
||||
const observer = new MutationObserver( (entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.target.nodeName === 'SCRIPT' || entry.type === 'characterData') {
|
||||
this.parseIfPossible();
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(this, options);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
requestAnimationFrame(() => {
|
||||
this.parseIfPossible();
|
||||
});
|
||||
}
|
||||
|
||||
parseIfPossible() {
|
||||
const scriptTag = this.querySelector('script');
|
||||
if (!scriptTag) return;
|
||||
if (scriptTag.type == 'text/bibtex') {
|
||||
const newBibtex = scriptTag.textContent;
|
||||
if (this.bibtex !== newBibtex) {
|
||||
this.bibtex = newBibtex;
|
||||
const bibliography = parseBibtex(this.bibtex);
|
||||
this.notify(bibliography);
|
||||
}
|
||||
} else if (scriptTag.type == 'text/json') {
|
||||
const bibliography = new Map(JSON.parse(scriptTag.textContent));
|
||||
this.notify(bibliography);
|
||||
} else {
|
||||
console.warn('Unsupported bibliography script tag type: ' + scriptTag.type);
|
||||
}
|
||||
}
|
||||
|
||||
notify(bibliography) {
|
||||
const options = { detail: bibliography, bubbles: true };
|
||||
const event = new CustomEvent('onBibliographyChanged', options);
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/* observe 'src' attribute */
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['src'];
|
||||
}
|
||||
|
||||
receivedBibtex(event) {
|
||||
const bibliography = parseBibtex(event.target.response);
|
||||
this.notify(bibliography);
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
var oReq = new XMLHttpRequest();
|
||||
oReq.onload = (e) => this.receivedBibtex(e);
|
||||
oReq.onerror = () => console.warn(`Could not load Bibtex! (tried ${newValue})`);
|
||||
oReq.responseType = 'text';
|
||||
oReq.open('GET', newValue, true);
|
||||
oReq.send();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// import style from '../styles/d-byline.css';
|
||||
|
||||
export function bylineTemplate(frontMatter) {
|
||||
return `
|
||||
<div class="byline grid">
|
||||
<div class="authors-affiliations grid">
|
||||
<h3>Authors</h3>
|
||||
<h3>Affiliations</h3>
|
||||
${frontMatter.authors.map(author => `
|
||||
<p class="author">
|
||||
${author.personalURL ? `
|
||||
<a class="name" href="${author.personalURL}">${author.name}</a>` : `
|
||||
<div class="name">${author.name}</div>`}
|
||||
</p>
|
||||
<p class="affiliation">
|
||||
${author.affiliationURL ? `
|
||||
<a class="affiliation" href="${author.affiliationURL}">${author.affiliation}</a>` : `
|
||||
<div class="affiliation">${author.affiliation}</div>`}
|
||||
</p>
|
||||
`).join('')}
|
||||
</div>
|
||||
<div>
|
||||
<h3>Published</h3>
|
||||
${frontMatter.publishedDate ? `
|
||||
<p>${frontMatter.publishedMonth} ${frontMatter.publishedDay}, ${frontMatter.publishedYear}</p> ` : `
|
||||
<p><em>Not published yet.</em></p>`}
|
||||
</div>
|
||||
<div>
|
||||
<h3>DOI</h3>
|
||||
${frontMatter.doi ? `
|
||||
<p><a href="https://doi.org/${frontMatter.doi}">${frontMatter.doi}</a></p>` : `
|
||||
<p><em>No DOI yet.</em></p>`}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
export class Byline extends HTMLElement {
|
||||
|
||||
static get is() { return 'd-byline'; }
|
||||
|
||||
set frontMatter(frontMatter) {
|
||||
this.innerHTML = bylineTemplate(frontMatter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { bibliography_cite } from '../helpers/citation';
|
||||
|
||||
const styles = `
|
||||
d-citation-list {
|
||||
contain: content;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
d-citation-list .references {
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
d-citation-list .references .title {
|
||||
font-weight: 500;
|
||||
}
|
||||
`;
|
||||
|
||||
export function renderCitationList(element, entries, dom=document) {
|
||||
if (entries.size > 0) {
|
||||
element.style.display = '';
|
||||
let list = element.querySelector('.references');
|
||||
if (list) {
|
||||
list.innerHTML = '';
|
||||
} else {
|
||||
const stylesTag = dom.createElement('style');
|
||||
stylesTag.innerHTML = styles;
|
||||
element.appendChild(stylesTag);
|
||||
|
||||
const heading = dom.createElement('h3');
|
||||
heading.id = 'references';
|
||||
heading.textContent = 'References';
|
||||
element.appendChild(heading);
|
||||
|
||||
list = dom.createElement('ol');
|
||||
list.id = 'references-list';
|
||||
list.className = 'references';
|
||||
element.appendChild(list);
|
||||
}
|
||||
|
||||
for (const [key, entry] of entries) {
|
||||
const listItem = dom.createElement('li');
|
||||
listItem.id = key;
|
||||
listItem.innerHTML = bibliography_cite(entry);
|
||||
list.appendChild(listItem);
|
||||
}
|
||||
} else {
|
||||
element.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
export class CitationList extends HTMLElement {
|
||||
|
||||
static get is() { return 'd-citation-list'; }
|
||||
|
||||
connectedCallback() {
|
||||
if (!this.hasAttribute('distill-prerendered')) {
|
||||
this.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
set citations(citations) {
|
||||
renderCitationList(this, citations);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import { Template } from '../mixins/template';
|
||||
import { hover_cite, bibliography_cite } from '../helpers/citation';
|
||||
|
||||
const T = Template('d-cite', `
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.citation {
|
||||
display: inline-block;
|
||||
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;
|
||||
}
|
||||
|
||||
d-hover-box {
|
||||
margin-top: 1.9em;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<d-hover-box id="hover-box"></d-hover-box>
|
||||
|
||||
<div id="citation-" class="citation"><slot></slot><span class="citation-number"></span></div>
|
||||
`);
|
||||
|
||||
export class Cite extends T(HTMLElement) {
|
||||
|
||||
/* Lifecycle */
|
||||
|
||||
connectedCallback() {
|
||||
this.outerSpan = this.root.querySelector('#citation-');
|
||||
this.innerSpan = this.root.querySelector('.citation-number');
|
||||
this.hoverBox = this.root.querySelector('d-hover-box');
|
||||
window.customElements.whenDefined('d-hover-box').then(() => {
|
||||
this.hoverBox.listen(this);
|
||||
});
|
||||
}
|
||||
|
||||
//TODO This causes an infinite loop on firefox with polyfills.
|
||||
// This is only needed for interactive editing so no priority.
|
||||
// disconnectedCallback() {
|
||||
// const options = { detail: [this, this.keys], bubbles: true };
|
||||
// const event = new CustomEvent('onCiteKeyRemoved', options);
|
||||
// document.dispatchEvent(event);
|
||||
// }
|
||||
|
||||
/* 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(', ') + ']';
|
||||
if (this.innerSpan) {
|
||||
this.innerSpan.textContent = textContent;
|
||||
}
|
||||
}
|
||||
|
||||
set entries(entries) {
|
||||
if (this.hoverBox) {
|
||||
this.hoverBox.innerHTML = entries.map(hover_cite).join('<br><br>');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import Prism from 'prismjs';
|
||||
import 'prismjs/components/prism-python';
|
||||
import 'prismjs/components/prism-clike';
|
||||
import 'prismjs/components/prism-python';
|
||||
import 'prismjs/components/prism-clike';
|
||||
import 'prismjs/components/prism-lua';
|
||||
import 'prismjs/components/prism-bash';
|
||||
import 'prismjs/components/prism-go';
|
||||
import 'prismjs/components/prism-markdown';
|
||||
import 'prismjs/components/prism-julia';
|
||||
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;
|
||||
border-left: 2px solid rgba(0, 0, 0, .1);
|
||||
padding: 0 0 0 36px;
|
||||
}
|
||||
|
||||
${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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
// Figure
|
||||
//
|
||||
// d-figure provides a state-machine of visibility events:
|
||||
//
|
||||
// scroll out of view
|
||||
// +----------------+
|
||||
// *do work here* | |
|
||||
// +----------------+ +-+---------+ +-v---------+
|
||||
// | ready +----> onscreen | | offscreen |
|
||||
// +----------------+ +---------^-+ +---------+-+
|
||||
// | |
|
||||
// +----------------+
|
||||
// scroll into view
|
||||
//
|
||||
|
||||
export class Figure extends HTMLElement {
|
||||
|
||||
static get is() { return 'd-figure'; }
|
||||
|
||||
static get readyQueue() {
|
||||
if (!Figure._readyQueue) {
|
||||
Figure._readyQueue = [];
|
||||
}
|
||||
return Figure._readyQueue;
|
||||
}
|
||||
|
||||
static addToReadyQueue(figure) {
|
||||
if (Figure.readyQueue.indexOf(figure) === -1) {
|
||||
Figure.readyQueue.push(figure);
|
||||
Figure.runReadyQueue();
|
||||
}
|
||||
}
|
||||
|
||||
static runReadyQueue() {
|
||||
// console.log("Checking to run readyQueue, length: " + Figure.readyQueue.length + ", scrolling: " + Figure.isScrolling);
|
||||
// if (Figure.isScrolling) return;
|
||||
// console.log("Running ready Queue");
|
||||
const figure = Figure.readyQueue
|
||||
.sort((a,b) => a._seenOnScreen - b._seenOnScreen )
|
||||
.filter((figure) => !figure._ready)
|
||||
.pop();
|
||||
if (figure) {
|
||||
figure.ready();
|
||||
requestAnimationFrame(Figure.runReadyQueue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
// debugger
|
||||
this._ready = false;
|
||||
this._onscreen = false;
|
||||
this._offscreen = true;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.loadsWhileScrolling = this.hasAttribute('loadsWhileScrolling');
|
||||
Figure.marginObserver.observe(this);
|
||||
Figure.directObserver.observe(this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
Figure.marginObserver.unobserve(this);
|
||||
Figure.directObserver.unobserve(this);
|
||||
}
|
||||
|
||||
// We use two separate observers:
|
||||
// One with an extra 1000px margin to warn if the viewpoint gets close,
|
||||
// And one for the actual on/off screen events
|
||||
|
||||
static get marginObserver() {
|
||||
if (!Figure._marginObserver) {
|
||||
// if (!('IntersectionObserver' in window)) {
|
||||
// throw new Error('no interscetionobbserver!');
|
||||
// }
|
||||
const viewportHeight = window.innerHeight;
|
||||
const margin = Math.floor(2 * viewportHeight);
|
||||
const options = {rootMargin: margin + 'px 0px ' + margin + 'px 0px', threshold: 0.01};
|
||||
const callback = Figure.didObserveMarginIntersection;
|
||||
const observer = new IntersectionObserver(callback, options);
|
||||
Figure._marginObserver = observer;
|
||||
}
|
||||
return Figure._marginObserver;
|
||||
}
|
||||
|
||||
static didObserveMarginIntersection(entries) {
|
||||
for (const entry of entries) {
|
||||
const figure = entry.target;
|
||||
if (entry.isIntersecting && !figure._ready) {
|
||||
Figure.addToReadyQueue(figure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static get directObserver() {
|
||||
if (!Figure._directObserver) {
|
||||
Figure._directObserver = new IntersectionObserver(
|
||||
Figure.didObserveDirectIntersection, {
|
||||
rootMargin: '0px', threshold: [0, 1.0],
|
||||
}
|
||||
);
|
||||
}
|
||||
return Figure._directObserver;
|
||||
}
|
||||
|
||||
static didObserveDirectIntersection(entries) {
|
||||
for (const entry of entries) {
|
||||
const figure = entry.target;
|
||||
if (entry.isIntersecting) {
|
||||
figure._seenOnScreen = new Date();
|
||||
// if (!figure._ready) { figure.ready(); }
|
||||
if (figure._offscreen) { figure.onscreen(); }
|
||||
} else {
|
||||
if (figure._onscreen) { figure.offscreen(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners that registered late, too:
|
||||
|
||||
addEventListener(eventName, callback) {
|
||||
super.addEventListener(eventName, callback);
|
||||
// if we had already dispatched something while presumingly no one was listening, we do so again
|
||||
// debugger
|
||||
if (eventName === 'ready') {
|
||||
if (Figure.readyQueue.indexOf(this) !== -1) {
|
||||
this._ready = false;
|
||||
Figure.runReadyQueue();
|
||||
}
|
||||
}
|
||||
if (eventName === 'onscreen') {
|
||||
this.onscreen();
|
||||
}
|
||||
}
|
||||
|
||||
// Custom Events
|
||||
|
||||
ready() {
|
||||
// debugger
|
||||
this._ready = true;
|
||||
Figure.marginObserver.unobserve(this);
|
||||
const event = new CustomEvent('ready');
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
onscreen() {
|
||||
this._onscreen = true;
|
||||
this._offscreen = false;
|
||||
const event = new CustomEvent('onscreen');
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
offscreen() {
|
||||
this._onscreen = false;
|
||||
this._offscreen = true;
|
||||
const event = new CustomEvent('offscreen');
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
|
||||
Figure.isScrolling = false;
|
||||
let timeout;
|
||||
const resetTimer = () => {
|
||||
Figure.isScrolling = true;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
Figure.isScrolling = false;
|
||||
Figure.runReadyQueue();
|
||||
}, 500);
|
||||
};
|
||||
window.addEventListener('scroll', resetTimer, true);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Template } from '../mixins/template';
|
||||
|
||||
const T = Template('d-footnote-list', `
|
||||
<style>
|
||||
|
||||
d-footnote-list {
|
||||
contain: content;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
d-footnote-list > * {
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
d-footnote-list a.footnote-backlink {
|
||||
color: rgba(0,0,0,0.3);
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<h3>Footnotes</h3>
|
||||
<ol></ol>
|
||||
`, false);
|
||||
|
||||
export class FootnoteList extends T(HTMLElement) {
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this.list = this.root.querySelector('ol');
|
||||
// footnotes list is initially hidden
|
||||
this.root.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.style.display = '';
|
||||
|
||||
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.root.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { Template } from '../mixins/template.js';
|
||||
|
||||
const T = Template('d-footnote', `
|
||||
<style>
|
||||
|
||||
d-math[block] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:host {
|
||||
}
|
||||
|
||||
sup {
|
||||
line-height: 1em;
|
||||
font-size: 0.75em;
|
||||
position: relative;
|
||||
top: -.5em;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
span {
|
||||
color: hsla(206, 90%, 20%, 0.7);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.dt-hover-box {
|
||||
margin: 0 auto;
|
||||
width: 704px;
|
||||
max-width: 100vw;
|
||||
background-color: #FFF;
|
||||
opacity: 0.95;
|
||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||
padding: 8px 16px;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<d-hover-box>
|
||||
<slot id="slot"></slot>
|
||||
</d-hover-box>
|
||||
|
||||
<sup>
|
||||
<span id="fn-" data-hover-ref=""></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');
|
||||
// console.warn(slot.textContent);
|
||||
// slot.addEventListener('slotchange', this.notify);
|
||||
this.hoverBox = this.root.querySelector('d-hover-box');
|
||||
window.customElements.whenDefined('d-hover-box').then(() => {
|
||||
this.hoverBox.listen(this);
|
||||
});
|
||||
// create numeric ID
|
||||
Footnote.currentFootnoteId += 1;
|
||||
const IdString = Footnote.currentFootnoteId.toString();
|
||||
this.root.host.id = 'd-footnote-' + IdString;
|
||||
|
||||
// set up hidden hover box
|
||||
const id = 'dt-fn-hover-box-' + IdString;
|
||||
this.hoverBox.id = id
|
||||
|
||||
// set up visible footnote marker
|
||||
const span = this.root.querySelector('#fn-');
|
||||
span.setAttribute('id', 'fn-' + IdString);
|
||||
span.setAttribute('data-hover-ref', id);
|
||||
span.textContent = IdString;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Footnote.currentFootnoteId = 0;
|
||||
@@ -0,0 +1,42 @@
|
||||
export function parseFrontmatter(element) {
|
||||
const scriptTag = element.querySelector('script');
|
||||
if (scriptTag) {
|
||||
const type = scriptTag.getAttribute('type');
|
||||
if (type.split('/')[1] == 'json') {
|
||||
const content = scriptTag.textContent;
|
||||
return JSON.parse(content);
|
||||
} else {
|
||||
console.error('Distill only supports JSON frontmatter tags anymore; no more YAML.');
|
||||
}
|
||||
} 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'; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
const options = {childList: true, characterData: true, subtree: true};
|
||||
const observer = new MutationObserver( (entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.target.nodeName === 'SCRIPT' || entry.type === 'characterData') {
|
||||
const data = parseFrontmatter(this);
|
||||
this.notify(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
observer.observe(this, options);
|
||||
}
|
||||
|
||||
notify(data) {
|
||||
const options = { detail: data, bubbles: true };
|
||||
const event = new CustomEvent('onFrontMatterChanged', options);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { Template } from '../mixins/template.js';
|
||||
|
||||
const T = Template('d-hover-box', `
|
||||
<style>
|
||||
|
||||
:host {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
z-index: 10000;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 704px;
|
||||
max-width: 100vw;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.panel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
background-color: rgb(250, 250, 250);
|
||||
box-shadow: 0 0 7px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="panel">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
export class HoverBox extends T(HTMLElement) {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
|
||||
}
|
||||
|
||||
listen(element) {
|
||||
console.log(element)
|
||||
this.bindDivEvents(this);
|
||||
this.bindTriggerEvents(element);
|
||||
// this.style.display = "block";
|
||||
}
|
||||
|
||||
bindDivEvents(element) {
|
||||
// For mice, same behavior as hovering on links
|
||||
element.addEventListener('mouseover', () => {
|
||||
if (!this.visible) this.showAtNode(element);
|
||||
this.stopTimeout();
|
||||
});
|
||||
element.addEventListener('mouseout', () => {
|
||||
this.extendTimeout(500);
|
||||
});
|
||||
// Don't trigger body touchstart event when touching within box
|
||||
element.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(300);
|
||||
});
|
||||
|
||||
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;
|
||||
this.style.display = 'block';
|
||||
}
|
||||
|
||||
showAtNode(node) {
|
||||
const bbox = node.getBoundingClientRect();
|
||||
this.show([bbox.right, bbox.bottom]);
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.visible = false;
|
||||
this.style.display = 'none';
|
||||
this.stopTimeout();
|
||||
}
|
||||
|
||||
stopTimeout() {
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
extendTimeout(time) {
|
||||
this.stopTimeout();
|
||||
this.timeout = setTimeout(() => {
|
||||
this.hide();
|
||||
}, time);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
import { Template } from '../mixins/template';
|
||||
|
||||
// This overlay is not secure.
|
||||
// It is only meant as a social deterrent.
|
||||
|
||||
const T = Template('d-interstitial', `
|
||||
<style>
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: white;
|
||||
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
z-index: 2147483647 /* MaxInt32 */
|
||||
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 420px;
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: hsl(0,100%,40%);
|
||||
-webkit-text-decoration-color: hsl(0,100%,40%);
|
||||
margin-bottom: 1em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
input[type="password"] {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
-webkit-border-radius: none;
|
||||
-moz-border-radius: none;
|
||||
-ms-border-radius: none;
|
||||
-o-border-radius: none;
|
||||
border-radius: none;
|
||||
outline: none;
|
||||
|
||||
font-size: 18px;
|
||||
background: none;
|
||||
width: 25%;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-bottom: solid 2px #999;
|
||||
transition: border .3s;
|
||||
}
|
||||
|
||||
input[type="password"]:focus {
|
||||
border-bottom: solid 2px #333;
|
||||
}
|
||||
|
||||
input[type="password"].wrong {
|
||||
border-bottom: solid 2px hsl(0,100%,40%);
|
||||
}
|
||||
|
||||
p small {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: relative;
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 3em;
|
||||
}
|
||||
|
||||
.logo svg {
|
||||
width: 36px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.logo svg path {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="overlay">
|
||||
<div class="container">
|
||||
<h1>This article is in review.</h1>
|
||||
<p>Do not share this URL or the contents of this article. Thank you!</p>
|
||||
<input id="interstitial-password-input" type="password" name="password" autofocus/>
|
||||
<p><small>Enter the password we shared with you as part of the review process to view the article.</small></p>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
|
||||
export class Interstitial extends T(HTMLElement) {
|
||||
|
||||
connectedCallback() {
|
||||
const passwordInput = this.root.querySelector('#interstitial-password-input');
|
||||
passwordInput.oninput = (event) => this.passwordChanged(event);
|
||||
if (typeof(Storage) !== 'undefined') {
|
||||
if (localStorage.getItem('distill-interstitial-password-correct') === 'true') {
|
||||
console.log('Loaded that correct password was entered before; skipping interstitial.');
|
||||
this.parentElement.removeChild(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
passwordChanged(event) {
|
||||
const entered = event.target.value;
|
||||
if (entered === this.password) {
|
||||
console.log('Correct password entered.');
|
||||
this.parentElement.removeChild(this);
|
||||
if (typeof(Storage) !== 'undefined') {
|
||||
console.log('Saved that correct password was entered.');
|
||||
localStorage.setItem('distill-interstitial-password-correct', 'true');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*global katex */
|
||||
import { Mutating } from '../mixins/mutating.js';
|
||||
import { Template } from '../mixins/template.js';
|
||||
|
||||
import style from '../styles/d-math.css';
|
||||
|
||||
// attaches renderMathInElement to window
|
||||
import { renderMathInElement } from '../helpers/katex-auto-render';
|
||||
|
||||
export const katexJSURL = 'https://distill.pub/third-party/katex/katex.min.js';
|
||||
export const katexCSSTag = '<link rel="stylesheet" href="https://distill.pub/third-party/katex/katex.min.css" crossorigin="anonymous">';
|
||||
|
||||
const T = Template('d-math', `
|
||||
${katexCSSTag}
|
||||
<style>
|
||||
|
||||
:host {
|
||||
display: inline-block;
|
||||
contain: content;
|
||||
}
|
||||
|
||||
:host([block]) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
${style}
|
||||
</style>
|
||||
<span id='katex-container'></span>
|
||||
`);
|
||||
|
||||
// DMath, not Math, because that would conflict with the JS built-in
|
||||
export class DMath extends Mutating(T(HTMLElement)) {
|
||||
|
||||
static set katexOptions(options) {
|
||||
DMath._katexOptions = options;
|
||||
if (DMath.katexOptions.delimiters) {
|
||||
if (!DMath.katexAdded) {
|
||||
DMath.addKatex();
|
||||
} else {
|
||||
DMath.katexLoadedCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static get katexOptions() {
|
||||
if (!DMath._katexOptions) {
|
||||
DMath._katexOptions = {
|
||||
delimiters: [ { 'left':'$$', 'right':'$$', 'display': false } ]
|
||||
};
|
||||
}
|
||||
return DMath._katexOptions;
|
||||
}
|
||||
|
||||
static katexLoadedCallback() {
|
||||
// render all d-math tags
|
||||
const mathTags = document.querySelectorAll('d-math');
|
||||
for (const mathTag of mathTags) {
|
||||
mathTag.renderContent();
|
||||
}
|
||||
// transform inline delimited math to d-math tags
|
||||
if (DMath.katexOptions.delimiters) {
|
||||
const article = document.querySelector('d-article');
|
||||
renderMathInElement(article, DMath.katexOptions);
|
||||
}
|
||||
}
|
||||
|
||||
static addKatex() {
|
||||
// css tag can use this convenience function
|
||||
document.head.insertAdjacentHTML('beforeend', katexCSSTag);
|
||||
// script tag has to be created to work properly
|
||||
const scriptTag = document.createElement('script');
|
||||
scriptTag.src = katexJSURL;
|
||||
scriptTag.async = true;
|
||||
scriptTag.onload = DMath.katexLoadedCallback;
|
||||
scriptTag.crossorigin = 'anonymous';
|
||||
document.head.appendChild(scriptTag);
|
||||
|
||||
DMath.katexAdded = true;
|
||||
}
|
||||
|
||||
get options() {
|
||||
const localOptions = { displayMode: this.hasAttribute('block') };
|
||||
return Object.assign(localOptions, DMath.katexOptions);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
if (!DMath.katexAdded) {
|
||||
DMath.addKatex();
|
||||
}
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
if (typeof katex !== 'undefined') {
|
||||
const container = this.root.querySelector('#katex-container');
|
||||
katex.render(this.textContent, container, this.options);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DMath.katexAdded = false;
|
||||
DMath.inlineMathRendered = false;
|
||||
window.DMath = DMath; // TODO: check if this can be removed, or if we should expose a distill global
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Template } from '../mixins/template';
|
||||
|
||||
const T = Template('d-references', `
|
||||
<style>
|
||||
d-references {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
`, false);
|
||||
|
||||
export class References extends T(HTMLElement) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export class Title extends HTMLElement {
|
||||
static get is() { return 'd-title'; }
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
export class TOC extends HTMLElement {
|
||||
|
||||
static get is() { return 'd-toc'; }
|
||||
|
||||
connectedCallback() {
|
||||
if (!this.getAttribute('prerendered')) {
|
||||
window.onload = () => {
|
||||
const article = document.querySelector('d-article');
|
||||
const headings = article.querySelectorAll('h2, h3');
|
||||
renderTOC(this, headings);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function renderTOC(element, headings) {
|
||||
|
||||
let ToC =`
|
||||
<style>
|
||||
|
||||
d-toc {
|
||||
contain: content;
|
||||
display: block;
|
||||
}
|
||||
|
||||
d-toc ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
d-toc ul > ul {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
d-toc a {
|
||||
border-bottom: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
<nav role="navigation" class="table-of-contents"></nav>
|
||||
<h2>Table of contents</h2>
|
||||
<ul>`;
|
||||
|
||||
for (const el of headings) {
|
||||
// should element be included in TOC?
|
||||
const isInTitle = el.parentElement.tagName == 'D-TITLE';
|
||||
const isException = el.getAttribute('no-toc');
|
||||
if (isInTitle || isException) continue;
|
||||
// create TOC entry
|
||||
const title = el.textContent;
|
||||
const link = '#' + el.getAttribute('id');
|
||||
|
||||
let newLine = '<li>' + '<a href="' + link + '">' + title + '</a>' + '</li>';
|
||||
if (el.tagName == 'H3') {
|
||||
newLine = '<ul>' + newLine + '</ul>';
|
||||
} else {
|
||||
newLine += '<br>';
|
||||
}
|
||||
ToC += newLine;
|
||||
|
||||
}
|
||||
|
||||
ToC += '</ul></nav>';
|
||||
element.innerHTML = ToC;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import { FrontMatter, mergeFromYMLFrontmatter } from './front-matter';
|
||||
import { DMath } from './components/d-math';
|
||||
import { collect_citations } from './helpers/citation.js';
|
||||
import { parseFrontmatter } from './components/d-front-matter';
|
||||
import optionalComponents from './transforms/optional-components';
|
||||
|
||||
const frontMatter = new FrontMatter();
|
||||
|
||||
export const Controller = {
|
||||
|
||||
frontMatter: frontMatter,
|
||||
waitingOn: {
|
||||
bibliography: [],
|
||||
citations: [],
|
||||
},
|
||||
listeners: {
|
||||
|
||||
onCiteKeyCreated(event) {
|
||||
const [citeTag, keys] = event.detail;
|
||||
|
||||
// ensure we have citations
|
||||
if (!frontMatter.citationsCollected) {
|
||||
// console.debug('onCiteKeyCreated, but unresolved dependency ("citations"). Enqueing.');
|
||||
Controller.waitingOn.citations.push(() => Controller.listeners.onCiteKeyCreated(event));
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure we have a loaded bibliography
|
||||
if (!frontMatter.bibliographyParsed) {
|
||||
// console.debug('onCiteKeyCreated, but unresolved dependency ("bibliography"). Enqueing.');
|
||||
Controller.waitingOn.bibliography.push(() => Controller.listeners.onCiteKeyCreated(event));
|
||||
return;
|
||||
}
|
||||
|
||||
const numbers = keys.map( key => frontMatter.citations.indexOf(key) );
|
||||
citeTag.numbers = numbers;
|
||||
const entries = keys.map( key => frontMatter.bibliography.get(key) );
|
||||
citeTag.entries = entries;
|
||||
},
|
||||
|
||||
onCiteKeyChanged() {
|
||||
// const [citeTag, keys] = event.detail;
|
||||
|
||||
// update citations
|
||||
frontMatter.citations = collect_citations();
|
||||
frontMatter.citationsCollected = true;
|
||||
for (const waitingCallback of Controller.waitingOn.citations.slice()) {
|
||||
waitingCallback();
|
||||
}
|
||||
|
||||
// update bibliography
|
||||
const citationListTag = document.querySelector('d-citation-list');
|
||||
const bibliographyEntries = new Map(frontMatter.citations.map( citationKey => {
|
||||
return [citationKey, frontMatter.bibliography.get(citationKey)];
|
||||
}));
|
||||
citationListTag.citations = bibliographyEntries;
|
||||
|
||||
const citeTags = document.querySelectorAll('d-cite');
|
||||
for (const citeTag of citeTags) {
|
||||
const keys = citeTag.keys;
|
||||
const numbers = keys.map( key => frontMatter.citations.indexOf(key) );
|
||||
citeTag.numbers = numbers;
|
||||
const entries = keys.map( key => frontMatter.bibliography.get(key) );
|
||||
citeTag.entries = entries;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
onCiteKeyRemoved(event) {
|
||||
Controller.listeners.onCiteKeyChanged(event);
|
||||
},
|
||||
|
||||
onBibliographyChanged(event) {
|
||||
const citationListTag = document.querySelector('d-citation-list');
|
||||
|
||||
const bibliography = event.detail;
|
||||
|
||||
frontMatter.bibliography = bibliography;
|
||||
frontMatter.bibliographyParsed = true;
|
||||
for (const waitingCallback of Controller.waitingOn.bibliography.slice()) {
|
||||
waitingCallback();
|
||||
}
|
||||
|
||||
// ensure we have citations
|
||||
if (!frontMatter.citationsCollected) {
|
||||
Controller.waitingOn.citations.push( function() {
|
||||
Controller.listeners.onBibliographyChanged({target: event.target, detail: event.detail});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (citationListTag.hasAttribute('distill-prerendered')) {
|
||||
console.info('Citation list was prerendered; not updating it.');
|
||||
} else {
|
||||
const entries = new Map(frontMatter.citations.map( citationKey => {
|
||||
return [citationKey, frontMatter.bibliography.get(citationKey)];
|
||||
}));
|
||||
citationListTag.citations = entries;
|
||||
}
|
||||
},
|
||||
|
||||
onFootnoteChanged() {
|
||||
// const footnote = event.detail;
|
||||
//TODO: optimize to only update current footnote
|
||||
const footnotesList = document.querySelector('d-footnote-list');
|
||||
if (footnotesList) {
|
||||
const footnotes = document.querySelectorAll('d-footnote');
|
||||
footnotesList.footnotes = footnotes;
|
||||
}
|
||||
},
|
||||
|
||||
onFrontMatterChanged(event) {
|
||||
const data = event.detail;
|
||||
mergeFromYMLFrontmatter(frontMatter, data);
|
||||
|
||||
const interstitial = document.querySelector('d-interstitial');
|
||||
if (interstitial) {
|
||||
interstitial.password = frontMatter.password;
|
||||
}
|
||||
|
||||
const prerendered = document.body.hasAttribute('distill-prerendered');
|
||||
if (!prerendered) {
|
||||
optionalComponents(document, frontMatter);
|
||||
|
||||
const appendix = document.querySelector('distill-appendix');
|
||||
if (appendix) {
|
||||
appendix.frontMatter = frontMatter;
|
||||
}
|
||||
|
||||
const byline = document.querySelector('d-byline');
|
||||
if (byline) {
|
||||
byline.frontMatter = frontMatter;
|
||||
}
|
||||
|
||||
if (data.katex) {
|
||||
DMath.katexOptions = data.katex;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
DOMContentLoaded() {
|
||||
if (Controller.loaded || ['interactive', 'complete'].indexOf(document.readyState) === -1) {
|
||||
return;
|
||||
} else {
|
||||
Controller.loaded = true;
|
||||
console.log('Controller running DOMContentLoaded');
|
||||
}
|
||||
|
||||
const frontMatterTag = document.querySelector('d-front-matter');
|
||||
const data = parseFrontmatter(frontMatterTag);
|
||||
Controller.listeners.onFrontMatterChanged({detail: data});
|
||||
|
||||
// console.debug('Resolving "citations" dependency due to initial DOM load.');
|
||||
frontMatter.citations = collect_citations();
|
||||
frontMatter.citationsCollected = true;
|
||||
for (const waitingCallback of Controller.waitingOn.citations.slice()) {
|
||||
waitingCallback();
|
||||
}
|
||||
|
||||
if (frontMatter.bibliographyParsed) {
|
||||
for (const waitingCallback of Controller.waitingOn.bibliography.slice()) {
|
||||
waitingCallback();
|
||||
}
|
||||
}
|
||||
|
||||
const footnotesList = document.querySelector('d-footnote-list');
|
||||
if (footnotesList) {
|
||||
const footnotes = document.querySelectorAll('d-footnote');
|
||||
footnotesList.footnotes = footnotes;
|
||||
}
|
||||
}
|
||||
|
||||
}, // listeners
|
||||
|
||||
}; // Controller
|
||||
@@ -0,0 +1,76 @@
|
||||
import { serializeFrontmatterToBibtex } from '../helpers/bibtex';
|
||||
|
||||
const styles = `
|
||||
<style>
|
||||
distill-appendix {
|
||||
contain: content;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
distill-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;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
distill-appendix > * {
|
||||
grid-column: text;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
export function appendixTemplate(frontMatter) {
|
||||
let html = styles;
|
||||
|
||||
if (typeof frontMatter.githubUrl !== 'undefined') {
|
||||
html += `
|
||||
<h3 id="updates-and-corrections">Updates and Corrections</h3>
|
||||
<p>`;
|
||||
if (frontMatter.githubCompareUpdatesUrl) {
|
||||
html += `<a href="${frontMatter.githubCompareUpdatesUrl}">View all changes</a> to this article since it was first published.`;
|
||||
}
|
||||
html += `
|
||||
If you see mistakes or want to suggest changes, please <a href="${frontMatter.githubUrl + '/issues/new'}">create an issue on GitHub</a>. </p>
|
||||
`;
|
||||
}
|
||||
|
||||
const journal = frontMatter.journal;
|
||||
if (typeof journal !== 'undefined' && journal.title === 'Distill') {
|
||||
html += `
|
||||
<h3 id="reuse">Reuse</h3>
|
||||
<p>Diagrams and text are licensed under Creative Commons Attribution <a href="https://creativecommons.org/licenses/by/4.0/">CC-BY 4.0</a> with the <a class="github" href="${frontMatter.githubUrl}">source available on GitHub</a>, unless noted otherwise. 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>
|
||||
`;
|
||||
}
|
||||
|
||||
if (typeof frontMatter.publishedDate !== 'undefined') {
|
||||
html += `
|
||||
<h3 id="citation">Citation</h3>
|
||||
<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">${serializeFrontmatterToBibtex(frontMatter)}</pre>
|
||||
`;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
export class DistillAppendix extends HTMLElement {
|
||||
|
||||
static get is() { return 'distill-appendix'; }
|
||||
|
||||
set frontMatter(frontMatter) {
|
||||
this.innerHTML = appendixTemplate(frontMatter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { Template } from '../mixins/template';
|
||||
import logo from '../assets/distill-logo.svg';
|
||||
|
||||
const T = Template('distill-footer', `
|
||||
<style>
|
||||
|
||||
:host {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-weight: 300;
|
||||
padding: 2rem 0;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
background-color: hsl(180, 5%, 15%); /*hsl(200, 60%, 15%);*/
|
||||
text-align: left;
|
||||
contain: content;
|
||||
}
|
||||
|
||||
.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: text;
|
||||
}
|
||||
|
||||
.nav {
|
||||
font-size: 0.9em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-right: 6px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class='container'>
|
||||
|
||||
<a href="/" class="logo">
|
||||
${logo}
|
||||
Distill
|
||||
</a> is dedicated to clear explanations of machine learning
|
||||
|
||||
<div class="nav">
|
||||
<a href="https://distill.pub/about/">About</a>
|
||||
<a href="https://distill.pub/journal/">Submit</a>
|
||||
<a href="https://distill.pub/prize/">Prize</a>
|
||||
<a href="https://distill.pub/archive/">Archive</a>
|
||||
<a href="https://distill.pub/rss.xml">RSS</a>
|
||||
<a href="https://github.com/distillpub">GitHub</a>
|
||||
<a href="https://twitter.com/distillpub">Twitter</a>
|
||||
ISSN 2476-0757
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
`);
|
||||
|
||||
export class DistillFooter extends T(HTMLElement) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Template } from '../mixins/template';
|
||||
|
||||
import logo from '../assets/distill-logo.svg';
|
||||
|
||||
const T = Template('distill-header', `
|
||||
<style>
|
||||
distill-header {
|
||||
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);
|
||||
}
|
||||
distill-header .content {
|
||||
height: 70px;
|
||||
grid-column: page;
|
||||
}
|
||||
distill-header a {
|
||||
font-size: 16px;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
text-decoration: none;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
padding: 22px 0;
|
||||
}
|
||||
distill-header a:hover {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
distill-header svg {
|
||||
width: 24px;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
@media(min-width: 1080px) {
|
||||
distill-header {
|
||||
height: 70px;
|
||||
}
|
||||
distill-header a {
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
padding: 28px 0;
|
||||
}
|
||||
distill-header .logo {
|
||||
}
|
||||
}
|
||||
distill-header svg path {
|
||||
fill: none;
|
||||
stroke: rgba(255, 255, 255, 0.8);
|
||||
stroke-width: 3px;
|
||||
}
|
||||
distill-header .logo {
|
||||
font-size: 17px;
|
||||
font-weight: 200;
|
||||
}
|
||||
distill-header .nav {
|
||||
float: right;
|
||||
font-weight: 300;
|
||||
}
|
||||
distill-header .nav a {
|
||||
font-size: 12px;
|
||||
margin-left: 24px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
<div class="content">
|
||||
<a href="/" class="logo">
|
||||
${logo}
|
||||
Distill
|
||||
</a>
|
||||
<div class="nav">
|
||||
<a href="/about/">About</a>
|
||||
<a href="/prize/">Prize</a>
|
||||
<a href="/journal/">Submit</a>
|
||||
</div>
|
||||
</div>
|
||||
`, false);
|
||||
|
||||
// <div class="nav">
|
||||
// <a href="https://github.com/distillpub">GitHub</a>
|
||||
// <!-- https://twitter.com/distillpub -->
|
||||
// </div>
|
||||
|
||||
export class DistillHeader extends T(HTMLElement) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { appendixTemplate } from '../distill-components/distill-appendix';
|
||||
|
||||
export default function(dom, data) {
|
||||
|
||||
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);
|
||||
distillAppendix.innerHTML = appendixTemplate(data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { parseBibtex } from '../helpers/bibtex';
|
||||
import fs from 'fs';
|
||||
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;
|
||||
}
|
||||
|
||||
const src = bibliographyTag.getAttribute('src');
|
||||
if (src) {
|
||||
const path = data.inputDirectory + '/' + src;
|
||||
const text = fs.readFileSync(path, 'utf-8');
|
||||
const bibliography = parseBibtex(text);
|
||||
const scriptTag = dom.createElement('script');
|
||||
scriptTag.type = 'text/json';
|
||||
scriptTag.textContent = JSON.stringify([...bibliography]);
|
||||
bibliographyTag.appendChild(scriptTag);
|
||||
bibliographyTag.removeAttribute('src');
|
||||
}
|
||||
|
||||
data.bibliography = parseBibliography(bibliographyTag);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { collect_citations } from '../helpers/citation.js';
|
||||
|
||||
export default function(dom, data) {
|
||||
const citations = new Set(data.citations);
|
||||
const newCitations = collect_citations(dom);
|
||||
for (const citation of newCitations) {
|
||||
citations.add(citation);
|
||||
}
|
||||
data.citations = Array.from(citations);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { parseFrontmatter } from '../components/d-front-matter';
|
||||
import { mergeFromYMLFrontmatter } from '../front-matter.js';
|
||||
|
||||
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);
|
||||
mergeFromYMLFrontmatter(data, extractedData);
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||
const months = ['Jan.', 'Feb.', 'March', 'April', 'May', 'June', 'July', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'];
|
||||
const zeroPad = n => n < 10 ? '0' + n : n;
|
||||
|
||||
const RFC = function(date) {
|
||||
const day = days[date.getDay()].substring(0, 3);
|
||||
const paddedDate = zeroPad(date.getDate());
|
||||
const month = months[date.getMonth()].substring(0,3);
|
||||
const year = date.getFullYear().toString();
|
||||
const hours = date.getUTCHours().toString();
|
||||
const minutes = date.getUTCMinutes().toString();
|
||||
const seconds = date.getUTCSeconds().toString();
|
||||
return `${day}, ${paddedDate} ${month} ${year} ${hours}:${minutes}:${seconds} Z`;
|
||||
};
|
||||
|
||||
const objectFromMap = function(map) {
|
||||
const object = Array.from(map).reduce((object, [key, value]) => (
|
||||
Object.assign(object, { [key]: value }) // Be careful! Maps can have non-String keys; object literals can't.
|
||||
), {});
|
||||
return object;
|
||||
};
|
||||
|
||||
const mapFromObject = function(object) {
|
||||
const map = new Map();
|
||||
for (var property in object) {
|
||||
if (object.hasOwnProperty(property)) {
|
||||
map.set(property, object[property]);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
};
|
||||
|
||||
class Author {
|
||||
|
||||
// constructor(name='', personalURL='', affiliation='', affiliationURL='') {
|
||||
// this.name = name; // 'Chris Olah'
|
||||
// this.personalURL = personalURL; // 'https://colah.github.io'
|
||||
// this.affiliation = affiliation; // 'Google Brain'
|
||||
// this.affiliationURL = affiliationURL; // 'https://g.co/brain'
|
||||
// }
|
||||
|
||||
constructor(object) {
|
||||
this.name = object.author; // 'Chris Olah'
|
||||
this.personalURL = object.authorURL; // 'https://colah.github.io'
|
||||
this.affiliation = object.affiliation; // 'Google Brain'
|
||||
this.affiliationURL = object.affiliationURL; // 'https://g.co/brain'
|
||||
}
|
||||
|
||||
// 'Chris'
|
||||
get firstName() {
|
||||
const names = this.name.split(' ');
|
||||
return names.slice(0, names.length - 1).join(' ');
|
||||
}
|
||||
|
||||
// 'Olah'
|
||||
get lastName() {
|
||||
const names = this.name.split(' ');
|
||||
return names[names.length -1];
|
||||
}
|
||||
}
|
||||
|
||||
export function mergeFromYMLFrontmatter(target, source) {
|
||||
target.title = source.title;
|
||||
if (source.published) {
|
||||
if (source.published instanceof Date) {
|
||||
target.publishedDate = source.published;
|
||||
} else if (source.published.constructor === String) {
|
||||
target.publishedDate = new Date(source.published);
|
||||
}
|
||||
}
|
||||
if (source.publishedDate) {
|
||||
if (source.publishedDate instanceof Date) {
|
||||
target.publishedDate = source.publishedDate;
|
||||
} else if (source.publishedDate.constructor === String) {
|
||||
target.publishedDate = new Date(source.publishedDate);
|
||||
}
|
||||
}
|
||||
target.description = source.description;
|
||||
target.authors = source.authors.map( (authorObject) => new Author(authorObject));
|
||||
target.katex = source.katex;
|
||||
target.password = source.password;
|
||||
}
|
||||
|
||||
export class FrontMatter {
|
||||
constructor() {
|
||||
this.title = 'unnamed article'; // 'Attention and Augmented Recurrent Neural Networks'
|
||||
this.description = ''; // 'A visual overview of neural attention...'
|
||||
this.authors = []; // Array of Author(s)
|
||||
|
||||
this.bibliography = new Map();
|
||||
this.bibliographyParsed = false;
|
||||
// {
|
||||
// 'gregor2015draw': {
|
||||
// 'title': 'DRAW: A recurrent neural network for image generation',
|
||||
// 'author': 'Gregor, Karol and Danihelka, Ivo and Graves, Alex and Rezende, Danilo Jimenez and Wierstra, Daan',
|
||||
// 'journal': 'arXiv preprint arXiv:1502.04623',
|
||||
// 'year': '2015',
|
||||
// 'url': 'https://arxiv.org/pdf/1502.04623.pdf',
|
||||
// 'type': 'article'
|
||||
// },
|
||||
// }
|
||||
|
||||
// Citation keys should be listed in the order that they are appear in the document.
|
||||
// Each key refers to a key in the bibliography dictionary.
|
||||
this.citations = []; // [ 'gregor2015draw', 'mercier2011humans' ]
|
||||
this.citationsCollected = false;
|
||||
|
||||
//
|
||||
// Assigned from posts.csv
|
||||
//
|
||||
|
||||
// publishedDate: 2016-09-08T07:00:00.000Z,
|
||||
// tags: [ 'rnn' ],
|
||||
// distillPath: '2016/augmented-rnns',
|
||||
// githubPath: 'distillpub/post--augmented-rnns',
|
||||
// doiSuffix: 1,
|
||||
|
||||
//
|
||||
// Assigned from journal
|
||||
//
|
||||
this.journal = {};
|
||||
// journal: {
|
||||
// 'title': 'Distill',
|
||||
// 'full_title': 'Distill',
|
||||
// 'abbrev_title': 'Distill',
|
||||
// 'url': 'http://distill.pub',
|
||||
// 'doi': '10.23915/distill',
|
||||
// 'publisherName': 'Distill Working Group',
|
||||
// 'publisherEmail': 'admin@distill.pub',
|
||||
// 'issn': '2476-0757',
|
||||
// 'editors': [...],
|
||||
// 'committee': [...]
|
||||
// }
|
||||
// volume: 1,
|
||||
// issue: 9,
|
||||
|
||||
this.katex = {};
|
||||
|
||||
//
|
||||
// Assigned from publishing process
|
||||
//
|
||||
|
||||
// githubCompareUpdatesUrl: 'https://github.com/distillpub/post--augmented-rnns/compare/1596e094d8943d2dc0ea445d92071129c6419c59...3bd9209e0c24d020f87cf6152dcecc6017cbc193',
|
||||
// updatedDate: 2017-03-21T07:13:16.000Z,
|
||||
// doi: '10.23915/distill.00001',
|
||||
this.publishedDate = undefined;
|
||||
}
|
||||
|
||||
// Example:
|
||||
// title: Demo Title Attention and Augmented Recurrent Neural Networks
|
||||
// published: Jan 10, 2017
|
||||
// authors:
|
||||
// - Chris Olah:
|
||||
// - Shan Carter: http://shancarter.com
|
||||
// affiliations:
|
||||
// - Google Brain:
|
||||
// - Google Brain: http://g.co/brain
|
||||
|
||||
//
|
||||
// Computed Properties
|
||||
//
|
||||
|
||||
// 'http://distill.pub/2016/augmented-rnns',
|
||||
set url(value) {
|
||||
this._url = value;
|
||||
}
|
||||
get url() {
|
||||
if (this._url) {
|
||||
return this._url;
|
||||
} else if (this.distillPath && this.journal.url) {
|
||||
return this.journal.url + '/' + this.distillPath;
|
||||
} else if (this.journal.url) {
|
||||
return this.journal.url;
|
||||
}
|
||||
}
|
||||
|
||||
// 'https://github.com/distillpub/post--augmented-rnns',
|
||||
get githubUrl() {
|
||||
if (this.githubPath) {
|
||||
return 'https://github.com/' + this.githubPath;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO resolve differences in naming of URL/Url/url.
|
||||
// 'http://distill.pub/2016/augmented-rnns/thumbnail.jpg',
|
||||
set previewURL(value) {
|
||||
this._previewURL = value;
|
||||
}
|
||||
get previewURL() {
|
||||
return this._previewURL ? this._previewURL : this.url + '/thumbnail.jpg';
|
||||
}
|
||||
|
||||
// 'Thu, 08 Sep 2016 00:00:00 -0700',
|
||||
get publishedDateRFC() {
|
||||
return RFC(this.publishedDate);
|
||||
}
|
||||
|
||||
// 'Thu, 08 Sep 2016 00:00:00 -0700',
|
||||
get updatedDateRFC() {
|
||||
return RFC(this.updatedDate);
|
||||
}
|
||||
|
||||
// 2016,
|
||||
get publishedYear() {
|
||||
return this.publishedDate.getFullYear();
|
||||
}
|
||||
|
||||
// 'Sept',
|
||||
get publishedMonth() {
|
||||
return months[this.publishedDate.getMonth()];
|
||||
}
|
||||
|
||||
// 8,
|
||||
get publishedDay() {
|
||||
return this.publishedDate.getDate();
|
||||
}
|
||||
|
||||
// '09',
|
||||
get publishedMonthPadded() {
|
||||
return zeroPad(this.publishedDate.getMonth() + 1);
|
||||
}
|
||||
|
||||
// '08',
|
||||
get publishedDayPadded() {
|
||||
return zeroPad(this.publishedDate.getDate());
|
||||
}
|
||||
|
||||
get publishedISODateOnly() {
|
||||
return this.publishedDate.toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
get volume() {
|
||||
const volume = this.publishedYear - 2015;
|
||||
if (volume < 1) {
|
||||
throw new Error('Invalid publish date detected during computing volume');
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
get issue() {
|
||||
return this.publishedDate.getMonth() + 1;
|
||||
}
|
||||
|
||||
// 'Olah & Carter',
|
||||
get concatenatedAuthors() {
|
||||
if (this.authors.length > 2) {
|
||||
return this.authors[0].lastName + ', et al.';
|
||||
} else if (this.authors.length === 2) {
|
||||
return this.authors[0].lastName + ' & ' + this.authors[1].lastName;
|
||||
} else if (this.authors.length === 1) {
|
||||
return this.authors[0].lastName;
|
||||
}
|
||||
}
|
||||
|
||||
// 'Olah, Chris and Carter, Shan',
|
||||
get bibtexAuthors() {
|
||||
return this.authors.map(author => {
|
||||
return author.lastName + ', ' + author.firstName;
|
||||
}).join(' and ');
|
||||
}
|
||||
|
||||
// 'olah2016attention'
|
||||
get slug() {
|
||||
let slug = '';
|
||||
if (this.authors.length) {
|
||||
slug += this.authors[0].lastName.toLowerCase();
|
||||
slug += this.publishedYear;
|
||||
slug += this.title.split(' ')[0].toLowerCase();
|
||||
}
|
||||
return slug || 'Untitled';
|
||||
}
|
||||
|
||||
get bibliographyEntries() {
|
||||
return new Map(this.citations.map( citationKey => {
|
||||
const entry = this.bibliography.get(citationKey);
|
||||
return [citationKey, entry];
|
||||
}));
|
||||
}
|
||||
|
||||
set bibliography(bibliography) {
|
||||
if (bibliography instanceof Map) {
|
||||
this._bibliography = bibliography;
|
||||
} else if (typeof bibliography === 'object') {
|
||||
this._bibliography = mapFromObject(bibliography);
|
||||
}
|
||||
}
|
||||
|
||||
get bibliography() {
|
||||
return this._bibliography;
|
||||
}
|
||||
|
||||
static fromObject(source) {
|
||||
const frontMatter = new FrontMatter();
|
||||
Object.assign(frontMatter, source);
|
||||
return frontMatter;
|
||||
}
|
||||
|
||||
assignToObject(target) {
|
||||
Object.assign(target, this);
|
||||
target.bibliography = objectFromMap(this.bibliographyEntries);
|
||||
target.url = this.url;
|
||||
target.githubUrl = this.githubUrl;
|
||||
target.previewURL = this.previewURL;
|
||||
target.volume = this.volume;
|
||||
target.issue = this.issue;
|
||||
target.publishedDateRFC = this.publishedDateRFC;
|
||||
target.publishedYear = this.publishedYear;
|
||||
target.publishedMonth = this.publishedMonth;
|
||||
target.publishedDay = this.publishedDay;
|
||||
target.publishedMonthPadded = this.publishedMonthPadded;
|
||||
target.publishedDayPadded = this.publishedDayPadded;
|
||||
target.updatedDateRFC = this.updatedDateRFC;
|
||||
target.concatenatedAuthors = this.concatenatedAuthors;
|
||||
target.bibtexAuthors = this.bibtexAuthors;
|
||||
target.slug = this.slug;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
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.toLowerCase()] = 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}},
|
||||
doi = {${frontMatter.doi}}
|
||||
}`;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
export function collect_citations(dom=document) {
|
||||
const citations = new Set();
|
||||
const citeTags = dom.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 function inline_cite_short(keys){
|
||||
function cite_string(key){
|
||||
if (key in data.bibliography){
|
||||
var n = data.citations.indexOf(key)+1;
|
||||
return ''+n;
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return '['+keys.map(cite_string).join(', ')+']';
|
||||
}
|
||||
|
||||
export function inline_cite_long(keys){
|
||||
function cite_string(key){
|
||||
if (key in data.bibliography){
|
||||
var ent = data.bibliography[key];
|
||||
var names = ent.author.split(' and ');
|
||||
names = names.map(name => name.split(',')[0].trim());
|
||||
var year = ent.year;
|
||||
if (names.length == 1) return names[0] + ', ' + year;
|
||||
if (names.length == 2) return names[0] + ' & ' + names[1] + ', ' + year;
|
||||
if (names.length > 2) return names[0] + ', et al., ' + year;
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return keys.map(cite_string).join(', ');
|
||||
}
|
||||
|
||||
function author_string(ent, template, sep, finalSep){
|
||||
var names = ent.author.split(' and ');
|
||||
let name_strings = names.map(name => {
|
||||
name = name.trim();
|
||||
if (name.indexOf(',') != -1){
|
||||
var last = name.split(',')[0].trim();
|
||||
var firsts = name.split(',')[1];
|
||||
} else {
|
||||
var last = name.split(' ').slice(-1)[0].trim();
|
||||
var firsts = name.split(' ').slice(0,-1).join(' ');
|
||||
}
|
||||
var initials = '';
|
||||
if (firsts != undefined) {
|
||||
initials = firsts.trim().split(' ').map(s => s.trim()[0]);
|
||||
initials = initials.join('.')+'.';
|
||||
}
|
||||
return template.replace('${F}', firsts)
|
||||
.replace('${L}', last)
|
||||
.replace('${I}', initials);
|
||||
});
|
||||
if (names.length > 1) {
|
||||
var str = name_strings.slice(0, names.length-1).join(sep);
|
||||
str += (finalSep || sep) + name_strings[names.length-1];
|
||||
return str;
|
||||
} else {
|
||||
return name_strings[0];
|
||||
}
|
||||
}
|
||||
|
||||
function venue_string(ent) {
|
||||
var cite = (ent.journal || ent.booktitle || '');
|
||||
if ('volume' in ent){
|
||||
var issue = ent.issue || ent.number;
|
||||
issue = (issue != undefined)? '('+issue+')' : '';
|
||||
cite += ', Vol ' + ent.volume + issue;
|
||||
}
|
||||
if ('pages' in ent){
|
||||
cite += ', pp. ' + ent.pages;
|
||||
}
|
||||
if (cite != '') cite += '. ';
|
||||
if ('publisher' in ent){
|
||||
cite += ent.publisher;
|
||||
if (cite[cite.length-1] != '.') cite += '.';
|
||||
}
|
||||
return cite;
|
||||
}
|
||||
|
||||
function link_string(ent){
|
||||
if ('url' in ent){
|
||||
var url = ent.url;
|
||||
var arxiv_match = (/arxiv\.org\/abs\/([0-9\.]*)/).exec(url);
|
||||
if (arxiv_match != null){
|
||||
url = `http://arxiv.org/pdf/${arxiv_match[1]}.pdf`;
|
||||
}
|
||||
|
||||
if (url.slice(-4) == '.pdf'){
|
||||
var label = 'PDF';
|
||||
} else if (url.slice(-5) == '.html') {
|
||||
var label = 'HTML';
|
||||
}
|
||||
return `  <a href="${url}">[${label||'link'}]</a>`;
|
||||
}/* else if ("doi" in ent){
|
||||
return `  <a href="https://doi.org/${ent.doi}" >[DOI]</a>`;
|
||||
}*/ else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
function doi_string(ent, new_line){
|
||||
if ('doi' in ent) {
|
||||
return `${new_line?'<br>':''} <a href="https://doi.org/${ent.doi}" style="text-decoration:inherit;">DOI: ${ent.doi}</a>`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function bibliography_cite(ent, fancy){
|
||||
if (ent){
|
||||
var cite = '<span class="title">' + ent.title + '</span> ';
|
||||
cite += link_string(ent) + '<br>';
|
||||
cite += author_string(ent, '${L}, ${I}', ', ', ' and ');
|
||||
if (ent.year || ent.date){
|
||||
cite += ', ' + (ent.year || ent.date) + '. ';
|
||||
} else {
|
||||
cite += '. ';
|
||||
}
|
||||
cite += venue_string(ent);
|
||||
cite += doi_string(ent);
|
||||
return cite;
|
||||
/*var cite = author_string(ent, "${L}, ${I}", ", ", " and ");
|
||||
if (ent.year || ent.date){
|
||||
cite += ", " + (ent.year || ent.date) + ". "
|
||||
} else {
|
||||
cite += ". "
|
||||
}
|
||||
cite += "<b>" + ent.title + "</b>. ";
|
||||
cite += venue_string(ent);
|
||||
cite += doi_string(ent);
|
||||
cite += link_string(ent);
|
||||
return cite*/
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
export function hover_cite(ent){
|
||||
if (ent){
|
||||
var cite = '';
|
||||
cite += '<b>' + ent.title + '</b>';
|
||||
cite += link_string(ent);
|
||||
cite += '<br>';
|
||||
|
||||
var a_str = author_string(ent, '${I} ${L}', ', ') + '.';
|
||||
var v_str = venue_string(ent).trim() + ' ' + ent.year + '. ' + doi_string(ent, true);
|
||||
|
||||
if ((a_str+v_str).length < Math.min(40, ent.title.length)) {
|
||||
cite += a_str + ' ' + v_str;
|
||||
} else {
|
||||
cite += a_str + '<br>' + v_str;
|
||||
}
|
||||
return cite;
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//https://scholar.google.com/scholar?q=allintitle%3ADocument+author%3Aolah
|
||||
function get_GS_URL(ent){
|
||||
if (ent){
|
||||
var names = ent.author.split(' and ');
|
||||
names = names.map(name => name.split(',')[0].trim());
|
||||
var title = ent.title.split(' ');//.replace(/[,:]/, "")
|
||||
var url = 'http://search.labs.crossref.org/dois?';//""https://scholar.google.com/scholar?"
|
||||
url += uris({q: names.join(' ') + ' ' + title.join(' ')});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// This is a straight concatenation of code from KaTeX's contrib folder,
|
||||
// but we aren't using some of their helpers that don't work well outside a browser environment.
|
||||
|
||||
/*global katex */
|
||||
|
||||
const findEndOfMath = function(delimiter, text, startIndex) {
|
||||
// Adapted from
|
||||
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
|
||||
let index = startIndex;
|
||||
let braceLevel = 0;
|
||||
|
||||
const delimLength = delimiter.length;
|
||||
|
||||
while (index < text.length) {
|
||||
const character = text[index];
|
||||
|
||||
if (braceLevel <= 0 &&
|
||||
text.slice(index, index + delimLength) === delimiter) {
|
||||
return index;
|
||||
} else if (character === '\\') {
|
||||
index++;
|
||||
} else if (character === '{') {
|
||||
braceLevel++;
|
||||
} else if (character === '}') {
|
||||
braceLevel--;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
};
|
||||
|
||||
const splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
|
||||
const finalData = [];
|
||||
|
||||
for (let i = 0; i < startData.length; i++) {
|
||||
if (startData[i].type === 'text') {
|
||||
const text = startData[i].data;
|
||||
|
||||
let lookingForLeft = true;
|
||||
let currIndex = 0;
|
||||
let nextIndex;
|
||||
|
||||
nextIndex = text.indexOf(leftDelim);
|
||||
if (nextIndex !== -1) {
|
||||
currIndex = nextIndex;
|
||||
finalData.push({
|
||||
type: 'text',
|
||||
data: text.slice(0, currIndex),
|
||||
});
|
||||
lookingForLeft = false;
|
||||
}
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
if (lookingForLeft) {
|
||||
nextIndex = text.indexOf(leftDelim, currIndex);
|
||||
if (nextIndex === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
finalData.push({
|
||||
type: 'text',
|
||||
data: text.slice(currIndex, nextIndex),
|
||||
});
|
||||
|
||||
currIndex = nextIndex;
|
||||
} else {
|
||||
nextIndex = findEndOfMath(
|
||||
rightDelim,
|
||||
text,
|
||||
currIndex + leftDelim.length);
|
||||
if (nextIndex === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
finalData.push({
|
||||
type: 'math',
|
||||
data: text.slice(
|
||||
currIndex + leftDelim.length,
|
||||
nextIndex),
|
||||
rawData: text.slice(
|
||||
currIndex,
|
||||
nextIndex + rightDelim.length),
|
||||
display: display,
|
||||
});
|
||||
|
||||
currIndex = nextIndex + rightDelim.length;
|
||||
}
|
||||
|
||||
lookingForLeft = !lookingForLeft;
|
||||
}
|
||||
|
||||
finalData.push({
|
||||
type: 'text',
|
||||
data: text.slice(currIndex),
|
||||
});
|
||||
} else {
|
||||
finalData.push(startData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return finalData;
|
||||
};
|
||||
|
||||
|
||||
const splitWithDelimiters = function(text, delimiters) {
|
||||
let data = [{type: 'text', data: text}];
|
||||
for (let i = 0; i < delimiters.length; i++) {
|
||||
const delimiter = delimiters[i];
|
||||
data = splitAtDelimiters(
|
||||
data, delimiter.left, delimiter.right,
|
||||
delimiter.display || false);
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
/* Note: optionsCopy is mutated by this method. If it is ever exposed in the
|
||||
* API, we should copy it before mutating.
|
||||
*/
|
||||
const renderMathInText = function(text, optionsCopy) {
|
||||
const data = splitWithDelimiters(text, optionsCopy.delimiters);
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].type === 'text') {
|
||||
fragment.appendChild(document.createTextNode(data[i].data));
|
||||
} else {
|
||||
const tag = document.createElement('d-math');
|
||||
const math = data[i].data;
|
||||
// Override any display mode defined in the settings with that
|
||||
// defined by the text itself
|
||||
optionsCopy.displayMode = data[i].display;
|
||||
try {
|
||||
tag.textContent = math;
|
||||
if (optionsCopy.displayMode) {
|
||||
tag.setAttribute('block', '');
|
||||
}
|
||||
} catch (e) {
|
||||
if (!(e instanceof katex.ParseError)) {
|
||||
throw e;
|
||||
}
|
||||
optionsCopy.errorCallback(
|
||||
'KaTeX auto-render: Failed to parse `' + data[i].data +
|
||||
'` with ',
|
||||
e
|
||||
);
|
||||
fragment.appendChild(document.createTextNode(data[i].rawData));
|
||||
continue;
|
||||
}
|
||||
fragment.appendChild(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return fragment;
|
||||
};
|
||||
|
||||
const renderElem = function(elem, optionsCopy) {
|
||||
for (let i = 0; i < elem.childNodes.length; i++) {
|
||||
const childNode = elem.childNodes[i];
|
||||
if (childNode.nodeType === 3) {
|
||||
// Text node
|
||||
const frag = renderMathInText(childNode.textContent, optionsCopy);
|
||||
i += frag.childNodes.length - 1;
|
||||
elem.replaceChild(frag, childNode);
|
||||
} else if (childNode.nodeType === 1) {
|
||||
// Element node
|
||||
const shouldRender = optionsCopy.ignoredTags.indexOf(
|
||||
childNode.nodeName.toLowerCase()) === -1;
|
||||
|
||||
if (shouldRender) {
|
||||
renderElem(childNode, optionsCopy);
|
||||
}
|
||||
}
|
||||
// Otherwise, it's something else, and ignore it.
|
||||
}
|
||||
};
|
||||
|
||||
const defaultAutoRenderOptions = {
|
||||
delimiters: [
|
||||
{left: '$$', right: '$$', display: true},
|
||||
{left: '\\[', right: '\\]', display: true},
|
||||
{left: '\\(', right: '\\)', display: false},
|
||||
// LaTeX uses this, but it ruins the display of normal `$` in text:
|
||||
// {left: '$', right: '$', display: false},
|
||||
],
|
||||
|
||||
ignoredTags: [
|
||||
'script', 'noscript', 'style', 'textarea', 'pre', 'code', 'svg',
|
||||
],
|
||||
|
||||
errorCallback: function(msg, err) {
|
||||
console.error(msg, err);
|
||||
},
|
||||
};
|
||||
|
||||
export const renderMathInElement = function(elem, options) {
|
||||
if (!elem) {
|
||||
throw new Error('No element provided to render');
|
||||
}
|
||||
|
||||
const optionsCopy = Object.assign({}, defaultAutoRenderOptions, options);
|
||||
renderElem(elem, optionsCopy);
|
||||
};
|
||||
@@ -0,0 +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} {
|
||||
grid-column: left / text;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
export function page(selector) {
|
||||
return `${selector} {
|
||||
grid-column: left / page;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
export function screen(selector) {
|
||||
return `${selector} {
|
||||
grid-column: start / end;
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
export function addPolyfill(polyfill, polyfillLoadedCallback) {
|
||||
console.info('Runlevel 0: Polyfill required: ' + polyfill.name);
|
||||
const script = document.createElement('script');
|
||||
script.src = polyfill.url;
|
||||
script.async = false;
|
||||
if (polyfillLoadedCallback) {
|
||||
script.onload = function() { polyfillLoadedCallback(polyfill); };
|
||||
}
|
||||
script.onerror = function() {
|
||||
new Error('Runlevel 0: Polyfills failed to load script ' + polyfill.name);
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
export const polyfills = [
|
||||
{
|
||||
name: 'WebComponents',
|
||||
support: function() {
|
||||
return 'customElements' in window &&
|
||||
'attachShadow' in Element.prototype &&
|
||||
'getRootNode' in Element.prototype &&
|
||||
'content' in document.createElement('template') &&
|
||||
'Promise' in window &&
|
||||
'from' in Array;
|
||||
},
|
||||
url: 'https://distill.pub/third-party/polyfills/webcomponents-lite.js'
|
||||
}, {
|
||||
name: 'IntersectionObserver',
|
||||
support: function() {
|
||||
return 'IntersectionObserver' in window &&
|
||||
'IntersectionObserverEntry' in window;
|
||||
},
|
||||
url: 'https://distill.pub/third-party/polyfills/intersection-observer.js'
|
||||
},
|
||||
];
|
||||
|
||||
export class Polyfills {
|
||||
|
||||
static browserSupportsAllFeatures() {
|
||||
return polyfills.every((poly) => poly.support());
|
||||
}
|
||||
|
||||
static load(callback) {
|
||||
// Define an intermediate callback that checks if all is loaded.
|
||||
const polyfillLoaded = function(polyfill) {
|
||||
polyfill.loaded = true;
|
||||
console.info('Runlevel 0: Polyfill has finished loading: ' + polyfill.name);
|
||||
// console.info(window[polyfill.name]);
|
||||
if (Polyfills.neededPolyfills.every((poly) => poly.loaded)) {
|
||||
console.info('Runlevel 0: All required polyfills have finished loading.');
|
||||
console.info('Runlevel 0->1.');
|
||||
window.distillRunlevel = 1;
|
||||
callback();
|
||||
}
|
||||
};
|
||||
// Add polyfill script tags
|
||||
for (const polyfill of Polyfills.neededPolyfills) {
|
||||
addPolyfill(polyfill, polyfillLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
static get neededPolyfills() {
|
||||
if (!Polyfills._neededPolyfills) {
|
||||
Polyfills._neededPolyfills = polyfills.filter((poly) => !poly.support());
|
||||
}
|
||||
return Polyfills._neededPolyfills;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
export const Mutating = (superclass) => {
|
||||
return class extends superclass {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// set up mutation observer
|
||||
const options = {childList: true, characterData: true, subtree: true};
|
||||
const observer = new MutationObserver( () => {
|
||||
observer.disconnect();
|
||||
this.renderIfPossible();
|
||||
observer.observe(this, options);
|
||||
});
|
||||
|
||||
// ...and listen for changes
|
||||
observer.observe(this, options);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
this.renderIfPossible();
|
||||
}
|
||||
|
||||
// potential TODO: check if this is enough for all our usecases
|
||||
// maybe provide a custom function to tell if we have enough information to render
|
||||
renderIfPossible() {
|
||||
if (this.textContent && this.root) {
|
||||
this.renderContent();
|
||||
}
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
console.error(`Your class ${this.constructor.name} must provide a custom renderContent() method!` );
|
||||
}
|
||||
|
||||
}; // end class
|
||||
}; // end mixin function
|
||||
@@ -0,0 +1,85 @@
|
||||
export function propName(attr) {
|
||||
return attr.replace(/(-[a-z])/g, (s) => s.toUpperCase().replace('-', ''));
|
||||
}
|
||||
|
||||
export function attrName(prop) {
|
||||
return prop.replace(/([A-Z])/g, (s) => '-' + s.toLowerCase());
|
||||
}
|
||||
|
||||
export function deserializeAttribute(value, type) {
|
||||
switch (type) {
|
||||
case String:
|
||||
break;
|
||||
case Array:
|
||||
case Object:
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {}
|
||||
break;
|
||||
case Boolean:
|
||||
value = value != 'false' && value != '0' && value;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
const immediately = window.setImmediate || function(fn, args) {
|
||||
window.setTimeout(function() {
|
||||
fn.apply(this, args);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
export const Properties = (properties) => {
|
||||
const keys = Object.keys(properties);
|
||||
const attrs = keys.map((k) => attrName(k));
|
||||
return (superclass) => {
|
||||
const cls = class extends superclass {
|
||||
static get observedAttributes() {
|
||||
return attrs;
|
||||
}
|
||||
attributeChangedCallback(attr, oldValue, newValue) {
|
||||
const prop = propName(attr);
|
||||
const value = deserializeAttribute(newValue, properties[prop].type);
|
||||
this[prop] = value;
|
||||
}
|
||||
_propertiesChanged() {
|
||||
if (!this.propertiesChangedCallback) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(this._propertiesChangedTimeout);
|
||||
this._propertiesChangedTimeout = immediately(() => {
|
||||
this.propertiesChangedCallback(this);
|
||||
});
|
||||
}
|
||||
};
|
||||
keys.forEach(function(k) {
|
||||
const secret = `_${k}`;
|
||||
const callback = `${k}Changed`;
|
||||
const defaultValue = properties[k].value;
|
||||
Object.defineProperty(cls.prototype, k, {
|
||||
get: function() {
|
||||
let value = this[secret];
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
if (defaultValue && typeof defaultValue == 'function') {
|
||||
this[secret] = defaultValue();
|
||||
} else {
|
||||
this[secret] = defaultValue;
|
||||
}
|
||||
return this[secret];
|
||||
},
|
||||
set: function(value) {
|
||||
const oldValue = this[secret];
|
||||
this[secret] = value;
|
||||
if (this[callback]) {
|
||||
this[callback](value, oldValue);
|
||||
}
|
||||
this._propertiesChanged();
|
||||
}
|
||||
});
|
||||
});
|
||||
return cls;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
/*global ShadyCSS*/
|
||||
|
||||
export const Template = (name, templateString, useShadow = true) => {
|
||||
|
||||
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; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.clone = document.importNode(template.content, true);
|
||||
if (useShadow) {
|
||||
this.attachShadow({mode: 'open'});
|
||||
this.shadowRoot.appendChild(this.clone);
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (useShadow) {
|
||||
if ('ShadyCSS' in window) {
|
||||
ShadyCSS.styleElement(this);
|
||||
}
|
||||
} else {
|
||||
this.insertBefore(this.clone, this.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
get root() {
|
||||
if (useShadow) {
|
||||
return this.shadowRoot;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Are we using these? Should we even? */
|
||||
$(query) {
|
||||
return this.root.querySelector(query);
|
||||
}
|
||||
|
||||
$$(query) {
|
||||
return this.root.querySelectorAll(query);
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,232 @@
|
||||
d-article {
|
||||
contain: content;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
padding-top: 2rem;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
d-article > * {
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
d-article {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
d-article {
|
||||
font-size: 1.06rem;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* H2 */
|
||||
|
||||
|
||||
d-article .marker {
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
counter-reset: section;
|
||||
grid-column: kicker;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
|
||||
d-article .marker:hover {
|
||||
border: none;
|
||||
}
|
||||
|
||||
d-article .marker span {
|
||||
padding: 0 3px 4px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
||||
position: relative;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
d-article .marker:hover span {
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
d-article h2 {
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
line-height: 1.25em;
|
||||
margin: 2rem 0 1.5rem 0;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
d-article h2 {
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
/* H3 */
|
||||
|
||||
d-article h3 {
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
line-height: 1.4em;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
d-article h3 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* H4 */
|
||||
|
||||
d-article h4 {
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
font-size: 14px;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
d-article a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
d-article p,
|
||||
d-article ul,
|
||||
d-article ol,
|
||||
d-article blockquote {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
d-article blockquote {
|
||||
border-left: 2px solid rgba(0, 0, 0, 0.2);
|
||||
padding-left: 2em;
|
||||
font-style: italic;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
d-article a {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
d-article a:hover {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
d-article .link {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
d-article ul,
|
||||
d-article ol {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
d-article li {
|
||||
margin-bottom: 1em;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
d-article li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
d-article pre {
|
||||
font-size: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
d-article hr {
|
||||
grid-column: screen;
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
d-article section {
|
||||
margin-top: 60px;
|
||||
margin-bottom: 60px;
|
||||
}
|
||||
|
||||
d-article span.equation-mimic {
|
||||
font-family: georgia;
|
||||
font-size: 115%;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
d-article > d-code,
|
||||
d-article section > d-code {
|
||||
display: block;
|
||||
overflow-x: scroll;
|
||||
|
||||
}
|
||||
|
||||
d-article > d-math[block],
|
||||
d-article section > d-math[block] {
|
||||
display: block;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
d-article .citation {
|
||||
color: #668;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
d-include {
|
||||
width: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
d-figure {
|
||||
contain: content;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* KaTeX */
|
||||
|
||||
.katex, .katex-prerendered {
|
||||
contain: content;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
|
||||
d-article table {
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1.5rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
d-article table th {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
d-article table td {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
d-article table tr:last-of-type td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
d-article table th,
|
||||
d-article table td {
|
||||
font-size: 15px;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
d-article table tbody :first-child td {
|
||||
padding-top: 2px;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
d-byline {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
contain: content;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.8em;
|
||||
padding: 1.5rem 0;
|
||||
min-height: 1.8em;
|
||||
}
|
||||
|
||||
|
||||
d-byline .byline {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
d-byline .byline {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
d-byline .authors-affiliations {
|
||||
grid-column-end: span 2;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
d-byline .authors-affiliations {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
d-byline h3 {
|
||||
font-size: 0.6rem;
|
||||
font-weight: 400;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
d-byline p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
d-byline a,
|
||||
d-article d-byline a {
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
text-decoration: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
d-article d-byline a:hover {
|
||||
text-decoration: underline;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
d-byline p.author {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
d-byline .affiliations {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
span.katex-display {
|
||||
text-align: left;
|
||||
padding: 8px 0 8px 0;
|
||||
margin: 0.5em 0 0.5em 1em;
|
||||
}
|
||||
|
||||
span.katex {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
font-size: 1.18em;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
d-title {
|
||||
padding: 2rem 0 1.5rem;
|
||||
contain: content;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
d-title {
|
||||
padding: 4rem 0 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
d-title h1 {
|
||||
grid-column: text;
|
||||
font-size: 40px;
|
||||
font-weight: 700;
|
||||
line-height: 1.05em;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
d-title h1 {
|
||||
font-size: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
d-title p {
|
||||
font-weight: 300;
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.7em;
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
d-title p {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
d-title .status {
|
||||
margin-top: 0px;
|
||||
font-size: 12px;
|
||||
color: #009688;
|
||||
opacity: 0.8;
|
||||
grid-column: kicker;
|
||||
}
|
||||
|
||||
d-title .status span {
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid #80cbc4;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
html {
|
||||
font-size: 14px;
|
||||
line-height: 1.6em;
|
||||
/* font-family: "Libre Franklin", "Helvetica Neue", sans-serif; */
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Arial, sans-serif;
|
||||
/*, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";*/
|
||||
text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #004276;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
table th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
sup, sub {
|
||||
vertical-align: baseline;
|
||||
position: relative;
|
||||
top: -0.4em;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
sub {
|
||||
top: 0.4em;
|
||||
}
|
||||
|
||||
.kicker,
|
||||
.marker {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
|
||||
/* Headline */
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
d-title h1 span {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure */
|
||||
|
||||
figure {
|
||||
position: relative;
|
||||
margin-bottom: 2.5em;
|
||||
margin-top: 2.5em;
|
||||
}
|
||||
|
||||
figcaption+figure {
|
||||
|
||||
}
|
||||
|
||||
figure img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
figure svg text,
|
||||
figure svg tspan {
|
||||
}
|
||||
|
||||
figcaption,
|
||||
.figcaption {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
font-size: 12px;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
@media(min-width: 1024px) {
|
||||
figcaption,
|
||||
.figcaption {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
figure.external img {
|
||||
background: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
|
||||
padding: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
figcaption a {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
figcaption b {
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
@supports not (display: grid) {
|
||||
.base-grid,
|
||||
distill-header,
|
||||
d-title,
|
||||
d-abstract,
|
||||
d-article,
|
||||
d-appendix,
|
||||
distill-appendix,
|
||||
d-byline,
|
||||
d-footnote-list,
|
||||
d-citation-list,
|
||||
distill-footer {
|
||||
display: block;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.base-grid,
|
||||
distill-header,
|
||||
d-title,
|
||||
d-abstract,
|
||||
d-article,
|
||||
d-appendix,
|
||||
distill-appendix,
|
||||
d-byline,
|
||||
d-footnote-list,
|
||||
d-citation-list,
|
||||
distill-footer {
|
||||
display: grid;
|
||||
justify-items: stretch;
|
||||
grid-template-columns: [screen-start] 8px [page-start kicker-start text-start gutter-start middle-start] 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr [text-end page-end gutter-end kicker-end middle-end] 8px [screen-end];
|
||||
grid-column-gap: 8px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-column-gap: 8px;
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
.base-grid,
|
||||
distill-header,
|
||||
d-title,
|
||||
d-abstract,
|
||||
d-article,
|
||||
d-appendix,
|
||||
distill-appendix,
|
||||
d-byline,
|
||||
d-footnote-list,
|
||||
d-citation-list,
|
||||
distill-footer {
|
||||
grid-template-columns: [screen-start] 1fr [page-start kicker-start middle-start text-start] 45px 45px 45px 45px 45px 45px 45px 45px [ kicker-end text-end gutter-start] 45px [middle-end] 45px [page-end gutter-end] 1fr [screen-end];
|
||||
grid-column-gap: 16px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-column-gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1000px) {
|
||||
.base-grid,
|
||||
distill-header,
|
||||
d-title,
|
||||
d-abstract,
|
||||
d-article,
|
||||
d-appendix,
|
||||
distill-appendix,
|
||||
d-byline,
|
||||
d-footnote-list,
|
||||
d-citation-list,
|
||||
distill-footer {
|
||||
grid-template-columns: [screen-start] 1fr [page-start kicker-start] 50px [middle-start] 50px [text-start kicker-end] 50px 50px 50px 50px 50px 50px 50px 50px [text-end gutter-start] 50px [middle-end] 50px [page-end gutter-end] 1fr [screen-end];
|
||||
grid-column-gap: 16px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-column-gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width: 1280px) {
|
||||
.base-grid,
|
||||
distill-header,
|
||||
d-title,
|
||||
d-abstract,
|
||||
d-article,
|
||||
d-appendix,
|
||||
distill-appendix,
|
||||
d-byline,
|
||||
d-footnote-list,
|
||||
d-citation-list,
|
||||
distill-footer {
|
||||
grid-template-columns: [screen-start] 1fr [page-start kicker-start] 60px [middle-start] 60px [text-start kicker-end] 60px 60px 60px 60px 60px 60px 60px 60px [text-end gutter-start] 60px [middle-end] 60px [page-end gutter-end] 1fr [screen-end];
|
||||
grid-column-gap: 32px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-column-gap: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.base-grid {
|
||||
grid-column: screen;
|
||||
}
|
||||
|
||||
/* .l-body,
|
||||
d-article > * {
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
.l-page,
|
||||
d-title > *,
|
||||
d-figure {
|
||||
grid-column: page;
|
||||
} */
|
||||
|
||||
.l-gutter {
|
||||
grid-column: gutter;
|
||||
}
|
||||
|
||||
.l-text,
|
||||
.l-body {
|
||||
grid-column: text;
|
||||
}
|
||||
|
||||
.l-page {
|
||||
grid-column: page;
|
||||
}
|
||||
|
||||
.l-body-outset {
|
||||
grid-column: middle;
|
||||
}
|
||||
|
||||
.l-page-outset {
|
||||
grid-column: page;
|
||||
}
|
||||
|
||||
.l-screen {
|
||||
grid-column: screen;
|
||||
}
|
||||
|
||||
.l-screen-inset {
|
||||
grid-column: screen;
|
||||
padding-left: 16px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* Aside */
|
||||
|
||||
d-article aside {
|
||||
grid-column: gutter;
|
||||
font-size: 12px;
|
||||
line-height: 1.6em;
|
||||
color: rgba(0, 0, 0, 0.6)
|
||||
}
|
||||
|
||||
@media(min-width: 768px) {
|
||||
aside {
|
||||
grid-column: gutter;
|
||||
}
|
||||
|
||||
.side {
|
||||
grid-column: gutter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import base from './styles-base.css';
|
||||
import layout from './styles-layout.css';
|
||||
import print from './styles-print.css';
|
||||
import byline from './d-byline.css';
|
||||
import article from './d-article.css';
|
||||
import title from './d-title.css';
|
||||
import math from './d-math.css';
|
||||
|
||||
export const styles = base + layout + title + byline + article + math + print;
|
||||
|
||||
export function makeStyleTag(dom) {
|
||||
|
||||
const styleTagId = 'distill-prerendered-styles';
|
||||
const prerenderedTag = dom.getElementById(styleTagId);
|
||||
if (!prerenderedTag) {
|
||||
const styleTag = dom.createElement('style');
|
||||
styleTag.id = styleTagId;
|
||||
styleTag.type = 'text/css';
|
||||
const cssTextTag = dom.createTextNode(styles);
|
||||
styleTag.appendChild(cssTextTag);
|
||||
const firstScriptTag = dom.head.querySelector('script');
|
||||
dom.head.insertBefore(styleTag, firstScriptTag);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* eslint-env node, mocha */
|
||||
|
||||
import { FrontMatter } from './front-matter';
|
||||
|
||||
/* Extractors */
|
||||
import ExtractFrontmatter from './extractors/front-matter';
|
||||
import ExtractBibliography from './extractors/bibliography';
|
||||
import ExtractCitations from './extractors/citations';
|
||||
|
||||
const extractors = new Map([
|
||||
['ExtractFrontmatter', ExtractFrontmatter],
|
||||
['ExtractBibliography', ExtractBibliography],
|
||||
['ExtractCitations', ExtractCitations],
|
||||
]);
|
||||
|
||||
/* Transforms */
|
||||
import HTML from './transforms/html';
|
||||
import Byline from './transforms/byline';
|
||||
import OptionalComponents from './transforms/optional-components';
|
||||
import Mathematics from './transforms/mathematics';
|
||||
import Meta from './transforms/meta';
|
||||
import { makeStyleTag } from './styles/styles';
|
||||
import TOC from './transforms/toc';
|
||||
import Typeset from './transforms/typeset';
|
||||
import Polyfills from './transforms/polyfills';
|
||||
import CitationList from './transforms/citation-list';
|
||||
import Reorder from './transforms/reorder';
|
||||
|
||||
const transforms = new Map([
|
||||
['HTML', HTML],
|
||||
['makeStyleTag', makeStyleTag],
|
||||
['OptionalComponents', OptionalComponents],
|
||||
['TOC', TOC],
|
||||
['Byline', Byline],
|
||||
['Mathematics', Mathematics],
|
||||
['Meta', Meta],
|
||||
['Typeset', Typeset],
|
||||
['Polyfills', Polyfills],
|
||||
['CitationList', CitationList],
|
||||
['Reorder', Reorder] // keep last
|
||||
]);
|
||||
|
||||
/* 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 = new Map([
|
||||
['DistillHeader', DistillHeader],
|
||||
['DistillAppendix', DistillAppendix],
|
||||
['DistillFooter', DistillFooter],
|
||||
]);
|
||||
|
||||
/* Exported functions */
|
||||
|
||||
export function render(dom, data, verbose=true) {
|
||||
let frontMatter;
|
||||
if (data instanceof FrontMatter) {
|
||||
frontMatter = data;
|
||||
} else {
|
||||
frontMatter = FrontMatter.fromObject(data);
|
||||
}
|
||||
// first, we collect static data from the dom
|
||||
for (const [name, extract] of extractors.entries()) {
|
||||
if (verbose) console.warn('Running extractor: ' + name);
|
||||
extract(dom, frontMatter, verbose);
|
||||
}
|
||||
// secondly we use it to transform parts of the dom
|
||||
for (const [name, transform] of transforms.entries()) {
|
||||
if (verbose) console.warn('Running transform: ' + name);
|
||||
// console.warn('Running transform: ', transform);
|
||||
transform(dom, frontMatter, verbose);
|
||||
}
|
||||
dom.body.setAttribute('distill-prerendered', '');
|
||||
// the function calling us can now use the transformed dom and filled data object
|
||||
if (data instanceof FrontMatter) {
|
||||
// frontMatter will already have needed properties
|
||||
} else {
|
||||
frontMatter.assignToObject(data);
|
||||
}
|
||||
}
|
||||
|
||||
export function distillify(dom, data, verbose=true) {
|
||||
// thirdly, we can use these additional transforms when publishing on the Distill website
|
||||
for (const [name, transform] of distillTransforms.entries()) {
|
||||
if (verbose) console.warn('Running distillify: ', name);
|
||||
transform(dom, data, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
export function usesTemplateV2(dom) {
|
||||
const tags = dom.querySelectorAll('script');
|
||||
let usesV2 = undefined;
|
||||
for (const tag of tags) {
|
||||
const src = tag.src;
|
||||
if (src.includes('template.v1.js')) {
|
||||
usesV2 = false;
|
||||
} else if (src.includes('template.v2.js')) {
|
||||
usesV2 = true;
|
||||
} else if (src.includes('template.')) {
|
||||
throw new Error('Uses distill template, but unknown version?!');
|
||||
}
|
||||
}
|
||||
|
||||
if (usesV2 === undefined) {
|
||||
throw new Error('Does not seem to use Distill template at all.');
|
||||
} else {
|
||||
return usesV2;
|
||||
}
|
||||
}
|
||||
|
||||
export { FrontMatter }; // TODO: removable?
|
||||
|
||||
export const testing = {
|
||||
extractors: extractors,
|
||||
transforms: transforms,
|
||||
distillTransforms: distillTransforms
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
const html = `
|
||||
<style>
|
||||
dt-banner {
|
||||
background: #FFF59D;
|
||||
display: block;
|
||||
text-align: center;
|
||||
color: black;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
}
|
||||
</style>
|
||||
<div>This article is a draft, awaiting review for publication in Distill</div>
|
||||
`;
|
||||
|
||||
export default function(dom, data) {
|
||||
let banner = dom.createElement('dt-banner');
|
||||
banner.innerHTML = html;
|
||||
let b = dom.querySelector('body');
|
||||
b.insertBefore(banner, b.firstChild);
|
||||
banner.addEventListener('click', function() {
|
||||
banner.style.display = 'none';
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { bylineTemplate } from '../components/d-byline.js';
|
||||
|
||||
export default function(dom, data) {
|
||||
const byline = dom.querySelector('d-byline');
|
||||
if (byline) {
|
||||
byline.innerHTML = bylineTemplate(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { renderCitationList } from '../components/d-citation-list'; // (element, entries)
|
||||
|
||||
export default function(dom, data) {
|
||||
const citationListTag = dom.querySelector('d-citation-list');
|
||||
if (citationListTag) {
|
||||
const entries = new Map(data.citations.map( citationKey => {
|
||||
return [citationKey, data.bibliography.get(citationKey)];
|
||||
}));
|
||||
renderCitationList(citationListTag, entries, dom);
|
||||
citationListTag.setAttribute('distill-prerendered', 'true');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
export default function(dom, data) {
|
||||
let css = `
|
||||
dt-cite {
|
||||
color: hsla(206, 90%, 20%, 0.7);
|
||||
}
|
||||
dt-cite .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 dt-cite .citation-number {
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
top: -2px;
|
||||
line-height: 1em;
|
||||
}
|
||||
`;
|
||||
|
||||
let style = dom.createElement('style');
|
||||
style.textContent = css;
|
||||
dom.querySelector('body').appendChild(style);
|
||||
|
||||
let citations = data.citations;
|
||||
/*if (data.citations) {
|
||||
citations = Object.keys(data.citations).map(c => data.citations[c]);
|
||||
citations.sort((a, b) => {
|
||||
return a.author.localeCompare(b.author);
|
||||
});
|
||||
}*/
|
||||
|
||||
var citeTags = [].slice.apply(dom.querySelectorAll('dt-cite'));
|
||||
citeTags.forEach((el,n) => {
|
||||
var key = el.getAttribute('key');
|
||||
if (key) {
|
||||
var keys = key.split(',');
|
||||
var cite_string = inline_cite_short(keys);
|
||||
var cite_hover_str = '';
|
||||
keys.map((key,n) => {
|
||||
if (n>0) cite_hover_str += '<br><br>';
|
||||
cite_hover_str += hover_cite(data.bibliography[key]);
|
||||
});
|
||||
cite_hover_str = cite_hover_str.replace(/"/g, ''');
|
||||
var orig_string = el.innerHTML;
|
||||
if (orig_string != '') orig_string += ' ';
|
||||
el.innerHTML = `<span id="citation-${n}" data-hover="${cite_hover_str}">${orig_string}<span class="citation-number">${cite_string}</span></span>`;
|
||||
}
|
||||
});
|
||||
|
||||
let bibEl = dom.querySelector('dt-bibliography');
|
||||
if (bibEl) {
|
||||
let ol = dom.createElement('ol');
|
||||
citations.forEach(key => {
|
||||
let el = dom.createElement('li');
|
||||
el.innerHTML = bibliography_cite(data.bibliography[key]);
|
||||
ol.appendChild(el);
|
||||
});
|
||||
bibEl.appendChild(ol);
|
||||
}
|
||||
|
||||
function inline_cite_short(keys){
|
||||
function cite_string(key){
|
||||
if (key in data.bibliography){
|
||||
var n = data.citations.indexOf(key)+1;
|
||||
return ''+n;
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return '['+keys.map(cite_string).join(', ')+']';
|
||||
}
|
||||
|
||||
function inline_cite_long(keys){
|
||||
function cite_string(key){
|
||||
if (key in data.bibliography){
|
||||
var ent = data.bibliography[key];
|
||||
var names = ent.author.split(' and ');
|
||||
names = names.map(name => name.split(',')[0].trim());
|
||||
var year = ent.year;
|
||||
if (names.length == 1) return names[0] + ', ' + year;
|
||||
if (names.length == 2) return names[0] + ' & ' + names[1] + ', ' + year;
|
||||
if (names.length > 2) return names[0] + ', et al., ' + year;
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
return keys.map(cite_string).join(', ');
|
||||
}
|
||||
|
||||
function author_string(ent, template, sep, finalSep){
|
||||
var names = ent.author.split(' and ');
|
||||
let name_strings = names.map(name => {
|
||||
name = name.trim();
|
||||
if (name.indexOf(',') != -1){
|
||||
var last = name.split(',')[0].trim();
|
||||
var firsts = name.split(',')[1];
|
||||
} else {
|
||||
var last = name.split(' ').slice(-1)[0].trim();
|
||||
var firsts = name.split(' ').slice(0,-1).join(' ');
|
||||
}
|
||||
var initials = '';
|
||||
if (firsts != undefined) {
|
||||
initials = firsts.trim().split(' ').map(s => s.trim()[0]);
|
||||
initials = initials.join('.')+'.';
|
||||
}
|
||||
return template.replace('${F}', firsts)
|
||||
.replace('${L}', last)
|
||||
.replace('${I}', initials);
|
||||
});
|
||||
if (names.length > 1) {
|
||||
var str = name_strings.slice(0, names.length-1).join(sep);
|
||||
str += (finalSep || sep) + name_strings[names.length-1];
|
||||
return str;
|
||||
} else {
|
||||
return name_strings[0];
|
||||
}
|
||||
}
|
||||
|
||||
function venue_string(ent) {
|
||||
var cite = (ent.journal || ent.booktitle || '');
|
||||
if ('volume' in ent){
|
||||
var issue = ent.issue || ent.number;
|
||||
issue = (issue != undefined)? '('+issue+')' : '';
|
||||
cite += ', Vol ' + ent.volume + issue;
|
||||
}
|
||||
if ('pages' in ent){
|
||||
cite += ', pp. ' + ent.pages;
|
||||
}
|
||||
if (cite != '') cite += '. ';
|
||||
if ('publisher' in ent){
|
||||
cite += ent.publisher;
|
||||
if (cite[cite.length-1] != '.') cite += '.';
|
||||
}
|
||||
return cite;
|
||||
}
|
||||
|
||||
function link_string(ent){
|
||||
if ('url' in ent){
|
||||
var url = ent.url;
|
||||
var arxiv_match = (/arxiv\.org\/abs\/([0-9\.]*)/).exec(url);
|
||||
if (arxiv_match != null){
|
||||
url = `http://arxiv.org/pdf/${arxiv_match[1]}.pdf`;
|
||||
}
|
||||
|
||||
if (url.slice(-4) == '.pdf'){
|
||||
var label = 'PDF';
|
||||
} else if (url.slice(-5) == '.html') {
|
||||
var label = 'HTML';
|
||||
}
|
||||
return `  <a href="${url}">[${label||'link'}]</a>`;
|
||||
}/* else if ("doi" in ent){
|
||||
return `  <a href="https://doi.org/${ent.doi}" >[DOI]</a>`;
|
||||
}*/ else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
function doi_string(ent, new_line){
|
||||
if ('doi' in ent) {
|
||||
return `${new_line?'<br>':''} <a href="https://doi.org/${ent.doi}" style="text-decoration:inherit;">DOI: ${ent.doi}</a>`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function bibliography_cite(ent, fancy){
|
||||
if (ent){
|
||||
var cite = '<b>' + ent.title + '</b> ';
|
||||
cite += link_string(ent) + '<br>';
|
||||
cite += author_string(ent, '${L}, ${I}', ', ', ' and ');
|
||||
if (ent.year || ent.date){
|
||||
cite += ', ' + (ent.year || ent.date) + '. ';
|
||||
} else {
|
||||
cite += '. ';
|
||||
}
|
||||
cite += venue_string(ent);
|
||||
cite += doi_string(ent);
|
||||
return cite;
|
||||
/*var cite = author_string(ent, "${L}, ${I}", ", ", " and ");
|
||||
if (ent.year || ent.date){
|
||||
cite += ", " + (ent.year || ent.date) + ". "
|
||||
} else {
|
||||
cite += ". "
|
||||
}
|
||||
cite += "<b>" + ent.title + "</b>. ";
|
||||
cite += venue_string(ent);
|
||||
cite += doi_string(ent);
|
||||
cite += link_string(ent);
|
||||
return cite*/
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
function hover_cite(ent){
|
||||
if (ent){
|
||||
var cite = '';
|
||||
cite += '<b>' + ent.title + '</b>';
|
||||
cite += link_string(ent);
|
||||
cite += '<br>';
|
||||
|
||||
var a_str = author_string(ent, '${I} ${L}', ', ') + '.';
|
||||
var v_str = venue_string(ent).trim() + ' ' + ent.year + '. ' + doi_string(ent, true);
|
||||
|
||||
if ((a_str+v_str).length < Math.min(40, ent.title.length)) {
|
||||
cite += a_str + ' ' + v_str;
|
||||
} else {
|
||||
cite += a_str + '<br>' + v_str;
|
||||
}
|
||||
return cite;
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//https://scholar.google.com/scholar?q=allintitle%3ADocument+author%3Aolah
|
||||
function get_GS_URL(ent){
|
||||
if (ent){
|
||||
var names = ent.author.split(' and ');
|
||||
names = names.map(name => name.split(',')[0].trim());
|
||||
var title = ent.title.split(' ');//.replace(/[,:]/, "")
|
||||
var url = 'http://search.labs.crossref.org/dois?';//""https://scholar.google.com/scholar?"
|
||||
url += uris({q: names.join(' ') + ' ' + title.join(' ')});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
import Prism from "prismjs";
|
||||
import Prism from 'prismjs';
|
||||
|
||||
export default function(dom, data) {
|
||||
let codeElements = [].slice.call(dom.querySelectorAll("dt-code"));
|
||||
let codeElements = [].slice.call(dom.querySelectorAll('dt-code'));
|
||||
codeElements.forEach(el => {
|
||||
let content = el.textContent;
|
||||
el.innerHTML = "";
|
||||
let language = el.getAttribute("language");
|
||||
let c = dom.createElement("code");
|
||||
if (el.getAttribute("block") === "") {
|
||||
el.innerHTML = '';
|
||||
let language = el.getAttribute('language');
|
||||
let c = dom.createElement('code');
|
||||
if (el.getAttribute('block') === '') {
|
||||
// Let's normalize the tab indents
|
||||
content = content.replace(/\n/, "");
|
||||
content = content.replace(/\n/, '');
|
||||
let tabs = content.match(/\s*/);
|
||||
content = content.replace(new RegExp("\n" + tabs, "g"), "\n");
|
||||
content = content.replace(new RegExp('\n' + tabs, 'g'), '\n');
|
||||
content = content.trim();
|
||||
let p = dom.createElement("pre");
|
||||
let p = dom.createElement('pre');
|
||||
p.appendChild(c);
|
||||
el.appendChild(p);
|
||||
} else {
|
||||
@@ -21,7 +21,7 @@ export default function(dom, data) {
|
||||
}
|
||||
let highlighted = content;
|
||||
if (Prism.languages[language]) {
|
||||
c.setAttribute("class", "language-" + language);
|
||||
c.setAttribute('class', 'language-' + language);
|
||||
highlighted = Prism.highlight(content, Prism.languages[language]);
|
||||
}
|
||||
c.innerHTML = highlighted;
|
||||
@@ -0,0 +1,25 @@
|
||||
export default function(dom, data) {
|
||||
|
||||
var fnTags = [].slice.apply(dom.querySelectorAll('dt-fn'));
|
||||
var fnContent = [];
|
||||
fnTags.forEach((el,n) => {
|
||||
var content = el.innerHTML;
|
||||
fnContent.push(content);
|
||||
n = (n+1)+'';
|
||||
var key = 'fn-'+n;
|
||||
var escaped_content = content.replace(/"/g, ''');
|
||||
el.innerHTML = `<sup><span id="${key}" data-hover="${escaped_content}" style="cursor:pointer">${n}</span></sup>`;
|
||||
});
|
||||
|
||||
let fnList = dom.querySelector('dt-fn-list');
|
||||
if (fnList) {
|
||||
let ol = dom.createElement('ol');
|
||||
fnContent.forEach(content => {
|
||||
let el = dom.createElement('li');
|
||||
el.innerHTML = content;
|
||||
ol.appendChild(el);
|
||||
});
|
||||
fnList.appendChild(ol);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import ymlParse from 'js-yaml';
|
||||
|
||||
export default function(dom, data) {
|
||||
let localData = {};
|
||||
let el = dom.querySelector('script[type="text/front-matter"]');
|
||||
if (el) {
|
||||
let text = el.textContent;
|
||||
localData = ymlParse.safeLoad(text);
|
||||
}
|
||||
|
||||
data.title = localData.title ? localData.title : 'Untitled';
|
||||
data.description = localData.description ? localData.description : 'No description.';
|
||||
|
||||
data.authors = localData.authors ? localData.authors : [];
|
||||
|
||||
data.authors = data.authors.map((author, i) =>{
|
||||
let a = {};
|
||||
let name = Object.keys(author)[0];
|
||||
if ((typeof author) === 'string') {
|
||||
name = author;
|
||||
} else {
|
||||
a.personalURL = author[name];
|
||||
}
|
||||
let names = name.split(' ');
|
||||
a.name = name;
|
||||
a.firstName = names.slice(0, names.length - 1).join(' ');
|
||||
a.lastName = names[names.length -1];
|
||||
if(localData.affiliations[i]) {
|
||||
let affiliation = Object.keys(localData.affiliations[i])[0];
|
||||
if ((typeof localData.affiliations[i]) === 'string') {
|
||||
affiliation = localData.affiliations[i];
|
||||
} else {
|
||||
a.affiliationURL = localData.affiliations[i][affiliation];
|
||||
}
|
||||
a.affiliation = affiliation;
|
||||
}
|
||||
return a;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
//import xml from "xml";
|
||||
|
||||
export default function(data) {
|
||||
|
||||
|
||||
var date = data.publishedDate;
|
||||
|
||||
var batch_timestamp = Math.floor(Date.now() / 1000);
|
||||
var batch_id = data.authors.length ? data.authors[0].lastName.toLowerCase().slice(0,20) : 'Anonymous';
|
||||
batch_id += '_' + date.getFullYear();
|
||||
batch_id += '_' + data.title.split(' ')[0].toLowerCase().slice(0,20) + '_' + batch_timestamp;
|
||||
// generate XML
|
||||
var crf_data =
|
||||
{doi_batch : [
|
||||
|
||||
{ _attr: {
|
||||
version: '4.3.7',
|
||||
xmlns: 'http://www.crossref.org/schema/4.3.7',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xsi:schemaLocation': 'http://www.crossref.org/schema/4.3.7 http://www.crossref.org/schemas/crossref4.3.7.xsd',
|
||||
}},
|
||||
|
||||
{ head: [
|
||||
{doi_batch_id: batch_id},
|
||||
{timestamp: batch_timestamp},
|
||||
{depositor: [
|
||||
{depositor_name: data.journal.publisherName},
|
||||
{email_address: data.journal.publisherEmail},
|
||||
]},
|
||||
{registrant: data.journal.publisherName},
|
||||
]},
|
||||
|
||||
{body: [
|
||||
{journal: [
|
||||
|
||||
{journal_metadata: [
|
||||
{full_title: data.journal.full_title || data.journal.title},
|
||||
{abbrev_title: data.journal.abbrev_title || data.journal.title || data.journal.full_title},
|
||||
{issn: data.journal.issn},
|
||||
{doi_data: [
|
||||
{doi: data.journal.doi},
|
||||
{resource: data.journal.url},
|
||||
]},
|
||||
]},
|
||||
|
||||
{journal_issue: [
|
||||
{publication_date: [
|
||||
{month: date.getMonth()+1},
|
||||
{year: date.getFullYear()},
|
||||
]},
|
||||
{journal_volume: [
|
||||
{volume: data.volume},
|
||||
]},
|
||||
{issue: data.issue},
|
||||
]},
|
||||
|
||||
{journal_article: [
|
||||
{titles: [
|
||||
{title: data.title},
|
||||
]},
|
||||
{ contributors:
|
||||
data.authors.map((author, ind) => (
|
||||
{person_name: [
|
||||
{ _attr: {
|
||||
contributor_role: 'author',
|
||||
sequence: (ind == 0)? 'first' : 'additional'
|
||||
}},
|
||||
{given_name: author.firstName},
|
||||
{surname: author.lastName},
|
||||
{affiliation: author.affiliation}
|
||||
// TODO: ORCID?
|
||||
]}
|
||||
))
|
||||
},
|
||||
{publication_date: [
|
||||
{month: date.getMonth()+1},
|
||||
{day: date.getDate()},
|
||||
{year: date.getFullYear()}
|
||||
]},
|
||||
{ publisher_item: [
|
||||
{item_number: data.doi}
|
||||
]},
|
||||
{doi_data: [
|
||||
{doi: data.doi},
|
||||
//{timestamp: ""},
|
||||
{resource: data.url},
|
||||
]},
|
||||
{citation_list:
|
||||
data.citations.map(key =>
|
||||
citation_xml(key, data.bibliography[key]))
|
||||
}
|
||||
|
||||
]},
|
||||
|
||||
]},
|
||||
]},
|
||||
]};
|
||||
|
||||
return xml(crf_data);
|
||||
}
|
||||
|
||||
function citation_xml(key, ent){
|
||||
if (ent == undefined) return {};
|
||||
var info = [];
|
||||
info.push({_attr: {key: key}});
|
||||
if ('title' in ent)
|
||||
info.push({article_title: ent.title});
|
||||
if ('author' in ent)
|
||||
info.push({author: ent.author.split(' and ')[0].split(',')[0].trim()});
|
||||
if ('journal' in ent)
|
||||
info.push({journal_title: ent.journal});
|
||||
if ('booktitle' in ent)
|
||||
info.push({volume_title: ent.booktitle});
|
||||
if ('volume' in ent)
|
||||
info.push({volume: ent.volume});
|
||||
if ('issue' in ent)
|
||||
info.push({issue: ent.issue});
|
||||
if ('doi' in ent)
|
||||
info.push({doi: ent.doi});
|
||||
return {citation: info};
|
||||
}
|
||||
|
||||
function xml(obj) {
|
||||
//console.log(typeof(obj), obj)
|
||||
if (typeof obj === 'string') return obj;
|
||||
if (typeof obj === 'number') return ''+obj;
|
||||
let keys = Object.keys(obj);
|
||||
if (keys.length != 1) console.error('can\'t interpret ', obj, 'as xml');
|
||||
let name = keys[0];
|
||||
var full_content = obj[name];
|
||||
var attr = {};
|
||||
if (Array.isArray(full_content)){
|
||||
var content = [];
|
||||
for (var i in full_content) {
|
||||
var obj = full_content[i];
|
||||
var obj_name = Object.keys(obj)[0];
|
||||
if ('_attr' == obj_name) {
|
||||
attr = obj['_attr'];
|
||||
} else {
|
||||
//console.log(Object.keys(obj)[0])
|
||||
content.push(obj);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
content = full_content;
|
||||
}
|
||||
if (content == undefined){
|
||||
content = 'undefined';
|
||||
}
|
||||
|
||||
let attr_string = '';
|
||||
for (var k in attr) {
|
||||
attr_string += ` ${k}=\"${attr[k]}\"`;
|
||||
}
|
||||
|
||||
//console.log(typeof content, Array.isArray(content), content instanceof String, content)
|
||||
if (Array.isArray(content)){
|
||||
content = content.map(xml);
|
||||
content = content.join('\n').split('\n');
|
||||
content = content.map(s => ' ' + s).join('\n');
|
||||
var result = `<${name}${attr_string}>\n${content}\n</${name}>`;
|
||||
} else {
|
||||
content = xml(content);
|
||||
var result = `<${name}${attr_string}>${content}</${name}>`;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import code from './hover-box.txt';
|
||||
|
||||
export default function(dom) {
|
||||
let s = dom.createElement('script');
|
||||
s.textContent = code;
|
||||
dom.querySelector('body').appendChild(s);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
// DistillHoverBox
|
||||
//=====================================
|
||||
|
||||
function DistillHoverBox(key, pos){
|
||||
|
||||
if (!(key in DistillHoverBox.contentMap)){
|
||||
console.error("No DistillHoverBox content registered for key", key);
|
||||
}
|
||||
if (key in DistillHoverBox.liveBoxes) {
|
||||
console.error("There already exists a DistillHoverBox for key", key);
|
||||
} else {
|
||||
for (var k in DistillHoverBox.liveBoxes)
|
||||
DistillHoverBox.liveBoxes[k].remove();
|
||||
DistillHoverBox.liveBoxes[key] = this;
|
||||
}
|
||||
this.key = key;
|
||||
|
||||
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);
|
||||
left = Math.min(left, window.innerWidth-width-outer_padding);
|
||||
width = width - 2*padding;
|
||||
|
||||
var str = `<div style="position: absolute;
|
||||
background-color: #FFF;
|
||||
white-s
|
||||
opacity: 0.95;
|
||||
max-width: ${width}px;
|
||||
top: ${top}px;
|
||||
left: ${left}px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||
padding: ${padding}px;
|
||||
border-radius: ${pretty? 3 : 0}px;
|
||||
box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.2);
|
||||
z-index: ${1e6}" >
|
||||
${DistillHoverBox.contentMap[key]}
|
||||
</div>`;
|
||||
|
||||
this.div = appendBody(str);
|
||||
|
||||
DistillHoverBox.bind (this.div, key);
|
||||
}
|
||||
|
||||
DistillHoverBox.prototype.remove = function remove(){
|
||||
if (this.div) this.div.remove();
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
delete DistillHoverBox.liveBoxes[this.key];
|
||||
}
|
||||
|
||||
DistillHoverBox.prototype.stopTimeout = function stopTimeout() {
|
||||
if (this.timeout) clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
DistillHoverBox.prototype.extendTimeout = function extendTimeout(T) {
|
||||
//console.log("extend", T)
|
||||
var this_ = this;
|
||||
this.stopTimeout();
|
||||
this.timeout = setTimeout(() => this_.remove(), T);
|
||||
}
|
||||
|
||||
DistillHoverBox.liveBoxes = {};
|
||||
DistillHoverBox.contentMap = {};
|
||||
|
||||
DistillHoverBox.bind = function bind(node, key) {
|
||||
if (typeof node == "string"){
|
||||
node = document.querySelector(node);
|
||||
}
|
||||
node.addEventListener("mouseover", () => {
|
||||
var bbox = node.getBoundingClientRect();
|
||||
if (!(key in DistillHoverBox.liveBoxes)){
|
||||
new DistillHoverBox(key, [bbox.right, bbox.bottom]);
|
||||
}
|
||||
DistillHoverBox.liveBoxes[key].stopTimeout();
|
||||
});
|
||||
node.addEventListener("mouseout", () => {
|
||||
if (key in DistillHoverBox.liveBoxes){
|
||||
DistillHoverBox.liveBoxes[key].extendTimeout(250);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function appendBody(str){
|
||||
var node = nodeFromString(str);
|
||||
var body = document.querySelector("body");
|
||||
body.appendChild(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
function nodeFromString(str) {
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = str;
|
||||
return div.firstChild;
|
||||
}
|
||||
|
||||
var hover_es = document.querySelectorAll("span[data-hover]");
|
||||
hover_es = [].slice.apply(hover_es);
|
||||
hover_es.forEach((e,n) => {
|
||||
var key = "hover-"+n;
|
||||
var content = e.getAttribute("data-hover");
|
||||
DistillHoverBox.contentMap[key] = content;
|
||||
DistillHoverBox.bind(e, key);
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
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');
|
||||
}
|
||||
|
||||
// set charset to 'utf-8'
|
||||
if (!dom.querySelector('meta[charset]')) {
|
||||
const meta = dom.createElement('meta');
|
||||
meta.setAttribute('charset', 'utf-8');
|
||||
head.appendChild(meta);
|
||||
}
|
||||
|
||||
// set viewport
|
||||
if (!dom.querySelector('meta[name=viewport]')) {
|
||||
const meta = dom.createElement('meta');
|
||||
meta.setAttribute('name', 'viewport');
|
||||
meta.setAttribute('content', 'width=device-width, initial-scale=1');
|
||||
head.appendChild(meta);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import fetch from "fetch";
|
||||
let fetchUrl = fetch.fetchUrl
|
||||
import fetch from 'fetch';
|
||||
let fetchUrl = fetch.fetchUrl;
|
||||
|
||||
export default function(dom, data) {
|
||||
|
||||
var includeTags = [].slice.apply(dom.querySelectorAll("dt-include"));
|
||||
var includeTags = [].slice.apply(dom.querySelectorAll('dt-include'));
|
||||
|
||||
includeTags.forEach(el => {
|
||||
let src = el.getAttribute("src");
|
||||
let src = el.getAttribute('src');
|
||||
fetchUrl(src, (err, meta, body) => {
|
||||
console.log(err, meta, body);
|
||||
el.innerHTML = body.toString();
|
||||
})
|
||||
});
|
||||
});
|
||||
data.bibliography = bibliography;
|
||||
data.citations = citations;
|
||||
@@ -10,9 +10,9 @@ export default function(dom, data) {
|
||||
markdownElements.forEach(el => {
|
||||
let content = el.innerHTML;
|
||||
// Set default indents
|
||||
content = content.replace(/\n/, "");
|
||||
content = content.replace(/\n/, '');
|
||||
let tabs = content.match(/\s*/);
|
||||
content = content.replace(new RegExp("\n" + tabs, "g"), "\n");
|
||||
content = content.replace(new RegExp('\n' + tabs, 'g'), '\n');
|
||||
content = content.trim();
|
||||
|
||||
el.innerHTML = marked(content);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user