svelte-docsmith 0.13.0 → 0.14.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/README.md +30 -26
- package/dist/buildtime/archive.d.ts +4 -3
- package/dist/buildtime/archive.js +4 -3
- package/dist/buildtime/markdown-layout.svelte +3 -1
- package/dist/buildtime/markdown-layout.svelte.d.ts +2 -2
- package/dist/buildtime/vite/frontmatter.js +5 -3
- package/dist/components/chrome/background-pattern.svelte +22 -4
- package/dist/components/chrome/search-trigger.svelte +1 -0
- package/dist/components/chrome/search.svelte +64 -9
- package/dist/components/chrome/theme-toggle.svelte +5 -1
- package/dist/components/docs/badge.svelte +1 -7
- package/dist/components/landing/cta.svelte +15 -3
- package/dist/components/landing/cta.svelte.d.ts +6 -1
- package/dist/components/landing/feature-grid.svelte +4 -2
- package/dist/components/landing/feature.svelte +1 -1
- package/dist/components/landing/hero.svelte +2 -2
- package/dist/components/layouts/copy-page-menu.svelte +2 -2
- package/dist/components/layouts/docs-mobile-header.svelte +22 -4
- package/dist/components/layouts/docs-shell.svelte +5 -1
- package/dist/components/layouts/docs-sidebar.svelte +1 -1
- package/dist/components/layouts/page-feedback.svelte +44 -2
- package/dist/components/layouts/page-feedback.svelte.d.ts +4 -0
- package/dist/components/layouts/prev-next-nav.svelte +16 -4
- package/dist/components/shadcn/badge/badge.svelte.d.ts +2 -20
- package/dist/components/shadcn/button/button.svelte.d.ts +2 -40
- package/dist/components/shadcn/input-group/input-group-addon.svelte.d.ts +2 -16
- package/dist/components/shadcn/input-group/input-group-button.svelte.d.ts +2 -16
- package/dist/components/shadcn/input-group/input-group-input.svelte.d.ts +1 -1
- package/dist/components/shadcn/tabs/tabs-list.svelte.d.ts +2 -12
- package/dist/components/shadcn/textarea/textarea.svelte +1 -2
- package/dist/core/docs-page.d.ts +5 -4
- package/dist/core/docs-page.js +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/nav.d.ts +9 -4
- package/dist/core/nav.js +24 -5
- package/dist/core/version.js +1 -1
- package/dist/theme.css +8 -3
- package/dist/toc/toc.svelte.js +2 -0
- package/package.json +42 -37
package/README.md
CHANGED
|
@@ -42,50 +42,54 @@ To add DocSmith to an existing SvelteKit app, install the package instead:
|
|
|
42
42
|
npm install svelte-docsmith
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Peer dependencies: Svelte 5, SvelteKit 2, and Tailwind v4, set up the
|
|
46
|
-
way in your app.
|
|
45
|
+
Peer dependencies: Svelte 5, SvelteKit 2 or 3, and Tailwind v4, set up the
|
|
46
|
+
standard way in your app.
|
|
47
47
|
|
|
48
48
|
## Setup
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
Two small pieces, once.
|
|
51
51
|
|
|
52
|
-
**1.
|
|
53
|
-
|
|
54
|
-
fallback for unknown languages), heading anchors, and the packaged page layout:
|
|
52
|
+
**1. Vite.** Everything goes in `vite.config.ts`. DocSmith has two halves, both
|
|
53
|
+
called `docsmith()`:
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
extensions: ['.svelte', '.md'],
|
|
64
|
-
preprocess: [vitePreprocess(), docsmith()],
|
|
65
|
-
kit: { adapter: adapter() }
|
|
66
|
-
};
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**2. The Vite plugin.** In `vite.config.ts`, it scans your doc pages' frontmatter
|
|
70
|
-
into the `svelte-docsmith/content` module (so the sidebar is derived from
|
|
71
|
-
content, never hand-written), builds the search index, and powers `LiveExample`:
|
|
55
|
+
- The **Vite plugin** (`svelte-docsmith/vite`) scans your doc pages' frontmatter
|
|
56
|
+
into the `svelte-docsmith/content` module (so the sidebar is derived from
|
|
57
|
+
content, never hand-written), builds the search index, and powers
|
|
58
|
+
`LiveExample`. It goes before `sveltekit()`.
|
|
59
|
+
- The **markdown pipeline** (`svelte-docsmith/preprocess`) bundles mdsvex, Shiki
|
|
60
|
+
highlighting (dual light/dark themes, a generous language set, plain-text
|
|
61
|
+
fallback for unknown languages), heading anchors, and the packaged page layout.
|
|
72
62
|
|
|
73
63
|
```ts
|
|
74
64
|
// vite.config.ts
|
|
65
|
+
import adapter from '@sveltejs/adapter-auto';
|
|
75
66
|
import { sveltekit } from '@sveltejs/kit/vite';
|
|
67
|
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
76
68
|
import tailwindcss from '@tailwindcss/vite';
|
|
77
69
|
import { docsmith } from 'svelte-docsmith/vite';
|
|
70
|
+
import { docsmith as markdown } from 'svelte-docsmith/preprocess';
|
|
78
71
|
import { defineConfig } from 'vite';
|
|
79
72
|
|
|
80
73
|
export default defineConfig({
|
|
81
|
-
plugins: [
|
|
74
|
+
plugins: [
|
|
75
|
+
docsmith(),
|
|
76
|
+
tailwindcss(),
|
|
77
|
+
sveltekit({
|
|
78
|
+
extensions: ['.svelte', '.md'],
|
|
79
|
+
preprocess: [vitePreprocess(), markdown()],
|
|
80
|
+
adapter: adapter()
|
|
81
|
+
})
|
|
82
|
+
]
|
|
82
83
|
});
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
On SvelteKit 2, `extensions` and `preprocess` go in `svelte.config.js` instead,
|
|
87
|
+
and `sveltekit()` takes no options.
|
|
88
|
+
|
|
85
89
|
By default it scans `src/routes/docs`; pass `docsmith({ content: 'src/routes/guide' })`
|
|
86
90
|
to point elsewhere.
|
|
87
91
|
|
|
88
|
-
**
|
|
92
|
+
**2. The stylesheet.** In your root `app.css`, once Tailwind v4 is set up the
|
|
89
93
|
standard way (`tailwindcss` + the `@tailwindcss/vite` plugin, stylesheet imported
|
|
90
94
|
in the root layout), the whole style contract is one import:
|
|
91
95
|
|
|
@@ -157,8 +161,8 @@ plugin you already added:
|
|
|
157
161
|
```svelte
|
|
158
162
|
<script>
|
|
159
163
|
import { LiveExample } from 'svelte-docsmith';
|
|
160
|
-
import Counter from '
|
|
161
|
-
import counterSource from '
|
|
164
|
+
import Counter from '#lib/examples/counter.svelte';
|
|
165
|
+
import counterSource from '#lib/examples/counter.svelte?source';
|
|
162
166
|
</script>
|
|
163
167
|
|
|
164
168
|
<LiveExample source={counterSource}>
|
|
@@ -37,9 +37,10 @@ export declare function freezeLastUpdated(text: string, date: string | undefined
|
|
|
37
37
|
* Archiving copies the docs root and nothing else, so anything reached from
|
|
38
38
|
* outside it keeps resolving to current code: a live example on an archived
|
|
39
39
|
* page demonstrates the current library rather than the version the page
|
|
40
|
-
* documents, with a green build and nothing said. Hence `$lib
|
|
41
|
-
* specifiers and relative paths that climb out all count,
|
|
42
|
-
* import landing inside the docs root is frozen along with
|
|
40
|
+
* documents, with a green build and nothing said. Hence `$lib` (Kit 2), `#lib`
|
|
41
|
+
* (Kit 3), bare npm specifiers and relative paths that climb out all count,
|
|
42
|
+
* while a relative import landing inside the docs root is frozen along with
|
|
43
|
+
* the page.
|
|
43
44
|
*
|
|
44
45
|
* `svelte-docsmith` itself is never reported. An archived page importing the
|
|
45
46
|
* authoring components is the expected shape, and those are covered by the
|
|
@@ -85,9 +85,10 @@ function escapesRoot(specifier, depth) {
|
|
|
85
85
|
* Archiving copies the docs root and nothing else, so anything reached from
|
|
86
86
|
* outside it keeps resolving to current code: a live example on an archived
|
|
87
87
|
* page demonstrates the current library rather than the version the page
|
|
88
|
-
* documents, with a green build and nothing said. Hence `$lib
|
|
89
|
-
* specifiers and relative paths that climb out all count,
|
|
90
|
-
* import landing inside the docs root is frozen along with
|
|
88
|
+
* documents, with a green build and nothing said. Hence `$lib` (Kit 2), `#lib`
|
|
89
|
+
* (Kit 3), bare npm specifiers and relative paths that climb out all count,
|
|
90
|
+
* while a relative import landing inside the docs root is frozen along with
|
|
91
|
+
* the page.
|
|
91
92
|
*
|
|
92
93
|
* `svelte-docsmith` itself is never reported. An archived page importing the
|
|
93
94
|
* authoring components is the expected shape, and those are covered by the
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
}: { title?: string; description?: string; children: Snippet } = $props();
|
|
24
24
|
</script>
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
<!-- max-w-prose (~65ch) keeps body measure in the DESIGN.md 65–75ch band on
|
|
27
|
+
ultrawide screens; code blocks and not-prose widgets still overflow locally. -->
|
|
28
|
+
<article class="prose prose-base dark:prose-invert max-w-prose pb-16">
|
|
27
29
|
{#if title}
|
|
28
30
|
<h1>{title}</h1>
|
|
29
31
|
{/if}
|
|
@@ -7,8 +7,8 @@ export declare const pre: import("svelte").Component<{
|
|
|
7
7
|
export declare const code: import("svelte").Component<{
|
|
8
8
|
children: Snippet;
|
|
9
9
|
}, {}, "">;
|
|
10
|
-
export declare const h2: import("svelte").Component<import("../components/markdown/types.
|
|
11
|
-
export declare const h3: import("svelte").Component<import("../components/markdown/types.
|
|
10
|
+
export declare const h2: import("svelte").Component<import("../components/markdown/types.ts").HeadingProps, {}, "">;
|
|
11
|
+
export declare const h3: import("svelte").Component<import("../components/markdown/types.ts").HeadingProps, {}, "">;
|
|
12
12
|
export declare const table: import("svelte").Component<{
|
|
13
13
|
children: Snippet;
|
|
14
14
|
}, {}, "">;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { load as loadYaml } from 'js-yaml';
|
|
2
2
|
import { splitFrontmatter } from '../markdown-source.js';
|
|
3
3
|
/**
|
|
4
4
|
* Parse a page's leading YAML frontmatter block into a plain object. Returns an
|
|
@@ -11,11 +11,13 @@ export function parseFrontmatter(source, file) {
|
|
|
11
11
|
return {};
|
|
12
12
|
let data;
|
|
13
13
|
try {
|
|
14
|
-
data =
|
|
14
|
+
data = loadYaml(frontmatter);
|
|
15
15
|
}
|
|
16
16
|
catch (err) {
|
|
17
17
|
const reason = err instanceof Error ? err.message : String(err);
|
|
18
|
-
throw new Error(`[svelte-docsmith] invalid YAML frontmatter in ${file}\n${reason}
|
|
18
|
+
throw new Error(`[svelte-docsmith] invalid YAML frontmatter in ${file}\n${reason}`, {
|
|
19
|
+
cause: err
|
|
20
|
+
});
|
|
19
21
|
}
|
|
20
22
|
return data && typeof data === 'object' ? data : {};
|
|
21
23
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<!-- Decorative page background: a faint grid fading out from the top, with two
|
|
2
|
-
soft primary/accent glows.
|
|
2
|
+
soft primary/accent glows. Grid lines use --border so they track every theme
|
|
3
|
+
preset; render inside a `relative isolate` container. -->
|
|
3
4
|
<div
|
|
4
5
|
class="pointer-events-none absolute inset-0 -z-10 h-full w-full overflow-hidden"
|
|
5
6
|
aria-hidden="true"
|
|
6
7
|
>
|
|
7
|
-
<div
|
|
8
|
-
class="fixed inset-0 bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-size-[24px_24px] mask-[radial-gradient(ellipse_80%_80%_at_50%_0%,#000_70%,transparent_100%)]"
|
|
9
|
-
></div>
|
|
8
|
+
<div class="pattern-grid fixed inset-0"></div>
|
|
10
9
|
|
|
11
10
|
<div
|
|
12
11
|
class="bg-primary/20 pointer-events-none fixed top-0 left-1/2 h-[500px] w-[800px] -translate-x-1/2 rounded-full opacity-40 mix-blend-screen blur-[120px] dark:opacity-20 dark:mix-blend-normal"
|
|
@@ -15,3 +14,22 @@ soft primary/accent glows. Render it inside a `relative isolate` container. -->
|
|
|
15
14
|
class="bg-accent/25 pointer-events-none fixed top-28 left-1/2 h-[400px] w-[600px] -translate-x-1/2 rounded-full opacity-30 mix-blend-screen blur-[100px] dark:opacity-20 dark:mix-blend-normal"
|
|
16
15
|
></div>
|
|
17
16
|
</div>
|
|
17
|
+
|
|
18
|
+
<style>
|
|
19
|
+
.pattern-grid {
|
|
20
|
+
/* 24px cell; line colour follows the theme border token at low opacity. */
|
|
21
|
+
background-image:
|
|
22
|
+
linear-gradient(
|
|
23
|
+
to right,
|
|
24
|
+
color-mix(in oklch, var(--border) 70%, transparent) 1px,
|
|
25
|
+
transparent 1px
|
|
26
|
+
),
|
|
27
|
+
linear-gradient(
|
|
28
|
+
to bottom,
|
|
29
|
+
color-mix(in oklch, var(--border) 70%, transparent) 1px,
|
|
30
|
+
transparent 1px
|
|
31
|
+
);
|
|
32
|
+
background-size: 24px 24px;
|
|
33
|
+
mask-image: radial-gradient(ellipse 80% 80% at 50% 0%, #000 70%, transparent 100%);
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const search = useSearch();
|
|
8
8
|
|
|
9
9
|
// Resolve the modifier label client-side so SSR stays platform-neutral.
|
|
10
|
+
// eslint-disable-next-line svelte/prefer-writable-derived
|
|
10
11
|
let isMac = $state(false);
|
|
11
12
|
$effect(() => {
|
|
12
13
|
isMac = navigator.platform.toLowerCase().includes('mac');
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
let query = $state('');
|
|
36
36
|
let engine = $state<SearchEngine | null>(null);
|
|
37
|
+
let indexDocs = $state<SearchDoc[]>([]);
|
|
37
38
|
let status = $state<'idle' | 'loading' | 'error'>('idle');
|
|
38
39
|
// The version the cached engine was built for, so a loader that returns only
|
|
39
40
|
// one version's records is rebuilt when the reader switches versions. Stays
|
|
@@ -44,6 +45,27 @@
|
|
|
44
45
|
// Scope to the active version on a versioned site; `undefined` otherwise.
|
|
45
46
|
const results = $derived(engine && trimmed ? engine.search(query, undefined, activeVersion) : []);
|
|
46
47
|
|
|
48
|
+
// Empty-state starters: prefer common first pages when present, then fill
|
|
49
|
+
// from the rest of the index so a custom site still has something useful.
|
|
50
|
+
const suggestions = $derived.by(() => {
|
|
51
|
+
const scoped = activeVersion ? indexDocs.filter((d) => d.version === activeVersion) : indexDocs;
|
|
52
|
+
if (!scoped.length) return [];
|
|
53
|
+
const preferred = [/introduction/i, /quick[- ]?start/i, /install/i, /getting started/i];
|
|
54
|
+
const picked: SearchDoc[] = [];
|
|
55
|
+
for (const re of preferred) {
|
|
56
|
+
const hit = scoped.find(
|
|
57
|
+
(d) =>
|
|
58
|
+
!picked.includes(d) && (re.test(d.title) || re.test(d.path) || re.test(d.section ?? ''))
|
|
59
|
+
);
|
|
60
|
+
if (hit) picked.push(hit);
|
|
61
|
+
}
|
|
62
|
+
for (const d of scoped) {
|
|
63
|
+
if (picked.length >= 4) break;
|
|
64
|
+
if (!picked.includes(d)) picked.push(d);
|
|
65
|
+
}
|
|
66
|
+
return picked.slice(0, 4);
|
|
67
|
+
});
|
|
68
|
+
|
|
47
69
|
// Build the index the first time the palette opens; keep it for later opens.
|
|
48
70
|
async function ensureEngine() {
|
|
49
71
|
const version = activeVersion;
|
|
@@ -54,6 +76,7 @@
|
|
|
54
76
|
import('../../search/create-search.js'),
|
|
55
77
|
load(version)
|
|
56
78
|
]);
|
|
79
|
+
indexDocs = docs;
|
|
57
80
|
engine = createSearchEngine(docs);
|
|
58
81
|
engineVersion = version;
|
|
59
82
|
status = 'idle';
|
|
@@ -106,16 +129,48 @@
|
|
|
106
129
|
Search is unavailable right now.
|
|
107
130
|
</div>
|
|
108
131
|
{:else if !trimmed}
|
|
109
|
-
|
|
110
|
-
class="text-muted-foreground
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
{#if suggestions.length}
|
|
133
|
+
<p class="text-muted-foreground px-2.5 pb-1.5 text-xs font-medium tracking-wide">
|
|
134
|
+
Suggested
|
|
135
|
+
</p>
|
|
136
|
+
{#each suggestions as doc (doc.path)}
|
|
137
|
+
<Command.LinkItem
|
|
138
|
+
href={doc.path}
|
|
139
|
+
onSelect={() => select(doc.path)}
|
|
140
|
+
class="group/result mb-0.5 flex items-center gap-3 rounded-lg px-2.5 py-2 aria-selected:bg-accent aria-selected:text-accent-foreground"
|
|
141
|
+
>
|
|
142
|
+
<span
|
|
143
|
+
class="border-border/60 bg-muted/40 text-muted-foreground group-aria-selected/result:border-accent-foreground/20 group-aria-selected/result:text-accent-foreground flex size-8 shrink-0 items-center justify-center rounded-md border"
|
|
144
|
+
>
|
|
145
|
+
<FileText class="size-4" />
|
|
146
|
+
</span>
|
|
147
|
+
<span class="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
148
|
+
<span class="truncate font-medium">{doc.title}</span>
|
|
149
|
+
{#if doc.section}
|
|
150
|
+
<span
|
|
151
|
+
class="text-muted-foreground group-aria-selected/result:text-accent-foreground/80 text-xs"
|
|
152
|
+
>
|
|
153
|
+
{doc.section}
|
|
154
|
+
</span>
|
|
155
|
+
{/if}
|
|
156
|
+
</span>
|
|
157
|
+
<CornerDownLeft
|
|
158
|
+
class="text-muted-foreground group-aria-selected/result:text-accent-foreground size-4 shrink-0 opacity-0 group-aria-selected/result:opacity-100"
|
|
159
|
+
/>
|
|
160
|
+
</Command.LinkItem>
|
|
161
|
+
{/each}
|
|
162
|
+
{:else}
|
|
163
|
+
<div
|
|
164
|
+
class="text-muted-foreground flex flex-col items-center gap-3 px-4 py-10 text-center text-sm"
|
|
114
165
|
>
|
|
115
|
-
<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
166
|
+
<span
|
|
167
|
+
class="bg-muted/60 text-muted-foreground flex size-11 items-center justify-center rounded-full"
|
|
168
|
+
>
|
|
169
|
+
<SearchIcon class="size-5" />
|
|
170
|
+
</span>
|
|
171
|
+
<span>Search across every page of the documentation.</span>
|
|
172
|
+
</div>
|
|
173
|
+
{/if}
|
|
119
174
|
{:else if results.length === 0}
|
|
120
175
|
<div class="text-muted-foreground px-4 py-10 text-center text-sm">
|
|
121
176
|
No results for <span class="text-foreground font-medium">“{trimmed}”</span>.
|
|
@@ -5,12 +5,17 @@
|
|
|
5
5
|
import { mode, toggleMode } from 'mode-watcher';
|
|
6
6
|
|
|
7
7
|
const { class: className }: { class?: string } = $props();
|
|
8
|
+
|
|
9
|
+
// Label names the destination mode so the control is self-describing for
|
|
10
|
+
// assistive tech and matches what the icon shows (sun = go light, moon = go dark).
|
|
11
|
+
const label = $derived(mode.current === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
|
|
8
12
|
</script>
|
|
9
13
|
|
|
10
14
|
<Button
|
|
11
15
|
size="icon"
|
|
12
16
|
variant="ghost"
|
|
13
17
|
onclick={toggleMode}
|
|
18
|
+
aria-label={label}
|
|
14
19
|
class="text-muted-foreground hover:text-foreground size-8 {className ?? ''}"
|
|
15
20
|
>
|
|
16
21
|
{#if mode.current === 'dark'}
|
|
@@ -18,5 +23,4 @@
|
|
|
18
23
|
{:else}
|
|
19
24
|
<Moon class="size-4" />
|
|
20
25
|
{/if}
|
|
21
|
-
<span class="sr-only">Toggle theme</span>
|
|
22
26
|
</Button>
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
export type BadgeVariant =
|
|
3
|
-
| '
|
|
4
|
-
| 'primary'
|
|
5
|
-
| 'secondary'
|
|
6
|
-
| 'success'
|
|
7
|
-
| 'warning'
|
|
8
|
-
| 'danger'
|
|
9
|
-
| 'outline';
|
|
3
|
+
'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'outline';
|
|
10
4
|
</script>
|
|
11
5
|
|
|
12
6
|
<script lang="ts">
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
title,
|
|
6
6
|
description,
|
|
7
7
|
actions,
|
|
8
|
+
before,
|
|
8
9
|
children
|
|
9
10
|
}: {
|
|
10
11
|
title: string;
|
|
@@ -12,7 +13,12 @@
|
|
|
12
13
|
description?: string;
|
|
13
14
|
/** Call-to-action buttons. */
|
|
14
15
|
actions?: Snippet;
|
|
15
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Optional content above the heading (e.g. a pre-release note). Placed
|
|
18
|
+
* before the title so the section can still *end* on the actions.
|
|
19
|
+
*/
|
|
20
|
+
before?: Snippet;
|
|
21
|
+
/** Anything to sit below the actions, e.g. a secondary note. */
|
|
16
22
|
children?: Snippet;
|
|
17
23
|
} = $props();
|
|
18
24
|
</script>
|
|
@@ -29,12 +35,18 @@
|
|
|
29
35
|
></div>
|
|
30
36
|
</div>
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
{#if before}
|
|
39
|
+
<div class="mx-auto mb-8 max-w-xl text-left">{@render before()}</div>
|
|
40
|
+
{/if}
|
|
41
|
+
|
|
42
|
+
<h2
|
|
43
|
+
class="font-serif mx-auto max-w-2xl text-3xl font-semibold tracking-tight text-balance sm:text-4xl"
|
|
44
|
+
>
|
|
33
45
|
{title}
|
|
34
46
|
</h2>
|
|
35
47
|
|
|
36
48
|
{#if description}
|
|
37
|
-
<p class="text-
|
|
49
|
+
<p class="text-foreground mx-auto mt-4 max-w-xl text-lg leading-relaxed text-pretty">
|
|
38
50
|
{description}
|
|
39
51
|
</p>
|
|
40
52
|
{/if}
|
|
@@ -5,7 +5,12 @@ type $$ComponentProps = {
|
|
|
5
5
|
description?: string;
|
|
6
6
|
/** Call-to-action buttons. */
|
|
7
7
|
actions?: Snippet;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Optional content above the heading (e.g. a pre-release note). Placed
|
|
10
|
+
* before the title so the section can still *end* on the actions.
|
|
11
|
+
*/
|
|
12
|
+
before?: Snippet;
|
|
13
|
+
/** Anything to sit below the actions, e.g. a secondary note. */
|
|
9
14
|
children?: Snippet;
|
|
10
15
|
};
|
|
11
16
|
declare const Cta: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -29,10 +29,12 @@
|
|
|
29
29
|
{#if title || description}
|
|
30
30
|
<div class="mx-auto max-w-2xl text-center">
|
|
31
31
|
{#if title}
|
|
32
|
-
<h2 class="text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
|
32
|
+
<h2 class="font-serif text-3xl font-semibold tracking-tight text-balance sm:text-4xl">
|
|
33
|
+
{title}
|
|
34
|
+
</h2>
|
|
33
35
|
{/if}
|
|
34
36
|
{#if description}
|
|
35
|
-
<p class="text-
|
|
37
|
+
<p class="text-foreground mt-4 text-lg leading-relaxed text-pretty">
|
|
36
38
|
{description}
|
|
37
39
|
</p>
|
|
38
40
|
{/if}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<div class="min-w-0">
|
|
28
28
|
<h3 class="font-semibold">{title}</h3>
|
|
29
29
|
{#if children}
|
|
30
|
-
<p class="text-
|
|
30
|
+
<p class="text-foreground/80 mt-1 text-sm leading-relaxed">{@render children()}</p>
|
|
31
31
|
{/if}
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
{/if}
|
|
41
41
|
|
|
42
42
|
<h1
|
|
43
|
-
class="text-5xl font-semibold tracking-[-0.03em] text-balance sm:text-6xl lg:text-[4.25rem] lg:leading-[1.02] {eyebrow
|
|
43
|
+
class="font-serif text-5xl font-semibold tracking-[-0.03em] text-balance sm:text-6xl lg:text-[4.25rem] lg:leading-[1.02] {eyebrow
|
|
44
44
|
? 'mt-6'
|
|
45
45
|
: ''}"
|
|
46
46
|
>
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
|
|
50
50
|
{#if description}
|
|
51
51
|
<p
|
|
52
|
-
class="text-
|
|
52
|
+
class="text-foreground mt-6 max-w-xl text-lg leading-relaxed text-pretty {media
|
|
53
53
|
? ''
|
|
54
54
|
: 'mx-auto'}"
|
|
55
55
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { BROWSER } from 'esm-env';
|
|
3
3
|
import { Button } from '../shadcn/button/index.js';
|
|
4
4
|
import * as DropdownMenu from '../shadcn/dropdown-menu/index.js';
|
|
5
5
|
import Check from '@lucide/svelte/icons/check';
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
const mdHref = $derived(`${path}.md`);
|
|
25
25
|
// Before hydration with no configured origin there is nothing to prefix, and
|
|
26
26
|
// `join` leaves the link site-relative rather than mangling it.
|
|
27
|
-
const absoluteMd = $derived(join(origin || (
|
|
27
|
+
const absoluteMd = $derived(join(origin || (BROWSER ? location.origin : ''), mdHref));
|
|
28
28
|
const prompt = $derived(`Read ${absoluteMd} so I can ask questions about this page.`);
|
|
29
29
|
const chatgptHref = $derived(`https://chatgpt.com/?hints=search&q=${encodeURIComponent(prompt)}`);
|
|
30
30
|
const claudeHref = $derived(`https://claude.ai/new?q=${encodeURIComponent(prompt)}`);
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
import * as Sheet from '../shadcn/sheet/index.js';
|
|
14
14
|
import { useSearch } from '../../search/context.svelte.js';
|
|
15
15
|
import { useDocsPage } from '../docs-page-context.js';
|
|
16
|
+
import GithubIcon from '../icons/github.svelte';
|
|
16
17
|
import BookOpenText from '@lucide/svelte/icons/book-open-text';
|
|
18
|
+
import List from '@lucide/svelte/icons/list';
|
|
17
19
|
import Menu from '@lucide/svelte/icons/menu';
|
|
18
|
-
import PanelRight from '@lucide/svelte/icons/panel-right';
|
|
19
20
|
import SearchIcon from '@lucide/svelte/icons/search';
|
|
20
21
|
import type { Snippet } from 'svelte';
|
|
21
22
|
|
|
@@ -124,15 +125,32 @@
|
|
|
124
125
|
</Button>
|
|
125
126
|
{/if}
|
|
126
127
|
|
|
128
|
+
{#if config.github}
|
|
129
|
+
<Button
|
|
130
|
+
size="icon"
|
|
131
|
+
variant="ghost"
|
|
132
|
+
target="_blank"
|
|
133
|
+
rel="noopener noreferrer"
|
|
134
|
+
href={config.github}
|
|
135
|
+
class="text-muted-foreground hover:text-foreground size-8"
|
|
136
|
+
>
|
|
137
|
+
<GithubIcon class="size-4" />
|
|
138
|
+
<span class="sr-only">GitHub</span>
|
|
139
|
+
</Button>
|
|
140
|
+
{/if}
|
|
141
|
+
|
|
127
142
|
<ThemeToggle />
|
|
128
143
|
|
|
129
144
|
{#if tocItems.length > 0}
|
|
130
145
|
<Popover.Root bind:open={isTocOpen}>
|
|
131
146
|
<Popover.Trigger>
|
|
132
147
|
{#snippet child({ props })}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
148
|
+
<!-- Labeled (not icon-only) so first-timers find "on this page"
|
|
149
|
+
without guessing PanelRight. Label collapses on the narrowest
|
|
150
|
+
phones so the title still has room. -->
|
|
151
|
+
<Button variant="ghost" size="sm" class="h-8 gap-1.5 px-2" {...props}>
|
|
152
|
+
<List class="size-4 shrink-0" />
|
|
153
|
+
<span class="text-xs font-medium max-[22rem]:sr-only">On this page</span>
|
|
136
154
|
</Button>
|
|
137
155
|
{/snippet}
|
|
138
156
|
</Popover.Trigger>
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
readingTime && view.readingMinutes ? `${view.readingMinutes} min read` : undefined
|
|
152
152
|
);
|
|
153
153
|
|
|
154
|
-
const breadcrumbs = $derived(view.breadcrumbs
|
|
154
|
+
const breadcrumbs = $derived(view.breadcrumbs);
|
|
155
155
|
|
|
156
156
|
// The archived-version banner, or nothing. Its "view this page in <current>"
|
|
157
157
|
// link is the current version's entry in the same list the switcher renders,
|
|
@@ -286,6 +286,10 @@
|
|
|
286
286
|
<PageFeedback
|
|
287
287
|
path={view.pathname}
|
|
288
288
|
onfeedback={typeof feedback === 'function' ? feedback : undefined}
|
|
289
|
+
editHref={view.editHref}
|
|
290
|
+
issueHref={config.github
|
|
291
|
+
? `${config.github}/issues/new?title=${encodeURIComponent(`Feedback: ${view.title}`)}&body=${encodeURIComponent(`Page: ${view.pathname}\n\n<!-- What was unclear or missing? -->\n`)}`
|
|
292
|
+
: undefined}
|
|
289
293
|
/>
|
|
290
294
|
</div>
|
|
291
295
|
{/key}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
href={node.url}
|
|
44
44
|
aria-current={current === node.url ? 'page' : undefined}
|
|
45
45
|
class={cn(
|
|
46
|
-
'hover:text-primary hover:bg-primary/
|
|
46
|
+
'hover:text-primary hover:bg-primary/10 block rounded-md px-2 py-1.5 text-sm transition-colors',
|
|
47
47
|
current === node.url
|
|
48
48
|
? 'text-primary bg-primary/20 font-medium'
|
|
49
49
|
: 'text-muted-foreground'
|
|
@@ -2,19 +2,29 @@
|
|
|
2
2
|
import { Button } from '../shadcn/button/index.js';
|
|
3
3
|
import ThumbsUp from '@lucide/svelte/icons/thumbs-up';
|
|
4
4
|
import ThumbsDown from '@lucide/svelte/icons/thumbs-down';
|
|
5
|
+
import SquarePen from '@lucide/svelte/icons/square-pen';
|
|
6
|
+
import ExternalLink from '@lucide/svelte/icons/external-link';
|
|
5
7
|
|
|
6
8
|
const {
|
|
7
9
|
path,
|
|
8
|
-
onfeedback
|
|
10
|
+
onfeedback,
|
|
11
|
+
editHref,
|
|
12
|
+
issueHref
|
|
9
13
|
}: {
|
|
10
14
|
/** The current page path, passed to the callback so it can attribute votes. */
|
|
11
15
|
path: string;
|
|
12
16
|
/** Called once per page when the reader votes; wire it to your analytics. */
|
|
13
17
|
onfeedback?: (vote: 'up' | 'down', path: string) => void;
|
|
18
|
+
/** "Edit this page" target — offered after a "No" vote when present. */
|
|
19
|
+
editHref?: string;
|
|
20
|
+
/** "Open an issue" target — offered after a "No" vote when present. */
|
|
21
|
+
issueHref?: string;
|
|
14
22
|
} = $props();
|
|
15
23
|
|
|
16
24
|
let vote = $state<'up' | 'down' | null>(null);
|
|
17
25
|
|
|
26
|
+
const hasRecovery = $derived(Boolean(editHref || issueHref));
|
|
27
|
+
|
|
18
28
|
function cast(value: 'up' | 'down') {
|
|
19
29
|
if (vote) return;
|
|
20
30
|
vote = value;
|
|
@@ -23,8 +33,40 @@
|
|
|
23
33
|
</script>
|
|
24
34
|
|
|
25
35
|
<div class="flex flex-col items-center gap-2.5 text-center">
|
|
26
|
-
{#if vote}
|
|
36
|
+
{#if vote === 'up'}
|
|
27
37
|
<p class="text-muted-foreground text-sm">Thanks for your feedback!</p>
|
|
38
|
+
{:else if vote === 'down'}
|
|
39
|
+
<p class="text-muted-foreground text-sm">
|
|
40
|
+
{hasRecovery ? 'Thanks — want to help improve this page?' : 'Thanks for your feedback!'}
|
|
41
|
+
</p>
|
|
42
|
+
{#if hasRecovery}
|
|
43
|
+
<div class="flex flex-wrap items-center justify-center gap-2">
|
|
44
|
+
{#if editHref}
|
|
45
|
+
<Button
|
|
46
|
+
variant="outline"
|
|
47
|
+
size="sm"
|
|
48
|
+
href={editHref}
|
|
49
|
+
target="_blank"
|
|
50
|
+
rel="noopener noreferrer"
|
|
51
|
+
>
|
|
52
|
+
<SquarePen />
|
|
53
|
+
Edit this page
|
|
54
|
+
</Button>
|
|
55
|
+
{/if}
|
|
56
|
+
{#if issueHref}
|
|
57
|
+
<Button
|
|
58
|
+
variant="outline"
|
|
59
|
+
size="sm"
|
|
60
|
+
href={issueHref}
|
|
61
|
+
target="_blank"
|
|
62
|
+
rel="noopener noreferrer"
|
|
63
|
+
>
|
|
64
|
+
<ExternalLink />
|
|
65
|
+
Open an issue
|
|
66
|
+
</Button>
|
|
67
|
+
{/if}
|
|
68
|
+
</div>
|
|
69
|
+
{/if}
|
|
28
70
|
{:else}
|
|
29
71
|
<p class="text-muted-foreground text-sm">Was this page helpful?</p>
|
|
30
72
|
<div class="flex items-center gap-2">
|
|
@@ -3,6 +3,10 @@ type $$ComponentProps = {
|
|
|
3
3
|
path: string;
|
|
4
4
|
/** Called once per page when the reader votes; wire it to your analytics. */
|
|
5
5
|
onfeedback?: (vote: 'up' | 'down', path: string) => void;
|
|
6
|
+
/** "Edit this page" target — offered after a "No" vote when present. */
|
|
7
|
+
editHref?: string;
|
|
8
|
+
/** "Open an issue" target — offered after a "No" vote when present. */
|
|
9
|
+
issueHref?: string;
|
|
6
10
|
};
|
|
7
11
|
declare const PageFeedback: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
12
|
type PageFeedback = ReturnType<typeof PageFeedback>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { NavItem } from '../../core/index.js';
|
|
3
|
+
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
|
|
4
|
+
import ChevronRight from '@lucide/svelte/icons/chevron-right';
|
|
3
5
|
|
|
4
6
|
const {
|
|
5
7
|
prev,
|
|
@@ -16,9 +18,14 @@
|
|
|
16
18
|
{#if prev}
|
|
17
19
|
<a
|
|
18
20
|
href={prev.url}
|
|
19
|
-
class="border-border hover:border-primary flex min-w-0 flex-1 flex-col gap-1 rounded-lg border p-4 transition-colors"
|
|
21
|
+
class="border-border hover:border-primary/60 hover:bg-primary/5 group flex min-w-0 flex-1 flex-col gap-1 rounded-lg border p-4 transition-colors"
|
|
20
22
|
>
|
|
21
|
-
<span
|
|
23
|
+
<span
|
|
24
|
+
class="text-muted-foreground group-hover:text-primary flex items-center gap-1 text-xs"
|
|
25
|
+
>
|
|
26
|
+
<ChevronLeft class="size-3.5" aria-hidden="true" />
|
|
27
|
+
Previous
|
|
28
|
+
</span>
|
|
22
29
|
<span class="text-foreground truncate font-medium">{prev.title}</span>
|
|
23
30
|
</a>
|
|
24
31
|
{:else}
|
|
@@ -27,9 +34,14 @@
|
|
|
27
34
|
{#if next}
|
|
28
35
|
<a
|
|
29
36
|
href={next.url}
|
|
30
|
-
class="border-border hover:border-primary ml-auto flex min-w-0 flex-1 flex-col gap-1 rounded-lg border p-4 text-right transition-colors"
|
|
37
|
+
class="border-border hover:border-primary/60 hover:bg-primary/5 group ml-auto flex min-w-0 flex-1 flex-col items-end gap-1 rounded-lg border p-4 text-right transition-colors"
|
|
31
38
|
>
|
|
32
|
-
<span
|
|
39
|
+
<span
|
|
40
|
+
class="text-muted-foreground group-hover:text-primary flex items-center gap-1 text-xs"
|
|
41
|
+
>
|
|
42
|
+
Next
|
|
43
|
+
<ChevronRight class="size-3.5" aria-hidden="true" />
|
|
44
|
+
</span>
|
|
33
45
|
<span class="text-foreground truncate font-medium">{next.title}</span>
|
|
34
46
|
</a>
|
|
35
47
|
{:else}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
-
export declare const badgeVariants: import("tailwind-variants").
|
|
2
|
+
export declare const badgeVariants: import("tailwind-variants/dist/types-BNulpdf_.cjs").s<{
|
|
3
3
|
variant: {
|
|
4
4
|
default: string;
|
|
5
5
|
secondary: string;
|
|
@@ -8,25 +8,7 @@ export declare const badgeVariants: import("tailwind-variants").TVReturnType<{
|
|
|
8
8
|
ghost: string;
|
|
9
9
|
link: string;
|
|
10
10
|
};
|
|
11
|
-
}, undefined, "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-colors focus-visible:ring-[3px] [&>svg]:pointer-events-none",
|
|
12
|
-
variant: {
|
|
13
|
-
default: string;
|
|
14
|
-
secondary: string;
|
|
15
|
-
destructive: string;
|
|
16
|
-
outline: string;
|
|
17
|
-
ghost: string;
|
|
18
|
-
link: string;
|
|
19
|
-
};
|
|
20
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
21
|
-
variant: {
|
|
22
|
-
default: string;
|
|
23
|
-
secondary: string;
|
|
24
|
-
destructive: string;
|
|
25
|
-
outline: string;
|
|
26
|
-
ghost: string;
|
|
27
|
-
link: string;
|
|
28
|
-
};
|
|
29
|
-
}, undefined, "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-colors focus-visible:ring-[3px] [&>svg]:pointer-events-none", unknown, unknown, undefined>>;
|
|
11
|
+
}, undefined, "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-colors focus-visible:ring-[3px] [&>svg]:pointer-events-none", undefined, undefined, undefined>;
|
|
30
12
|
export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
|
|
31
13
|
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
32
14
|
import { type WithElementRef } from '../../../utils/cn.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type WithElementRef } from '../../../utils/cn.js';
|
|
2
2
|
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
3
3
|
import { type VariantProps } from 'tailwind-variants';
|
|
4
|
-
export declare const buttonVariants: import("tailwind-variants").
|
|
4
|
+
export declare const buttonVariants: import("tailwind-variants/dist/types-BNulpdf_.cjs").s<{
|
|
5
5
|
variant: {
|
|
6
6
|
default: string;
|
|
7
7
|
outline: string;
|
|
@@ -20,45 +20,7 @@ export declare const buttonVariants: import("tailwind-variants").TVReturnType<{
|
|
|
20
20
|
'icon-sm': string;
|
|
21
21
|
'icon-lg': string;
|
|
22
22
|
};
|
|
23
|
-
}, undefined, "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 active:not-aria-[haspopup]:translate-y-px aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
24
|
-
variant: {
|
|
25
|
-
default: string;
|
|
26
|
-
outline: string;
|
|
27
|
-
secondary: string;
|
|
28
|
-
ghost: string;
|
|
29
|
-
destructive: string;
|
|
30
|
-
link: string;
|
|
31
|
-
};
|
|
32
|
-
size: {
|
|
33
|
-
default: string;
|
|
34
|
-
xs: string;
|
|
35
|
-
sm: string;
|
|
36
|
-
lg: string;
|
|
37
|
-
icon: string;
|
|
38
|
-
'icon-xs': string;
|
|
39
|
-
'icon-sm': string;
|
|
40
|
-
'icon-lg': string;
|
|
41
|
-
};
|
|
42
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
43
|
-
variant: {
|
|
44
|
-
default: string;
|
|
45
|
-
outline: string;
|
|
46
|
-
secondary: string;
|
|
47
|
-
ghost: string;
|
|
48
|
-
destructive: string;
|
|
49
|
-
link: string;
|
|
50
|
-
};
|
|
51
|
-
size: {
|
|
52
|
-
default: string;
|
|
53
|
-
xs: string;
|
|
54
|
-
sm: string;
|
|
55
|
-
lg: string;
|
|
56
|
-
icon: string;
|
|
57
|
-
'icon-xs': string;
|
|
58
|
-
'icon-sm': string;
|
|
59
|
-
'icon-lg': string;
|
|
60
|
-
};
|
|
61
|
-
}, undefined, "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 active:not-aria-[haspopup]:translate-y-px aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", unknown, unknown, undefined>>;
|
|
23
|
+
}, undefined, "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 active:not-aria-[haspopup]:translate-y-px aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", undefined, undefined, undefined>;
|
|
62
24
|
export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
|
|
63
25
|
export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
|
|
64
26
|
export type ButtonProps = WithElementRef<HTMLButtonAttributes> & WithElementRef<HTMLAnchorAttributes> & {
|
|
@@ -1,26 +1,12 @@
|
|
|
1
1
|
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
-
export declare const inputGroupAddonVariants: import("tailwind-variants").
|
|
2
|
+
export declare const inputGroupAddonVariants: import("tailwind-variants/dist/types-BNulpdf_.cjs").s<{
|
|
3
3
|
align: {
|
|
4
4
|
'inline-start': string;
|
|
5
5
|
'inline-end': string;
|
|
6
6
|
'block-start': string;
|
|
7
7
|
'block-end': string;
|
|
8
8
|
};
|
|
9
|
-
}, undefined, "text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none",
|
|
10
|
-
align: {
|
|
11
|
-
'inline-start': string;
|
|
12
|
-
'inline-end': string;
|
|
13
|
-
'block-start': string;
|
|
14
|
-
'block-end': string;
|
|
15
|
-
};
|
|
16
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
17
|
-
align: {
|
|
18
|
-
'inline-start': string;
|
|
19
|
-
'inline-end': string;
|
|
20
|
-
'block-start': string;
|
|
21
|
-
'block-end': string;
|
|
22
|
-
};
|
|
23
|
-
}, undefined, "text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none", unknown, unknown, undefined>>;
|
|
9
|
+
}, undefined, "text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none", undefined, undefined, undefined>;
|
|
24
10
|
export type InputGroupAddonAlign = VariantProps<typeof inputGroupAddonVariants>['align'];
|
|
25
11
|
import { type WithElementRef } from '../../../utils/cn.js';
|
|
26
12
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
@@ -1,26 +1,12 @@
|
|
|
1
1
|
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
-
declare const inputGroupButtonVariants: import("tailwind-variants").
|
|
2
|
+
declare const inputGroupButtonVariants: import("tailwind-variants/dist/types-BNulpdf_.cjs").s<{
|
|
3
3
|
size: {
|
|
4
4
|
xs: string;
|
|
5
5
|
sm: string;
|
|
6
6
|
'icon-xs': string;
|
|
7
7
|
'icon-sm': string;
|
|
8
8
|
};
|
|
9
|
-
}, undefined, "gap-2 text-sm flex items-center shadow-none",
|
|
10
|
-
size: {
|
|
11
|
-
xs: string;
|
|
12
|
-
sm: string;
|
|
13
|
-
'icon-xs': string;
|
|
14
|
-
'icon-sm': string;
|
|
15
|
-
};
|
|
16
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
17
|
-
size: {
|
|
18
|
-
xs: string;
|
|
19
|
-
sm: string;
|
|
20
|
-
'icon-xs': string;
|
|
21
|
-
'icon-sm': string;
|
|
22
|
-
};
|
|
23
|
-
}, undefined, "gap-2 text-sm flex items-center shadow-none", unknown, unknown, undefined>>;
|
|
9
|
+
}, undefined, "gap-2 text-sm flex items-center shadow-none", undefined, undefined, undefined>;
|
|
24
10
|
export type InputGroupButtonSize = VariantProps<typeof inputGroupButtonVariants>['size'];
|
|
25
11
|
import type { ComponentProps } from 'svelte';
|
|
26
12
|
import { Button } from '../button/index.js';
|
|
@@ -2,7 +2,7 @@ declare const InputGroupInput: import("svelte").Component<(Omit<import("svelte/e
|
|
|
2
2
|
type: "file";
|
|
3
3
|
files?: FileList;
|
|
4
4
|
} | {
|
|
5
|
-
type?: "number" | "
|
|
5
|
+
type?: "number" | "hidden" | "color" | "submit" | "reset" | "button" | "search" | "checkbox" | "radio" | (string & {}) | "text" | "tel" | "url" | "email" | "date" | "datetime-local" | "image" | "month" | "password" | "range" | "time" | "week";
|
|
6
6
|
files?: undefined;
|
|
7
7
|
})) & {
|
|
8
8
|
ref?: HTMLElement | null | undefined;
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
import { type VariantProps } from 'tailwind-variants';
|
|
2
|
-
export declare const tabsListVariants: import("tailwind-variants").
|
|
2
|
+
export declare const tabsListVariants: import("tailwind-variants/dist/types-BNulpdf_.cjs").s<{
|
|
3
3
|
variant: {
|
|
4
4
|
default: string;
|
|
5
5
|
line: string;
|
|
6
6
|
};
|
|
7
|
-
}, undefined, "rounded-lg p-[3px] group-data-horizontal/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col",
|
|
8
|
-
variant: {
|
|
9
|
-
default: string;
|
|
10
|
-
line: string;
|
|
11
|
-
};
|
|
12
|
-
}, undefined, import("tailwind-variants").TVReturnType<{
|
|
13
|
-
variant: {
|
|
14
|
-
default: string;
|
|
15
|
-
line: string;
|
|
16
|
-
};
|
|
17
|
-
}, undefined, "rounded-lg p-[3px] group-data-horizontal/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col", unknown, unknown, undefined>>;
|
|
7
|
+
}, undefined, "rounded-lg p-[3px] group-data-horizontal/tabs:h-9 data-[variant=line]:rounded-none group/tabs-list text-muted-foreground inline-flex w-fit items-center justify-center group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col", undefined, undefined, undefined>;
|
|
18
8
|
export type TabsListVariant = VariantProps<typeof tabsListVariants>['variant'];
|
|
19
9
|
import { Tabs as TabsPrimitive } from 'bits-ui';
|
|
20
10
|
type $$ComponentProps = TabsPrimitive.ListProps & {
|
package/dist/core/docs-page.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* component that renders them.
|
|
10
10
|
*/
|
|
11
11
|
import type { DocsContentItem } from './content.js';
|
|
12
|
-
import { type NavGroup, type NavItem } from './nav.js';
|
|
12
|
+
import { type Breadcrumb, type NavGroup, type NavItem } from './nav.js';
|
|
13
13
|
import { type ResolvedVersion } from './version.js';
|
|
14
14
|
/** The page's build-time headings, as extracted into the content index. */
|
|
15
15
|
type PageToc = NonNullable<DocsContentItem['toc']>;
|
|
@@ -56,10 +56,11 @@ export type DocsPageView = {
|
|
|
56
56
|
/** The page's nav title, falling back to the site title off the nav tree. */
|
|
57
57
|
title: string;
|
|
58
58
|
/**
|
|
59
|
-
* Breadcrumb
|
|
60
|
-
*
|
|
59
|
+
* Breadcrumb trail: group steps (with a jump URL to the group's first page),
|
|
60
|
+
* then the current page as a title-only final crumb. No component types
|
|
61
|
+
* here — the shell maps this onto its `Crumb` shape.
|
|
61
62
|
*/
|
|
62
|
-
breadcrumbs:
|
|
63
|
+
breadcrumbs: Breadcrumb[];
|
|
63
64
|
/** The page's server-rendered TOC, from {@link entry}. */
|
|
64
65
|
toc: PageToc;
|
|
65
66
|
/**
|
package/dist/core/docs-page.js
CHANGED
|
@@ -24,7 +24,7 @@ export function resolveDocsPage(input) {
|
|
|
24
24
|
const title = pageIndex >= 0 ? flatNav[pageIndex].title : siteTitle;
|
|
25
25
|
const breadcrumbs = navTrail(nav, pathname) ?? [];
|
|
26
26
|
if (pageIndex >= 0)
|
|
27
|
-
breadcrumbs.push(title);
|
|
27
|
+
breadcrumbs.push({ title });
|
|
28
28
|
return {
|
|
29
29
|
pathname,
|
|
30
30
|
activeVersion: active,
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { defineConfig, type DocsmithConfig, type DocsmithLink, type DocsmithFooterColumn, type DocsmithAnnouncement } from './config.js';
|
|
2
2
|
export type { DocsContentItem, SearchDoc, LlmsDoc } from './content.js';
|
|
3
3
|
export { resolveVersions, activeVersion, currentVersion, currentOnly, scopeContent, mapPathToVersion, type DocsVersion, type DocsVersions, type ResolvedVersion } from './version.js';
|
|
4
|
-
export { navFromContent, flattenNav, navTrail, isNavGroup, type NavItem, type NavGroup, type NavNode } from './nav.js';
|
|
4
|
+
export { navFromContent, flattenNav, navTrail, type Breadcrumb, isNavGroup, type NavItem, type NavGroup, type NavNode } from './nav.js';
|
|
5
5
|
export { resolveDocsPage, type DocsPageView, type VersionLink } from './docs-page.js';
|
package/dist/core/nav.d.ts
CHANGED
|
@@ -26,9 +26,14 @@ export declare function navFromContent(content: DocsContentItem[]): NavGroup[];
|
|
|
26
26
|
* for the prev/next pager.
|
|
27
27
|
*/
|
|
28
28
|
export declare function flattenNav(nodes: NavNode[]): NavItem[];
|
|
29
|
+
/** One step in a breadcrumb trail: a label, and an optional jump target. */
|
|
30
|
+
export type Breadcrumb = {
|
|
31
|
+
title: string;
|
|
32
|
+
url?: string;
|
|
33
|
+
};
|
|
29
34
|
/**
|
|
30
|
-
* The trail of
|
|
31
|
-
*
|
|
32
|
-
*
|
|
35
|
+
* The trail of groups leading to the page at `url` (top group first, excluding
|
|
36
|
+
* the page itself), or `undefined` if the page is not in the tree. Each group
|
|
37
|
+
* step carries a `url` to its first leaf so breadcrumbs are navigable.
|
|
33
38
|
*/
|
|
34
|
-
export declare function navTrail(nodes: NavNode[], url: string):
|
|
39
|
+
export declare function navTrail(nodes: NavNode[], url: string): Breadcrumb[] | undefined;
|
package/dist/core/nav.js
CHANGED
|
@@ -82,16 +82,35 @@ export function flattenNav(nodes) {
|
|
|
82
82
|
return out;
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
85
|
+
* First leaf URL under a group, depth-first. Groups have no page of their own,
|
|
86
|
+
* so breadcrumbs that name a group link to its earliest page (the place a
|
|
87
|
+
* reader lands if they "go up" into that section).
|
|
88
|
+
*/
|
|
89
|
+
function firstLeafUrl(group) {
|
|
90
|
+
for (const child of group.items) {
|
|
91
|
+
if (isNavGroup(child)) {
|
|
92
|
+
const url = firstLeafUrl(child);
|
|
93
|
+
if (url)
|
|
94
|
+
return url;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return child.url;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The trail of groups leading to the page at `url` (top group first, excluding
|
|
104
|
+
* the page itself), or `undefined` if the page is not in the tree. Each group
|
|
105
|
+
* step carries a `url` to its first leaf so breadcrumbs are navigable.
|
|
88
106
|
*/
|
|
89
107
|
export function navTrail(nodes, url) {
|
|
90
108
|
for (const node of nodes) {
|
|
91
109
|
if (isNavGroup(node)) {
|
|
92
110
|
const inner = navTrail(node.items, url);
|
|
93
|
-
if (inner)
|
|
94
|
-
return [node.title, ...inner];
|
|
111
|
+
if (inner) {
|
|
112
|
+
return [{ title: node.title, url: firstLeafUrl(node) }, ...inner];
|
|
113
|
+
}
|
|
95
114
|
}
|
|
96
115
|
else if (node.url === url) {
|
|
97
116
|
return [];
|
package/dist/core/version.js
CHANGED
|
@@ -63,7 +63,7 @@ export function checkVersions(versions, disk, markerName) {
|
|
|
63
63
|
assertValidVersionId(version?.id);
|
|
64
64
|
}
|
|
65
65
|
catch (error) {
|
|
66
|
-
throw new Error(`[svelte-docsmith] ${error.message}
|
|
66
|
+
throw new Error(`[svelte-docsmith] ${error.message}`, { cause: error });
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
const seen = new Set();
|
package/dist/theme.css
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
@import 'tw-animate-css';
|
|
17
17
|
@import 'tailwindcss';
|
|
18
18
|
@import '@fontsource-variable/inter';
|
|
19
|
+
@import '@fontsource-variable/source-serif-4';
|
|
20
|
+
@import '@fontsource/jetbrains-mono';
|
|
19
21
|
|
|
20
22
|
/* Generate utilities for the classes used inside this package. */
|
|
21
23
|
@source './';
|
|
@@ -139,9 +141,12 @@
|
|
|
139
141
|
--sidebar-accent-foreground: oklch(0.2101 0.0318 264.6645);
|
|
140
142
|
--sidebar-border: oklch(0.9276 0.0058 264.5313);
|
|
141
143
|
--sidebar-ring: oklch(0.6716 0.1368 48.513);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
/* Fontsource variable packages register as "… Variable"; keep the
|
|
145
|
+
* static family names as fallbacks for consumers who load Google Fonts
|
|
146
|
+
* or system stacks instead. */
|
|
147
|
+
--font-sans: 'Inter Variable', Inter, sans-serif;
|
|
148
|
+
--font-serif: 'Source Serif 4 Variable', 'Source Serif 4', serif;
|
|
149
|
+
--font-mono: 'JetBrains Mono', ui-monospace, monospace;
|
|
145
150
|
--radius: 0.75rem;
|
|
146
151
|
--shadow-2xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
|
147
152
|
--shadow-xs: 0px 1px 3px 0px hsl(0 0% 0% / 0.05);
|
package/dist/toc/toc.svelte.js
CHANGED
|
@@ -34,6 +34,8 @@ export function createToc(contentFn) {
|
|
|
34
34
|
const headings = headingItems
|
|
35
35
|
.map((item) => el.querySelector(`#${CSS.escape(item.id)}`))
|
|
36
36
|
.filter((node) => node !== null);
|
|
37
|
+
// Plain Set on purpose: it's scratch state read only inside recompute(), never rendered.
|
|
38
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity
|
|
37
39
|
const visible = new Set();
|
|
38
40
|
function recompute() {
|
|
39
41
|
// The first heading (in document order) inside the active band wins.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-docsmith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "A framework for building beautiful documentation sites with Svelte.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "George Daskalakis",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
},
|
|
71
71
|
"license": "MIT",
|
|
72
72
|
"peerDependencies": {
|
|
73
|
-
"@sveltejs/kit": "^2.16.0",
|
|
74
|
-
"mermaid": "^10.0.0 || ^11.0.0",
|
|
73
|
+
"@sveltejs/kit": "^2.16.0 || ^3.0.0",
|
|
74
|
+
"mermaid": "^10.0.0 || ^11.0.0 || ^12.0.0",
|
|
75
75
|
"svelte": "^5.0.0",
|
|
76
76
|
"tailwindcss": "^4.0.0"
|
|
77
77
|
},
|
|
@@ -81,49 +81,50 @@
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@internationalized/date": "^3.12.
|
|
85
|
-
"@shikijs/twoslash": "
|
|
86
|
-
"@sveltejs/adapter-auto": "^
|
|
87
|
-
"@sveltejs/adapter-vercel": "^
|
|
88
|
-
"@sveltejs/kit": "^
|
|
89
|
-
"@sveltejs/package": "^
|
|
90
|
-
"@sveltejs/vite-plugin-svelte": "^7.1
|
|
91
|
-
"@testing-library/jest-dom": "^
|
|
92
|
-
"@testing-library/svelte": "^5.2
|
|
93
|
-
"@types/
|
|
94
|
-
"@
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"svelte": "^
|
|
101
|
-
"
|
|
102
|
-
"tailwindcss": "^4.3.2",
|
|
84
|
+
"@internationalized/date": "^3.12.4",
|
|
85
|
+
"@shikijs/twoslash": "4.6.0",
|
|
86
|
+
"@sveltejs/adapter-auto": "^8.0.0",
|
|
87
|
+
"@sveltejs/adapter-vercel": "^7.0.0",
|
|
88
|
+
"@sveltejs/kit": "^3.0.0",
|
|
89
|
+
"@sveltejs/package": "^3.0.0",
|
|
90
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
91
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
92
|
+
"@testing-library/svelte": "^5.4.2",
|
|
93
|
+
"@types/node": "^22.20.5",
|
|
94
|
+
"@vitest/coverage-v8": "5.1.0",
|
|
95
|
+
"jsdom": "^31.0.0",
|
|
96
|
+
"mermaid": "^12.3.0",
|
|
97
|
+
"publint": "^0.3.25",
|
|
98
|
+
"shadcn-svelte": "^1.8.0",
|
|
99
|
+
"svelte": "^5.57.3",
|
|
100
|
+
"svelte-check": "^4.7.8",
|
|
101
|
+
"tailwindcss": "^4.3.4",
|
|
103
102
|
"twoslash-svelte": "0.3.9",
|
|
104
|
-
"typescript": "^
|
|
105
|
-
"vite": "^8.
|
|
106
|
-
"vitest": "^
|
|
103
|
+
"typescript": "^6.0.3",
|
|
104
|
+
"vite": "^8.3.6",
|
|
105
|
+
"vitest": "^5.1.0"
|
|
107
106
|
},
|
|
108
107
|
"dependencies": {
|
|
109
|
-
"@fontsource-variable/inter": "^5.
|
|
108
|
+
"@fontsource-variable/inter": "^5.3.0",
|
|
109
|
+
"@fontsource-variable/source-serif-4": "^5.3.1",
|
|
110
|
+
"@fontsource/jetbrains-mono": "^5.3.0",
|
|
110
111
|
"@hbsnow/rehype-sectionize": "^1.0.7",
|
|
111
|
-
"@lucide/svelte": "^1.
|
|
112
|
-
"@shikijs/transformers": "^
|
|
113
|
-
"@tailwindcss/typography": "^0.5.
|
|
114
|
-
"bits-ui": "^2.
|
|
112
|
+
"@lucide/svelte": "^1.70.0",
|
|
113
|
+
"@shikijs/transformers": "^4.6.0",
|
|
114
|
+
"@tailwindcss/typography": "^0.5.20",
|
|
115
|
+
"bits-ui": "^2.20.6",
|
|
115
116
|
"clsx": "^2.1.1",
|
|
116
117
|
"esm-env": "^1.2.2",
|
|
117
118
|
"flexsearch": "^0.8.212",
|
|
118
119
|
"github-slugger": "^2.0.0",
|
|
119
|
-
"js-yaml": "^
|
|
120
|
-
"marked": "^18.
|
|
121
|
-
"mdsvex": "^0.12.
|
|
122
|
-
"mode-watcher": "^1.0
|
|
120
|
+
"js-yaml": "^5.5.0",
|
|
121
|
+
"marked": "^18.1.3",
|
|
122
|
+
"mdsvex": "^0.12.8",
|
|
123
|
+
"mode-watcher": "^1.1.0",
|
|
123
124
|
"rehype-slug": "^6.0.0",
|
|
124
|
-
"shiki": "^
|
|
125
|
-
"tailwind-merge": "^3.
|
|
126
|
-
"tailwind-variants": "^
|
|
125
|
+
"shiki": "^4.6.0",
|
|
126
|
+
"tailwind-merge": "^3.7.0",
|
|
127
|
+
"tailwind-variants": "^4.0.1",
|
|
127
128
|
"tw-animate-css": "^1.4.0"
|
|
128
129
|
},
|
|
129
130
|
"keywords": [
|
|
@@ -140,6 +141,10 @@
|
|
|
140
141
|
"ui",
|
|
141
142
|
"components"
|
|
142
143
|
],
|
|
144
|
+
"imports": {
|
|
145
|
+
"#lib": "./src/lib/index.js",
|
|
146
|
+
"#lib/*": "./src/lib/*"
|
|
147
|
+
},
|
|
143
148
|
"scripts": {
|
|
144
149
|
"dev": "vite dev",
|
|
145
150
|
"build": "vite build && npm run prepack",
|