From d5faab4309f4f5b64eb7304379f795a497dd0ead Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Tue, 3 Sep 2024 23:47:45 +0200 Subject: [PATCH 1/3] feat: shorter docs URLs Removes the section part from the slugs Fixes #62 --- .../src/routes/content.json/+server.ts | 3 +- .../routes/docs/[...path]/+layout.server.ts | 4 +- .../src/routes/docs/[...path]/+page.server.js | 4 +- .../src/routes/docs/content.server.ts | 44 +++++++++++++++++++ .../svelte.dev/src/routes/nav.json/+server.ts | 21 +++++---- 5 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 apps/svelte.dev/src/routes/docs/content.server.ts diff --git a/apps/svelte.dev/src/routes/content.json/+server.ts b/apps/svelte.dev/src/routes/content.json/+server.ts index bc43de6446..37ecec27e0 100644 --- a/apps/svelte.dev/src/routes/content.json/+server.ts +++ b/apps/svelte.dev/src/routes/content.json/+server.ts @@ -2,6 +2,7 @@ import { index } from '$lib/server/content'; import { json } from '@sveltejs/kit'; import { markedTransform, normalizeSlugify, removeMarkdown } from '@sveltejs/site-kit/markdown'; import type { Block } from '@sveltejs/site-kit/search'; +import { docs as _docs } from '../docs/content.server'; export const prerender = true; @@ -19,7 +20,7 @@ async function content() { const blocks: Block[] = []; const breadcrumbs: string[] = []; // We want the actual contents: docs -> docs/svelte etc -> docs/svelte/overview etc -> docs/svelte/overview/introduction etc - let docs = index.docs.children.flatMap((topic) => + let docs = Object.values(_docs).flatMap((topic) => topic.children.flatMap((section) => section.children) ); docs = docs.concat( diff --git a/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts b/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts index 5f6e4c30e2..3aadc218c9 100644 --- a/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts +++ b/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts @@ -1,10 +1,10 @@ -import { index } from '$lib/server/content'; import { error } from '@sveltejs/kit'; +import { docs } from '../content.server'; export const prerender = true; export async function load({ params }) { - const page = index[`docs/${params.path.split('/')[0]}`]; + const page = docs[`docs/${params.path.split('/')[0]}`]; if (!page) { error(404, 'Not found'); diff --git a/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js b/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js index b14a2fa09d..4959b587f7 100644 --- a/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js +++ b/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js @@ -1,9 +1,9 @@ -import { index } from '$lib/server/content'; import { render_content } from '$lib/server/renderer'; import { error, redirect } from '@sveltejs/kit'; +import { docs } from '../content.server'; export async function load({ params }) { - const document = index[`docs/${params.path}`]; + const document = docs[`docs/${params.path}`]; if (!document) { error(404); diff --git a/apps/svelte.dev/src/routes/docs/content.server.ts b/apps/svelte.dev/src/routes/docs/content.server.ts new file mode 100644 index 0000000000..096297e080 --- /dev/null +++ b/apps/svelte.dev/src/routes/docs/content.server.ts @@ -0,0 +1,44 @@ +import { index } from '$lib/server/content'; +import type { Document } from '@sveltejs/site-kit'; + +export function remove_section_from_slug(slug: string) { + return slug.replace(/\/[^/]+(\/[^/]+)$/g, '$1'); +} + +/** + * Create docs index, which is basically the same structure as the original index + * but with adjusted slugs: The section part is omitted for cleaner URLs. + */ +function create_docs() { + let docs: Record = {}; + + for (const topic of index.docs.children) { + const sections = topic.children; + docs[topic.slug] = { ...topic, children: [] }; + + for (const section of sections) { + const pages = section.children; + docs[section.slug] = { ...section, children: [] }; + docs[topic.slug].children.push(docs[section.slug]); + + for (const page of pages) { + const slug = remove_section_from_slug(page.slug); + docs[slug] = { + ...page, + slug: remove_section_from_slug(page.slug), + next: page.next + ? { slug: remove_section_from_slug(page.next.slug), title: page.next.title } + : null, + prev: page.prev + ? { slug: remove_section_from_slug(page.prev.slug), title: page.prev.title } + : null + }; + docs[section.slug].children.push(docs[slug]); + } + } + } + + return docs; +} + +export const docs = create_docs(); diff --git a/apps/svelte.dev/src/routes/nav.json/+server.ts b/apps/svelte.dev/src/routes/nav.json/+server.ts index e71856e111..7d312e6858 100644 --- a/apps/svelte.dev/src/routes/nav.json/+server.ts +++ b/apps/svelte.dev/src/routes/nav.json/+server.ts @@ -1,6 +1,7 @@ import { json } from '@sveltejs/kit'; import { blog_posts, index } from '$lib/server/content'; import type { NavigationLink } from '@sveltejs/site-kit'; +import { docs as _docs } from '../docs/content.server'; export const prerender = true; @@ -9,16 +10,18 @@ export const GET = async () => { }; async function get_nav_list(): Promise { - const docs = index.docs.children.map((topic) => ({ - title: topic.metadata.title, - sections: topic.children.map((section) => ({ - title: section.metadata.title, - sections: section.children.map((page) => ({ - title: page.metadata.title, - path: '/' + page.slug + const docs = Object.values(_docs) + .filter((entry) => entry.slug.split('/').length === 2) + .map((topic) => ({ + title: topic.metadata.title, + sections: topic.children.map((section) => ({ + title: section.metadata.title, + sections: section.children.map((page) => ({ + title: page.metadata.title, + path: '/' + page.slug + })) })) - })) - })); + })); const blog = [ { From 5ada106c371d4ebebcf96087c93a451eca84becc Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 4 Sep 2024 09:20:11 +0200 Subject: [PATCH 2/3] move --- apps/svelte.dev/src/lib/server/content.ts | 43 ++++++++++++++++++ .../src/routes/content.json/+server.ts | 3 +- .../routes/docs/[...path]/+layout.server.ts | 2 +- .../src/routes/docs/[...path]/+page.server.js | 2 +- .../src/routes/docs/content.server.ts | 44 ------------------- .../svelte.dev/src/routes/nav.json/+server.ts | 3 +- 6 files changed, 47 insertions(+), 50 deletions(-) delete mode 100644 apps/svelte.dev/src/routes/docs/content.server.ts diff --git a/apps/svelte.dev/src/lib/server/content.ts b/apps/svelte.dev/src/lib/server/content.ts index 0a38d4304d..959f8d33e1 100644 --- a/apps/svelte.dev/src/lib/server/content.ts +++ b/apps/svelte.dev/src/lib/server/content.ts @@ -1,4 +1,5 @@ import { read } from '$app/server'; +import type { Document } from '@sveltejs/site-kit'; import { create_index } from '@sveltejs/site-kit/server/content'; const documents = import.meta.glob('../../../content/**/*.md', { @@ -51,3 +52,45 @@ export const blog_posts = index.blog.children }; }) .sort((a, b) => (a.date < b.date ? 1 : -1)); + +export function remove_section_from_slug(slug: string) { + return slug.replace(/\/[^/]+(\/[^/]+)$/g, '$1'); +} + +/** + * Create docs index, which is basically the same structure as the original index + * but with adjusted slugs: The section part is omitted for cleaner URLs. + */ +function create_docs() { + let docs: Record = {}; + + for (const topic of index.docs.children) { + const sections = topic.children; + docs[topic.slug] = { ...topic, children: [] }; + + for (const section of sections) { + const pages = section.children; + docs[section.slug] = { ...section, children: [] }; + docs[topic.slug].children.push(docs[section.slug]); + + for (const page of pages) { + const slug = remove_section_from_slug(page.slug); + docs[slug] = { + ...page, + slug: remove_section_from_slug(page.slug), + next: page.next + ? { slug: remove_section_from_slug(page.next.slug), title: page.next.title } + : null, + prev: page.prev + ? { slug: remove_section_from_slug(page.prev.slug), title: page.prev.title } + : null + }; + docs[section.slug].children.push(docs[slug]); + } + } + } + + return docs; +} + +export const docs = create_docs(); diff --git a/apps/svelte.dev/src/routes/content.json/+server.ts b/apps/svelte.dev/src/routes/content.json/+server.ts index 37ecec27e0..9e56411fd4 100644 --- a/apps/svelte.dev/src/routes/content.json/+server.ts +++ b/apps/svelte.dev/src/routes/content.json/+server.ts @@ -1,8 +1,7 @@ -import { index } from '$lib/server/content'; +import { index, docs as _docs } from '$lib/server/content'; import { json } from '@sveltejs/kit'; import { markedTransform, normalizeSlugify, removeMarkdown } from '@sveltejs/site-kit/markdown'; import type { Block } from '@sveltejs/site-kit/search'; -import { docs as _docs } from '../docs/content.server'; export const prerender = true; diff --git a/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts b/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts index 3aadc218c9..7dbf9d3441 100644 --- a/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts +++ b/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts @@ -1,5 +1,5 @@ +import { docs } from '$lib/server/content'; import { error } from '@sveltejs/kit'; -import { docs } from '../content.server'; export const prerender = true; diff --git a/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js b/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js index 4959b587f7..f0667220a5 100644 --- a/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js +++ b/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js @@ -1,6 +1,6 @@ +import { docs } from '$lib/server/content'; import { render_content } from '$lib/server/renderer'; import { error, redirect } from '@sveltejs/kit'; -import { docs } from '../content.server'; export async function load({ params }) { const document = docs[`docs/${params.path}`]; diff --git a/apps/svelte.dev/src/routes/docs/content.server.ts b/apps/svelte.dev/src/routes/docs/content.server.ts deleted file mode 100644 index 096297e080..0000000000 --- a/apps/svelte.dev/src/routes/docs/content.server.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { index } from '$lib/server/content'; -import type { Document } from '@sveltejs/site-kit'; - -export function remove_section_from_slug(slug: string) { - return slug.replace(/\/[^/]+(\/[^/]+)$/g, '$1'); -} - -/** - * Create docs index, which is basically the same structure as the original index - * but with adjusted slugs: The section part is omitted for cleaner URLs. - */ -function create_docs() { - let docs: Record = {}; - - for (const topic of index.docs.children) { - const sections = topic.children; - docs[topic.slug] = { ...topic, children: [] }; - - for (const section of sections) { - const pages = section.children; - docs[section.slug] = { ...section, children: [] }; - docs[topic.slug].children.push(docs[section.slug]); - - for (const page of pages) { - const slug = remove_section_from_slug(page.slug); - docs[slug] = { - ...page, - slug: remove_section_from_slug(page.slug), - next: page.next - ? { slug: remove_section_from_slug(page.next.slug), title: page.next.title } - : null, - prev: page.prev - ? { slug: remove_section_from_slug(page.prev.slug), title: page.prev.title } - : null - }; - docs[section.slug].children.push(docs[slug]); - } - } - } - - return docs; -} - -export const docs = create_docs(); diff --git a/apps/svelte.dev/src/routes/nav.json/+server.ts b/apps/svelte.dev/src/routes/nav.json/+server.ts index 7d312e6858..fe51035be4 100644 --- a/apps/svelte.dev/src/routes/nav.json/+server.ts +++ b/apps/svelte.dev/src/routes/nav.json/+server.ts @@ -1,7 +1,6 @@ import { json } from '@sveltejs/kit'; -import { blog_posts, index } from '$lib/server/content'; +import { blog_posts, docs as _docs, index } from '$lib/server/content'; import type { NavigationLink } from '@sveltejs/site-kit'; -import { docs as _docs } from '../docs/content.server'; export const prerender = true; From 8e70dd9ddbdbe0163f25b6be7f0ad99258276b49 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Wed, 4 Sep 2024 10:17:24 +0200 Subject: [PATCH 3/3] adjust structure to better fit usage --- apps/svelte.dev/src/lib/server/content.ts | 55 +++++++++++++------ .../src/routes/content.json/+server.ts | 6 +- .../routes/docs/[...path]/+layout.server.ts | 2 +- .../src/routes/docs/[...path]/+page.server.js | 26 ++------- .../svelte.dev/src/routes/nav.json/+server.ts | 20 +++---- 5 files changed, 54 insertions(+), 55 deletions(-) diff --git a/apps/svelte.dev/src/lib/server/content.ts b/apps/svelte.dev/src/lib/server/content.ts index 959f8d33e1..4136e7b295 100644 --- a/apps/svelte.dev/src/lib/server/content.ts +++ b/apps/svelte.dev/src/lib/server/content.ts @@ -53,39 +53,58 @@ export const blog_posts = index.blog.children }) .sort((a, b) => (a.date < b.date ? 1 : -1)); -export function remove_section_from_slug(slug: string) { - return slug.replace(/\/[^/]+(\/[^/]+)$/g, '$1'); -} - /** * Create docs index, which is basically the same structure as the original index - * but with adjusted slugs: The section part is omitted for cleaner URLs. + * but with adjusted slugs (the section part is omitted for cleaner URLs), separated + * topics/pages and next/prev adjusted so that they don't point to different topics. */ function create_docs() { - let docs: Record = {}; + function remove_section(slug: string) { + return slug.replace(/\/[^/]+(\/[^/]+)$/g, '$1'); + } + + function remove_docs(slugs: string) { + return slugs.replace(/^docs\//, ''); + } + + let docs: { + /** The top level entries/packages: svelte/kit/etc. Key is the topic */ + topics: Record; + /** The docs pages themselves. Key is the topic + page */ + pages: Record; + } = { topics: {}, pages: {} }; for (const topic of index.docs.children) { + const pkg = topic.slug.split('/')[1]; const sections = topic.children; - docs[topic.slug] = { ...topic, children: [] }; + const transformed_topic: Document = (docs.topics[remove_docs(topic.slug)] = { + ...topic, + children: [] + }); for (const section of sections) { const pages = section.children; - docs[section.slug] = { ...section, children: [] }; - docs[topic.slug].children.push(docs[section.slug]); + const transformed_section: Document = { + ...section, + children: [] + }; + + transformed_topic.children.push(transformed_section); for (const page of pages) { - const slug = remove_section_from_slug(page.slug); - docs[slug] = { + const slug = remove_section(page.slug); + const transformed_page: Document = (docs.pages[remove_docs(slug)] = { ...page, - slug: remove_section_from_slug(page.slug), - next: page.next - ? { slug: remove_section_from_slug(page.next.slug), title: page.next.title } + slug, + next: page.next?.slug.startsWith(`docs/${pkg}/`) + ? { slug: remove_section(page.next.slug), title: page.next.title } : null, - prev: page.prev - ? { slug: remove_section_from_slug(page.prev.slug), title: page.prev.title } + prev: page.prev?.slug.startsWith(`docs/${pkg}/`) + ? { slug: remove_section(page.prev.slug), title: page.prev.title } : null - }; - docs[section.slug].children.push(docs[slug]); + }); + + transformed_section.children.push(transformed_page); } } } diff --git a/apps/svelte.dev/src/routes/content.json/+server.ts b/apps/svelte.dev/src/routes/content.json/+server.ts index 9e56411fd4..65e5efbf18 100644 --- a/apps/svelte.dev/src/routes/content.json/+server.ts +++ b/apps/svelte.dev/src/routes/content.json/+server.ts @@ -18,11 +18,7 @@ function get_href(parts: string[]) { async function content() { const blocks: Block[] = []; const breadcrumbs: string[] = []; - // We want the actual contents: docs -> docs/svelte etc -> docs/svelte/overview etc -> docs/svelte/overview/introduction etc - let docs = Object.values(_docs).flatMap((topic) => - topic.children.flatMap((section) => section.children) - ); - docs = docs.concat( + const docs = Object.values(_docs.pages).concat( index.tutorial.children.flatMap((topic) => topic.children.flatMap((section) => section.children.map((entry) => ({ diff --git a/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts b/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts index 7dbf9d3441..56b4c3cb09 100644 --- a/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts +++ b/apps/svelte.dev/src/routes/docs/[...path]/+layout.server.ts @@ -4,7 +4,7 @@ import { error } from '@sveltejs/kit'; export const prerender = true; export async function load({ params }) { - const page = docs[`docs/${params.path.split('/')[0]}`]; + const page = docs.topics[params.path.split('/')[0]]; if (!page) { error(404, 'Not found'); diff --git a/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js b/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js index f0667220a5..6f224b0712 100644 --- a/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js +++ b/apps/svelte.dev/src/routes/docs/[...path]/+page.server.js @@ -3,34 +3,20 @@ import { render_content } from '$lib/server/renderer'; import { error, redirect } from '@sveltejs/kit'; export async function load({ params }) { - const document = docs[`docs/${params.path}`]; + const document = docs.pages[params.path]; if (!document) { - error(404); - } - - if (!document.body) { - let child = document; - - while (child.children[0]) { - child = child.children[0]; + const topic = docs.topics[params.path]; + if (topic) { + redirect(307, `/${topic.children[0].children[0].slug}`); } - - if (child === document) { - error(404); - } - - redirect(307, `/${child.slug}`); + error(404); } - const pkg = params.path.split('/')[0]; - return { document: { ...document, - body: await render_content(document.file, document.body), - prev: document.prev?.slug.startsWith(`docs/${pkg}/`) ? document.prev : null, - next: document.next?.slug.startsWith(`docs/${pkg}/`) ? document.next : null + body: await render_content(document.file, document.body) } }; } diff --git a/apps/svelte.dev/src/routes/nav.json/+server.ts b/apps/svelte.dev/src/routes/nav.json/+server.ts index fe51035be4..5bf3d179e7 100644 --- a/apps/svelte.dev/src/routes/nav.json/+server.ts +++ b/apps/svelte.dev/src/routes/nav.json/+server.ts @@ -9,18 +9,16 @@ export const GET = async () => { }; async function get_nav_list(): Promise { - const docs = Object.values(_docs) - .filter((entry) => entry.slug.split('/').length === 2) - .map((topic) => ({ - title: topic.metadata.title, - sections: topic.children.map((section) => ({ - title: section.metadata.title, - sections: section.children.map((page) => ({ - title: page.metadata.title, - path: '/' + page.slug - })) + const docs = Object.values(_docs.topics).map((topic) => ({ + title: topic.metadata.title, + sections: topic.children.map((section) => ({ + title: section.metadata.title, + sections: section.children.map((page) => ({ + title: page.metadata.title, + path: '/' + page.slug })) - })); + })) + })); const blog = [ {