From 35e7a852fce792bc8e9f277d1224d3339446fc9e Mon Sep 17 00:00:00 2001 From: Puru Vijay <47742487+PuruVJ@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:37:21 +0530 Subject: [PATCH 1/2] feat(site-2): Local tutorial (#8427) * feat(docs): Local tutorial * Refactor some stuff * Better error handling * Fix search imports * Prerender tutorial * try prerendering hack * fix super stupid display hidden bug * Shorten the rendered URL * Shorten URL code even more --- sites/svelte.dev/.prettierrc | 3 +- .../src/lib/components/ReplWidget.svelte | 4 +- .../svelte.dev/src/lib/server/blog/marked.js | 12 +-- .../lib/server/tutorial/get-tutorial-data.js | 81 +++++++++++++++++ .../src/lib/server/tutorial/index.js | 89 +++++++++++++++++++ .../src/lib/server/tutorial/types.d.ts | 24 +++++ .../src/routes/docs/+layout.server.js | 1 - .../svelte.dev/src/routes/docs/+layout.svelte | 2 +- .../svelte.dev/src/routes/tutorial/+layout.js | 6 -- .../src/routes/tutorial/+layout.svelte | 10 --- .../tutorial/{+page.js => +page.server.js} | 2 + .../src/routes/tutorial/[slug]/+page.js | 17 ---- .../routes/tutorial/[slug]/+page.server.js | 20 +++++ .../src/routes/tutorial/[slug]/+page.svelte | 73 ++++++++++----- ...Contents.svelte => TableOfContents.svelte} | 13 ++- sites/svelte.dev/svelte.config.js | 1 + 16 files changed, 283 insertions(+), 75 deletions(-) create mode 100644 sites/svelte.dev/src/lib/server/tutorial/get-tutorial-data.js create mode 100644 sites/svelte.dev/src/lib/server/tutorial/index.js create mode 100644 sites/svelte.dev/src/lib/server/tutorial/types.d.ts delete mode 100644 sites/svelte.dev/src/routes/tutorial/+layout.js delete mode 100644 sites/svelte.dev/src/routes/tutorial/+layout.svelte rename sites/svelte.dev/src/routes/tutorial/{+page.js => +page.server.js} (77%) delete mode 100644 sites/svelte.dev/src/routes/tutorial/[slug]/+page.js create mode 100644 sites/svelte.dev/src/routes/tutorial/[slug]/+page.server.js rename sites/svelte.dev/src/routes/tutorial/[slug]/{_TableOfContents.svelte => TableOfContents.svelte} (89%) diff --git a/sites/svelte.dev/.prettierrc b/sites/svelte.dev/.prettierrc index 1cb44838c1..cc9aa8e796 100644 --- a/sites/svelte.dev/.prettierrc +++ b/sites/svelte.dev/.prettierrc @@ -1,5 +1,6 @@ { "singleQuote": true, "printWidth": 100, - "useTabs": true + "useTabs": true, + "trailingComma": "es5" } diff --git a/sites/svelte.dev/src/lib/components/ReplWidget.svelte b/sites/svelte.dev/src/lib/components/ReplWidget.svelte index d51bc14b81..497081233f 100644 --- a/sites/svelte.dev/src/lib/components/ReplWidget.svelte +++ b/sites/svelte.dev/src/lib/components/ReplWidget.svelte @@ -42,7 +42,7 @@ return { name: file.slice(0, dot), type: file.slice(dot + 1), - source + source, }; }) .filter((x) => x.type === 'svelte' || x.type === 'js') @@ -64,7 +64,7 @@ const components = process_example(data.files); repl.set({ - components + components, }); } }); diff --git a/sites/svelte.dev/src/lib/server/blog/marked.js b/sites/svelte.dev/src/lib/server/blog/marked.js index 6741bb5f2d..ab18871010 100644 --- a/sites/svelte.dev/src/lib/server/blog/marked.js +++ b/sites/svelte.dev/src/lib/server/blog/marked.js @@ -14,13 +14,13 @@ const escape_replacements = { '<': '<', '>': '>', '"': '"', - "'": ''' + "'": ''', }; const get_escape_replacement = (ch) => escape_replacements[ch]; /** * @param {string} html - * @param {boolean} encode + * @param {boolean} [encode] */ export function escape(html, encode) { if (encode) { @@ -45,7 +45,7 @@ const prism_languages = { css: 'css', diff: 'diff', ts: 'typescript', - '': '' + '': '', }; /** @type {Partial} */ @@ -165,7 +165,7 @@ const default_renderer = { text(text) { return text; - } + }, }; /** @@ -179,8 +179,8 @@ export function transform(markdown, renderer = {}) { // options are global, and merged in confusing ways. You can't do e.g. // `new Marked(options).parse(markdown)` ...default_renderer, - ...renderer - } + ...renderer, + }, }); return marked(markdown); diff --git a/sites/svelte.dev/src/lib/server/tutorial/get-tutorial-data.js b/sites/svelte.dev/src/lib/server/tutorial/get-tutorial-data.js new file mode 100644 index 0000000000..77d153317d --- /dev/null +++ b/sites/svelte.dev/src/lib/server/tutorial/get-tutorial-data.js @@ -0,0 +1,81 @@ +// @ts-check +import fs from 'node:fs'; +import { extract_frontmatter } from '../markdown/index.js'; + +const base = '../../site/content/tutorial/'; + +/** + * @returns {import('./types').TutorialData} + */ +export function get_tutorial_data() { + const tutorials = []; + + for (const subdir of fs.readdirSync(base)) { + const section = { + title: '', // Initialise with empty + slug: subdir.split('-').slice(1).join('-'), + tutorials: [], + }; + + if (!(fs.statSync(`${base}/${subdir}`).isDirectory() || subdir.endsWith('meta.json'))) continue; + + if (!subdir.endsWith('meta.json')) + section.title = JSON.parse(fs.readFileSync(`${base}/${subdir}/meta.json`, 'utf-8')).title; + + for (const section_dir of fs.readdirSync(`${base}/${subdir}`)) { + const match = /\d{2}-(.+)/.exec(section_dir); + if (!match) continue; + + const slug = match[1]; + + const tutorial_base_dir = `${base}/${subdir}/${section_dir}`; + + // Read the file, get frontmatter + const contents = fs.readFileSync(`${tutorial_base_dir}/text.md`, 'utf-8'); + const { metadata, body } = extract_frontmatter(contents); + + // Get the contents of the apps. + const completion_states_data = { initial: [], complete: [] }; + for (const app_dir of fs.readdirSync(tutorial_base_dir)) { + if (!app_dir.startsWith('app-')) continue; + + const app_dir_path = `${tutorial_base_dir}/${app_dir}`; + const app_contents = fs.readdirSync(app_dir_path, 'utf-8'); + + for (const file of app_contents) { + completion_states_data[app_dir === 'app-a' ? 'initial' : 'complete'].push({ + name: file, + type: file.split('.').at(-1), + content: fs.readFileSync(`${app_dir_path}/${file}`, 'utf-8'), + }); + } + } + + section.tutorials.push({ + title: metadata.title, + slug, + content: body, + dir: `${subdir}/${section_dir}`, + ...completion_states_data, + }); + } + + tutorials.push(section); + } + + return tutorials; +} + +/** + * @param {import('./types').TutorialData} tutorial_data + * @returns {import('./types').TutorialsList} + */ +export function get_tutorial_list(tutorial_data) { + return tutorial_data.map((section) => ({ + title: section.title, + tutorials: section.tutorials.map((tutorial) => ({ + title: tutorial.title, + slug: tutorial.slug, + })), + })); +} diff --git a/sites/svelte.dev/src/lib/server/tutorial/index.js b/sites/svelte.dev/src/lib/server/tutorial/index.js new file mode 100644 index 0000000000..2da22f7659 --- /dev/null +++ b/sites/svelte.dev/src/lib/server/tutorial/index.js @@ -0,0 +1,89 @@ +import { createShikiHighlighter } from 'shiki-twoslash'; +import { transform } from '../markdown'; + +const languages = { + bash: 'bash', + env: 'bash', + html: 'svelte', + svelte: 'svelte', + sv: 'svelte', + js: 'javascript', + css: 'css', + diff: 'diff', + ts: 'typescript', + '': '', +}; + +/** + * @param {import('./types').TutorialData} tutorial_data + * @param {string} slug + */ +export async function get_parsed_tutorial(tutorial_data, slug) { + const tutorial = tutorial_data + .find(({ tutorials }) => tutorials.find((t) => t.slug === slug)) + ?.tutorials?.find((t) => t.slug === slug); + + if (!tutorial) return null; + + const body = tutorial.content; + + const highlighter = await createShikiHighlighter({ theme: 'css-variables' }); + + const content = transform(body, { + /** + * @param {string} html + */ + heading(html) { + const title = html + .replace(/<\/?code>/g, '') + .replace(/"/g, '"') + .replace(/</g, '<') + .replace(/>/g, '>'); + + return title; + }, + code: (source, language) => { + let html = ''; + + source = source + .replace(/^([\-\+])?((?: )+)/gm, (match, prefix = '', spaces) => { + if (prefix && language !== 'diff') return match; + + // for no good reason at all, marked replaces tabs with spaces + let tabs = ''; + for (let i = 0; i < spaces.length; i += 4) { + tabs += ' '; + } + return prefix + tabs; + }) + .replace(/\*\\\//g, '*/'); + + html = highlighter.codeToHtml(source, { lang: languages[language] }); + + html = html + .replace( + /^(\s+)([\s\S]+?)<\/span>\n/gm, + (match, intro_whitespace, content) => { + // we use some CSS trickery to make comments break onto multiple lines while preserving indentation + const lines = (intro_whitespace + content).split('\n'); + return lines + .map((line) => { + const match = /^(\s*)(.*)/.exec(line); + const indent = (match[1] ?? '').replace(/\t/g, ' ').length; + + return `${ + line ?? '' + }`; + }) + .join(''); + } + ) + .replace(/\/\*…\*\//g, '…'); + + return html; + }, + codespan: (text) => '' + text + '', + }); + + return { ...tutorial, content }; +} diff --git a/sites/svelte.dev/src/lib/server/tutorial/types.d.ts b/sites/svelte.dev/src/lib/server/tutorial/types.d.ts new file mode 100644 index 0000000000..2ec5bd99fb --- /dev/null +++ b/sites/svelte.dev/src/lib/server/tutorial/types.d.ts @@ -0,0 +1,24 @@ +export type TutorialData = { + title: string; + slug: string; + tutorials: { + title: string; + slug: string; + dir: string; + content: string; + initial: { name: string; type: string; content: string }[]; + complete: { name: string; type: string; content: string }[]; + }[]; +}[]; + +export interface Tutorial { + title: string; + slug: string; +} + +export interface TutorialSection { + title: string; + tutorials: Tutorial[]; +} + +export type TutorialsList = TutorialSection[]; diff --git a/sites/svelte.dev/src/routes/docs/+layout.server.js b/sites/svelte.dev/src/routes/docs/+layout.server.js index 222f0b3065..0c7eeaec6a 100644 --- a/sites/svelte.dev/src/routes/docs/+layout.server.js +++ b/sites/svelte.dev/src/routes/docs/+layout.server.js @@ -6,7 +6,6 @@ export const prerender = true; const base_dir = '../../site/content/docs/'; -/** @type {import('./$types').LayoutServerLoad} */ export function load() { const sections = fs.readdirSync(base_dir).map((file) => { const { title } = extract_frontmatter(fs.readFileSync(`${base_dir}/${file}`, 'utf-8')).metadata; diff --git a/sites/svelte.dev/src/routes/docs/+layout.svelte b/sites/svelte.dev/src/routes/docs/+layout.svelte index 5c79a2c47f..4a14f4a962 100644 --- a/sites/svelte.dev/src/routes/docs/+layout.svelte +++ b/sites/svelte.dev/src/routes/docs/+layout.svelte @@ -181,7 +181,7 @@ } .content :global(code) { - padding: 0.4rem; + /* padding: 0.4rem; */ margin: 0 0.2rem; top: -0.1rem; background: var(--sk-back-4); diff --git a/sites/svelte.dev/src/routes/tutorial/+layout.js b/sites/svelte.dev/src/routes/tutorial/+layout.js deleted file mode 100644 index 027240c0b5..0000000000 --- a/sites/svelte.dev/src/routes/tutorial/+layout.js +++ /dev/null @@ -1,6 +0,0 @@ -import { PUBLIC_API_BASE } from '$env/static/public'; - -export async function load({ fetch }) { - const tutorials = await fetch(`${PUBLIC_API_BASE}/docs/svelte/tutorial`).then((r) => r.json()); - return { tutorials }; -} diff --git a/sites/svelte.dev/src/routes/tutorial/+layout.svelte b/sites/svelte.dev/src/routes/tutorial/+layout.svelte deleted file mode 100644 index 210060b178..0000000000 --- a/sites/svelte.dev/src/routes/tutorial/+layout.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/sites/svelte.dev/src/routes/tutorial/+page.js b/sites/svelte.dev/src/routes/tutorial/+page.server.js similarity index 77% rename from sites/svelte.dev/src/routes/tutorial/+page.js rename to sites/svelte.dev/src/routes/tutorial/+page.server.js index 81a8307aa2..ccafa42ec9 100644 --- a/sites/svelte.dev/src/routes/tutorial/+page.js +++ b/sites/svelte.dev/src/routes/tutorial/+page.server.js @@ -1,5 +1,7 @@ import { redirect } from '@sveltejs/kit'; +export const prerender = true; + export function load() { throw redirect(301, '/tutorial/basics'); } diff --git a/sites/svelte.dev/src/routes/tutorial/[slug]/+page.js b/sites/svelte.dev/src/routes/tutorial/[slug]/+page.js deleted file mode 100644 index f7c5f71759..0000000000 --- a/sites/svelte.dev/src/routes/tutorial/[slug]/+page.js +++ /dev/null @@ -1,17 +0,0 @@ -import { redirect } from '@sveltejs/kit'; -import { PUBLIC_API_BASE } from '$env/static/public'; - -export async function load({ fetch, params, setHeaders }) { - // TODO: Use local data - const tutorial = await fetch(`${PUBLIC_API_BASE}/docs/svelte/tutorial/${params.slug}`); - - if (!tutorial.ok) { - throw redirect(301, '/tutorial/basics'); - } - - setHeaders({ - 'cache-control': 'public, max-age=60', - }); - - return { tutorial: await tutorial.json(), slug: params.slug }; -} diff --git a/sites/svelte.dev/src/routes/tutorial/[slug]/+page.server.js b/sites/svelte.dev/src/routes/tutorial/[slug]/+page.server.js new file mode 100644 index 0000000000..9cb550decc --- /dev/null +++ b/sites/svelte.dev/src/routes/tutorial/[slug]/+page.server.js @@ -0,0 +1,20 @@ +import { get_parsed_tutorial } from '$lib/server/tutorial'; +import { get_tutorial_data, get_tutorial_list } from '$lib/server/tutorial/get-tutorial-data'; +import { error } from '@sveltejs/kit'; + +export const prerender = true; + +export async function load({ params }) { + const tutorial_data = get_tutorial_data(); + const tutorials_list = get_tutorial_list(tutorial_data); + + const tutorial = await get_parsed_tutorial(tutorial_data, params.slug); + + if (!tutorial) throw error(404); + + return { + tutorials_list, + tutorial, + slug: params.slug, + }; +} diff --git a/sites/svelte.dev/src/routes/tutorial/[slug]/+page.svelte b/sites/svelte.dev/src/routes/tutorial/[slug]/+page.svelte index 9cee2aa90a..c9b310f71b 100644 --- a/sites/svelte.dev/src/routes/tutorial/[slug]/+page.svelte +++ b/sites/svelte.dev/src/routes/tutorial/[slug]/+page.svelte @@ -1,31 +1,32 @@ - {selected.section.name} / {selected.chapter.name} • Svelte Tutorial + {selected.section.title} / {selected.chapter.title} • Svelte Tutorial - - + + @@ -106,10 +107,10 @@
- +
-
+
{@html data.tutorial.content}
@@ -152,6 +153,16 @@ {/if}
+ +

+ {#each data.tutorials_list as { tutorials }} + {#each tutorials as { slug }} + + + {/each} + {/each} +

+ diff --git a/sites/svelte.dev/svelte.config.js b/sites/svelte.dev/svelte.config.js index 68268902e0..f86cd1a197 100644 --- a/sites/svelte.dev/svelte.config.js +++ b/sites/svelte.dev/svelte.config.js @@ -1,3 +1,4 @@ +// @ts-check import adapter from '@sveltejs/adapter-auto'; /** @type {import('@sveltejs/kit').Config} */ From 9793b418177488807f5fa0480448117388e78856 Mon Sep 17 00:00:00 2001 From: Puru Vijay <47742487+PuruVJ@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:40:31 +0530 Subject: [PATCH 2/2] feat(site-2): Local examples (#8431) * feat(docs): Local tutorial * Refactor some stuff * Better error handling * Fix search imports * Prerender tutorial * try prerendering hack * fix super stupid display hidden bug * Shorten the rendered URL * Shorten URL code even more * Prerender in svelte.config.js * Refactor * Fix ScreenToggle dark mode styles * Initial POC * Rvert to old hack * Fix svelte-document.jpg --- .../src/lib/components/ScreenToggle.svelte | 12 +-- .../src/lib/server/examples/get-examples.js | 72 ++++++++++++++++++ .../src/lib/server/examples/index.js | 11 +++ .../src/lib/server/examples/types.d.ts | 25 ++++++ .../svelte.dev/src/routes/examples/+layout.js | 6 -- .../src/routes/examples/+layout.svelte | 10 --- sites/svelte.dev/src/routes/examples/+page.js | 2 + .../src/routes/examples/[slug]/+page.js | 17 ----- .../routes/examples/[slug]/+page.server.js | 17 +++++ .../src/routes/examples/[slug]/+page.svelte | 24 +++--- ...Contents.svelte => TableOfContents.svelte} | 6 +- .../examples/thumbnails/svelte-document.jpg | Bin 0 -> 5625 bytes 12 files changed, 147 insertions(+), 55 deletions(-) create mode 100644 sites/svelte.dev/src/lib/server/examples/get-examples.js create mode 100644 sites/svelte.dev/src/lib/server/examples/index.js create mode 100644 sites/svelte.dev/src/lib/server/examples/types.d.ts delete mode 100644 sites/svelte.dev/src/routes/examples/+layout.js delete mode 100644 sites/svelte.dev/src/routes/examples/+layout.svelte delete mode 100644 sites/svelte.dev/src/routes/examples/[slug]/+page.js create mode 100644 sites/svelte.dev/src/routes/examples/[slug]/+page.server.js rename sites/svelte.dev/src/routes/examples/[slug]/{_TableOfContents.svelte => TableOfContents.svelte} (94%) create mode 100644 sites/svelte.dev/static/examples/thumbnails/svelte-document.jpg diff --git a/sites/svelte.dev/src/lib/components/ScreenToggle.svelte b/sites/svelte.dev/src/lib/components/ScreenToggle.svelte index 399f96bd71..14a9341fb0 100644 --- a/sites/svelte.dev/src/lib/components/ScreenToggle.svelte +++ b/sites/svelte.dev/src/lib/components/ScreenToggle.svelte @@ -20,8 +20,8 @@ display: flex; justify-content: center; align-items: center; - border-top: 1px solid var(--second); - background-color: white; + border-top: 1px solid var(--sk-theme-2); + background-color: var(--sk-back-4); } button { @@ -29,15 +29,15 @@ width: 4em; height: 1em; padding: 0.3em 0.4em; - border-radius: var(--border-r); + border-radius: var(--sk-border-radius); line-height: 1em; box-sizing: content-box; - color: #888; - border: 1px solid var(--back-light); + color: var(--sk-text-3); + border: 1px solid var(--sk-back-3); } .selected { - background-color: var(--prime); + background-color: var(--sk-theme-1); color: white; } diff --git a/sites/svelte.dev/src/lib/server/examples/get-examples.js b/sites/svelte.dev/src/lib/server/examples/get-examples.js new file mode 100644 index 0000000000..09b06723df --- /dev/null +++ b/sites/svelte.dev/src/lib/server/examples/get-examples.js @@ -0,0 +1,72 @@ +// @ts-check +import fs from 'node:fs'; + +const base = '../../site/content/examples/'; + +/** + * @returns {import('./types').ExamplesData} + */ +export function get_examples_data() { + const examples = []; + + for (const subdir of fs.readdirSync(base)) { + // Exclude embeds + if (subdir.endsWith('99-embeds')) continue; + + const section = { + title: '', // Initialise with empty + slug: subdir.split('-').slice(1).join('-'), + examples: [], + }; + + if (!(fs.statSync(`${base}/${subdir}`).isDirectory() || subdir.endsWith('meta.json'))) continue; + + if (!subdir.endsWith('meta.json')) + section.title = JSON.parse(fs.readFileSync(`${base}/${subdir}/meta.json`, 'utf-8')).title; + + for (const section_dir of fs.readdirSync(`${base}/${subdir}`)) { + const match = /\d{2}-(.+)/.exec(section_dir); + if (!match) continue; + + const slug = match[1]; + + const example_base_dir = `${base}/${subdir}/${section_dir}`; + + // Get title for + const example_title = JSON.parse( + fs.readFileSync(`${example_base_dir}/meta.json`, 'utf-8') + ).title; + + const files = []; + for (const file of fs + .readdirSync(example_base_dir) + .filter((file) => !file.endsWith('meta.json'))) { + files.push({ + filename: file, + type: file.split('.').at(-1), + content: fs.readFileSync(`${example_base_dir}/${file}`, 'utf-8'), + }); + } + + section.examples.push({ title: example_title, slug, files }); + } + + examples.push(section); + } + + return examples; +} + +/** + * @param {import('./types').ExamplesData} examples_data + * @returns {import('./types').ExamplesList} + */ +export function get_examples_list(examples_data) { + return examples_data.map((section) => ({ + title: section.title, + examples: section.examples.map((example) => ({ + title: example.title, + slug: example.slug, + })), + })); +} diff --git a/sites/svelte.dev/src/lib/server/examples/index.js b/sites/svelte.dev/src/lib/server/examples/index.js new file mode 100644 index 0000000000..822d072636 --- /dev/null +++ b/sites/svelte.dev/src/lib/server/examples/index.js @@ -0,0 +1,11 @@ +/** + * @param {import('./types').ExamplesData} examples_data + * @param {string} slug + */ +export function get_example(examples_data, slug) { + const example = examples_data + .find((section) => section.examples.find((example) => example.slug === slug)) + ?.examples.find((example) => example.slug === slug); + + return example; +} diff --git a/sites/svelte.dev/src/lib/server/examples/types.d.ts b/sites/svelte.dev/src/lib/server/examples/types.d.ts new file mode 100644 index 0000000000..5fe93a0ca5 --- /dev/null +++ b/sites/svelte.dev/src/lib/server/examples/types.d.ts @@ -0,0 +1,25 @@ +export type ExamplesData = { + title: string; + slug: string; + examples: { + title: string; + slug: string; + files: { + content: string; + type: 'svelte' | 'js'; + filename: string; + }[]; + }[]; +}[]; + +export interface Example { + title: string; + slug: string; +} + +export interface ExampleSection { + title: string; + examples: Example[]; +} + +export type ExamplesList = ExampleSection[]; diff --git a/sites/svelte.dev/src/routes/examples/+layout.js b/sites/svelte.dev/src/routes/examples/+layout.js deleted file mode 100644 index e0904af004..0000000000 --- a/sites/svelte.dev/src/routes/examples/+layout.js +++ /dev/null @@ -1,6 +0,0 @@ -import { PUBLIC_API_BASE } from '$env/static/public'; - -export async function load({ fetch }) { - const examples = await fetch(`${PUBLIC_API_BASE}/docs/svelte/examples`).then((r) => r.json()); - return { examples }; -} diff --git a/sites/svelte.dev/src/routes/examples/+layout.svelte b/sites/svelte.dev/src/routes/examples/+layout.svelte deleted file mode 100644 index 75bd0e2cfd..0000000000 --- a/sites/svelte.dev/src/routes/examples/+layout.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/sites/svelte.dev/src/routes/examples/+page.js b/sites/svelte.dev/src/routes/examples/+page.js index ac962514a0..6c39a1de34 100644 --- a/sites/svelte.dev/src/routes/examples/+page.js +++ b/sites/svelte.dev/src/routes/examples/+page.js @@ -1,5 +1,7 @@ import { redirect } from '@sveltejs/kit'; +export const prerender = true; + /** @type {import('./$types').PageLoad} */ export function load() { throw redirect(301, 'examples/hello-world'); diff --git a/sites/svelte.dev/src/routes/examples/[slug]/+page.js b/sites/svelte.dev/src/routes/examples/[slug]/+page.js deleted file mode 100644 index e2a1472cea..0000000000 --- a/sites/svelte.dev/src/routes/examples/[slug]/+page.js +++ /dev/null @@ -1,17 +0,0 @@ -import { PUBLIC_API_BASE } from '$env/static/public'; - -/** @type {import('./$types').PageLoad} */ -export async function load({ fetch, params, setHeaders }) { - const example = await fetch(`${PUBLIC_API_BASE}/docs/svelte/examples/${params.slug}`, { - credentials: 'omit' - }); - - setHeaders({ - 'cache-control': 'public, max-age=60' - }); - - return { - example: await example.json(), - slug: params.slug - }; -} diff --git a/sites/svelte.dev/src/routes/examples/[slug]/+page.server.js b/sites/svelte.dev/src/routes/examples/[slug]/+page.server.js new file mode 100644 index 0000000000..6bc280e098 --- /dev/null +++ b/sites/svelte.dev/src/routes/examples/[slug]/+page.server.js @@ -0,0 +1,17 @@ +import { get_example } from '$lib/server/examples'; +import { get_examples_data, get_examples_list } from '$lib/server/examples/get-examples'; + +export const prerender = true; + +export async function load({ params }) { + const examples_data = get_examples_data(); + + const examples_list = get_examples_list(examples_data); + const example = get_example(examples_data, params.slug); + + return { + examples_list, + example, + slug: params.slug, + }; +} diff --git a/sites/svelte.dev/src/routes/examples/[slug]/+page.svelte b/sites/svelte.dev/src/routes/examples/[slug]/+page.svelte index 6a12d3d0a3..c27de536b7 100644 --- a/sites/svelte.dev/src/routes/examples/[slug]/+page.svelte +++ b/sites/svelte.dev/src/routes/examples/[slug]/+page.svelte @@ -1,16 +1,12 @@ - {data.example.name} {data.example.name ? '•' : ''} Svelte Examples + {data.example.title} {data.example.title ? '•' : ''} Svelte Examples @@ -44,7 +38,11 @@

Examples

- +
{#each sections as section}
  • - {section.name} + {section.title} {#each section.examples as example}
    @@ -31,7 +31,7 @@ src="/examples/thumbnails/{example.slug}.jpg" /> - {example.name} + {example.title} {#if example.slug === active_section} REPL @@ -109,7 +109,7 @@ } .thumbnail { - background-color: var(--sk-back-1); + background-color: #fff; object-fit: contain; width: 5rem; height: 5rem; diff --git a/sites/svelte.dev/static/examples/thumbnails/svelte-document.jpg b/sites/svelte.dev/static/examples/thumbnails/svelte-document.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4449279e50fe1a0311224f7164c46de291a3ff93 GIT binary patch literal 5625 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 literal 0 HcmV?d00001