move old docs over

This commit is contained in:
Richard Harris
2019-04-28 21:44:34 -04:00
parent 36f91d4e9a
commit 381af86f04
30 changed files with 816 additions and 198 deletions

3
site/config.js Normal file
View File

@@ -0,0 +1,3 @@
export const SLUG_PRESERVE_UNICODE = false;
export const SLUG_SEPARATOR = '_';
export const SLUG_LANG = 'en';

View File

@@ -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`:

View File

@@ -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 `<head>` 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`.

51
site/package-lock.json generated
View File

@@ -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",

View File

@@ -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": {

View File

@@ -1,60 +0,0 @@
<script>
export let segment;
</script>
<style>
nav {
border-bottom: 1px solid rgba(170,30,30,0.1);
font-weight: 300;
padding: 0 1em;
}
ul {
margin: 0;
padding: 0;
}
/* clearfix */
ul::after {
content: '';
display: block;
clear: both;
}
li {
display: block;
float: left;
}
.selected {
position: relative;
display: inline-block;
}
.selected::after {
position: absolute;
content: '';
width: calc(100% - 1em);
height: 2px;
background-color: rgb(170,30,30);
display: block;
bottom: -1px;
}
a {
text-decoration: none;
padding: 1em 0.5em;
display: block;
}
</style>
<nav>
<ul>
<li><a class='{segment === undefined ? "selected" : ""}' href='.'>home</a></li>
<li><a class='{segment === "about" ? "selected" : ""}' href='about'>about</a></li>
<!-- for the blog link, we're using rel=prefetch so that Sapper prefetches
the blog data when we hover over the link or tap it on a touchscreen -->
<li><a rel=prefetch class='{segment === "blog" ? "selected" : ""}' href='blog'>blog</a></li>
</ul>
</nav>

View File

@@ -1,40 +1,71 @@
<script>
const dev = process.env.NODE_ENV === 'development';
export let status;
export let error;
const dev = process.env.NODE_ENV === 'development';
// we don't want to use <svelte:window bind:online> here,
// because we only care about the online state when
// the page first loads
let online = typeof navigator !== 'undefined'
? navigator.onLine
: true;
</script>
<style>
h1, p {
margin: 0 auto;
.container {
padding: var(--top-offset) var(--side-nav) 6rem var(--side-nav);
}
h1, p { margin: 0 auto }
h1 {
font-size: 2.8em;
font-weight: 700;
font-weight: 300;
margin: 0 0 0.5em 0;
}
p {
margin: 1em auto;
p { margin: 1em auto }
.error {
background-color: #da106e;
color: white;
padding: 12px 16px;
font: 600 16px/1.7 var(--font);
border-radius: 2px;
}
@media (min-width: 480px) {
h1 {
font-size: 4em;
}
}
/* @media (min-width: 480px) {
h1 { font-size: 4em }
} */
</style>
<svelte:head>
<title>{status}</title>
</svelte:head>
<h1>{status}</h1>
<div class="container">
{#if online}
<h1>Yikes!</h1>
<p>{error.message}</p>
{#if error.message}
<p class="error">{status}: {error.message}</p>
{:else}
<p class="error">Encountered a {status} error</p>
{/if}
{#if dev && error.stack}
<pre>{error.stack}</pre>
{/if}
{#if dev && error.stack}
<pre>{error.stack}</pre>
{:else}
{#if status >= 500}
<p>Please try reloading the page.</p>
{/if}
<p>If the error persists, please drop by <a href="https://discord.gg/yy75DKs">Discord chatroom</a> and let us know, or raise an issue on <a href="https://github.com/sveltejs/svelte">GitHub</a>. Thanks!</p>
{/if}
{:else}
<h1>It looks like you're offline</h1>
<p>Reload the page once you've found the internet.</p>
{/if}
</div>

View File

@@ -0,0 +1,136 @@
<script>
import { onMount, afterUpdate } from 'svelte';
import { Icon } from '@sveltejs/site-kit';
export let sections = [];
export let active_section = null;
export let show_contents;
export let prevent_sidebar_scroll = false;
let ul;
afterUpdate(() => {
// bit of a hack — prevent sidebar scrolling if
// TOC is open on mobile, or scroll came from within sidebar
if (prevent_sidebar_scroll || show_contents && window.innerWidth < 832) return;
const active = ul.querySelector('.active');
if (active) {
const { top, bottom } = active.getBoundingClientRect();
const min = 200;
const max = window.innerHeight - 200;
if (top > max) {
ul.parentNode.scrollBy({
top: top - max,
left: 0,
behavior: 'smooth'
});
} else if (bottom < min) {
ul.parentNode.scrollBy({
top: bottom - min,
left: 0,
behavior: 'smooth'
});
}
}
});
</script>
<style>
.reference-toc li {
display: block;
line-height: 1.2;
margin: 0 0 4rem 0;
}
a {
position: relative;
opacity: 0.75;
transition: opacity 0.2s;
border-bottom: none;
padding: 0;
color: var(--second);
}
@media (min-width: 832px) {
a {
color: white;
}
}
.section {
display: block;
padding: 0 0 .8rem 0;
font-size: var(--h6);
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 600;
}
.subsection {
display: block;
font-size: 1.6rem;
font-family: var(--font);
padding: 0 0 0.6em 0;
}
.section:hover,
.subsection:hover {
color: var(--flash);
opacity: 1
}
.subsection[data-level="4"] {
padding-left: 1.2rem;
}
.active { opacity: 1 }
.icon-container {
position: absolute;
top: -.2rem;
right: 2.4rem;
}
</style>
<ul
bind:this={ul}
class="reference-toc"
on:mouseenter="{() => prevent_sidebar_scroll = true}"
on:mouseleave="{() => prevent_sidebar_scroll = false}"
>
{#each sections as section}
<li>
<a class="section" class:active="{section.slug === active_section}" href="docs#{section.slug}">
{section.metadata.title}
{#if section.slug === active_section}
<div class="icon-container">
<Icon name="arrow-right" />
</div>
{/if}
</a>
{#each section.subsections as subsection}
<!-- see <script> below: on:click='scrollTo(event, subsection.slug)' -->
<a
class="subsection"
class:active="{subsection.slug === active_section}"
href="docs#{subsection.slug}"
data-level="{subsection.level}"
>
{subsection.title}
{#if subsection.slug === active_section}
<div class="icon-container">
<Icon name="arrow-right" />
</div>
{/if}
</a>
{/each}
</li>
{/each}
</ul>

View File

@@ -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 = {
'"': '&quot;',
"'": '&#39;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
};
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 '<div class="side-by-side"><div class="copy">';
};
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 = `<span class='filename'>${prefix} ${filename}</span>`;
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 = `<div class='${class_name}'>${prefix}<pre class='language-${plang}'><code>${highlighted}</code></pre></div>`;
if (block_open) {
block_open = false;
return `</div><div class="code">${html}</div></div>`;
}
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 `
<h${level}>
<span id="${slug}" class="offset-anchor" ${level > 4 ? 'data-scrollignore' : ''}></span>
<a href="docs#${slug}" class="anchor" aria-hidden="true"></a>
${text}
</h${level}>`;
};
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,
};
});
}

View File

@@ -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'
});
}

View File

@@ -0,0 +1,397 @@
<script context="module">
export async function preload() {
const sections = await this.fetch(`docs.json`).then(r => r.json());
return { sections };
}
</script>
<script>
import { onMount } from 'svelte';
import GuideContents from './_GuideContents.svelte';
import { Icon } from '@sveltejs/site-kit';
import { getFragment } from '@sveltejs/site-kit/utils/navigation';
export let sections;
let active_section;
let container;
let aside;
let show_contents = false;
onMount(() => {
// don't update `active_section` for headings above level 4, see _sections.js
const anchors = container.querySelectorAll('[id]:not([data-scrollignore])');
let positions;
const onresize = () => {
const { top } = container.getBoundingClientRect();
positions = [].map.call(anchors, anchor => {
return anchor.getBoundingClientRect().top - top;
});
}
let last_id = getFragment();
const onscroll = () => {
const top = -window.scrollY;
let i = anchors.length;
while (i--) {
if (positions[i] + top < 40) {
const anchor = anchors[i];
const { id } = anchor;
if (id !== last_id) {
active_section = id;
last_id = id;
}
return;
}
}
};
window.addEventListener('scroll', onscroll, true);
window.addEventListener('resize', onresize, true);
// wait for fonts to load...
const timeouts = [
setTimeout(onresize, 1000),
setTimeout(onscroll, 5000)
];
onresize();
onscroll();
return () => {
window.removeEventListener('scroll', onscroll, true);
window.removeEventListener('resize', onresize, true);
timeouts.forEach(timeout => clearTimeout(timeout));
};
});
</script>
<style>
aside {
position: fixed;
background-color: white;
left: 0.8rem;
bottom: 0.8rem;
width: 2em;
height: 2em;
overflow: hidden;
border: 1px solid #eee;
box-shadow: 1px 1px 6px rgba(0,0,0,0.1);
transition: width 0.2s, height 0.2s;
}
aside button {
position: absolute;
bottom: 0;
left: 0;
width: 3.4rem;
height: 3.4rem;
}
aside.open {
width: calc(100vw - 3rem);
height: calc(100vh - var(--nav-h));
}
aside.open::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: calc(100% - 2rem);
height: 2em;
background: linear-gradient(to top, rgba(255,255,255,0) 0%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,1) 100%);
pointer-events: none;
z-index: 2;
}
aside::after {
content: '';
position: absolute;
left: 0;
bottom: 1.9em;
width: calc(100% - 2rem);
height: 2em;
background: linear-gradient(to bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,0.7) 50%, rgba(255,255,255,1) 100%);
pointer-events: none;
}
.sidebar {
position: absolute;
font-family: var(--font);
overflow-y: auto;
width: 100%;
height: 100%;
padding: 4em 1.6rem 2em 3.2rem;
bottom: 2em;
}
.content {
width: 100%;
margin: 0;
padding: var(--top-offset) var(--side-nav);
tab-size: 2;
-moz-tab-size: 2;
}
@media (min-width: 832px) { /* can't use vars in @media :( */
aside {
display: block;
width: var(--sidebar-w);
height: 100vh;
top: 0;
left: 0;
overflow: hidden;
box-shadow: none;
border: none;
overflow: hidden;
background-color: var(--second);
color: white;
}
aside.open::before {
display: none;
}
aside::after {
content: '';
bottom: 0;
height: var(--top-offset);
background: linear-gradient(to bottom, rgba(103,103,120,0) 0%, rgba(103,103,120,0.7) 50%, rgba(103,103,120,1) 100%);
}
aside button {
display: none;
}
.sidebar {
padding: var(--top-offset) 0 6.4rem 3.2rem;
font-family: var(--font);
overflow-y: auto;
height: 100%;
bottom: auto;
width: 100%;
}
.content {
padding-left: calc(var(--sidebar-w) + var(--side-nav));
}
.content :global(.side-by-side) {
display: grid;
grid-template-columns: calc(50% - 0.5em) calc(50% - 0.5em);
grid-gap: 1em;
}
}
.content h2 {
margin-top: 8rem;
padding: 2rem 1.6rem 4rem 0.2rem;
border-top: var(--border-w) solid #6767785b; /* based on --second */
color: var(--text);
line-height: 1;
font-size: var(--h3);
letter-spacing: .05em;
text-transform: uppercase;
}
.content section:first-of-type > h2 {
margin-top: 0;
}
.content :global(h4) {
margin: 2em 0 1em 0;
}
.content :global(.offset-anchor) {
position: relative;
display: block;
top: calc(-1 * (var(--nav-h) + var(--top-offset) - 1rem));
width: 0;
height: 0;
}
.content :global(.anchor) {
position: absolute;
display: block;
background: url(/icons/link.svg) 0 50% no-repeat;
background-size: 1em 1em;
width: 1.4em;
height: 1em;
left: -1.3em;
opacity: 0;
transition: opacity 0.2s;
border: none !important; /* TODO get rid of linkify */
}
@media (min-width: 768px) {
.content :global(h2):hover :global(.anchor),
.content :global(h3):hover :global(.anchor),
.content :global(h4):hover :global(.anchor),
.content :global(h5):hover :global(.anchor),
.content :global(h6):hover :global(.anchor) {
opacity: 1;
}
.content :global(h5) :global(.anchor),
.content :global(h6) :global(.anchor) {
top: 0.5em;
}
}
.content :global(h3),
.content :global(h3 > code) {
margin: 6.4rem 0 0 0;
padding: 2rem 1.6rem 5.6rem .2rem;
color: var(--text);
border-top: var(--border-w) solid #6767781f; /* based on --second */
background: transparent;
line-height: 1;
}
.content :global(h3):first-of-type {
border: none;
margin: 0;
}
/* avoid doubled border-top */
.content :global(h3 > code) {
border-radius: 0 0 0 0;
border: none;
font-size: var(--h4);
line-height: 1.2;
}
.content :global(h4),
.content :global(h4 > code) {
font-weight: 600;
font-size: var(--h4);
color: var(--second);
margin: 6.4rem 0 1.6rem 0;
padding-left: 0;
background: transparent;
line-height: 1;
padding: 0;
}
.content :global(h5) {
font-size: 2rem;
}
.content :global(code) {
padding: .3rem .8rem .3rem;
margin: 0 0.2rem;
top: -.1rem;
background: var(--back-api);
}
.content :global(pre) :global(code) {
padding: 0;
margin: 0;
top: 0;
background: transparent;
}
.content :global(pre) {
margin: 0 0 2em 0;
}
.content :global(.icon) {
width: 2rem;
height: 2rem;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
.content :global(table) {
margin: 0 0 2em 0;
}
section > :global(.code-block) > :global(pre) {
display: inline-block;
background: var(--back-api);
color: white;
padding: .3rem .8rem;
margin: 0;
max-width: 100%;
}
section > :global(.code-block)> :global(pre.language-markup) {
padding: .3rem .8rem .2rem;
background: var(--back-api);
}
section > :global(p) {
max-width: var(--linemax)
}
small {
font-size: var(--h5);
float: right;
pointer-events: all;
color: var(--prime);
cursor: pointer;
}
/* no linkify on these */
small a { all: unset }
small a:before { all: unset }
section :global(blockquote) {
color: hsl(204, 100%, 50%);
border: 2px solid var(--flash);
}
section :global(blockquote) :global(code) {
background: hsl(204, 100%, 95%) !important;
color: hsl(204, 100%, 50%);
}
</style>
<svelte:head>
<title>API Docs • Svelte</title>
<meta name="twitter:title" content="Svelte API docs">
<meta name="twitter:description" content="Cybernetically enhanced web apps">
<meta name="Description" content="Cybernetically enhanced web apps">
</svelte:head>
<div bind:this={container} class='content listify'>
{#each sections as section}
<section data-id={section.slug}>
<h2>
<span class="offset-anchor" id={section.slug}></span>
<a href="docs#{section.slug}" class="anchor" aria-hidden></a>
{section.metadata.title}
<small>
<a href='https://github.com/sveltejs/svelte/edit/master/site/content/docs/{section.file}' title='edit this section'>
<Icon name='edit' /></a>
</small>
</h2>
{@html section.html}
</section>
{/each}
</div>
<aside bind:this={aside} class="sidebar-container" class:open={show_contents}>
<div class="sidebar" on:click="{() => show_contents = false}"> <!-- scroll container -->
<GuideContents {sections} {active_section} {show_contents} />
</div>
<button on:click="{() => show_contents = !show_contents}">
<Icon name="{show_contents? 'close' : 'menu'}"/>
</button>
</aside>

View File

@@ -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 };
}

View File

@@ -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 = {
'"': '&quot;',
"'": '&#39;',
'&': '&amp;',
'<': '&lt;',
'>': '&gt;'
};
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(/<p>@@(\d+)<\/p>/g, (match, id) => {
return `<pre><code>${highlighted[id]}</code></pre>`;
})
.replace(/^\t+/gm, match => match.split('\t').join(' '));
const subsections = [];
const pattern = /<h3 id="(.+?)">(.+?)<\/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
};
});

View File

@@ -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);
}

View File

@@ -1 +0,0 @@
TODO