mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-17 21:24:59 +00:00
move old docs over
This commit is contained in:
3
site/config.js
Normal file
3
site/config.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const SLUG_PRESERVE_UNICODE = false;
|
||||||
|
export const SLUG_SEPARATOR = '_';
|
||||||
|
export const SLUG_LANG = 'en';
|
||||||
@@ -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`:
|
Like page components, layout components can use `preload`:
|
||||||
|
|
||||||
@@ -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.
|
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.
|
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.
|
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`.
|
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.
|
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:
|
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
|
### <0.9 to 0.10
|
||||||
|
|
||||||
#### app/template.html
|
##### app/template.html
|
||||||
|
|
||||||
* Your `<head>` element must contain `%sapper.base%` (see ([base URLs](guide#base-urls))
|
* 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%`
|
* 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`.
|
* 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
51
site/package-lock.json
generated
@@ -825,6 +825,11 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"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": {
|
"@polka/url": {
|
||||||
"version": "0.5.0",
|
"version": "0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz",
|
"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": {
|
"collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
"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": {
|
"electron-to-chromium": {
|
||||||
"version": "1.3.127",
|
"version": "1.3.127",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.127.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.127.tgz",
|
||||||
@@ -2193,6 +2215,15 @@
|
|||||||
"integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==",
|
"integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==",
|
||||||
"dev": true
|
"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": {
|
"graceful-fs": {
|
||||||
"version": "4.1.15",
|
"version": "4.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
|
||||||
@@ -2969,6 +3000,14 @@
|
|||||||
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
|
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
|
||||||
"dev": true
|
"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": {
|
"private": {
|
||||||
"version": "0.1.8",
|
"version": "0.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
|
||||||
@@ -3267,6 +3306,12 @@
|
|||||||
"string-hash": "^1.1.3"
|
"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": {
|
"semver": {
|
||||||
"version": "5.7.0",
|
"version": "5.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
"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": {
|
"to-fast-properties": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||||
|
|||||||
@@ -12,10 +12,12 @@
|
|||||||
"test": "run-p --race dev cy:run"
|
"test": "run-p --race dev cy:run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@polka/send": "^0.4.0",
|
||||||
"compression": "^1.7.1",
|
"compression": "^1.7.1",
|
||||||
"highlight.js": "^9.15.6",
|
"highlight.js": "^9.15.6",
|
||||||
"marked": "^0.6.2",
|
"marked": "^0.6.2",
|
||||||
"polka": "^0.5.0",
|
"polka": "^0.5.2",
|
||||||
|
"prismjs": "^1.16.0",
|
||||||
"sirv": "^0.2.0"
|
"sirv": "^0.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -1,40 +1,71 @@
|
|||||||
<script>
|
<script>
|
||||||
|
const dev = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
export let status;
|
export let status;
|
||||||
export let error;
|
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>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
h1, p {
|
.container {
|
||||||
margin: 0 auto;
|
padding: var(--top-offset) var(--side-nav) 6rem var(--side-nav);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1, p { margin: 0 auto }
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 2.8em;
|
font-size: 2.8em;
|
||||||
font-weight: 700;
|
font-weight: 300;
|
||||||
margin: 0 0 0.5em 0;
|
margin: 0 0 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p { margin: 1em auto }
|
||||||
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) {
|
/* @media (min-width: 480px) {
|
||||||
h1 {
|
h1 { font-size: 4em }
|
||||||
font-size: 4em;
|
} */
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>{status}</title>
|
<title>{status}</title>
|
||||||
</svelte:head>
|
</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}
|
{#if dev && error.stack}
|
||||||
<pre>{error.stack}</pre>
|
<pre>{error.stack}</pre>
|
||||||
{/if}
|
{: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>
|
||||||
136
site/src/routes/docs/_GuideContents.svelte
Normal file
136
site/src/routes/docs/_GuideContents.svelte
Normal 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>
|
||||||
158
site/src/routes/docs/_sections.js
Normal file
158
site/src/routes/docs/_sections.js
Normal 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 = {
|
||||||
|
'"': '"',
|
||||||
|
"'": ''',
|
||||||
|
'&': '&',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
14
site/src/routes/docs/index.json.js
Normal file
14
site/src/routes/docs/index.json.js
Normal 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'
|
||||||
|
});
|
||||||
|
}
|
||||||
397
site/src/routes/docs/index.svelte
Normal file
397
site/src/routes/docs/index.svelte
Normal 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>
|
||||||
@@ -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 };
|
|
||||||
}
|
|
||||||
@@ -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(/<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
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
TODO
|
|
||||||
Reference in New Issue
Block a user