svelte-docsmith 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/svelte-docsmith.mjs +161 -0
- package/dist/buildtime/archive.d.ts +31 -0
- package/dist/buildtime/archive.js +50 -0
- package/dist/buildtime/markdown-source.d.ts +31 -0
- package/dist/buildtime/markdown-source.js +90 -0
- package/dist/buildtime/vite/collect.d.ts +4 -3
- package/dist/buildtime/vite/collect.js +31 -12
- package/dist/buildtime/vite/extract.js +9 -35
- package/dist/buildtime/vite/frontmatter.js +4 -3
- package/dist/buildtime/vite/index.d.ts +9 -0
- package/dist/buildtime/vite/index.js +11 -4
- package/dist/components/chrome/copy-button.svelte +3 -2
- package/dist/components/chrome/search.svelte +16 -4
- package/dist/components/chrome/search.svelte.d.ts +4 -1
- package/dist/components/chrome/version-banner.svelte +82 -0
- package/dist/components/chrome/version-banner.svelte.d.ts +10 -0
- package/dist/components/chrome/version-switcher.svelte +63 -0
- package/dist/components/chrome/version-switcher.svelte.d.ts +14 -0
- package/dist/components/layouts/docs-header.svelte +26 -3
- package/dist/components/layouts/docs-header.svelte.d.ts +9 -1
- package/dist/components/layouts/docs-mobile-header.svelte +25 -2
- package/dist/components/layouts/docs-mobile-header.svelte.d.ts +9 -1
- package/dist/components/layouts/docs-shell.svelte +84 -66
- package/dist/components/layouts/docs-shell.svelte.d.ts +11 -2
- package/dist/components/layouts/error-page.svelte +23 -3
- package/dist/components/layouts/error-page.svelte.d.ts +8 -2
- package/dist/components/layouts/seo-head.svelte +8 -1
- package/dist/components/layouts/seo-head.svelte.d.ts +2 -0
- package/dist/core/content.d.ts +9 -0
- package/dist/core/docs-page.d.ts +70 -0
- package/dist/core/docs-page.js +55 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/core/version.d.ts +80 -0
- package/dist/core/version.js +85 -0
- package/dist/fallbacks/content.d.ts +2 -0
- package/dist/fallbacks/content.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/search/context.svelte.d.ts +2 -0
- package/dist/search/context.svelte.js +2 -0
- package/dist/search/create-search.d.ts +8 -2
- package/dist/search/create-search.js +11 -3
- package/dist/theme.css +21 -0
- package/package.json +7 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { navFromContent, flattenNav } from './nav.js';
|
|
2
|
+
import { normalizePath } from '../utils/normalize-path.js';
|
|
3
|
+
/** True when `pathname` is `base` or sits beneath it on a segment boundary. */
|
|
4
|
+
function underBase(pathname, base) {
|
|
5
|
+
return pathname === base || pathname.startsWith(base + '/');
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve author versions against the docs URL base (e.g. `/docs`) and the
|
|
9
|
+
* collected content: compute each version's `basePath` and its `landing` (first
|
|
10
|
+
* page in sidebar reading order). Emitted as the `versions` manifest in
|
|
11
|
+
* `svelte-docsmith/content`, current first, then archives in declared order.
|
|
12
|
+
*
|
|
13
|
+
* Returns an empty manifest for an unversioned site, which makes every
|
|
14
|
+
* downstream scoping, switcher and banner step a no-op.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveVersions(versions, docsBase, content) {
|
|
17
|
+
if (!versions)
|
|
18
|
+
return [];
|
|
19
|
+
const base = normalizePath(docsBase);
|
|
20
|
+
const resolve = (version, basePath, current) => {
|
|
21
|
+
const items = content.filter((item) => item.version === version.id);
|
|
22
|
+
return {
|
|
23
|
+
...version,
|
|
24
|
+
basePath,
|
|
25
|
+
landing: flattenNav(navFromContent(items))[0]?.url ?? basePath,
|
|
26
|
+
current,
|
|
27
|
+
noindex: version.noindex ?? false
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
return [
|
|
31
|
+
resolve(versions.current, base, true),
|
|
32
|
+
...(versions.archived ?? []).map((version) => resolve(version, normalizePath(base + '/' + version.id), false))
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The resolved version owning `pathname`, by longest matching `basePath`. An
|
|
37
|
+
* archive's base is longer than the current version's, so `/docs/v1/x` picks
|
|
38
|
+
* `v1` while `/docs/x` falls to the current version. `undefined` off the docs
|
|
39
|
+
* tree entirely, or on an unversioned site.
|
|
40
|
+
*/
|
|
41
|
+
export function activeVersion(versions, pathname) {
|
|
42
|
+
const path = normalizePath(pathname);
|
|
43
|
+
let best;
|
|
44
|
+
for (const v of versions) {
|
|
45
|
+
if (underBase(path, v.basePath) && (!best || v.basePath.length > best.basePath.length)) {
|
|
46
|
+
best = v;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return best;
|
|
50
|
+
}
|
|
51
|
+
/** The current version: the docs for the latest release. */
|
|
52
|
+
export function currentVersion(versions) {
|
|
53
|
+
return versions.find((v) => v.current);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Keep only the current version's pages, for `sitemap.xml` and `llms.txt`, so
|
|
57
|
+
* search engines and LLMs index one canonical set. A no-op when the site
|
|
58
|
+
* declares no versions. Works over any record carrying `version`.
|
|
59
|
+
*/
|
|
60
|
+
export function currentOnly(items, versions) {
|
|
61
|
+
const current = currentVersion(versions);
|
|
62
|
+
return current ? items.filter((item) => item.version === current.id) : items;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Content scoped to one version. With no version id (unversioned site) the
|
|
66
|
+
* content passes through unchanged, so every caller stays a no-op off the
|
|
67
|
+
* versioned path.
|
|
68
|
+
*/
|
|
69
|
+
export function scopeContent(content, versionId) {
|
|
70
|
+
if (!versionId)
|
|
71
|
+
return content;
|
|
72
|
+
return content.filter((item) => item.version === versionId);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Map the current page to its equivalent under `to`: swap the version base, and
|
|
76
|
+
* fall back to the target's landing page when that doc doesn't exist there.
|
|
77
|
+
* `targetPaths` is the set of the target version's page URLs.
|
|
78
|
+
*/
|
|
79
|
+
export function mapPathToVersion(pathname, from, to, targetPaths) {
|
|
80
|
+
const path = normalizePath(pathname);
|
|
81
|
+
const rel = underBase(path, from.basePath) ? path.slice(from.basePath.length) : '';
|
|
82
|
+
const candidate = normalizePath(to.basePath + rel);
|
|
83
|
+
const set = targetPaths instanceof Set ? targetPaths : new Set(targetPaths);
|
|
84
|
+
return set.has(candidate) ? candidate : to.landing;
|
|
85
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export { default as Feature } from './components/landing/feature.svelte';
|
|
|
24
24
|
export { default as CTA } from './components/landing/cta.svelte';
|
|
25
25
|
export { default as Action } from './components/landing/action.svelte';
|
|
26
26
|
export { defineConfig, type DocsmithConfig, type DocsContentItem, type SearchDoc, type LlmsDoc } from './core/index.js';
|
|
27
|
+
export { currentOnly, type DocsVersion, type DocsVersions, type ResolvedVersion } from './core/index.js';
|
|
27
28
|
export { createSearchEngine, type SearchEngine, type SearchResult } from './search/create-search.js';
|
|
28
29
|
export { generateSitemap, type SitemapEntry } from './generate/sitemap.js';
|
|
29
30
|
export { generateLlmsTxt, generateLlmsFullTxt, type LlmsSite } from './generate/llms.js';
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,11 @@ export { default as CTA } from './components/landing/cta.svelte';
|
|
|
31
31
|
export { default as Action } from './components/landing/action.svelte';
|
|
32
32
|
// Config
|
|
33
33
|
export { defineConfig } from './core/index.js';
|
|
34
|
+
// Versioned docs. Declare `versions` in the `docsmith()` vite plugin; the
|
|
35
|
+
// resolved manifest is exported from `svelte-docsmith/content` and passed to
|
|
36
|
+
// `DocsShell`. `currentOnly` scopes sitemap.xml / llms.txt to the current
|
|
37
|
+
// version, so archived releases don't compete with it in search results.
|
|
38
|
+
export { currentOnly } from './core/index.js';
|
|
34
39
|
// Search engine (framework-agnostic; for building a custom search UI over the
|
|
35
40
|
// generated `svelte-docsmith/search` index)
|
|
36
41
|
export { createSearchEngine } from './search/create-search.js';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare class SearchState {
|
|
2
2
|
open: boolean;
|
|
3
|
+
/** Active version id on a versioned site; scopes results. `undefined` otherwise. */
|
|
4
|
+
version: string | undefined;
|
|
3
5
|
}
|
|
4
6
|
/** Create the search state and publish it on context. Call in `DocsShell`. */
|
|
5
7
|
export declare function createSearchState(): SearchState;
|
|
@@ -7,6 +7,8 @@ import { getContext, setContext } from 'svelte';
|
|
|
7
7
|
const KEY = Symbol('docsmith-search');
|
|
8
8
|
export class SearchState {
|
|
9
9
|
open = $state(false);
|
|
10
|
+
/** Active version id on a versioned site; scopes results. `undefined` otherwise. */
|
|
11
|
+
version = $state(undefined);
|
|
10
12
|
}
|
|
11
13
|
/** Create the search state and publish it on context. Call in `DocsShell`. */
|
|
12
14
|
export function createSearchState() {
|
|
@@ -5,10 +5,16 @@ export type SearchResult = {
|
|
|
5
5
|
title: string;
|
|
6
6
|
section?: string;
|
|
7
7
|
snippet: string;
|
|
8
|
+
/** The page's version id, so a versioned site can scope results. */
|
|
9
|
+
version?: string;
|
|
8
10
|
};
|
|
9
11
|
export type SearchEngine = {
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Ranked results for `query`, at most `limit` (default 8). Pass `version` to
|
|
14
|
+
* return only that version's pages (over-fetches internally so the limit is
|
|
15
|
+
* still met after filtering).
|
|
16
|
+
*/
|
|
17
|
+
search(query: string, limit?: number, version?: string): SearchResult[];
|
|
12
18
|
};
|
|
13
19
|
/** Build a search engine over `docs`. Indexing is synchronous and one-time. */
|
|
14
20
|
export declare function createSearchEngine(docs: SearchDoc[]): SearchEngine;
|
|
@@ -32,23 +32,31 @@ export function createSearchEngine(docs) {
|
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
return {
|
|
35
|
-
search(query, limit = 8) {
|
|
35
|
+
search(query, limit = 8, version) {
|
|
36
36
|
const trimmed = query.trim();
|
|
37
37
|
if (!trimmed)
|
|
38
38
|
return [];
|
|
39
|
+
// When scoping to a version, over-fetch so the limit still holds after
|
|
40
|
+
// filtering out the other versions' hits.
|
|
41
|
+
const fetch = version ? limit * 5 : limit;
|
|
39
42
|
// `merge: true` returns unified, unique ids ranked across fields.
|
|
40
|
-
const hits = index.search(trimmed, { limit, merge: true });
|
|
43
|
+
const hits = index.search(trimmed, { limit: fetch, merge: true });
|
|
41
44
|
const results = [];
|
|
42
45
|
for (const { id } of hits) {
|
|
43
46
|
const doc = docs[id];
|
|
44
47
|
if (!doc)
|
|
45
48
|
continue;
|
|
49
|
+
if (version && doc.version !== version)
|
|
50
|
+
continue;
|
|
46
51
|
results.push({
|
|
47
52
|
path: doc.path,
|
|
48
53
|
title: doc.title,
|
|
49
54
|
section: doc.section,
|
|
50
|
-
snippet: buildSnippet(doc.text || doc.description || '', trimmed)
|
|
55
|
+
snippet: buildSnippet(doc.text || doc.description || '', trimmed),
|
|
56
|
+
version: doc.version
|
|
51
57
|
});
|
|
58
|
+
if (results.length >= limit)
|
|
59
|
+
break;
|
|
52
60
|
}
|
|
53
61
|
return results;
|
|
54
62
|
}
|
package/dist/theme.css
CHANGED
|
@@ -210,6 +210,27 @@
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
/*
|
|
214
|
+
* Reduced motion. When a reader asks the OS to minimise motion, neutralise the
|
|
215
|
+
* framework's movement in one place: the overlay slide/scale (dialog, sheet,
|
|
216
|
+
* popover, dropdown) and accordion height animations come from tw-animate-css,
|
|
217
|
+
* which ships no guard of its own, and those overlays portal to <body> — outside
|
|
218
|
+
* any shell wrapper — so the rule has to be global to reach them. Durations
|
|
219
|
+
* collapse to ~0 rather than `none` so the animation/transition *end* events
|
|
220
|
+
* bits-ui relies on to mount and unmount still fire. Opacity-only fades are the
|
|
221
|
+
* accessible alternative to motion and are intentionally left to play.
|
|
222
|
+
*/
|
|
223
|
+
@media (prefers-reduced-motion: reduce) {
|
|
224
|
+
*,
|
|
225
|
+
*::before,
|
|
226
|
+
*::after {
|
|
227
|
+
animation-duration: 0.01ms !important;
|
|
228
|
+
animation-iteration-count: 1 !important;
|
|
229
|
+
transition-duration: 0.01ms !important;
|
|
230
|
+
scroll-behavior: auto !important;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
213
234
|
/*
|
|
214
235
|
* Shiki dual-theme output: light colors are inline, dark colors ship as
|
|
215
236
|
* --shiki-dark/--shiki-dark-bg variables. Flip to them under `.dark`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-docsmith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A framework for building beautiful documentation sites with Svelte.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "George Daskalakis",
|
|
@@ -8,10 +8,15 @@
|
|
|
8
8
|
"url": "https://github.com/geodask"
|
|
9
9
|
},
|
|
10
10
|
"main": "dist/index.js",
|
|
11
|
+
"bin": {
|
|
12
|
+
"svelte-docsmith": "./bin/svelte-docsmith.mjs"
|
|
13
|
+
},
|
|
11
14
|
"files": [
|
|
12
15
|
"dist",
|
|
16
|
+
"bin",
|
|
13
17
|
"!dist/**/*.test.*",
|
|
14
|
-
"!dist/**/*.spec.*"
|
|
18
|
+
"!dist/**/*.spec.*",
|
|
19
|
+
"!dist/**/_fixtures/**"
|
|
15
20
|
],
|
|
16
21
|
"sideEffects": false,
|
|
17
22
|
"svelte": "./dist/index.js",
|