svelte-docsmith 0.1.1 → 0.3.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 +57 -25
- package/dist/clipboard.svelte.d.ts +1 -1
- package/dist/clipboard.svelte.js +15 -8
- package/dist/config.d.ts +41 -6
- package/dist/config.js +33 -7
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -0
- package/dist/markdown-layout.svelte +14 -1
- package/dist/markdown-layout.svelte.d.ts +2 -0
- package/dist/preprocess.d.ts +4 -5
- package/dist/preprocess.js +4 -5
- package/dist/search/context.svelte.d.ts +7 -0
- package/dist/search/context.svelte.js +20 -0
- package/dist/search/create-search.d.ts +14 -0
- package/dist/search/create-search.js +56 -0
- package/dist/search/snippet.d.ts +7 -0
- package/dist/search/snippet.js +43 -0
- package/dist/search.d.ts +10 -0
- package/dist/search.js +4 -0
- package/dist/theme.css +25 -0
- package/dist/themes/darkmatter.css +81 -0
- package/dist/types.d.ts +0 -6
- package/dist/ui/badge.svelte +10 -1
- package/dist/ui/badge.svelte.d.ts +2 -0
- package/dist/ui/callout.svelte +9 -9
- package/dist/ui/callout.svelte.d.ts +3 -3
- package/dist/ui/layouts/docs-footer.svelte +32 -6
- package/dist/ui/layouts/docs-header.svelte +5 -11
- package/dist/ui/layouts/docs-header.svelte.d.ts +0 -6
- package/dist/ui/layouts/docs-mobile-header.svelte +40 -8
- package/dist/ui/layouts/docs-mobile-header.svelte.d.ts +5 -4
- package/dist/ui/layouts/docs-shell.svelte +49 -5
- package/dist/ui/layouts/docs-shell.svelte.d.ts +16 -1
- package/dist/ui/layouts/error-page.svelte +82 -0
- package/dist/ui/layouts/error-page.svelte.d.ts +25 -0
- package/dist/ui/layouts/seo-head.svelte +65 -0
- package/dist/ui/layouts/seo-head.svelte.d.ts +11 -0
- package/dist/ui/markdown/h2.svelte +7 -3
- package/dist/ui/markdown/h3.svelte +7 -3
- package/dist/ui/markdown/pre.svelte +1 -1
- package/dist/ui/prop.svelte +71 -36
- package/dist/ui/prop.svelte.d.ts +1 -1
- package/dist/ui/props-table.svelte +10 -62
- package/dist/ui/search-trigger.svelte +31 -0
- package/dist/ui/search-trigger.svelte.d.ts +6 -0
- package/dist/ui/search.svelte +167 -0
- package/dist/ui/search.svelte.d.ts +13 -0
- package/dist/ui/shadcn/accordion/accordion.svelte.d.ts +1 -1
- package/dist/ui/shadcn/command/command-dialog.svelte +42 -0
- package/dist/ui/shadcn/command/command-dialog.svelte.d.ts +14 -0
- package/dist/ui/shadcn/command/command-empty.svelte +17 -0
- package/dist/ui/shadcn/command/command-empty.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-group.svelte +33 -0
- package/dist/ui/shadcn/command/command-group.svelte.d.ts +7 -0
- package/dist/ui/shadcn/command/command-input.svelte +36 -0
- package/dist/ui/shadcn/command/command-input.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-item.svelte +27 -0
- package/dist/ui/shadcn/command/command-item.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-link-item.svelte +20 -0
- package/dist/ui/shadcn/command/command-link-item.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-list.svelte +20 -0
- package/dist/ui/shadcn/command/command-list.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-loading.svelte +7 -0
- package/dist/ui/shadcn/command/command-loading.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-separator.svelte +17 -0
- package/dist/ui/shadcn/command/command-separator.svelte.d.ts +4 -0
- package/dist/ui/shadcn/command/command-shortcut.svelte +23 -0
- package/dist/ui/shadcn/command/command-shortcut.svelte.d.ts +5 -0
- package/dist/ui/shadcn/command/command.svelte +28 -0
- package/dist/ui/shadcn/command/command.svelte.d.ts +8 -0
- package/dist/ui/shadcn/command/index.d.ts +12 -0
- package/dist/ui/shadcn/command/index.js +14 -0
- package/dist/ui/shadcn/dialog/dialog-close.svelte +11 -0
- package/dist/ui/shadcn/dialog/dialog-close.svelte.d.ts +4 -0
- package/dist/ui/shadcn/dialog/dialog-content.svelte +48 -0
- package/dist/ui/shadcn/dialog/dialog-content.svelte.d.ts +13 -0
- package/dist/ui/shadcn/dialog/dialog-description.svelte +20 -0
- package/dist/ui/shadcn/dialog/dialog-description.svelte.d.ts +4 -0
- package/dist/ui/shadcn/dialog/dialog-footer.svelte +32 -0
- package/dist/ui/shadcn/dialog/dialog-footer.svelte.d.ts +8 -0
- package/dist/ui/shadcn/dialog/dialog-header.svelte +20 -0
- package/dist/ui/shadcn/dialog/dialog-header.svelte.d.ts +5 -0
- package/dist/ui/shadcn/dialog/dialog-overlay.svelte +20 -0
- package/dist/ui/shadcn/dialog/dialog-overlay.svelte.d.ts +4 -0
- package/dist/ui/shadcn/dialog/dialog-portal.svelte +7 -0
- package/dist/ui/shadcn/dialog/dialog-portal.svelte.d.ts +3 -0
- package/dist/ui/shadcn/dialog/dialog-title.svelte +17 -0
- package/dist/ui/shadcn/dialog/dialog-title.svelte.d.ts +4 -0
- package/dist/ui/shadcn/dialog/dialog-trigger.svelte +11 -0
- package/dist/ui/shadcn/dialog/dialog-trigger.svelte.d.ts +4 -0
- package/dist/ui/shadcn/dialog/dialog.svelte +7 -0
- package/dist/ui/shadcn/dialog/dialog.svelte.d.ts +3 -0
- package/dist/ui/shadcn/dialog/index.d.ts +11 -0
- package/dist/ui/shadcn/dialog/index.js +13 -0
- package/dist/ui/shadcn/input/index.d.ts +2 -0
- package/dist/ui/shadcn/input/index.js +4 -0
- package/dist/ui/shadcn/input/input.svelte +48 -0
- package/dist/ui/shadcn/input/input.svelte.d.ts +13 -0
- package/dist/ui/shadcn/input-group/index.d.ts +7 -0
- package/dist/ui/shadcn/input-group/index.js +9 -0
- package/dist/ui/shadcn/input-group/input-group-addon.svelte +53 -0
- package/dist/ui/shadcn/input-group/input-group-addon.svelte.d.ts +32 -0
- package/dist/ui/shadcn/input-group/input-group-button.svelte +49 -0
- package/dist/ui/shadcn/input-group/input-group-button.svelte.d.ts +32 -0
- package/dist/ui/shadcn/input-group/input-group-input.svelte +23 -0
- package/dist/ui/shadcn/input-group/input-group-input.svelte.d.ts +11 -0
- package/dist/ui/shadcn/input-group/input-group-text.svelte +22 -0
- package/dist/ui/shadcn/input-group/input-group-text.svelte.d.ts +5 -0
- package/dist/ui/shadcn/input-group/input-group-textarea.svelte +23 -0
- package/dist/ui/shadcn/input-group/input-group-textarea.svelte.d.ts +3 -0
- package/dist/ui/shadcn/input-group/input-group.svelte +24 -0
- package/dist/ui/shadcn/input-group/input-group.svelte.d.ts +5 -0
- package/dist/ui/shadcn/tabs/tabs.svelte.d.ts +1 -1
- package/dist/ui/shadcn/textarea/index.d.ts +2 -0
- package/dist/ui/shadcn/textarea/index.js +4 -0
- package/dist/ui/shadcn/textarea/textarea.svelte +23 -0
- package/dist/ui/shadcn/textarea/textarea.svelte.d.ts +5 -0
- package/dist/ui/tab-item.svelte +35 -9
- package/dist/ui/tab-item.svelte.d.ts +9 -4
- package/dist/ui/tabs-phase.svelte +19 -0
- package/dist/ui/tabs-phase.svelte.d.ts +9 -0
- package/dist/ui/tabs.svelte +47 -24
- package/dist/ui/tabs.svelte.d.ts +16 -6
- package/dist/vite.d.ts +8 -6
- package/dist/vite.js +140 -47
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
6
|
The documentation framework for Svelte 5 library authors whose interactive
|
|
7
|
-
examples need to live inside one real, stateful SvelteKit app
|
|
7
|
+
examples need to live inside one real, stateful SvelteKit app, not sandboxed as
|
|
8
8
|
isolated islands.
|
|
9
9
|
|
|
10
10
|
Write a markdown file under `src/routes/docs/` and you get a styled page with
|
|
11
11
|
syntax highlighting, heading anchors, a sidebar derived from your content, and a
|
|
12
|
-
live table of contents
|
|
12
|
+
live table of contents. No per-page wiring, no content collection to configure.
|
|
13
13
|
|
|
14
14
|
> **Status: pre-1.0.** Published to npm and usable today. The public API is still
|
|
15
15
|
> stabilising, so minor releases may include breaking changes until v1.0.
|
|
@@ -20,14 +20,14 @@ live table of contents — no per-page wiring, no content collection to configur
|
|
|
20
20
|
npm install svelte-docsmith
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Peer dependencies: Svelte 5, SvelteKit 2, and Tailwind v4
|
|
23
|
+
Peer dependencies: Svelte 5, SvelteKit 2, and Tailwind v4, set up the standard
|
|
24
24
|
way in your app.
|
|
25
25
|
|
|
26
26
|
## Setup
|
|
27
27
|
|
|
28
28
|
Three small pieces, once.
|
|
29
29
|
|
|
30
|
-
**1. The markdown pipeline
|
|
30
|
+
**1. The markdown pipeline.** In `svelte.config.js`, one call bundles mdsvex,
|
|
31
31
|
Shiki highlighting (dual light/dark themes, a generous language set, plain-text
|
|
32
32
|
fallback for unknown languages), heading anchors, and the packaged page layout:
|
|
33
33
|
|
|
@@ -44,9 +44,9 @@ export default {
|
|
|
44
44
|
};
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
**2. The Vite plugin
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
**2. The Vite plugin.** In `vite.config.ts`, it scans your doc pages' frontmatter
|
|
48
|
+
into the `svelte-docsmith/content` module (so the sidebar is derived from
|
|
49
|
+
content, never hand-written), builds the search index, and powers `LiveExample`:
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
52
|
// vite.config.ts
|
|
@@ -63,9 +63,9 @@ export default defineConfig({
|
|
|
63
63
|
By default it scans `src/routes/docs`; pass `docsmith({ content: 'src/routes/guide' })`
|
|
64
64
|
to point elsewhere.
|
|
65
65
|
|
|
66
|
-
**3. The stylesheet
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
**3. The stylesheet.** In your root `app.css`, once Tailwind v4 is set up the
|
|
67
|
+
standard way (`tailwindcss` + the `@tailwindcss/vite` plugin, stylesheet imported
|
|
68
|
+
in the root layout), the whole style contract is one import:
|
|
69
69
|
|
|
70
70
|
```css
|
|
71
71
|
@import 'tailwindcss';
|
|
@@ -75,13 +75,14 @@ imported in the root layout). After that the whole style contract is one import:
|
|
|
75
75
|
`theme.css` makes Tailwind scan the package, defines the shadcn theme tokens
|
|
76
76
|
(`--background`, `--primary`, `--radius`, …) for `:root` and `.dark`, and pulls
|
|
77
77
|
in the typography and animation plugins. Override any token by redefining it
|
|
78
|
-
after the import.
|
|
78
|
+
after the import, or import a preset (see [Themes](#themes)).
|
|
79
79
|
|
|
80
80
|
## The shell
|
|
81
81
|
|
|
82
82
|
Add `DocsShell` once, in `src/routes/docs/+layout.svelte`. It composes the
|
|
83
83
|
header, sidebar, content area, and table of contents. `docs` is the generated
|
|
84
|
-
content index
|
|
84
|
+
content index, so there is no content collection to import and no alias to
|
|
85
|
+
configure:
|
|
85
86
|
|
|
86
87
|
```svelte
|
|
87
88
|
<script lang="ts">
|
|
@@ -103,7 +104,7 @@ content index — no import of a content collection, no alias to configure:
|
|
|
103
104
|
## Doc pages
|
|
104
105
|
|
|
105
106
|
Each page is a `+page.md` under `src/routes/docs/`. Frontmatter drives the
|
|
106
|
-
sidebar
|
|
107
|
+
sidebar and the `<h1>`; the body is markdown, starting at `##`:
|
|
107
108
|
|
|
108
109
|
````md
|
|
109
110
|
---
|
|
@@ -122,12 +123,12 @@ npm install my-library
|
|
|
122
123
|
|
|
123
124
|
`title` names the page. `section` groups pages in the sidebar; `order` sorts
|
|
124
125
|
within a group (and orders the groups by their smallest `order`). Add the file
|
|
125
|
-
and it appears in the sidebar
|
|
126
|
+
and it appears in the sidebar, styled, highlighted, with a table of contents.
|
|
126
127
|
|
|
127
128
|
## Live examples
|
|
128
129
|
|
|
129
130
|
`LiveExample` renders a real, interactive component next to its own
|
|
130
|
-
syntax-highlighted source
|
|
131
|
+
syntax-highlighted source: one file, imported twice, so the demo and its code
|
|
131
132
|
can never drift. The `?source` import is served by the same `docsmith()` Vite
|
|
132
133
|
plugin you already added:
|
|
133
134
|
|
|
@@ -143,20 +144,51 @@ plugin you already added:
|
|
|
143
144
|
</LiveExample>
|
|
144
145
|
```
|
|
145
146
|
|
|
147
|
+
## Batteries included
|
|
148
|
+
|
|
149
|
+
- **Search.** A ⌘K / Ctrl-K command palette over a build-time full-text index, no
|
|
150
|
+
service to host. Pass a `search` loader to `DocsShell`:
|
|
151
|
+
`search={() => import('svelte-docsmith/search').then((m) => m.docs)}`.
|
|
152
|
+
- **SEO.** `DocsShell` writes `<title>`, meta description, canonical, and Open
|
|
153
|
+
Graph / Twitter tags for every page from its frontmatter, no per-page wiring.
|
|
154
|
+
- **Error pages.** `ErrorPage` gives a styled 404 that keeps the site chrome;
|
|
155
|
+
drop it into a SvelteKit `+error.svelte`.
|
|
156
|
+
- **Components.** `Callout`, `Tabs`, `Steps`, `Card`, `Accordion`, `Badge`,
|
|
157
|
+
`Kbd`, `FileTree`, `PropsTable`, and more, authored right inside markdown.
|
|
158
|
+
- Heading anchors, a scroll-spy table of contents, and one-click copy on every
|
|
159
|
+
code block, wired up for you.
|
|
160
|
+
|
|
161
|
+
## Themes
|
|
162
|
+
|
|
163
|
+
Eleven presets ship in the box. Pick one with a single import after the base
|
|
164
|
+
contract:
|
|
165
|
+
|
|
166
|
+
```css
|
|
167
|
+
@import 'svelte-docsmith/theme.css';
|
|
168
|
+
@import 'svelte-docsmith/themes/amethyst.css';
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Available: `darkmatter`, `tangerine`, `amethyst`, `graphite`, `evergreen`,
|
|
172
|
+
`rose`, `ocean`, `nord`, `claude`, `bubblegum`, `mono`. Or skip the preset and
|
|
173
|
+
override the tokens yourself.
|
|
174
|
+
|
|
146
175
|
## What's exported
|
|
147
176
|
|
|
148
|
-
| Entry point
|
|
149
|
-
|
|
|
150
|
-
| `svelte-docsmith`
|
|
151
|
-
| `svelte-docsmith/preprocess`
|
|
152
|
-
| `svelte-docsmith/vite`
|
|
153
|
-
| `svelte-docsmith/content`
|
|
154
|
-
| `svelte-docsmith/
|
|
177
|
+
| Entry point | What it is |
|
|
178
|
+
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
179
|
+
| `svelte-docsmith` | All components (`DocsShell`, `ErrorPage`, `LiveExample`, `Callout`, `Tabs`, …), plus `defineConfig`, `createSearchEngine`, and the types |
|
|
180
|
+
| `svelte-docsmith/preprocess` | `docsmith()`, the mdsvex/Shiki pipeline (Node, config time) |
|
|
181
|
+
| `svelte-docsmith/vite` | `docsmith()`, the content index, search index, and `?source` transform (Node, build) |
|
|
182
|
+
| `svelte-docsmith/content` | `docs`, the generated sidebar content index |
|
|
183
|
+
| `svelte-docsmith/search` | `docs`, the generated full-text search index (lazy-load it) |
|
|
184
|
+
| `svelte-docsmith/theme.css` | the base style contract |
|
|
185
|
+
| `svelte-docsmith/themes/*.css` | the eleven theme presets |
|
|
155
186
|
|
|
156
187
|
The vendored shadcn primitives and internal helpers (the TOC engine, clipboard
|
|
157
|
-
utility, markdown renderer map) are **not** part of the public API
|
|
158
|
-
change between releases. Get buttons, cards,
|
|
188
|
+
utility, markdown renderer map) are **not** part of the public API; they can
|
|
189
|
+
change between releases. Get buttons, cards, and the like from `shadcn-svelte`
|
|
190
|
+
directly.
|
|
159
191
|
|
|
160
192
|
## License
|
|
161
193
|
|
|
162
|
-
MIT
|
|
194
|
+
MIT. See [LICENSE](LICENSE).
|
package/dist/clipboard.svelte.js
CHANGED
|
@@ -4,14 +4,21 @@ export function useClipboard(timeout = 1500) {
|
|
|
4
4
|
function readText(node) {
|
|
5
5
|
text = node.innerText.trim();
|
|
6
6
|
}
|
|
7
|
-
function copy() {
|
|
8
|
-
if (text)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
async function copy() {
|
|
8
|
+
if (!text)
|
|
9
|
+
return;
|
|
10
|
+
// `navigator.clipboard` is undefined in insecure (non-HTTPS) contexts, and
|
|
11
|
+
// writeText can reject when the page lacks clipboard permission. Fail quietly
|
|
12
|
+
// so a copy button never throws an unhandled rejection.
|
|
13
|
+
try {
|
|
14
|
+
await navigator.clipboard.writeText(text);
|
|
15
|
+
copied = true;
|
|
16
|
+
setTimeout(() => {
|
|
17
|
+
copied = false;
|
|
18
|
+
}, timeout);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.warn('[svelte-docsmith] copy to clipboard failed', error);
|
|
15
22
|
}
|
|
16
23
|
}
|
|
17
24
|
return {
|
package/dist/config.d.ts
CHANGED
|
@@ -15,8 +15,20 @@ export type DocsmithFooterColumn = {
|
|
|
15
15
|
links: DocsmithLink[];
|
|
16
16
|
};
|
|
17
17
|
export type DocsmithConfig = {
|
|
18
|
-
/** Site title, shown in the header/sidebar. */
|
|
18
|
+
/** Site title, shown in the header/sidebar and in the `<title>` suffix. */
|
|
19
19
|
title: string;
|
|
20
|
+
/**
|
|
21
|
+
* Default meta description, used for pages whose frontmatter has none (and
|
|
22
|
+
* as the site's social-share description).
|
|
23
|
+
*/
|
|
24
|
+
description?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Canonical site origin, e.g. `https://docs.example.com`. When set, DocsShell
|
|
27
|
+
* emits `<link rel="canonical">` and absolute Open Graph URLs.
|
|
28
|
+
*/
|
|
29
|
+
url?: string;
|
|
30
|
+
/** Default social-share image (absolute URL, or a path resolved against `url`). */
|
|
31
|
+
ogImage?: string;
|
|
20
32
|
/** Optional GitHub URL; renders a link in the header when set. */
|
|
21
33
|
github?: string;
|
|
22
34
|
/** Optional version string, shown in the header (e.g. your library version). */
|
|
@@ -31,6 +43,11 @@ export type DocsmithConfig = {
|
|
|
31
43
|
copyright?: string;
|
|
32
44
|
/** Titled columns of links. */
|
|
33
45
|
columns?: DocsmithFooterColumn[];
|
|
46
|
+
/**
|
|
47
|
+
* Show the "Powered by Svelte DocSmith" attribution in the footer.
|
|
48
|
+
* Defaults to `true`; set `false` to hide it.
|
|
49
|
+
*/
|
|
50
|
+
poweredBy?: boolean;
|
|
34
51
|
};
|
|
35
52
|
};
|
|
36
53
|
/**
|
|
@@ -41,8 +58,9 @@ export type DocsmithConfig = {
|
|
|
41
58
|
export declare function defineConfig(config: DocsmithConfig): DocsmithConfig;
|
|
42
59
|
/**
|
|
43
60
|
* The minimal shape `DocsShell` needs from each content entry to build the
|
|
44
|
-
* sidebar.
|
|
45
|
-
*
|
|
61
|
+
* sidebar. The generated `svelte-docsmith/content` module produces these from
|
|
62
|
+
* your pages' frontmatter; any source with matching title/path/section/order
|
|
63
|
+
* fields satisfies it structurally.
|
|
46
64
|
*/
|
|
47
65
|
export type DocsContentItem = {
|
|
48
66
|
title: string;
|
|
@@ -61,6 +79,23 @@ export type DocsContentItem = {
|
|
|
61
79
|
depth: 2 | 3;
|
|
62
80
|
}[];
|
|
63
81
|
};
|
|
82
|
+
/**
|
|
83
|
+
* One page's searchable record, emitted at build time by the `docsmith()` vite
|
|
84
|
+
* plugin as the `svelte-docsmith/search` virtual module. `text` is the page's
|
|
85
|
+
* prose and headings reduced to plain text (frontmatter, `<script>` blocks,
|
|
86
|
+
* fenced code, tags, and markdown punctuation stripped) so a client-side search
|
|
87
|
+
* index can be built over it without shipping raw markdown.
|
|
88
|
+
*/
|
|
89
|
+
export type SearchDoc = {
|
|
90
|
+
path: string;
|
|
91
|
+
title: string;
|
|
92
|
+
section?: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
/** The page's `h2`/`h3` heading text, for weighting title/heading matches. */
|
|
95
|
+
headings: string[];
|
|
96
|
+
/** Plain-text body: prose and headings, code and markup removed. */
|
|
97
|
+
text: string;
|
|
98
|
+
};
|
|
64
99
|
/** A single sidebar link. */
|
|
65
100
|
export type NavItem = {
|
|
66
101
|
title: string;
|
|
@@ -72,8 +107,8 @@ export type NavGroup = {
|
|
|
72
107
|
items: NavItem[];
|
|
73
108
|
};
|
|
74
109
|
/**
|
|
75
|
-
* Derive sidebar nav from a content collection
|
|
76
|
-
* `
|
|
77
|
-
*
|
|
110
|
+
* Derive sidebar nav from a content collection: group by `section`, order by
|
|
111
|
+
* `order` within a group, and order groups by the smallest `order` they
|
|
112
|
+
* contain. Entries without a `section` fall under "Docs".
|
|
78
113
|
*/
|
|
79
114
|
export declare function navFromContent(content: DocsContentItem[]): NavGroup[];
|
package/dist/config.js
CHANGED
|
@@ -10,7 +10,7 @@ export function defineConfig(config) {
|
|
|
10
10
|
if (typeof config.title !== 'string' || config.title.trim() === '') {
|
|
11
11
|
throw new Error('[svelte-docsmith] config.title is required — the site title shown in the sidebar header.');
|
|
12
12
|
}
|
|
13
|
-
for (const key of ['github', 'version', 'logo']) {
|
|
13
|
+
for (const key of ['github', 'version', 'logo', 'description', 'url', 'ogImage']) {
|
|
14
14
|
if (config[key] !== undefined && typeof config[key] !== 'string') {
|
|
15
15
|
throw new Error(`[svelte-docsmith] config.${key} must be a string when set.`);
|
|
16
16
|
}
|
|
@@ -25,16 +25,42 @@ export function defineConfig(config) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
if (config.footer !== undefined
|
|
29
|
-
(typeof config.footer !== 'object' || config.footer === null)
|
|
30
|
-
|
|
28
|
+
if (config.footer !== undefined) {
|
|
29
|
+
if (typeof config.footer !== 'object' || config.footer === null) {
|
|
30
|
+
throw new Error('[svelte-docsmith] config.footer must be an object ({ copyright?, columns?, poweredBy? }).');
|
|
31
|
+
}
|
|
32
|
+
const { copyright, columns, poweredBy } = config.footer;
|
|
33
|
+
if (copyright !== undefined && typeof copyright !== 'string') {
|
|
34
|
+
throw new Error('[svelte-docsmith] config.footer.copyright must be a string when set.');
|
|
35
|
+
}
|
|
36
|
+
if (poweredBy !== undefined && typeof poweredBy !== 'boolean') {
|
|
37
|
+
throw new Error('[svelte-docsmith] config.footer.poweredBy must be a boolean when set.');
|
|
38
|
+
}
|
|
39
|
+
if (columns !== undefined) {
|
|
40
|
+
if (!Array.isArray(columns)) {
|
|
41
|
+
throw new Error('[svelte-docsmith] config.footer.columns must be an array of { title, links } columns.');
|
|
42
|
+
}
|
|
43
|
+
for (const column of columns) {
|
|
44
|
+
if (typeof column?.title !== 'string') {
|
|
45
|
+
throw new Error('[svelte-docsmith] each config.footer.columns entry needs a string `title`.');
|
|
46
|
+
}
|
|
47
|
+
if (!Array.isArray(column.links)) {
|
|
48
|
+
throw new Error(`[svelte-docsmith] config.footer column "${column.title}" needs a \`links\` array.`);
|
|
49
|
+
}
|
|
50
|
+
for (const link of column.links) {
|
|
51
|
+
if (typeof link?.label !== 'string' || typeof link?.href !== 'string') {
|
|
52
|
+
throw new Error(`[svelte-docsmith] each link in config.footer column "${column.title}" needs a string \`label\` and \`href\`.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
31
57
|
}
|
|
32
58
|
return config;
|
|
33
59
|
}
|
|
34
60
|
/**
|
|
35
|
-
* Derive sidebar nav from a content collection
|
|
36
|
-
* `
|
|
37
|
-
*
|
|
61
|
+
* Derive sidebar nav from a content collection: group by `section`, order by
|
|
62
|
+
* `order` within a group, and order groups by the smallest `order` they
|
|
63
|
+
* contain. Entries without a `section` fall under "Docs".
|
|
38
64
|
*/
|
|
39
65
|
export function navFromContent(content) {
|
|
40
66
|
const groups = new Map();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export { default as DocsShell } from './ui/layouts/docs-shell.svelte';
|
|
2
|
+
export { default as ErrorPage } from './ui/layouts/error-page.svelte';
|
|
2
3
|
export { default as ThemeProvider } from './ui/theme-provider.svelte';
|
|
3
4
|
export { default as ThemeToggle } from './ui/theme-toggle.svelte';
|
|
4
5
|
export { default as LiveExample } from './ui/live-example.svelte';
|
|
5
6
|
export { default as Tabs } from './ui/tabs.svelte';
|
|
6
7
|
export { default as TabItem } from './ui/tab-item.svelte';
|
|
7
|
-
export { default as Callout } from './ui/callout.svelte';
|
|
8
|
+
export { default as Callout, type CalloutVariant } from './ui/callout.svelte';
|
|
8
9
|
export { default as Steps } from './ui/steps.svelte';
|
|
9
10
|
export { default as Step } from './ui/step.svelte';
|
|
10
11
|
export { default as Card } from './ui/card.svelte';
|
|
@@ -17,4 +18,5 @@ export { default as FileTree } from './ui/file-tree.svelte';
|
|
|
17
18
|
export { default as FileTreeItem } from './ui/file-tree-item.svelte';
|
|
18
19
|
export { default as PropsTable } from './ui/props-table.svelte';
|
|
19
20
|
export { default as Prop } from './ui/prop.svelte';
|
|
20
|
-
export { defineConfig, type DocsmithConfig, type DocsContentItem } from './config.js';
|
|
21
|
+
export { defineConfig, type DocsmithConfig, type DocsContentItem, type SearchDoc } from './config.js';
|
|
22
|
+
export { createSearchEngine, type SearchEngine, type SearchResult } from './search/create-search.js';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// renderer map — is internal and may change between releases.
|
|
4
4
|
// Chrome
|
|
5
5
|
export { default as DocsShell } from './ui/layouts/docs-shell.svelte';
|
|
6
|
+
export { default as ErrorPage } from './ui/layouts/error-page.svelte';
|
|
6
7
|
export { default as ThemeProvider } from './ui/theme-provider.svelte';
|
|
7
8
|
export { default as ThemeToggle } from './ui/theme-toggle.svelte';
|
|
8
9
|
// Docs components (authored inside markdown or composed in pages)
|
|
@@ -24,3 +25,6 @@ export { default as PropsTable } from './ui/props-table.svelte';
|
|
|
24
25
|
export { default as Prop } from './ui/prop.svelte';
|
|
25
26
|
// Config
|
|
26
27
|
export { defineConfig } from './config.js';
|
|
28
|
+
// Search engine (framework-agnostic; for building a custom search UI over the
|
|
29
|
+
// generated `svelte-docsmith/search` index)
|
|
30
|
+
export { createSearchEngine } from './search/create-search.js';
|
|
@@ -13,9 +13,22 @@
|
|
|
13
13
|
<script lang="ts">
|
|
14
14
|
import type { Snippet } from 'svelte';
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// mdsvex passes each frontmatter field to the layout as a prop, so the page's
|
|
17
|
+
// `<h1>` (and lead subtitle) come from `title`/`description` — authored once in
|
|
18
|
+
// frontmatter, never repeated in the body. Pages start their content at `##`.
|
|
19
|
+
const {
|
|
20
|
+
title,
|
|
21
|
+
description,
|
|
22
|
+
children
|
|
23
|
+
}: { title?: string; description?: string; children: Snippet } = $props();
|
|
17
24
|
</script>
|
|
18
25
|
|
|
19
26
|
<article class="prose prose-base dark:prose-invert max-w-none pb-16">
|
|
27
|
+
{#if title}
|
|
28
|
+
<h1>{title}</h1>
|
|
29
|
+
{/if}
|
|
30
|
+
{#if description}
|
|
31
|
+
<p class="lead">{description}</p>
|
|
32
|
+
{/if}
|
|
20
33
|
{@render children()}
|
|
21
34
|
</article>
|
|
@@ -11,6 +11,8 @@ export declare const table: import("svelte").Component<{
|
|
|
11
11
|
}, {}, "">;
|
|
12
12
|
import type { Snippet } from 'svelte';
|
|
13
13
|
type $$ComponentProps = {
|
|
14
|
+
title?: string;
|
|
15
|
+
description?: string;
|
|
14
16
|
children: Snippet;
|
|
15
17
|
};
|
|
16
18
|
declare const MarkdownLayout: import("svelte").Component<$$ComponentProps, {}, "">;
|
package/dist/preprocess.d.ts
CHANGED
|
@@ -24,10 +24,9 @@ export interface DocsmithPreprocessOptions {
|
|
|
24
24
|
rehypePlugins?: MdsvexOptions['rehypePlugins'];
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Build the svelte-docsmith preprocessor: mdsvex with Shiki highlighting
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* failing the build.
|
|
27
|
+
* Build the svelte-docsmith preprocessor: mdsvex with Shiki highlighting (via
|
|
28
|
+
* the raw-code `highlight` hook, the correct mdsvex integration point), heading
|
|
29
|
+
* slugs/anchor sections, and the packaged doc layout. Unknown code-fence
|
|
30
|
+
* languages fall back to plain text instead of failing the build.
|
|
32
31
|
*/
|
|
33
32
|
export declare function docsmith(options?: DocsmithPreprocessOptions): PreprocessorGroup;
|
package/dist/preprocess.js
CHANGED
|
@@ -12,11 +12,10 @@ import { fileURLToPath } from 'node:url';
|
|
|
12
12
|
import rehypeSlug from 'rehype-slug';
|
|
13
13
|
import { DEFAULT_LANGS, DEFAULT_THEMES, lazyHighlighter } from './highlight.js';
|
|
14
14
|
/**
|
|
15
|
-
* Build the svelte-docsmith preprocessor: mdsvex with Shiki highlighting
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* failing the build.
|
|
15
|
+
* Build the svelte-docsmith preprocessor: mdsvex with Shiki highlighting (via
|
|
16
|
+
* the raw-code `highlight` hook, the correct mdsvex integration point), heading
|
|
17
|
+
* slugs/anchor sections, and the packaged doc layout. Unknown code-fence
|
|
18
|
+
* languages fall back to plain text instead of failing the build.
|
|
20
19
|
*/
|
|
21
20
|
export function docsmith(options = {}) {
|
|
22
21
|
const themes = options.themes ?? DEFAULT_THEMES;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class SearchState {
|
|
2
|
+
open: boolean;
|
|
3
|
+
}
|
|
4
|
+
/** Create the search state and publish it on context. Call in `DocsShell`. */
|
|
5
|
+
export declare function createSearchState(): SearchState;
|
|
6
|
+
/** Read the search state, or `undefined` when search is not enabled. */
|
|
7
|
+
export declare function useSearch(): SearchState | undefined;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared open-state for the search palette. `DocsShell` creates it once; the
|
|
3
|
+
* header/mobile-header triggers and the single `<Search>` dialog read it through
|
|
4
|
+
* context, so one keyboard shortcut and one dialog serve every trigger.
|
|
5
|
+
*/
|
|
6
|
+
import { getContext, setContext } from 'svelte';
|
|
7
|
+
const KEY = Symbol('docsmith-search');
|
|
8
|
+
export class SearchState {
|
|
9
|
+
open = $state(false);
|
|
10
|
+
}
|
|
11
|
+
/** Create the search state and publish it on context. Call in `DocsShell`. */
|
|
12
|
+
export function createSearchState() {
|
|
13
|
+
const state = new SearchState();
|
|
14
|
+
setContext(KEY, state);
|
|
15
|
+
return state;
|
|
16
|
+
}
|
|
17
|
+
/** Read the search state, or `undefined` when search is not enabled. */
|
|
18
|
+
export function useSearch() {
|
|
19
|
+
return getContext(KEY);
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SearchDoc } from '../config.js';
|
|
2
|
+
/** One result row: enough to render a link and a preview. */
|
|
3
|
+
export type SearchResult = {
|
|
4
|
+
path: string;
|
|
5
|
+
title: string;
|
|
6
|
+
section?: string;
|
|
7
|
+
snippet: string;
|
|
8
|
+
};
|
|
9
|
+
export type SearchEngine = {
|
|
10
|
+
/** Ranked results for `query`, at most `limit` (default 8). */
|
|
11
|
+
search(query: string, limit?: number): SearchResult[];
|
|
12
|
+
};
|
|
13
|
+
/** Build a search engine over `docs`. Indexing is synchronous and one-time. */
|
|
14
|
+
export declare function createSearchEngine(docs: SearchDoc[]): SearchEngine;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-side search engine. Builds a FlexSearch document index over the
|
|
3
|
+
* generated `svelte-docsmith/search` records (title, headings, description, and
|
|
4
|
+
* plain-text body) and returns a `search()` that maps hits back to page links
|
|
5
|
+
* with a context snippet. Framework-agnostic on purpose so it can be unit-tested
|
|
6
|
+
* without a DOM; the `<Search>` component lazy-loads both this and the index.
|
|
7
|
+
*/
|
|
8
|
+
import { Document } from 'flexsearch';
|
|
9
|
+
import { buildSnippet } from './snippet.js';
|
|
10
|
+
/** Build a search engine over `docs`. Indexing is synchronous and one-time. */
|
|
11
|
+
export function createSearchEngine(docs) {
|
|
12
|
+
const index = new Document({
|
|
13
|
+
tokenize: 'forward',
|
|
14
|
+
document: {
|
|
15
|
+
id: 'id',
|
|
16
|
+
// Title and headings first so their matches outrank body matches.
|
|
17
|
+
index: [
|
|
18
|
+
{ field: 'title' },
|
|
19
|
+
{ field: 'headings' },
|
|
20
|
+
{ field: 'description' },
|
|
21
|
+
{ field: 'text' }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
docs.forEach((doc, id) => {
|
|
26
|
+
index.add({
|
|
27
|
+
id,
|
|
28
|
+
title: doc.title,
|
|
29
|
+
headings: doc.headings.join(' '),
|
|
30
|
+
description: doc.description ?? '',
|
|
31
|
+
text: doc.text
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
search(query, limit = 8) {
|
|
36
|
+
const trimmed = query.trim();
|
|
37
|
+
if (!trimmed)
|
|
38
|
+
return [];
|
|
39
|
+
// `merge: true` returns unified, unique ids ranked across fields.
|
|
40
|
+
const hits = index.search(trimmed, { limit, merge: true });
|
|
41
|
+
const results = [];
|
|
42
|
+
for (const { id } of hits) {
|
|
43
|
+
const doc = docs[id];
|
|
44
|
+
if (!doc)
|
|
45
|
+
continue;
|
|
46
|
+
results.push({
|
|
47
|
+
path: doc.path,
|
|
48
|
+
title: doc.title,
|
|
49
|
+
section: doc.section,
|
|
50
|
+
snippet: buildSnippet(doc.text || doc.description || '', trimmed)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a short plain-text excerpt of `text` centered on the first matching
|
|
3
|
+
* query term, for showing context under a search result. Falls back to the head
|
|
4
|
+
* of the text when nothing matches. Word boundaries are respected so the excerpt
|
|
5
|
+
* never starts or ends mid-word, and elisions are marked with an ellipsis.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildSnippet(text: string, query: string, maxLength?: number): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a short plain-text excerpt of `text` centered on the first matching
|
|
3
|
+
* query term, for showing context under a search result. Falls back to the head
|
|
4
|
+
* of the text when nothing matches. Word boundaries are respected so the excerpt
|
|
5
|
+
* never starts or ends mid-word, and elisions are marked with an ellipsis.
|
|
6
|
+
*/
|
|
7
|
+
export function buildSnippet(text, query, maxLength = 160) {
|
|
8
|
+
const clean = text.replace(/\s+/g, ' ').trim();
|
|
9
|
+
if (!clean)
|
|
10
|
+
return '';
|
|
11
|
+
const haystack = clean.toLowerCase();
|
|
12
|
+
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
13
|
+
let match = -1;
|
|
14
|
+
for (const term of terms) {
|
|
15
|
+
const i = haystack.indexOf(term);
|
|
16
|
+
if (i !== -1 && (match === -1 || i < match))
|
|
17
|
+
match = i;
|
|
18
|
+
}
|
|
19
|
+
if (match === -1) {
|
|
20
|
+
return clean.length > maxLength ? clean.slice(0, maxLength).trimEnd() + '…' : clean;
|
|
21
|
+
}
|
|
22
|
+
// Window the text around the match, then snap the edges to word boundaries.
|
|
23
|
+
const half = Math.floor(maxLength / 2);
|
|
24
|
+
let end = Math.min(clean.length, Math.max(match + half, maxLength));
|
|
25
|
+
let start = Math.max(0, end - maxLength);
|
|
26
|
+
end = Math.min(clean.length, start + maxLength);
|
|
27
|
+
if (start > 0) {
|
|
28
|
+
const space = clean.indexOf(' ', start);
|
|
29
|
+
if (space !== -1 && space < match)
|
|
30
|
+
start = space + 1;
|
|
31
|
+
}
|
|
32
|
+
if (end < clean.length) {
|
|
33
|
+
const space = clean.lastIndexOf(' ', end);
|
|
34
|
+
if (space > match)
|
|
35
|
+
end = space;
|
|
36
|
+
}
|
|
37
|
+
let snippet = clean.slice(start, end).trim();
|
|
38
|
+
if (start > 0)
|
|
39
|
+
snippet = '…' + snippet;
|
|
40
|
+
if (end < clean.length)
|
|
41
|
+
snippet = snippet + '…';
|
|
42
|
+
return snippet;
|
|
43
|
+
}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `svelte-docsmith/search` — the generated search index.
|
|
3
|
+
*
|
|
4
|
+
* At build time the `docsmith()` Vite plugin (in `vite.config.ts`) intercepts
|
|
5
|
+
* this import and replaces it with your doc pages' plain-text bodies. This file
|
|
6
|
+
* is only the fallback that runs when the plugin is missing — it exists so the
|
|
7
|
+
* import type-checks and fails with a clear message instead of a mystery.
|
|
8
|
+
*/
|
|
9
|
+
import type { SearchDoc } from './config.js';
|
|
10
|
+
export declare const docs: SearchDoc[];
|
package/dist/search.js
ADDED
package/dist/theme.css
CHANGED
|
@@ -80,6 +80,31 @@
|
|
|
80
80
|
--shadow-2xl: var(--shadow-2xl);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/* A slim, rounded, theme-aware scrollbar — sits inset on transparent track so
|
|
84
|
+
* it reads as part of the surface, not a browser chrome. Used by scrolling
|
|
85
|
+
* overlays (the search palette, popovers) where the native bar looks heavy. */
|
|
86
|
+
@utility scrollbar-slim {
|
|
87
|
+
scrollbar-width: thin;
|
|
88
|
+
scrollbar-color: color-mix(in oklab, var(--border) 85%, transparent) transparent;
|
|
89
|
+
|
|
90
|
+
&::-webkit-scrollbar {
|
|
91
|
+
width: 10px;
|
|
92
|
+
height: 10px;
|
|
93
|
+
}
|
|
94
|
+
&::-webkit-scrollbar-track {
|
|
95
|
+
background: transparent;
|
|
96
|
+
}
|
|
97
|
+
&::-webkit-scrollbar-thumb {
|
|
98
|
+
border-radius: 9999px;
|
|
99
|
+
border: 3px solid transparent;
|
|
100
|
+
background-clip: padding-box;
|
|
101
|
+
background-color: color-mix(in oklab, var(--border) 85%, transparent);
|
|
102
|
+
}
|
|
103
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
104
|
+
background-color: var(--muted-foreground);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
83
108
|
@layer base {
|
|
84
109
|
:root {
|
|
85
110
|
--background: oklch(0.9383 0.0042 236.4993);
|