diff --git a/sites/svelte.dev/package-lock.json b/sites/svelte.dev/package-lock.json
index 05781d383c..b362543efd 100644
--- a/sites/svelte.dev/package-lock.json
+++ b/sites/svelte.dev/package-lock.json
@@ -15,6 +15,7 @@
"do-not-zip": "^1.0.0",
"flexsearch": "^0.7.31",
"flru": "^1.0.2",
+ "slugify": "^1.6.5",
"sourcemap-codec": "^1.4.8",
"svelte-local-storage-store": "^0.4.0"
},
@@ -3453,6 +3454,14 @@
"node": ">= 10"
}
},
+ "node_modules/slugify": {
+ "version": "1.6.5",
+ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.5.tgz",
+ "integrity": "sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ==",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/sorcery": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz",
@@ -6520,6 +6529,11 @@
"totalist": "^3.0.0"
}
},
+ "slugify": {
+ "version": "1.6.5",
+ "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.5.tgz",
+ "integrity": "sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ=="
+ },
"sorcery": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz",
diff --git a/sites/svelte.dev/package.json b/sites/svelte.dev/package.json
index e93bac371e..792ad728a5 100644
--- a/sites/svelte.dev/package.json
+++ b/sites/svelte.dev/package.json
@@ -23,6 +23,7 @@
"do-not-zip": "^1.0.0",
"flexsearch": "^0.7.31",
"flru": "^1.0.2",
+ "slugify": "^1.6.5",
"sourcemap-codec": "^1.4.8",
"svelte-local-storage-store": "^0.4.0"
},
diff --git a/sites/svelte.dev/src/lib/search/content.js b/sites/svelte.dev/src/lib/search/content.js
index d9c229588b..2de86eac7f 100644
--- a/sites/svelte.dev/src/lib/search/content.js
+++ b/sites/svelte.dev/src/lib/search/content.js
@@ -1,8 +1,8 @@
+import { normalizeSlugify, removeMarkdown } from '$lib/server/docs';
+import { extract_frontmatter, transform } from '$lib/server/markdown';
import fs from 'node:fs';
import path from 'node:path';
import glob from 'tiny-glob/sync.js';
-import { extract_frontmatter, transform } from '$lib/server/markdown';
-import { slugify } from '$lib/server/docs/index.js';
const base = '../../site/content/';
@@ -47,7 +47,7 @@ export function content() {
const rank = +metadata.rank || undefined;
blocks.push({
- breadcrumbs: [...breadcrumbs, metadata.title],
+ breadcrumbs: [...breadcrumbs, removeMarkdown(metadata.title ?? '')],
href: category.href([slug]),
content: plaintext(intro),
rank,
@@ -63,8 +63,8 @@ export function content() {
const intro = subsections.shift().trim();
blocks.push({
- breadcrumbs: [...breadcrumbs, metadata.title, h3],
- href: category.href([slug, slugify(h3)]),
+ breadcrumbs: [...breadcrumbs, removeMarkdown(metadata.title), removeMarkdown(h3)],
+ href: category.href([slug, normalizeSlugify(h3)]),
content: plaintext(intro),
rank,
});
@@ -74,8 +74,13 @@ export function content() {
const h4 = lines.shift();
blocks.push({
- breadcrumbs: [...breadcrumbs, metadata.title, h3, h4],
- href: category.href([slug, slugify(h3), slugify(h4)]),
+ breadcrumbs: [
+ ...breadcrumbs,
+ removeMarkdown(metadata.title),
+ removeMarkdown(h3),
+ removeMarkdown(h4),
+ ],
+ href: category.href([slug, normalizeSlugify(h3), normalizeSlugify(h4)]),
content: plaintext(lines.join('\n').trim()),
rank,
});
diff --git a/sites/svelte.dev/src/lib/server/docs/index.js b/sites/svelte.dev/src/lib/server/docs/index.js
index 6a4163f2b5..2a10a5a8ce 100644
--- a/sites/svelte.dev/src/lib/server/docs/index.js
+++ b/sites/svelte.dev/src/lib/server/docs/index.js
@@ -13,6 +13,25 @@ import ts, { ScriptTarget } from 'typescript';
import MagicString from 'magic-string';
import { fileURLToPath } from 'url';
import { createHash } from 'crypto';
+import slugify from 'slugify';
+
+/** @param {string} markdown */
+export function removeMarkdown(markdown) {
+ return markdown
+ .replace(/\*\*(.+?)\*\*/g, '$1')
+ .replace(/\*(.+?)\*/g, '$1')
+ .replace(/`(.+?)`/g, '$1')
+ .replace(/~~(.+?)~~/g, '$1')
+ .replace(/\[(.+?)\]\(.+?\)/g, '$1')
+ .replace(/\n/g, ' ')
+ .replace(/ {2,}/g, ' ')
+ .trim();
+}
+
+/** @param {string} str */
+export const normalizeSlugify = (str) => {
+ return slugify(removeMarkdown(str));
+};
const base = '../../site/content/docs/';
@@ -286,19 +305,6 @@ export async function read_file(file) {
};
}
-/** @param {string} title */
-export function slugify(title) {
- return title
- .toLowerCase()
- .replace(/'/g, '')
- .replace(/</g, '')
- .replace(/>/g, '')
- .replace(/[^a-z0-9-$]/g, '-')
- .replace(/-{2,}/g, '-')
- .replace(/^-/, '')
- .replace(/-$/, '');
-}
-
/**
* @param {{
* file: string;
@@ -326,7 +332,7 @@ function parse({ file, body, code, codespan }) {
* @param {string} html
* @param {number} level
*/
- heading(html, level) {
+ heading(html, level, raw) {
const title = html
.replace(/<\/?code>/g, '')
.replace(/"/g, '"')
@@ -335,7 +341,7 @@ function parse({ file, body, code, codespan }) {
current = title;
- const normalized = slugify(title);
+ const normalized = normalizeSlugify(raw).replace(/(<([^>]+)>)/gi, '');
headings[level - 1] = normalized;
headings.length = level;
diff --git a/sites/svelte.dev/src/routes/+layout.svelte b/sites/svelte.dev/src/routes/+layout.svelte
index 1750c0a4ac..59b45a065d 100644
--- a/sites/svelte.dev/src/routes/+layout.svelte
+++ b/sites/svelte.dev/src/routes/+layout.svelte
@@ -18,15 +18,6 @@