mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-15 20:34:44 +00:00
start adding site to main repo
This commit is contained in:
6
site/src/client.js
Normal file
6
site/src/client.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import '@sveltejs/site-kit/base.css';
|
||||
import * as sapper from '@sapper/app';
|
||||
|
||||
sapper.start({
|
||||
target: document.querySelector('#sapper')
|
||||
});
|
||||
60
site/src/components/Nav.svelte
Normal file
60
site/src/components/Nav.svelte
Normal file
@@ -0,0 +1,60 @@
|
||||
<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>
|
||||
40
site/src/routes/_error.svelte
Normal file
40
site/src/routes/_error.svelte
Normal file
@@ -0,0 +1,40 @@
|
||||
<script>
|
||||
export let status;
|
||||
export let error;
|
||||
|
||||
const dev = process.env.NODE_ENV === 'development';
|
||||
</script>
|
||||
|
||||
<style>
|
||||
h1, p {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.8em;
|
||||
font-weight: 700;
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
@media (min-width: 480px) {
|
||||
h1 {
|
||||
font-size: 4em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<title>{status}</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>{status}</h1>
|
||||
|
||||
<p>{error.message}</p>
|
||||
|
||||
{#if dev && error.stack}
|
||||
<pre>{error.stack}</pre>
|
||||
{/if}
|
||||
37
site/src/routes/_layout.svelte
Normal file
37
site/src/routes/_layout.svelte
Normal file
@@ -0,0 +1,37 @@
|
||||
<script>
|
||||
import { page } from '@sapper/app';
|
||||
import { Icons, Icon, Nav, NavItem } from '@sveltejs/site-kit';
|
||||
|
||||
export let segment;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
main {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
/* padding: var(--nav-h) var(--side-nav) 0 var(--side-nav); */
|
||||
padding: var(--nav-h) 0 0 0;
|
||||
overflow-x: hidden;
|
||||
--prime: rgb(21, 151, 148);
|
||||
}
|
||||
</style>
|
||||
|
||||
<Icons/>
|
||||
|
||||
<Nav {segment} {page} logo="sapper-logo-horizontal.svg">
|
||||
<NavItem segment="guide">Guide</NavItem>
|
||||
|
||||
<NavItem external="https://svelte.dev">Svelte</NavItem>
|
||||
|
||||
<NavItem external="https://discord.gg/yy75DKs" title="Discord Chat">
|
||||
<Icon name="message-square"/>
|
||||
</NavItem>
|
||||
|
||||
<NavItem external="https://github.com/sveltejs/sapper" title="GitHub Repo">
|
||||
<Icon name="github"/>
|
||||
</NavItem>
|
||||
</Nav>
|
||||
|
||||
<main>
|
||||
<slot></slot>
|
||||
</main>
|
||||
15
site/src/routes/guide/_process_markdown.js
Normal file
15
site/src/routes/guide/_process_markdown.js
Normal file
@@ -0,0 +1,15 @@
|
||||
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 };
|
||||
}
|
||||
82
site/src/routes/guide/_sections.js
Normal file
82
site/src/routes/guide/_sections.js
Normal file
@@ -0,0 +1,82 @@
|
||||
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
|
||||
};
|
||||
});
|
||||
16
site/src/routes/guide/index.json.js
Normal file
16
site/src/routes/guide/index.json.js
Normal file
@@ -0,0 +1,16 @@
|
||||
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
site/src/routes/guide/index.svelte
Normal file
1
site/src/routes/guide/index.svelte
Normal file
@@ -0,0 +1 @@
|
||||
TODO
|
||||
70
site/src/routes/index.svelte
Normal file
70
site/src/routes/index.svelte
Normal file
@@ -0,0 +1,70 @@
|
||||
<script>
|
||||
import { Hero, Blurb } from '@sveltejs/site-kit';
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<svelte:head>
|
||||
<title>Sapper • The next small thing in web development</title>
|
||||
</svelte:head>
|
||||
|
||||
<Hero
|
||||
title="Sapper"
|
||||
tagline="The next small thing in web development"
|
||||
outline="sapper-logo-outline.svg"
|
||||
logotype="sapper-logotype.svg"
|
||||
/>
|
||||
|
||||
<Blurb>
|
||||
<a href="https://svelte.dev" slot="one">
|
||||
<h2>Powered by Svelte</h2>
|
||||
<p>Sapper is an application framework powered by Svelte — build bigger apps with a smaller footprint</p>
|
||||
|
||||
<span class="learn-more">learn more</span>
|
||||
</a>
|
||||
|
||||
<a href="TKTK" slot="two">
|
||||
<h2>Best of both worlds</h2>
|
||||
<p>All the SEO and progressive enhancement of a server-rendered app, with the slick navigation of an SPA</p>
|
||||
|
||||
<span class="learn-more">learn more</span>
|
||||
</a>
|
||||
|
||||
<a href="TKTK" slot="three">
|
||||
<h2>Build fast</h2>
|
||||
<p>Hit the ground running with advanced routing, server-side rendering, code-splitting, offline support and more</p>
|
||||
|
||||
<span class="learn-more">learn more</span>
|
||||
</a>
|
||||
|
||||
<!-- <a href="TKTK" slot="three">
|
||||
<h2>Works everywhere</h2>
|
||||
<p>Deploy as a cloud function or a traditional Node.js app, or export your app as a collection of static files</p>
|
||||
|
||||
<span class="learn-more">learn more</span>
|
||||
</a> -->
|
||||
|
||||
<div class="description" slot="what">
|
||||
<p>Sapper is a framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.</p>
|
||||
|
||||
<p>Unlike single-page apps, Sapper doesn't compromise on SEO, progressive enhancement or the initial load experience — but unlike traditional server-rendered apps, navigation is instantaneous for that app-like feel.</p>
|
||||
|
||||
<p><a href="https://svelte.dev/blog/sapper-towards-the-ideal-web-app-framework">Read the introductory blog post</a> to learn more.</p>
|
||||
</div>
|
||||
|
||||
<div style="grid-area: start; display: flex; flex-direction: column; min-width: 0" slot="how">
|
||||
<pre class="language-bash" style="margin: 0 0 1em 0; min-width: 0; min-height: 0">
|
||||
npx degit sveltejs/template my-svelte-project
|
||||
cd my-svelte-project
|
||||
|
||||
npm install
|
||||
npm run dev & open http://localhost:5000
|
||||
</pre>
|
||||
|
||||
<p style="flex: 1">See the <a href="blog/the-easiest-way-to-get-started">quickstart guide</a> for more information.</p>
|
||||
|
||||
<p class="cta"><a rel="prefetch" href="tutorial">Learn Svelte</a></p>
|
||||
</div>
|
||||
</Blurb>
|
||||
17
site/src/server.js
Normal file
17
site/src/server.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import sirv from 'sirv';
|
||||
import polka from 'polka';
|
||||
import compression from 'compression';
|
||||
import * as sapper from '@sapper/server';
|
||||
|
||||
const { PORT, NODE_ENV } = process.env;
|
||||
const dev = NODE_ENV === 'development';
|
||||
|
||||
polka() // You can also use Express
|
||||
.use(
|
||||
compression({ threshold: 0 }),
|
||||
sirv('static', { dev }),
|
||||
sapper.middleware()
|
||||
)
|
||||
.listen(PORT, err => {
|
||||
if (err) console.log('error', err);
|
||||
});
|
||||
82
site/src/service-worker.js
Normal file
82
site/src/service-worker.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import { timestamp, files, shell, routes } from '@sapper/service-worker';
|
||||
|
||||
const ASSETS = `cache${timestamp}`;
|
||||
|
||||
// `shell` is an array of all the files generated by the bundler,
|
||||
// `files` is an array of everything in the `static` directory
|
||||
const to_cache = shell.concat(files);
|
||||
const cached = new Set(to_cache);
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.open(ASSETS)
|
||||
.then(cache => cache.addAll(to_cache))
|
||||
.then(() => {
|
||||
self.skipWaiting();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', event => {
|
||||
event.waitUntil(
|
||||
caches.keys().then(async keys => {
|
||||
// delete old caches
|
||||
for (const key of keys) {
|
||||
if (key !== ASSETS) await caches.delete(key);
|
||||
}
|
||||
|
||||
self.clients.claim();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', event => {
|
||||
if (event.request.method !== 'GET' || event.request.headers.has('range')) return;
|
||||
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// don't try to handle e.g. data: URIs
|
||||
if (!url.protocol.startsWith('http')) return;
|
||||
|
||||
// ignore dev server requests
|
||||
if (url.hostname === self.location.hostname && url.port !== self.location.port) return;
|
||||
|
||||
// always serve static files and bundler-generated assets from cache
|
||||
if (url.host === self.location.host && cached.has(url.pathname)) {
|
||||
event.respondWith(caches.match(event.request));
|
||||
return;
|
||||
}
|
||||
|
||||
// for pages, you might want to serve a shell `service-worker-index.html` file,
|
||||
// which Sapper has generated for you. It's not right for every
|
||||
// app, but if it's right for yours then uncomment this section
|
||||
/*
|
||||
if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) {
|
||||
event.respondWith(caches.match('/service-worker-index.html'));
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
if (event.request.cache === 'only-if-cached') return;
|
||||
|
||||
// for everything else, try the network first, falling back to
|
||||
// cache if the user is offline. (If the pages never change, you
|
||||
// might prefer a cache-first approach to a network-first one.)
|
||||
event.respondWith(
|
||||
caches
|
||||
.open(`offline${timestamp}`)
|
||||
.then(async cache => {
|
||||
try {
|
||||
const response = await fetch(event.request);
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
} catch(err) {
|
||||
const response = await cache.match(event.request);
|
||||
if (response) return response;
|
||||
|
||||
throw err;
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
38
site/src/template.html
Normal file
38
site/src/template.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<!doctype html>
|
||||
<html lang='en' class="theme-default typo-default">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width;initial-scale=1.0'>
|
||||
<meta name='theme-color' content='#ff3e00'>
|
||||
|
||||
%sapper.base%
|
||||
|
||||
<link href=prism.css rel=stylesheet>
|
||||
<link rel='manifest' href='manifest.json'>
|
||||
<link rel='icon' type='image/png' href='favicon.png'>
|
||||
|
||||
<meta name='twitter:card' content='summary_large_image'>
|
||||
<meta name='twitter:site' content='@sveltejs'>
|
||||
<meta name='twitter:creator' content='@sveltejs'>
|
||||
<meta name='twitter:image' content='https://sapper.svelte.dev/images/twitter-card.png'>
|
||||
|
||||
<!-- Sapper generates a <style> tag containing critical CSS
|
||||
for the current page. CSS for the rest of the app is
|
||||
lazily loaded when it precaches secondary pages -->
|
||||
%sapper.styles%
|
||||
|
||||
<!-- This contains the contents of the <svelte:head> component, if
|
||||
the current page has one -->
|
||||
%sapper.head%
|
||||
</head>
|
||||
<body>
|
||||
<!-- The application will be rendered inside this element,
|
||||
because `app/client.js` references it -->
|
||||
<div id='sapper'>%sapper.html%</div>
|
||||
|
||||
<!-- Sapper creates a <script> tag containing `app/client.js`
|
||||
and anything else it needs to hydrate the app and
|
||||
initialise the router -->
|
||||
%sapper.scripts%
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user