diff --git a/site/config.js b/site/config.js new file mode 100644 index 0000000..db59814 --- /dev/null +++ b/site/config.js @@ -0,0 +1,3 @@ +export const SLUG_PRESERVE_UNICODE = false; +export const SLUG_SEPARATOR = '_'; +export const SLUG_LANG = 'en'; \ No newline at end of file diff --git a/site/content/guide/00-introduction.md b/site/content/docs/00-introduction.md similarity index 100% rename from site/content/guide/00-introduction.md rename to site/content/docs/00-introduction.md diff --git a/site/content/guide/01-structure.md b/site/content/docs/01-structure.md similarity index 100% rename from site/content/guide/01-structure.md rename to site/content/docs/01-structure.md diff --git a/site/content/guide/02-routing.md b/site/content/docs/02-routing.md similarity index 100% rename from site/content/guide/02-routing.md rename to site/content/docs/02-routing.md diff --git a/site/content/guide/03-client-api.md b/site/content/docs/03-client-api.md similarity index 100% rename from site/content/guide/03-client-api.md rename to site/content/docs/03-client-api.md diff --git a/site/content/guide/04-preloading.md b/site/content/docs/04-preloading.md similarity index 100% rename from site/content/guide/04-preloading.md rename to site/content/docs/04-preloading.md diff --git a/site/content/guide/05-layouts.md b/site/content/docs/05-layouts.md similarity index 99% rename from site/content/guide/05-layouts.md rename to site/content/docs/05-layouts.md index 11a7165..f349a2d 100644 --- a/site/content/guide/05-layouts.md +++ b/site/content/docs/05-layouts.md @@ -82,7 +82,7 @@ In addition to `child.component` and `child.props`, there is a `child.segment` p ``` -### Preloading +### Preloading in layouts Like page components, layout components can use `preload`: diff --git a/site/content/guide/06-server-side-rendering.md b/site/content/docs/06-server-side-rendering.md similarity index 100% rename from site/content/guide/06-server-side-rendering.md rename to site/content/docs/06-server-side-rendering.md diff --git a/site/content/guide/07-state-management.md b/site/content/docs/07-state-management.md similarity index 100% rename from site/content/guide/07-state-management.md rename to site/content/docs/07-state-management.md diff --git a/site/content/guide/08-prefetching.md b/site/content/docs/08-prefetching.md similarity index 100% rename from site/content/guide/08-prefetching.md rename to site/content/docs/08-prefetching.md diff --git a/site/content/guide/09-building.md b/site/content/docs/09-building.md similarity index 100% rename from site/content/guide/09-building.md rename to site/content/docs/09-building.md diff --git a/site/content/guide/10-exporting.md b/site/content/docs/10-exporting.md similarity index 100% rename from site/content/guide/10-exporting.md rename to site/content/docs/10-exporting.md diff --git a/site/content/guide/11-deploying.md b/site/content/docs/11-deploying.md similarity index 100% rename from site/content/guide/11-deploying.md rename to site/content/docs/11-deploying.md diff --git a/site/content/guide/12-security.md b/site/content/docs/12-security.md similarity index 100% rename from site/content/guide/12-security.md rename to site/content/docs/12-security.md diff --git a/site/content/guide/13-base-urls.md b/site/content/docs/13-base-urls.md similarity index 100% rename from site/content/guide/13-base-urls.md rename to site/content/docs/13-base-urls.md diff --git a/site/content/guide/14-testing.md b/site/content/docs/14-testing.md similarity index 100% rename from site/content/guide/14-testing.md rename to site/content/docs/14-testing.md diff --git a/site/content/guide/15-debugging.md b/site/content/docs/15-debugging.md similarity index 100% rename from site/content/guide/15-debugging.md rename to site/content/docs/15-debugging.md diff --git a/site/content/guide/16-migrating.md b/site/content/docs/16-migrating.md similarity index 98% rename from site/content/guide/16-migrating.md rename to site/content/docs/16-migrating.md index 485d5b1..ce1d221 100644 --- a/site/content/guide/16-migrating.md +++ b/site/content/docs/16-migrating.md @@ -10,11 +10,11 @@ Until we reach version 1.0, there may be occasional changes to the project struc Consult [sapper-template](https://github.com/sveltejs/sapper-template) for full examples of all the below points. -#### package.json +##### package.json To start a dev server, use `sapper dev` rather than `node server.js`. In all likelihood, your package.json will have an `npm run dev` script that will need to be updated. -#### Entry points +##### Entry points As of version 0.7, Sapper expects to find your entry points — for client, server and service worker — in an `app` folder. Instead of using magically-injected `__variables__`, each entry point imports from its corresponding file in the `app/manifests` folder. These are automatically generated by Sapper. @@ -50,7 +50,7 @@ import { assets, shell, timestamp, routes } from './manifest/service-worker.js'; ``` -#### Templates and error pages +##### Templates and error pages In previous versions, we had `templates/2xx.html`, `templates/4xx.html` and `templates/5xx.html`. Now, we have a single template, `app/template.html`, which should look like your old `templates/2xx.html`. @@ -61,7 +61,7 @@ This page is just like any other, except that it will get rendered whenever an e Note that you can now use `this.error(statusCode, error)` inside your `preload` functions. -#### Webpack configs +##### Webpack configs Your webpack configs now live in a `webpack` directory: @@ -73,12 +73,12 @@ If you have a service worker, you should also have a `webpack/service-worker.con ### <0.9 to 0.10 -#### app/template.html +##### app/template.html * Your `` element must contain `%sapper.base%` (see ([base URLs](guide#base-urls)) * Remove references to your service worker; this is now handled by `%sapper.scripts%` -#### Pages +##### Pages * Your `preload` functions should now use `this.fetch` instead of `fetch`. `this.fetch` allows you to make credentialled requests on the server, and means that you no longer need to create a `global.fetch` object in `app/server.js`. diff --git a/site/package-lock.json b/site/package-lock.json index e8f513e..819344e 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -825,6 +825,11 @@ "to-fast-properties": "^2.0.0" } }, + "@polka/send": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@polka/send/-/send-0.4.0.tgz", + "integrity": "sha1-4nccVnHTYXWDJTSriGqIT3XzHm8=" + }, "@polka/url": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", @@ -1194,6 +1199,17 @@ } } }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1389,6 +1405,12 @@ } } }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, "electron-to-chromium": { "version": "1.3.127", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.127.tgz", @@ -2193,6 +2215,15 @@ "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", "dev": true }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -2969,6 +3000,14 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "prismjs": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.16.0.tgz", + "integrity": "sha512-OA4MKxjFZHSvZcisLGe14THYsug/nF6O1f0pAJc0KN0wTyAcLqmsbE+lTGKSpyh+9pEW57+k6pg2AfYR+coyHA==", + "requires": { + "clipboard": "^2.0.0" + } + }, "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", @@ -3267,6 +3306,12 @@ "string-hash": "^1.1.3" } }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "optional": true + }, "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", @@ -3628,6 +3673,12 @@ } } }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "optional": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/site/package.json b/site/package.json index 7a2776f..23763ff 100644 --- a/site/package.json +++ b/site/package.json @@ -12,10 +12,12 @@ "test": "run-p --race dev cy:run" }, "dependencies": { + "@polka/send": "^0.4.0", "compression": "^1.7.1", "highlight.js": "^9.15.6", "marked": "^0.6.2", - "polka": "^0.5.0", + "polka": "^0.5.2", + "prismjs": "^1.16.0", "sirv": "^0.2.0" }, "devDependencies": { diff --git a/site/src/components/Nav.svelte b/site/src/components/Nav.svelte deleted file mode 100644 index d7f8da1..0000000 --- a/site/src/components/Nav.svelte +++ /dev/null @@ -1,60 +0,0 @@ - - - - - \ No newline at end of file diff --git a/site/src/routes/_error.svelte b/site/src/routes/_error.svelte index 320e587..0071e3c 100644 --- a/site/src/routes/_error.svelte +++ b/site/src/routes/_error.svelte @@ -1,40 +1,71 @@ {status} -

{status}

+
+ {#if online} +

Yikes!

-

{error.message}

+ {#if error.message} +

{status}: {error.message}

+ {:else} +

Encountered a {status} error

+ {/if} -{#if dev && error.stack} -
{error.stack}
-{/if} + {#if dev && error.stack} +
{error.stack}
+ {:else} + {#if status >= 500} +

Please try reloading the page.

+ {/if} + +

If the error persists, please drop by Discord chatroom and let us know, or raise an issue on GitHub. Thanks!

+ {/if} + {:else} +

It looks like you're offline

+ +

Reload the page once you've found the internet.

+ {/if} +
\ No newline at end of file diff --git a/site/src/routes/docs/_GuideContents.svelte b/site/src/routes/docs/_GuideContents.svelte new file mode 100644 index 0000000..d2014ef --- /dev/null +++ b/site/src/routes/docs/_GuideContents.svelte @@ -0,0 +1,136 @@ + + + + + diff --git a/site/src/routes/docs/_sections.js b/site/src/routes/docs/_sections.js new file mode 100644 index 0000000..6fb7641 --- /dev/null +++ b/site/src/routes/docs/_sections.js @@ -0,0 +1,158 @@ +import fs from 'fs'; +import path from 'path'; +import { SLUG_SEPARATOR, SLUG_PRESERVE_UNICODE } from '../../../config'; +import { extract_frontmatter, extract_metadata, langs, link_renderer } from '@sveltejs/site-kit/utils/markdown.js'; +import { make_session_slug_processor } from '@sveltejs/site-kit/utils/slug'; +import marked from 'marked'; +// import PrismJS from 'prismjs'; +// import 'prismjs/components/prism-bash'; +import hljs from 'highlight.js'; + +const escaped = { + '"': '"', + "'": ''', + '&': '&', + '<': '<', + '>': '>', +}; + +const unescaped = Object.keys(escaped).reduce( + (unescaped, key) => ((unescaped[escaped[key]] = key), unescaped), + {} +); + +function unescape(str) { + return String(str).replace(/&.+?;/g, match => unescaped[match] || match); +} + +const blockTypes = [ + 'blockquote', + 'html', + 'heading', + 'hr', + 'list', + 'listitem', + 'paragraph', + 'table', + 'tablerow', + 'tablecell' +]; + +export default function() { + const make_slug = make_session_slug_processor({ + separator: SLUG_SEPARATOR, + preserve_unicode: SLUG_PRESERVE_UNICODE + }); + + return fs + .readdirSync(`content/docs`) + .filter(file => file[0] !== '.' && path.extname(file) === '.md') + .map(file => { + const markdown = fs.readFileSync(`content/docs/${file}`, 'utf-8'); + + const { content, metadata } = extract_frontmatter(markdown); + + const section_slug = make_slug(metadata.title); + + const subsections = []; + + const renderer = new marked.Renderer(); + + let block_open = false; + + renderer.link = link_renderer; + + renderer.hr = () => { + block_open = true; + + return '
'; + }; + + 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 class_name = 'code-block'; + + if (meta) { + source = lines.slice(1).join('\n'); + const filename = meta.filename || (lang === 'html' && 'App.svelte'); + if (filename) { + prefix = `${prefix} ${filename}`; + class_name += ' named'; + } + } + + if (meta && meta.hidden) { + return ''; + } + + const plang = langs[lang]; + const { value: highlighted } = hljs.highlight(lang, source); + // const highlighted = PrismJS.highlight( + // source, + // PrismJS.languages[plang], + // lang + // ); + + const html = `
${prefix}
${highlighted}
`; + + if (block_open) { + block_open = false; + return `
${html}
`; + } + + return html; + }; + + renderer.heading = (text, level, rawtext) => { + const slug = level <= 4 && make_slug(rawtext); + + if (level === 3 || level === 4) { + const title = unescape( + text + .replace(/<\/?code>/g, '') + .replace(/\.(\w+)(\((.+)?\))?/, (m, $1, $2, $3) => { + if ($3) return `.${$1}(...)`; + if ($2) return `.${$1}()`; + return `.${$1}`; + }) + ); + + subsections.push({ slug, title, level }); + } + + return ` + + 4 ? 'data-scrollignore' : ''}> + + ${text} + `; + }; + + blockTypes.forEach(type => { + const fn = renderer[type]; + renderer[type] = function() { + return fn.apply(this, arguments); + }; + }); + + const html = marked(content, { renderer }); + + const hashes = {}; + + return { + html: html.replace(/@@(\d+)/g, (m, id) => hashes[id] || m), + metadata, + subsections, + slug: section_slug, + file, + }; + }); +} diff --git a/site/src/routes/docs/index.json.js b/site/src/routes/docs/index.json.js new file mode 100644 index 0000000..d994b3c --- /dev/null +++ b/site/src/routes/docs/index.json.js @@ -0,0 +1,14 @@ +import send from '@polka/send'; +import get_sections from './_sections.js'; + +let json; + +export function get(req, res) { + if (!json || process.env.NODE_ENV !== 'production') { + json = JSON.stringify(get_sections()); // TODO it errors if I send the non-stringified value + } + + send(res, 200, json, { + 'Content-Type': 'application/json' + }); +} diff --git a/site/src/routes/docs/index.svelte b/site/src/routes/docs/index.svelte new file mode 100644 index 0000000..255bfa4 --- /dev/null +++ b/site/src/routes/docs/index.svelte @@ -0,0 +1,397 @@ + + + + + + + + API Docs • Svelte + + + + + + +
+ {#each sections as section} +
+

+ + + + {section.metadata.title} + + + + +

+ + {@html section.html} +
+ {/each} +
+ + diff --git a/site/src/routes/guide/_process_markdown.js b/site/src/routes/guide/_process_markdown.js deleted file mode 100644 index a79d759..0000000 --- a/site/src/routes/guide/_process_markdown.js +++ /dev/null @@ -1,15 +0,0 @@ -export default function process_markdown(markdown) { - const match = /---\n([\s\S]+?)\n---/.exec(markdown); - const frontMatter = match[1]; - const content = markdown.slice(match[0].length); - - const metadata = {}; - frontMatter.split('\n').forEach(pair => { - const colonIndex = pair.indexOf(':'); - metadata[pair.slice(0, colonIndex).trim()] = pair - .slice(colonIndex + 1) - .trim(); - }); - - return { metadata, content }; -} \ No newline at end of file diff --git a/site/src/routes/guide/_sections.js b/site/src/routes/guide/_sections.js deleted file mode 100644 index de3a144..0000000 --- a/site/src/routes/guide/_sections.js +++ /dev/null @@ -1,82 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import process_markdown from './_process_markdown.js'; -import marked from 'marked'; -import hljs from 'highlight.js'; - -const langs = { - 'hidden-data': 'json', - 'html-no-repl': 'html' -}; - -function btoa(str) { - return new Buffer(str).toString('base64'); -} - -const escaped = { - '"': '"', - "'": ''', - '&': '&', - '<': '<', - '>': '>' -}; - -const unescaped = Object.keys(escaped).reduce( - (unescaped, key) => ((unescaped[escaped[key]] = key), unescaped), - {} -); - -function unescape(str) { - return String(str).replace(/&.+?;/g, match => unescaped[match] || match); -} - -export default () => fs - .readdirSync(`content/guide`) - .filter(file => file[0] !== '.' && path.extname(file) === '.md') - .map(file => { - const markdown = fs.readFileSync(`content/guide/${file}`, 'utf-8'); - - const { content, metadata } = process_markdown(markdown); - - // syntax highlighting - let uid = 0; - const highlighted = {}; - - const tweaked_content = content.replace( - /```([\w-]+)?\n([\s\S]+?)```/g, - (match, lang, code) => { - const { value } = hljs.highlight(lang, code); - highlighted[++uid] = value; - - return `@@${uid}`; - } - ); - - const html = marked(tweaked_content) - .replace(/

@@(\d+)<\/p>/g, (match, id) => { - return `

${highlighted[id]}
`; - }) - .replace(/^\t+/gm, match => match.split('\t').join(' ')); - - const subsections = []; - const pattern = /

(.+?)<\/h3>/g; - let match; - - while ((match = pattern.exec(html))) { - const slug = match[1]; - // const title = unescape( - // match[2].replace(/<\/?code>/g, '').replace(/\.(\w+)\W.*/, '.$1') - // ); - const title = unescape(match[2]); - - subsections.push({ slug, title }); - } - - return { - html, - metadata, - subsections, - slug: file.replace(/^\d+-/, '').replace(/\.md$/, ''), - file - }; - }); diff --git a/site/src/routes/guide/index.json.js b/site/src/routes/guide/index.json.js deleted file mode 100644 index e7169a0..0000000 --- a/site/src/routes/guide/index.json.js +++ /dev/null @@ -1,16 +0,0 @@ -import sections from './_sections.js'; - -const dev = process.env.NODE_ENV === 'development'; -let json; - -export function get(req, res) { - if (dev || !json) { - json = JSON.stringify(sections()); - } - - res.set({ - 'Content-Type': 'application/json', - 'Cache-Control': `max-age=${30 * 60 * 1e3}` // 30 minutes - }); - res.end(json); -} \ No newline at end of file diff --git a/site/src/routes/guide/index.svelte b/site/src/routes/guide/index.svelte deleted file mode 100644 index 30404ce..0000000 --- a/site/src/routes/guide/index.svelte +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file