diff --git a/site/content/tutorials/01-introduction/01-basics/App.svelte b/site/content/tutorial/01-introduction/01-basics/App.svelte similarity index 100% rename from site/content/tutorials/01-introduction/01-basics/App.svelte rename to site/content/tutorial/01-introduction/01-basics/App.svelte diff --git a/site/content/tutorials/01-introduction/01-basics/text.md b/site/content/tutorial/01-introduction/01-basics/text.md similarity index 100% rename from site/content/tutorials/01-introduction/01-basics/text.md rename to site/content/tutorial/01-introduction/01-basics/text.md diff --git a/site/content/tutorials/01-introduction/02-adding-data/App.svelte b/site/content/tutorial/01-introduction/02-adding-data/App.svelte similarity index 100% rename from site/content/tutorials/01-introduction/02-adding-data/App.svelte rename to site/content/tutorial/01-introduction/02-adding-data/App.svelte diff --git a/site/content/tutorials/01-introduction/02-adding-data/text.md b/site/content/tutorial/01-introduction/02-adding-data/text.md similarity index 100% rename from site/content/tutorials/01-introduction/02-adding-data/text.md rename to site/content/tutorial/01-introduction/02-adding-data/text.md diff --git a/site/content/tutorials/01-introduction/03-dynamic-attributes/App.svelte b/site/content/tutorial/01-introduction/03-dynamic-attributes/App.svelte similarity index 100% rename from site/content/tutorials/01-introduction/03-dynamic-attributes/App.svelte rename to site/content/tutorial/01-introduction/03-dynamic-attributes/App.svelte diff --git a/site/content/tutorials/01-introduction/03-dynamic-attributes/text.md b/site/content/tutorial/01-introduction/03-dynamic-attributes/text.md similarity index 100% rename from site/content/tutorials/01-introduction/03-dynamic-attributes/text.md rename to site/content/tutorial/01-introduction/03-dynamic-attributes/text.md diff --git a/site/content/tutorial/01-introduction/meta.json b/site/content/tutorial/01-introduction/meta.json new file mode 100644 index 0000000000..5c8f7bc10b --- /dev/null +++ b/site/content/tutorial/01-introduction/meta.json @@ -0,0 +1,3 @@ +{ + "title": "Introduction" +} \ No newline at end of file diff --git a/site/package-lock.json b/site/package-lock.json index 052215363d..a6ac3b7e58 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -1579,7 +1579,7 @@ "dev": true }, "eslint-plugin-svelte3": { - "version": "git+https://github.com/sveltejs/eslint-plugin-svelte3.git#cf43fd9a1498bdffe7c5b4927eb785d63beb73a4", + "version": "git+https://github.com/sveltejs/eslint-plugin-svelte3.git#651d7e3695b1731251ab3a501d1067b561ede09f", "from": "git+https://github.com/sveltejs/eslint-plugin-svelte3.git#semver:*", "dev": true }, @@ -4291,9 +4291,9 @@ } }, "sapper": { - "version": "0.26.0-alpha.9", - "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.26.0-alpha.9.tgz", - "integrity": "sha512-3CnC8rQWgVv8IfqSgWV+MXfn+f/ZKMISQBwPsSBBX0x+vBckfmLZ31omKDRDyVnit1WgzFW4mXW/I3PdqRVMZw==", + "version": "0.26.0-alpha.10", + "resolved": "https://registry.npmjs.org/sapper/-/sapper-0.26.0-alpha.10.tgz", + "integrity": "sha512-S1XdAA0gxEPT3Ikh3jsLKAAbV3EnDd80sppCeUJ5wHCfXTRiP6STxe5PLYZ4Ym8uYU7Iez+6cGLTkfP0ZLPRQw==", "dev": true, "requires": { "html-minifier": "^3.5.21", diff --git a/site/package.json b/site/package.json index fcc3c23e9b..d5e5131e4b 100644 --- a/site/package.json +++ b/site/package.json @@ -52,7 +52,7 @@ "rollup-plugin-replace": "^2.1.0", "rollup-plugin-svelte": "^5.0.3", "rollup-plugin-terser": "^4.0.4", - "sapper": "^0.26.0-alpha.9", + "sapper": "^0.26.0-alpha.10", "svelte": "^3.0.0-beta.8" } } diff --git a/site/src/routes/api/blog/_posts.js b/site/src/routes/api/blog/_posts.js index 8b70483cd1..33c033b517 100644 --- a/site/src/routes/api/blog/_posts.js +++ b/site/src/routes/api/blog/_posts.js @@ -1,19 +1,10 @@ import fs from 'fs'; import path from 'path'; -import process_markdown from '../../../utils/_process_markdown.js'; +import { extract_frontmatter, langs } from '../../../utils/markdown.js'; import marked from 'marked'; - import PrismJS from 'prismjs'; import 'prismjs/components/prism-bash'; -// map lang to prism-language-attr -const prismLang = { - bash: 'bash', - html: 'markup', - js: 'javascript', - css: 'css', -}; - export default function() { return fs .readdirSync('content/blog') @@ -22,7 +13,7 @@ export default function() { const markdown = fs.readFileSync(`content/blog/${file}`, 'utf-8'); - const { content, metadata } = process_markdown(markdown); + const { content, metadata } = extract_frontmatter(markdown); const date = new Date(`${metadata.pubdate} EDT`); // cheeky hack metadata.dateString = date.toDateString(); @@ -30,7 +21,7 @@ export default function() { const renderer = new marked.Renderer(); renderer.code = (source, lang) => { - const plang = prismLang[lang]; + const plang = langs[lang]; const highlighted = PrismJS.highlight( source, PrismJS.languages[plang], diff --git a/site/src/routes/docs/_sections.js b/site/src/routes/docs/_sections.js index 59818bc464..0fd1382652 100644 --- a/site/src/routes/docs/_sections.js +++ b/site/src/routes/docs/_sections.js @@ -1,20 +1,10 @@ import fs from 'fs'; import path from 'path'; -import * as fleece from 'golden-fleece'; -import process_markdown from '../../utils/_process_markdown.js'; +import { extract_frontmatter, extract_metadata, langs } from '../../utils/markdown.js'; import marked from 'marked'; - import PrismJS from 'prismjs'; import 'prismjs/components/prism-bash'; -// map lang to prism-language-attr -const prismLang = { - bash: 'bash', - html: 'markup', - js: 'javascript', - css: 'css', -}; - const escaped = { '"': '"', "'": ''', @@ -45,24 +35,6 @@ const blockTypes = [ 'tablecell' ]; -function extractMeta(line, lang) { - try { - if (lang === 'html' && line.startsWith('')) { - return fleece.evaluate(line.slice(4, -3).trim()); - } - - if ( - lang === 'js' || - (lang === 'json' && line.startsWith('/*') && line.endsWith('*/')) - ) { - return fleece.evaluate(line.slice(2, -2).trim()); - } - } catch (err) { - // TODO report these errors, don't just squelch them - return null; - } -} - // https://github.com/darkskyapp/string-hash/blob/master/index.js function getHash(str) { let hash = 5381; @@ -81,7 +53,7 @@ export default function() { .map(file => { const markdown = fs.readFileSync(`content/guide/${file}`, 'utf-8'); - const { content, metadata } = process_markdown(markdown); + const { content, metadata } = extract_frontmatter(markdown); const subsections = []; const groups = []; @@ -97,7 +69,7 @@ export default function() { const lines = source.split('\n'); - const meta = extractMeta(lines[0], lang); + const meta = extract_metadata(lines[0], lang); let prefix = ''; let className = 'code-block'; @@ -124,7 +96,7 @@ export default function() { if (meta && meta.hidden) return ''; - const plang = prismLang[lang]; + const plang = langs[lang]; const highlighted = PrismJS.highlight( source, PrismJS.languages[plang], diff --git a/site/src/routes/tutorial/[slug]/_components/TableOfContents.svelte b/site/src/routes/tutorial/[slug]/_components/TableOfContents.svelte new file mode 100644 index 0000000000..21962ab03e --- /dev/null +++ b/site/src/routes/tutorial/[slug]/_components/TableOfContents.svelte @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/site/src/routes/tutorial/[slug]/index.json.js b/site/src/routes/tutorial/[slug]/index.json.js new file mode 100644 index 0000000000..c3c84e4f42 --- /dev/null +++ b/site/src/routes/tutorial/[slug]/index.json.js @@ -0,0 +1,95 @@ +import * as fs from 'fs'; +import marked from 'marked'; +import PrismJS from 'prismjs'; +import { extract_frontmatter, extract_metadata, langs } from '../../../utils/markdown'; + +const cache = new Map(); + +function find_tutorial(slug) { + const sections = fs.readdirSync(`content/tutorial`); + + for (const section of sections) { + const chapters = fs.readdirSync(`content/tutorial/${section}`).filter(dir => /^\d+/.test(dir)); + for (const chapter of chapters) { + if (slug === chapter.replace(/^\d+-/, '')) { + return { section, chapter }; + } + } + } +} + +function get_tutorial(slug) { + const found = find_tutorial(slug); + if (!found) return found; + + const dir = `content/tutorial/${found.section}/${found.chapter}`; + + const markdown = fs.readFileSync(`${dir}/text.md`, 'utf-8'); + const files = fs.readdirSync(dir).filter(file => file[0] !== '.' && file !== 'text.md'); + + const { content } = extract_frontmatter(markdown); + + const renderer = new marked.Renderer(); + + renderer.code = (source, lang) => { + source = source.replace(/^ +/gm, match => + match.split(' ').join('\t') + ); + + const lines = source.split('\n'); + + const meta = extract_metadata(lines[0], lang); + + let prefix = ''; + let className = 'code-block'; + + if (meta) { + source = lines.slice(1).join('\n'); + const filename = meta.filename || (lang === 'html' && 'App.svelte'); + if (filename) { + prefix = `${prefix} ${filename}`; + className += ' named'; + } + } + + const plang = langs[lang]; + const highlighted = PrismJS.highlight( + source, + PrismJS.languages[plang], + lang + ); + + return `
${highlighted}