sdocs 0.0.3 → 0.0.5

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.
Files changed (194) hide show
  1. package/bin/sdocs.js +1 -1
  2. package/dist/app-gen.d.ts +10 -0
  3. package/dist/app-gen.js +147 -0
  4. package/dist/cli.js +71 -0
  5. package/dist/client/App.svelte +151 -0
  6. package/dist/client/App.svelte.d.ts +14 -0
  7. package/dist/client/CollapsiblePanel.svelte +63 -0
  8. package/dist/client/CollapsiblePanel.svelte.d.ts +9 -0
  9. package/dist/client/ComponentView.svelte +321 -0
  10. package/dist/client/ComponentView.svelte.d.ts +10 -0
  11. package/dist/client/ControlsPanel.svelte +191 -0
  12. package/dist/client/ControlsPanel.svelte.d.ts +13 -0
  13. package/dist/client/DataTable.svelte +78 -0
  14. package/dist/client/DataTable.svelte.d.ts +11 -0
  15. package/dist/client/HomePage.svelte +92 -0
  16. package/dist/client/HomePage.svelte.d.ts +8 -0
  17. package/dist/client/LayoutView.svelte +27 -0
  18. package/dist/client/LayoutView.svelte.d.ts +8 -0
  19. package/dist/client/PageView.svelte +130 -0
  20. package/dist/client/PageView.svelte.d.ts +8 -0
  21. package/dist/client/PreviewFrame.svelte +100 -0
  22. package/dist/client/PreviewFrame.svelte.d.ts +10 -0
  23. package/dist/client/Sidebar.svelte +329 -0
  24. package/dist/client/Sidebar.svelte.d.ts +16 -0
  25. package/dist/client/controls/CheckboxControl.svelte +37 -0
  26. package/dist/client/controls/CheckboxControl.svelte.d.ts +8 -0
  27. package/dist/client/controls/ColorControl.svelte +47 -0
  28. package/dist/client/controls/ColorControl.svelte.d.ts +8 -0
  29. package/dist/client/controls/DimensionControl.svelte +56 -0
  30. package/dist/client/controls/DimensionControl.svelte.d.ts +8 -0
  31. package/dist/client/controls/NumberControl.svelte +44 -0
  32. package/dist/client/controls/NumberControl.svelte.d.ts +8 -0
  33. package/dist/client/controls/SelectControl.svelte +48 -0
  34. package/dist/client/controls/SelectControl.svelte.d.ts +9 -0
  35. package/dist/client/controls/TextControl.svelte +43 -0
  36. package/dist/client/controls/TextControl.svelte.d.ts +8 -0
  37. package/dist/client/router.svelte.d.ts +11 -0
  38. package/dist/client/router.svelte.js +45 -0
  39. package/dist/client/theme.css +34 -0
  40. package/dist/client/tree-builder.d.ts +30 -0
  41. package/dist/client/tree-builder.js +162 -0
  42. package/dist/commands/build.d.ts +1 -0
  43. package/dist/commands/build.js +38 -0
  44. package/dist/commands/dev.d.ts +1 -0
  45. package/dist/commands/dev.js +40 -0
  46. package/dist/commands/init.d.ts +1 -0
  47. package/dist/commands/init.js +41 -0
  48. package/dist/commands/preview.d.ts +1 -0
  49. package/dist/commands/preview.js +25 -0
  50. package/dist/config.d.ts +7 -0
  51. package/dist/config.js +57 -0
  52. package/dist/index.d.ts +2 -2
  53. package/dist/index.js +1 -4
  54. package/dist/server/discovery.d.ts +6 -0
  55. package/dist/server/discovery.js +24 -0
  56. package/dist/server/highlighter.d.ts +4 -0
  57. package/dist/server/highlighter.js +31 -0
  58. package/dist/server/meta-parser.d.ts +11 -0
  59. package/dist/server/meta-parser.js +107 -0
  60. package/dist/server/prop-parser.d.ts +5 -0
  61. package/dist/server/prop-parser.js +275 -0
  62. package/dist/server/sdocx-parser.d.ts +11 -0
  63. package/dist/server/sdocx-parser.js +197 -0
  64. package/dist/server/snippet-compiler.d.ts +27 -0
  65. package/dist/server/snippet-compiler.js +145 -0
  66. package/dist/server/snippet-extractor.d.ts +11 -0
  67. package/dist/server/snippet-extractor.js +37 -0
  68. package/dist/server/toc-extractor.d.ts +5 -0
  69. package/dist/server/toc-extractor.js +37 -0
  70. package/dist/types.d.ts +100 -148
  71. package/dist/vite.d.ts +5 -2
  72. package/dist/vite.js +266 -2
  73. package/package.json +50 -74
  74. package/README.md +0 -43
  75. package/dist/Sdocs.svelte +0 -1210
  76. package/dist/Sdocs.svelte.d.ts +0 -5
  77. package/dist/cli/app-plugin.d.ts +0 -7
  78. package/dist/cli/app-plugin.js +0 -69
  79. package/dist/cli/config.d.ts +0 -12
  80. package/dist/cli/config.js +0 -34
  81. package/dist/cli/index.js +0 -72
  82. package/dist/cli/server.d.ts +0 -2
  83. package/dist/cli/server.js +0 -64
  84. package/dist/docgen.d.ts +0 -47
  85. package/dist/docgen.js +0 -463
  86. package/dist/internal/ComponentPreview.svelte +0 -58
  87. package/dist/internal/ComponentPreview.svelte.d.ts +0 -17
  88. package/dist/internal/CssPropsTable.svelte +0 -239
  89. package/dist/internal/CssPropsTable.svelte.d.ts +0 -11
  90. package/dist/internal/Home.svelte +0 -92
  91. package/dist/internal/Home.svelte.d.ts +0 -9
  92. package/dist/internal/MethodsTable.svelte +0 -72
  93. package/dist/internal/MethodsTable.svelte.d.ts +0 -7
  94. package/dist/internal/PropsTable.svelte +0 -342
  95. package/dist/internal/PropsTable.svelte.d.ts +0 -12
  96. package/dist/internal/Showcase.svelte +0 -130
  97. package/dist/internal/Showcase.svelte.d.ts +0 -21
  98. package/dist/ui/Badge/Badge.docs.svelte +0 -46
  99. package/dist/ui/Badge/Badge.docs.svelte.d.ts +0 -26
  100. package/dist/ui/Badge/Badge.svelte +0 -59
  101. package/dist/ui/Badge/Badge.svelte.d.ts +0 -17
  102. package/dist/ui/Badge/index.d.ts +0 -1
  103. package/dist/ui/Badge/index.js +0 -1
  104. package/dist/ui/Checkbox/Checkbox.docs.svelte +0 -51
  105. package/dist/ui/Checkbox/Checkbox.docs.svelte.d.ts +0 -27
  106. package/dist/ui/Checkbox/Checkbox.svelte +0 -169
  107. package/dist/ui/Checkbox/Checkbox.svelte.d.ts +0 -18
  108. package/dist/ui/Checkbox/index.d.ts +0 -1
  109. package/dist/ui/Checkbox/index.js +0 -1
  110. package/dist/ui/CodeBlock/CodeBlock.docs.svelte +0 -28
  111. package/dist/ui/CodeBlock/CodeBlock.docs.svelte.d.ts +0 -24
  112. package/dist/ui/CodeBlock/CodeBlock.svelte +0 -101
  113. package/dist/ui/CodeBlock/CodeBlock.svelte.d.ts +0 -7
  114. package/dist/ui/CodeBlock/index.d.ts +0 -1
  115. package/dist/ui/CodeBlock/index.js +0 -1
  116. package/dist/ui/Frame/Frame.docs.svelte +0 -140
  117. package/dist/ui/Frame/Frame.docs.svelte.d.ts +0 -26
  118. package/dist/ui/Frame/Frame.svelte +0 -88
  119. package/dist/ui/Frame/Frame.svelte.d.ts +0 -15
  120. package/dist/ui/Frame/index.d.ts +0 -1
  121. package/dist/ui/Frame/index.js +0 -1
  122. package/dist/ui/InputNumber/InputNumber.docs.svelte +0 -50
  123. package/dist/ui/InputNumber/InputNumber.docs.svelte.d.ts +0 -26
  124. package/dist/ui/InputNumber/InputNumber.svelte +0 -275
  125. package/dist/ui/InputNumber/InputNumber.svelte.d.ts +0 -26
  126. package/dist/ui/InputNumber/index.d.ts +0 -1
  127. package/dist/ui/InputNumber/index.js +0 -1
  128. package/dist/ui/InputText/InputText.docs.svelte +0 -43
  129. package/dist/ui/InputText/InputText.docs.svelte.d.ts +0 -26
  130. package/dist/ui/InputText/InputText.svelte +0 -116
  131. package/dist/ui/InputText/InputText.svelte.d.ts +0 -22
  132. package/dist/ui/InputText/index.d.ts +0 -1
  133. package/dist/ui/InputText/index.js +0 -1
  134. package/dist/ui/Panel/CollapsiblePanel.docs.svelte +0 -45
  135. package/dist/ui/Panel/CollapsiblePanel.docs.svelte.d.ts +0 -25
  136. package/dist/ui/Panel/CollapsiblePanel.svelte +0 -93
  137. package/dist/ui/Panel/CollapsiblePanel.svelte.d.ts +0 -14
  138. package/dist/ui/Panel/index.d.ts +0 -1
  139. package/dist/ui/Panel/index.js +0 -1
  140. package/dist/ui/Placeholder/Placeholder.docs.svelte +0 -49
  141. package/dist/ui/Placeholder/Placeholder.docs.svelte.d.ts +0 -26
  142. package/dist/ui/Placeholder/Placeholder.svelte +0 -99
  143. package/dist/ui/Placeholder/Placeholder.svelte.d.ts +0 -21
  144. package/dist/ui/Placeholder/index.d.ts +0 -1
  145. package/dist/ui/Placeholder/index.js +0 -1
  146. package/dist/ui/Radio/Radio.docs.svelte +0 -67
  147. package/dist/ui/Radio/Radio.docs.svelte.d.ts +0 -27
  148. package/dist/ui/Radio/Radio.svelte +0 -165
  149. package/dist/ui/Radio/Radio.svelte.d.ts +0 -22
  150. package/dist/ui/Radio/RadioGroup.docs.svelte +0 -70
  151. package/dist/ui/Radio/RadioGroup.docs.svelte.d.ts +0 -27
  152. package/dist/ui/Radio/RadioGroup.svelte +0 -98
  153. package/dist/ui/Radio/RadioGroup.svelte.d.ts +0 -27
  154. package/dist/ui/Radio/index.d.ts +0 -2
  155. package/dist/ui/Radio/index.js +0 -2
  156. package/dist/ui/SegmentControl/SegmentControl.docs.svelte +0 -54
  157. package/dist/ui/SegmentControl/SegmentControl.docs.svelte.d.ts +0 -25
  158. package/dist/ui/SegmentControl/SegmentControl.svelte +0 -120
  159. package/dist/ui/SegmentControl/SegmentControl.svelte.d.ts +0 -18
  160. package/dist/ui/SegmentControl/index.d.ts +0 -1
  161. package/dist/ui/SegmentControl/index.js +0 -1
  162. package/dist/ui/Stack/Stack.docs.svelte +0 -63
  163. package/dist/ui/Stack/Stack.docs.svelte.d.ts +0 -26
  164. package/dist/ui/Stack/Stack.svelte +0 -45
  165. package/dist/ui/Stack/Stack.svelte.d.ts +0 -19
  166. package/dist/ui/Stack/index.d.ts +0 -1
  167. package/dist/ui/Stack/index.js +0 -1
  168. package/dist/ui/Table/Body.svelte +0 -17
  169. package/dist/ui/Table/Body.svelte.d.ts +0 -11
  170. package/dist/ui/Table/Caption.svelte +0 -17
  171. package/dist/ui/Table/Caption.svelte.d.ts +0 -11
  172. package/dist/ui/Table/Cell.svelte +0 -24
  173. package/dist/ui/Table/Cell.svelte.d.ts +0 -15
  174. package/dist/ui/Table/Foot.svelte +0 -17
  175. package/dist/ui/Table/Foot.svelte.d.ts +0 -11
  176. package/dist/ui/Table/Head.svelte +0 -17
  177. package/dist/ui/Table/Head.svelte.d.ts +0 -11
  178. package/dist/ui/Table/Header.svelte +0 -27
  179. package/dist/ui/Table/Header.svelte.d.ts +0 -17
  180. package/dist/ui/Table/Row.svelte +0 -19
  181. package/dist/ui/Table/Row.svelte.d.ts +0 -13
  182. package/dist/ui/Table/Table.docs.svelte +0 -197
  183. package/dist/ui/Table/Table.docs.svelte.d.ts +0 -28
  184. package/dist/ui/Table/Table.svelte +0 -140
  185. package/dist/ui/Table/Table.svelte.d.ts +0 -27
  186. package/dist/ui/Table/index.js +0 -10
  187. package/dist/ui/css/colors.css +0 -377
  188. package/dist/ui/css/global.css +0 -10
  189. package/dist/ui/index.d.ts +0 -12
  190. package/dist/ui/index.js +0 -12
  191. package/dist/virtual-sdocs.d.ts +0 -20
  192. package/dist/vite-plugin.d.ts +0 -18
  193. package/dist/vite-plugin.js +0 -206
  194. /package/dist/{cli/index.d.ts → cli.d.ts} +0 -0
package/bin/sdocs.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import('../dist/cli/index.js');
2
+ import '../dist/cli.js';
@@ -0,0 +1,10 @@
1
+ import type { ResolvedSdocsConfig } from './types.js';
2
+ /** Generate .sdocs/ directory with entry files for dev mode */
3
+ export declare function generateDevFiles(config: ResolvedSdocsConfig, cwd: string): Promise<string>;
4
+ /** Generate .sdocs/ directory with entry + preview HTML files for build mode */
5
+ export declare function generateBuildFiles(config: ResolvedSdocsConfig, cwd: string): Promise<{
6
+ sdocsDir: string;
7
+ inputs: Record<string, string>;
8
+ }>;
9
+ /** Remove the .sdocs/ temp directory */
10
+ export declare function cleanBuildFiles(cwd: string): Promise<void>;
@@ -0,0 +1,147 @@
1
+ import { mkdir, writeFile, rm, readFile } from 'node:fs/promises';
2
+ import { dirname, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { discoverDocFiles, getSdocKind } from './server/discovery.js';
5
+ import { extractSnippets, hasDefaultSnippet } from './server/snippet-extractor.js';
6
+ import { base64urlEncode } from './server/snippet-compiler.js';
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ /** Absolute path to the client App.svelte in the installed package */
9
+ function getAppComponentPath() {
10
+ return resolve(__dirname, 'client', 'App.svelte');
11
+ }
12
+ /** Generate the main index.html */
13
+ function generateIndexHtml(title) {
14
+ return `<!DOCTYPE html>
15
+ <html lang="en">
16
+ <head>
17
+ <meta charset="UTF-8">
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ <title>${title}</title>
20
+ </head>
21
+ <body>
22
+ <div id="app"></div>
23
+ <script type="module" src="./entry.js"></script>
24
+ </body>
25
+ </html>`;
26
+ }
27
+ /** Generate the entry.js that mounts the App */
28
+ function generateEntryJs(config) {
29
+ const appPath = getAppComponentPath().replace(/\\/g, '/');
30
+ return `import { mount } from 'svelte';
31
+ import { docs, cssNames } from 'virtual:sdocs';
32
+ import App from '${appPath}';
33
+
34
+ mount(App, {
35
+ target: document.getElementById('app'),
36
+ props: {
37
+ docs,
38
+ cssNames,
39
+ logo: ${JSON.stringify(config.logo)},
40
+ sidebarConfig: ${JSON.stringify(config.sidebar)},
41
+ }
42
+ });`;
43
+ }
44
+ /** Generate a preview HTML page for an iframe snippet */
45
+ function generatePreviewHtml(iframeVirtualId, css) {
46
+ let cssLinks = '';
47
+ if (css) {
48
+ if (typeof css === 'string') {
49
+ cssLinks = `<link rel="stylesheet" href="${css}">`;
50
+ }
51
+ else {
52
+ const names = Object.keys(css);
53
+ cssLinks = names
54
+ .map((name, i) => `<link rel="stylesheet" href="${css[name]}" data-sdocs-stylesheet="${name}"${i > 0 ? ' disabled' : ''}>`)
55
+ .join('\n\t');
56
+ }
57
+ }
58
+ return `<!DOCTYPE html>
59
+ <html>
60
+ <head>
61
+ <meta charset="utf-8">
62
+ <meta name="viewport" content="width=device-width, initial-scale=1">
63
+ ${cssLinks}
64
+ <style>body { margin: 0; }</style>
65
+ </head>
66
+ <body>
67
+ <div id="app"></div>
68
+ <script type="module">
69
+ import { mount } from 'svelte';
70
+ import App from '${iframeVirtualId}';
71
+ mount(App, { target: document.getElementById('app') });
72
+
73
+ window.addEventListener('message', (e) => {
74
+ if (e.data?.type === 'sdocs:update-stylesheet') {
75
+ const name = e.data.name;
76
+ document.querySelectorAll('link[data-sdocs-stylesheet]').forEach((link) => {
77
+ link.disabled = link.dataset.sdocsStylesheet !== name;
78
+ });
79
+ }
80
+ if (e.data?.type === 'sdocs:scroll-to') {
81
+ const el = document.getElementById(e.data.id);
82
+ if (el) el.scrollIntoView({ behavior: 'smooth' });
83
+ }
84
+ });
85
+ </script>
86
+ </body>
87
+ </html>`;
88
+ }
89
+ /** Discover doc files and extract snippet names (lightweight, no highlighting) */
90
+ async function discoverSnippets(config, cwd) {
91
+ const files = await discoverDocFiles(config.include, cwd);
92
+ const results = [];
93
+ for (const filePath of files) {
94
+ const source = await readFile(filePath, 'utf-8');
95
+ const kind = getSdocKind(filePath);
96
+ if (kind === 'page' || kind === 'layout') {
97
+ results.push({ filePath, snippetNames: ['Content'] });
98
+ }
99
+ else {
100
+ const snippets = extractSnippets(source);
101
+ const names = snippets.map((s) => s.name);
102
+ if (!hasDefaultSnippet(snippets)) {
103
+ names.unshift('Default');
104
+ }
105
+ results.push({ filePath, snippetNames: names });
106
+ }
107
+ }
108
+ return results;
109
+ }
110
+ /** Generate .sdocs/ directory with entry files for dev mode */
111
+ export async function generateDevFiles(config, cwd) {
112
+ const sdocsDir = resolve(cwd, '.sdocs');
113
+ await mkdir(sdocsDir, { recursive: true });
114
+ await writeFile(resolve(sdocsDir, 'index.html'), generateIndexHtml(config.logo));
115
+ await writeFile(resolve(sdocsDir, 'entry.js'), generateEntryJs(config));
116
+ return sdocsDir;
117
+ }
118
+ /** Generate .sdocs/ directory with entry + preview HTML files for build mode */
119
+ export async function generateBuildFiles(config, cwd) {
120
+ const sdocsDir = resolve(cwd, '.sdocs');
121
+ await mkdir(sdocsDir, { recursive: true });
122
+ await writeFile(resolve(sdocsDir, 'index.html'), generateIndexHtml(config.logo));
123
+ await writeFile(resolve(sdocsDir, 'entry.js'), generateEntryJs(config));
124
+ const inputs = {
125
+ main: resolve(sdocsDir, 'index.html'),
126
+ };
127
+ // Discover snippets and generate preview HTML pages
128
+ const docSnippets = await discoverSnippets(config, cwd);
129
+ for (const { filePath, snippetNames } of docSnippets) {
130
+ const encoded = base64urlEncode(filePath);
131
+ for (const snippetName of snippetNames) {
132
+ const iframeId = `/@sdocs/iframe/${encoded}/${snippetName}.svelte`;
133
+ const previewDir = resolve(sdocsDir, 'previews', encoded);
134
+ await mkdir(previewDir, { recursive: true });
135
+ const previewPath = resolve(previewDir, `${snippetName}.html`);
136
+ await writeFile(previewPath, generatePreviewHtml(iframeId, config.css));
137
+ const inputKey = `preview-${encoded}-${snippetName}`;
138
+ inputs[inputKey] = previewPath;
139
+ }
140
+ }
141
+ return { sdocsDir, inputs };
142
+ }
143
+ /** Remove the .sdocs/ temp directory */
144
+ export async function cleanBuildFiles(cwd) {
145
+ const sdocsDir = resolve(cwd, '.sdocs');
146
+ await rm(sdocsDir, { recursive: true, force: true });
147
+ }
package/dist/cli.js ADDED
@@ -0,0 +1,71 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, resolve } from 'node:path';
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ function getVersion() {
6
+ try {
7
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
8
+ return pkg.version;
9
+ }
10
+ catch {
11
+ return 'unknown';
12
+ }
13
+ }
14
+ const HELP = `
15
+ sdocs — A lightweight documentation tool for Svelte 5 components
16
+
17
+ Usage:
18
+ sdocs <command>
19
+
20
+ Commands:
21
+ dev Start development server with HMR
22
+ build Build static documentation site
23
+ preview Serve built site locally
24
+ init Scaffold sdocs.config.js
25
+
26
+ Options:
27
+ --help Show this help message
28
+ --version Show version number
29
+ `.trim();
30
+ async function main() {
31
+ const args = process.argv.slice(2);
32
+ const command = args[0];
33
+ if (!command || command === '--help' || command === '-h') {
34
+ console.log(HELP);
35
+ return;
36
+ }
37
+ if (command === '--version' || command === '-v') {
38
+ console.log(getVersion());
39
+ return;
40
+ }
41
+ switch (command) {
42
+ case 'dev': {
43
+ const { devCommand } = await import('./commands/dev.js');
44
+ await devCommand();
45
+ break;
46
+ }
47
+ case 'build': {
48
+ const { buildCommand } = await import('./commands/build.js');
49
+ await buildCommand();
50
+ break;
51
+ }
52
+ case 'preview': {
53
+ const { previewCommand } = await import('./commands/preview.js');
54
+ await previewCommand();
55
+ break;
56
+ }
57
+ case 'init': {
58
+ const { initCommand } = await import('./commands/init.js');
59
+ await initCommand();
60
+ break;
61
+ }
62
+ default:
63
+ console.error(`Unknown command: ${command}`);
64
+ console.log(HELP);
65
+ process.exit(1);
66
+ }
67
+ }
68
+ main().catch((err) => {
69
+ console.error(err);
70
+ process.exit(1);
71
+ });
@@ -0,0 +1,151 @@
1
+ <script lang="ts">
2
+ import type { DocEntry } from '../types.js';
3
+ import { initRouter, getPath } from './router.svelte.js';
4
+ import { buildTree, findDocByPath } from './tree-builder.js';
5
+ import Sidebar from './Sidebar.svelte';
6
+ import ComponentView from './ComponentView.svelte';
7
+ import PageView from './PageView.svelte';
8
+ import LayoutView from './LayoutView.svelte';
9
+ import HomePage from './HomePage.svelte';
10
+ import { onMount } from 'svelte';
11
+ import './theme.css';
12
+
13
+ type ThemeMode = 'light' | 'dark' | 'system';
14
+
15
+ interface Props {
16
+ docs: DocEntry[];
17
+ logo?: string;
18
+ cssNames?: string[];
19
+ sidebarConfig?: {
20
+ order?: Record<string, string[]>;
21
+ open?: string[];
22
+ };
23
+ }
24
+
25
+ let { docs, logo = 'sdocs', cssNames = [], sidebarConfig }: Props = $props();
26
+
27
+ let sidebarHidden = $state(false);
28
+ let activeStylesheet = $state<string | undefined>(undefined);
29
+ let theme = $state<ThemeMode>('system');
30
+
31
+ // Initialize active stylesheet to first named CSS (if any)
32
+ $effect(() => {
33
+ if (cssNames.length > 0 && !activeStylesheet) {
34
+ activeStylesheet = cssNames[0];
35
+ }
36
+ });
37
+
38
+ onMount(() => {
39
+ initRouter();
40
+ // Read saved theme preference
41
+ const saved = localStorage.getItem('sdocs-theme') as ThemeMode | null;
42
+ if (saved && ['light', 'dark', 'system'].includes(saved)) {
43
+ theme = saved;
44
+ }
45
+ });
46
+
47
+ // Apply theme attribute and persist
48
+ $effect(() => {
49
+ const root = document.querySelector('.sdocs-app');
50
+ if (!root) return;
51
+
52
+ let resolved: 'light' | 'dark';
53
+ if (theme === 'system') {
54
+ resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
55
+ } else {
56
+ resolved = theme;
57
+ }
58
+ root.setAttribute('data-sdocs-theme', resolved);
59
+ localStorage.setItem('sdocs-theme', theme);
60
+ });
61
+
62
+ // Listen for OS theme changes when in system mode
63
+ $effect(() => {
64
+ if (theme !== 'system') return;
65
+ const mq = window.matchMedia('(prefers-color-scheme: dark)');
66
+ const handler = () => {
67
+ const root = document.querySelector('.sdocs-app');
68
+ if (root) {
69
+ root.setAttribute('data-sdocs-theme', mq.matches ? 'dark' : 'light');
70
+ }
71
+ };
72
+ mq.addEventListener('change', handler);
73
+ return () => mq.removeEventListener('change', handler);
74
+ });
75
+
76
+ const currentPath = $derived(getPath());
77
+ const tree = $derived(buildTree(docs, sidebarConfig));
78
+ const resolved = $derived(findDocByPath(docs, currentPath));
79
+ </script>
80
+
81
+ <div class="sdocs-app">
82
+ {#if !sidebarHidden}
83
+ <Sidebar
84
+ {tree}
85
+ {currentPath}
86
+ {logo}
87
+ {cssNames}
88
+ {activeStylesheet}
89
+ {theme}
90
+ onToggleFullscreen={() => sidebarHidden = true}
91
+ onStylesheetChange={(name) => activeStylesheet = name}
92
+ onThemeChange={(t) => theme = t}
93
+ />
94
+ {:else}
95
+ <button class="sdocs-exit-fullscreen" onclick={() => sidebarHidden = false}>
96
+ &#9664; Exit fullscreen
97
+ </button>
98
+ {/if}
99
+ <main class="sdocs-main" class:sdocs-main-fullscreen={sidebarHidden}>
100
+ {#if resolved}
101
+ {#if resolved.doc.kind === 'page'}
102
+ <PageView doc={resolved.doc} {activeStylesheet} />
103
+ {:else if resolved.doc.kind === 'layout'}
104
+ <LayoutView doc={resolved.doc} {activeStylesheet} />
105
+ {:else}
106
+ <ComponentView doc={resolved.doc} snippetName={resolved.snippetName} {activeStylesheet} />
107
+ {/if}
108
+ {:else}
109
+ <HomePage {docs} {logo} />
110
+ {/if}
111
+ </main>
112
+ </div>
113
+
114
+ <style>
115
+ :global(body) {
116
+ margin: 0;
117
+ padding: 0;
118
+ }
119
+ .sdocs-app {
120
+ display: flex;
121
+ height: 100vh;
122
+ overflow: hidden;
123
+ position: relative;
124
+ }
125
+ .sdocs-main {
126
+ flex: 1;
127
+ overflow-y: auto;
128
+ background: var(--sdocs-bg);
129
+ }
130
+ .sdocs-main-fullscreen {
131
+ overflow-y: auto;
132
+ }
133
+ .sdocs-exit-fullscreen {
134
+ position: fixed;
135
+ top: 12px;
136
+ left: 12px;
137
+ z-index: 100;
138
+ padding: 6px 12px;
139
+ border: 1px solid var(--sdocs-border);
140
+ border-radius: 6px;
141
+ background: var(--sdocs-bg);
142
+ font-size: 12px;
143
+ color: var(--sdocs-text);
144
+ cursor: pointer;
145
+ box-shadow: 0 1px 3px var(--sdocs-shadow);
146
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
147
+ }
148
+ .sdocs-exit-fullscreen:hover {
149
+ background: var(--sdocs-bg-hover);
150
+ }
151
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { DocEntry } from '../types.js';
2
+ import './theme.css';
3
+ interface Props {
4
+ docs: DocEntry[];
5
+ logo?: string;
6
+ cssNames?: string[];
7
+ sidebarConfig?: {
8
+ order?: Record<string, string[]>;
9
+ open?: string[];
10
+ };
11
+ }
12
+ declare const App: import("svelte").Component<Props, {}, "">;
13
+ type App = ReturnType<typeof App>;
14
+ export default App;
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ title: string;
6
+ defaultExpanded?: boolean;
7
+ children: Snippet;
8
+ }
9
+
10
+ let { title, defaultExpanded = true, children }: Props = $props();
11
+ let expanded = $state(defaultExpanded);
12
+ </script>
13
+
14
+ <div class="sdocs-panel">
15
+ <button class="sdocs-panel-header" onclick={() => expanded = !expanded}>
16
+ <span class="sdocs-panel-arrow" class:expanded>&#9654;</span>
17
+ <span class="sdocs-panel-title">{title}</span>
18
+ </button>
19
+ {#if expanded}
20
+ <div class="sdocs-panel-body">
21
+ {@render children()}
22
+ </div>
23
+ {/if}
24
+ </div>
25
+
26
+ <style>
27
+ .sdocs-panel {
28
+ border: 1px solid var(--sdocs-border);
29
+ border-radius: 8px;
30
+ overflow: hidden;
31
+ }
32
+ .sdocs-panel-header {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: 8px;
36
+ width: 100%;
37
+ padding: 10px 14px;
38
+ border: none;
39
+ background: var(--sdocs-bg-subtle);
40
+ font: inherit;
41
+ font-size: 13px;
42
+ font-weight: 600;
43
+ color: var(--sdocs-text-heading);
44
+ cursor: pointer;
45
+ text-align: left;
46
+ }
47
+ .sdocs-panel-header:hover {
48
+ background: var(--sdocs-bg-hover);
49
+ }
50
+ .sdocs-panel-arrow {
51
+ font-size: 8px;
52
+ transition: transform 0.15s;
53
+ display: inline-block;
54
+ width: 10px;
55
+ }
56
+ .sdocs-panel-arrow.expanded {
57
+ transform: rotate(90deg);
58
+ }
59
+ .sdocs-panel-body {
60
+ padding: 14px;
61
+ border-top: 1px solid var(--sdocs-border);
62
+ }
63
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ title: string;
4
+ defaultExpanded?: boolean;
5
+ children: Snippet;
6
+ }
7
+ declare const CollapsiblePanel: import("svelte").Component<Props, {}, "">;
8
+ type CollapsiblePanel = ReturnType<typeof CollapsiblePanel>;
9
+ export default CollapsiblePanel;