svedocs 0.1.0-beta.2

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 (192) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +38 -0
  3. package/dist/ai/openai-compatible.d.ts +13 -0
  4. package/dist/ai/openai-compatible.d.ts.map +1 -0
  5. package/dist/ai/openai-compatible.js +92 -0
  6. package/dist/ai/providers.d.ts +19 -0
  7. package/dist/ai/providers.d.ts.map +1 -0
  8. package/dist/ai/providers.js +185 -0
  9. package/dist/ai/rate-limit.d.ts +18 -0
  10. package/dist/ai/rate-limit.d.ts.map +1 -0
  11. package/dist/ai/rate-limit.js +52 -0
  12. package/dist/ai/response.d.ts +4 -0
  13. package/dist/ai/response.d.ts.map +1 -0
  14. package/dist/ai/response.js +151 -0
  15. package/dist/ai/runtime.d.ts +30 -0
  16. package/dist/ai/runtime.d.ts.map +1 -0
  17. package/dist/ai/runtime.js +105 -0
  18. package/dist/ai/types.d.ts +93 -0
  19. package/dist/ai/types.d.ts.map +1 -0
  20. package/dist/ai/types.js +1 -0
  21. package/dist/ai.d.ts +7 -0
  22. package/dist/ai.d.ts.map +1 -0
  23. package/dist/ai.js +6 -0
  24. package/dist/ambient.d.ts +5 -0
  25. package/dist/cloudflare.d.ts +27 -0
  26. package/dist/cloudflare.d.ts.map +1 -0
  27. package/dist/cloudflare.js +146 -0
  28. package/dist/config.d.ts +311 -0
  29. package/dist/config.d.ts.map +1 -0
  30. package/dist/config.js +243 -0
  31. package/dist/core/checks.d.ts +4 -0
  32. package/dist/core/checks.d.ts.map +1 -0
  33. package/dist/core/checks.js +252 -0
  34. package/dist/core/config.d.ts +5 -0
  35. package/dist/core/config.d.ts.map +1 -0
  36. package/dist/core/config.js +182 -0
  37. package/dist/core/content.d.ts +7 -0
  38. package/dist/core/content.d.ts.map +1 -0
  39. package/dist/core/content.js +211 -0
  40. package/dist/core/links.d.ts +8 -0
  41. package/dist/core/links.d.ts.map +1 -0
  42. package/dist/core/links.js +94 -0
  43. package/dist/core/navigation.d.ts +5 -0
  44. package/dist/core/navigation.d.ts.map +1 -0
  45. package/dist/core/navigation.js +144 -0
  46. package/dist/core/search.d.ts +5 -0
  47. package/dist/core/search.d.ts.map +1 -0
  48. package/dist/core/search.js +41 -0
  49. package/dist/core/types.d.ts +269 -0
  50. package/dist/core/types.d.ts.map +1 -0
  51. package/dist/core/types.js +4 -0
  52. package/dist/core/utils.d.ts +12 -0
  53. package/dist/core/utils.d.ts.map +1 -0
  54. package/dist/core/utils.js +52 -0
  55. package/dist/core.d.ts +8 -0
  56. package/dist/core.d.ts.map +1 -0
  57. package/dist/core.js +7 -0
  58. package/dist/index.d.ts +6 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +3 -0
  61. package/dist/mdx/ast.d.ts +32 -0
  62. package/dist/mdx/ast.d.ts.map +1 -0
  63. package/dist/mdx/ast.js +148 -0
  64. package/dist/mdx/code.d.ts +14 -0
  65. package/dist/mdx/code.d.ts.map +1 -0
  66. package/dist/mdx/code.js +315 -0
  67. package/dist/mdx/compile.d.ts +26 -0
  68. package/dist/mdx/compile.d.ts.map +1 -0
  69. package/dist/mdx/compile.js +63 -0
  70. package/dist/mdx/diff.d.ts +5 -0
  71. package/dist/mdx/diff.d.ts.map +1 -0
  72. package/dist/mdx/diff.js +160 -0
  73. package/dist/mdx/utils.d.ts +10 -0
  74. package/dist/mdx/utils.d.ts.map +1 -0
  75. package/dist/mdx/utils.js +64 -0
  76. package/dist/og/image.d.ts +21 -0
  77. package/dist/og/image.d.ts.map +1 -0
  78. package/dist/og/image.js +216 -0
  79. package/dist/og/metadata.d.ts +7 -0
  80. package/dist/og/metadata.d.ts.map +1 -0
  81. package/dist/og/metadata.js +160 -0
  82. package/dist/og/types.d.ts +59 -0
  83. package/dist/og/types.d.ts.map +1 -0
  84. package/dist/og/types.js +1 -0
  85. package/dist/og.d.ts +4 -0
  86. package/dist/og.d.ts.map +1 -0
  87. package/dist/og.js +3 -0
  88. package/dist/search/algolia.d.ts +10 -0
  89. package/dist/search/algolia.d.ts.map +1 -0
  90. package/dist/search/algolia.js +82 -0
  91. package/dist/search/cloudflare-sync.d.ts +5 -0
  92. package/dist/search/cloudflare-sync.d.ts.map +1 -0
  93. package/dist/search/cloudflare-sync.js +169 -0
  94. package/dist/search/cloudflare.d.ts +9 -0
  95. package/dist/search/cloudflare.d.ts.map +1 -0
  96. package/dist/search/cloudflare.js +115 -0
  97. package/dist/search/local.d.ts +9 -0
  98. package/dist/search/local.d.ts.map +1 -0
  99. package/dist/search/local.js +122 -0
  100. package/dist/search/runtime.d.ts +41 -0
  101. package/dist/search/runtime.d.ts.map +1 -0
  102. package/dist/search/runtime.js +151 -0
  103. package/dist/search/types.d.ts +172 -0
  104. package/dist/search/types.d.ts.map +1 -0
  105. package/dist/search/types.js +1 -0
  106. package/dist/search/typesense.d.ts +11 -0
  107. package/dist/search/typesense.d.ts.map +1 -0
  108. package/dist/search/typesense.js +91 -0
  109. package/dist/search/utils.d.ts +10 -0
  110. package/dist/search/utils.d.ts.map +1 -0
  111. package/dist/search/utils.js +55 -0
  112. package/dist/search.d.ts +8 -0
  113. package/dist/search.d.ts.map +1 -0
  114. package/dist/search.js +7 -0
  115. package/dist/svelte.d.ts +24 -0
  116. package/dist/svelte.d.ts.map +1 -0
  117. package/dist/svelte.js +51 -0
  118. package/dist/testing.d.ts +3 -0
  119. package/dist/testing.d.ts.map +1 -0
  120. package/dist/testing.js +23 -0
  121. package/dist/theme/AskAiPanel.svelte +433 -0
  122. package/dist/theme/AskAiPanel.svelte.d.ts +27 -0
  123. package/dist/theme/AskAiPanel.svelte.d.ts.map +1 -0
  124. package/dist/theme/Button.svelte +34 -0
  125. package/dist/theme/Button.svelte.d.ts +41 -0
  126. package/dist/theme/Button.svelte.d.ts.map +1 -0
  127. package/dist/theme/Checkbox.svelte +63 -0
  128. package/dist/theme/Checkbox.svelte.d.ts +45 -0
  129. package/dist/theme/Checkbox.svelte.d.ts.map +1 -0
  130. package/dist/theme/CodeBlock.svelte +6 -0
  131. package/dist/theme/CodeBlock.svelte.d.ts +22 -0
  132. package/dist/theme/CodeBlock.svelte.d.ts.map +1 -0
  133. package/dist/theme/DocPage.svelte +121 -0
  134. package/dist/theme/DocPage.svelte.d.ts +33 -0
  135. package/dist/theme/DocPage.svelte.d.ts.map +1 -0
  136. package/dist/theme/DocsApp.svelte +78 -0
  137. package/dist/theme/DocsApp.svelte.d.ts +63 -0
  138. package/dist/theme/DocsApp.svelte.d.ts.map +1 -0
  139. package/dist/theme/DocsLayout.svelte +167 -0
  140. package/dist/theme/DocsLayout.svelte.d.ts +40 -0
  141. package/dist/theme/DocsLayout.svelte.d.ts.map +1 -0
  142. package/dist/theme/FloatingToolbar.svelte +73 -0
  143. package/dist/theme/FloatingToolbar.svelte.d.ts +22 -0
  144. package/dist/theme/FloatingToolbar.svelte.d.ts.map +1 -0
  145. package/dist/theme/FormField.svelte +41 -0
  146. package/dist/theme/FormField.svelte.d.ts +35 -0
  147. package/dist/theme/FormField.svelte.d.ts.map +1 -0
  148. package/dist/theme/HomePage.svelte +228 -0
  149. package/dist/theme/HomePage.svelte.d.ts +58 -0
  150. package/dist/theme/HomePage.svelte.d.ts.map +1 -0
  151. package/dist/theme/Input.svelte +36 -0
  152. package/dist/theme/Input.svelte.d.ts +34 -0
  153. package/dist/theme/Input.svelte.d.ts.map +1 -0
  154. package/dist/theme/PageLayout.svelte +36 -0
  155. package/dist/theme/PageLayout.svelte.d.ts +31 -0
  156. package/dist/theme/PageLayout.svelte.d.ts.map +1 -0
  157. package/dist/theme/RootLayout.svelte +330 -0
  158. package/dist/theme/RootLayout.svelte.d.ts +40 -0
  159. package/dist/theme/RootLayout.svelte.d.ts.map +1 -0
  160. package/dist/theme/ScopeSwitcher.svelte +103 -0
  161. package/dist/theme/ScopeSwitcher.svelte.d.ts +24 -0
  162. package/dist/theme/ScopeSwitcher.svelte.d.ts.map +1 -0
  163. package/dist/theme/SearchDialog.svelte +253 -0
  164. package/dist/theme/SearchDialog.svelte.d.ts +28 -0
  165. package/dist/theme/SearchDialog.svelte.d.ts.map +1 -0
  166. package/dist/theme/Select.svelte +37 -0
  167. package/dist/theme/Select.svelte.d.ts +42 -0
  168. package/dist/theme/Select.svelte.d.ts.map +1 -0
  169. package/dist/theme/SidebarTree.svelte +136 -0
  170. package/dist/theme/SidebarTree.svelte.d.ts +24 -0
  171. package/dist/theme/SidebarTree.svelte.d.ts.map +1 -0
  172. package/dist/theme/Textarea.svelte +33 -0
  173. package/dist/theme/Textarea.svelte.d.ts +33 -0
  174. package/dist/theme/Textarea.svelte.d.ts.map +1 -0
  175. package/dist/theme/ThemeToggle.svelte +39 -0
  176. package/dist/theme/ThemeToggle.svelte.d.ts +21 -0
  177. package/dist/theme/ThemeToggle.svelte.d.ts.map +1 -0
  178. package/dist/theme/forms.d.ts +4 -0
  179. package/dist/theme/forms.d.ts.map +1 -0
  180. package/dist/theme/forms.js +3 -0
  181. package/dist/theme/index.d.ts +21 -0
  182. package/dist/theme/index.d.ts.map +1 -0
  183. package/dist/theme/index.js +19 -0
  184. package/dist/theme/portal.d.ts +5 -0
  185. package/dist/theme/portal.d.ts.map +1 -0
  186. package/dist/theme/portal.js +19 -0
  187. package/dist/theme/styles.css +3697 -0
  188. package/dist/virtual.d.ts +59 -0
  189. package/dist/vite.d.ts +10 -0
  190. package/dist/vite.d.ts.map +1 -0
  191. package/dist/vite.js +304 -0
  192. package/package.json +118 -0
@@ -0,0 +1,330 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import type { SvedocsPage, SvedocsResolvedConfig, SvedocsSearchRecord, SvedocsTreeItem } from '../core/types.js';
4
+ import { createPageAlternates, createPageMetadata } from '../og/metadata.js';
5
+ import type { SearchScope } from '../search/types.js';
6
+ import AskAiPanel from './AskAiPanel.svelte';
7
+ import FloatingToolbar from './FloatingToolbar.svelte';
8
+ import SearchDialog from './SearchDialog.svelte';
9
+ import SidebarTree from './SidebarTree.svelte';
10
+ import ScopeSwitcher from './ScopeSwitcher.svelte';
11
+ import ThemeToggle from './ThemeToggle.svelte';
12
+
13
+ export let config: SvedocsResolvedConfig;
14
+ export let page: SvedocsPage | undefined = undefined;
15
+ export let pages: SvedocsPage[] = [];
16
+ export let search: SvedocsSearchRecord[] = [];
17
+ export let loadSearch: (() => Promise<SvedocsSearchRecord[]>) | undefined = undefined;
18
+ export let mobileTree: SvedocsTreeItem[] = [];
19
+ export let mobileCurrentPath = '';
20
+ export let hasBackgroundSlot: boolean | undefined = undefined;
21
+
22
+ const accentPalette: Record<string, string> = {
23
+ emerald: '#007f68',
24
+ teal: '#087f8c',
25
+ sky: '#0969da',
26
+ indigo: '#4f46e5',
27
+ rose: '#c83e4d',
28
+ amber: '#b36b00'
29
+ };
30
+
31
+ $: metadata = page ? createPageMetadata(config, page) : undefined;
32
+ $: alternates = page ? createPageAlternates(config, page, pages) : [];
33
+ $: jsonLd = metadata ? JSON.stringify(metadata.jsonLd) : '';
34
+ $: themeStyle = createThemeStyle(config);
35
+ $: searchScope = createRuntimeScope(config.search.scope, page);
36
+ $: aiScope = createRuntimeScope(config.ai.scope, page);
37
+ $: surface = page?.frontmatter.layout === 'home' || page?.routePath === '/' ? 'home' : 'reading';
38
+ $: isDocsPage = page?.kind === 'doc';
39
+ $: mobileMenuId = `sd-mobile-menu-${createDomId(page?.id ?? page?.routePath ?? 'site')}`;
40
+ $: mobileTreePath = mobileCurrentPath || page?.routePath || '';
41
+ $: showBackgroundSlot = hasBackgroundSlot ?? Boolean($$slots.background);
42
+ $: activeNavHref = resolveActiveNavHref(config.theme.nav, page?.routePath ?? '/');
43
+
44
+ let mounted = false;
45
+ let mobileMenuOpen = false;
46
+
47
+ onMount(() => {
48
+ mounted = true;
49
+ markHydratedRoute();
50
+ });
51
+
52
+ $: if (mounted) {
53
+ page?.routePath;
54
+ page?.locale;
55
+ markHydratedRoute();
56
+ closeMobileMenu();
57
+ }
58
+
59
+ function markHydratedRoute() {
60
+ document.documentElement.dataset.svedocsRoute = page?.routePath ?? '';
61
+ document.documentElement.lang = page?.locale ?? config.i18n.defaultLocale ?? 'en';
62
+ }
63
+
64
+ function toggleMobileMenu() {
65
+ mobileMenuOpen = !mobileMenuOpen;
66
+ }
67
+
68
+ function closeMobileMenu() {
69
+ mobileMenuOpen = false;
70
+ }
71
+
72
+ function handleWindowKeydown(event: KeyboardEvent) {
73
+ if (event.key === 'Escape') closeMobileMenu();
74
+ }
75
+
76
+ function createRuntimeScope(mode: 'current' | 'all', page: SvedocsPage | undefined): SearchScope {
77
+ if (mode === 'all' || !page) return {};
78
+ return {
79
+ ...(page.locale ? { locale: page.locale } : {})
80
+ };
81
+ }
82
+
83
+ function createThemeStyle(config: SvedocsResolvedConfig): string {
84
+ const accent = resolveColor(config.theme.palette.accent, accentPalette.emerald);
85
+ return [
86
+ `--font-sans:${config.theme.fonts.sans}`,
87
+ `--font-mono:${config.theme.fonts.mono}`,
88
+ `--sd-font-display:${config.theme.fonts.sans}`,
89
+ `--sd-radius:${config.theme.radius}`,
90
+ `--sd-accent:${accent}`
91
+ ].join(';');
92
+ }
93
+
94
+ function createThemeInitScript(defaultMode: 'light' | 'dark' | 'system'): string {
95
+ return `<script>(function(){try{var d=${JSON.stringify(defaultMode)};var s=localStorage.getItem('svedocs-theme');var t=s==='dark'||s==='light'?s:(d==='system'?(window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light'):d);document.documentElement.dataset.theme=t;document.documentElement.style.colorScheme=t;}catch(e){}})();<\/script>`;
96
+ }
97
+
98
+ function linkRel(item: { external?: boolean; rel?: string }): string | undefined {
99
+ return item.external ? 'noreferrer' : item.rel;
100
+ }
101
+
102
+ function isActiveNavItem(item: { href: string; external?: boolean }): boolean {
103
+ return !item.external && normalizePath(item.href) === activeNavHref;
104
+ }
105
+
106
+ function handleNavClick(event: MouseEvent, href: string, external?: boolean) {
107
+ if (external) return;
108
+ if (event.button !== 0) return;
109
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
110
+ if (typeof window === 'undefined') return;
111
+
112
+ const target = createComparableUrl(href, window.location.href);
113
+ if (!target) return;
114
+
115
+ const current = createComparableUrl(window.location.href, window.location.href);
116
+ if (target === current) event.preventDefault();
117
+ }
118
+
119
+ function isGithubFooterLink(item: { label: string; href: string }): boolean {
120
+ return item.label.trim().toLowerCase().includes('github');
121
+ }
122
+
123
+ function resolveColor(value: string, fallback: string): string {
124
+ if (/^(#|rgb|hsl|oklch|color-mix)/.test(value)) return value;
125
+ return accentPalette[value] ?? fallback;
126
+ }
127
+
128
+ function createDomId(value: string): string {
129
+ return value.toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/^-|-$/g, '') || 'site';
130
+ }
131
+
132
+ function resolveActiveNavHref(nav: Array<{ href: string; external?: boolean }>, currentPath: string): string {
133
+ const normalizedCurrentPath = normalizePath(currentPath);
134
+ let activeHref = '';
135
+
136
+ for (const item of nav) {
137
+ if (item.external) continue;
138
+
139
+ const normalizedHref = normalizePath(item.href);
140
+ if (!isPathMatch(normalizedCurrentPath, normalizedHref)) continue;
141
+
142
+ if (normalizedHref.length > activeHref.length) activeHref = normalizedHref;
143
+ }
144
+
145
+ return activeHref;
146
+ }
147
+
148
+ function isPathMatch(currentPath: string, hrefPath: string): boolean {
149
+ if (hrefPath === '/') return currentPath === '/';
150
+ return currentPath === hrefPath || currentPath.startsWith(`${hrefPath}/`);
151
+ }
152
+
153
+ function normalizePath(path: string): string {
154
+ const pathname = getPathname(path);
155
+ const withoutTrailingSlash = pathname.replace(/\/+$/, '');
156
+ return withoutTrailingSlash ? withoutTrailingSlash : '/';
157
+ }
158
+
159
+ function getPathname(path: string): string {
160
+ if (path.startsWith('http://') || path.startsWith('https://')) {
161
+ try {
162
+ return new URL(path).pathname;
163
+ } catch {
164
+ return path;
165
+ }
166
+ }
167
+
168
+ return path.split(/[?#]/, 1)[0] || '/';
169
+ }
170
+
171
+ function createComparableUrl(value: string, base: string): string | undefined {
172
+ try {
173
+ const url = new URL(value, base);
174
+ url.pathname = normalizePath(url.pathname);
175
+ return url.href;
176
+ } catch {
177
+ return undefined;
178
+ }
179
+ }
180
+ </script>
181
+
182
+ <svelte:window on:keydown={handleWindowKeydown} />
183
+
184
+ <svelte:head>
185
+ {@html createThemeInitScript(config.theme.defaultMode)}
186
+ <title>{metadata?.title ?? config.site.title}</title>
187
+ <meta name="description" content={metadata?.description ?? config.site.description} />
188
+ {#if metadata?.canonical}
189
+ <link rel="canonical" href={metadata.canonical} />
190
+ {/if}
191
+ {#each alternates as alternate}
192
+ <link rel="alternate" hreflang={alternate.lang} href={alternate.href} />
193
+ {/each}
194
+ {#if metadata}
195
+ <meta property="og:title" content={metadata.openGraph.title} />
196
+ <meta property="og:description" content={metadata.openGraph.description} />
197
+ <meta property="og:type" content={metadata.openGraph.type} />
198
+ <meta property="og:site_name" content={metadata.openGraph.siteName} />
199
+ {#if metadata.openGraph.url}
200
+ <meta property="og:url" content={metadata.openGraph.url} />
201
+ {/if}
202
+ {#if metadata.openGraph.image}
203
+ <meta property="og:image" content={metadata.openGraph.image} />
204
+ {/if}
205
+ {#if metadata.openGraph.author}
206
+ <meta property="article:author" content={metadata.openGraph.author} />
207
+ {/if}
208
+ {#if metadata.openGraph.publishedTime}
209
+ <meta property="article:published_time" content={metadata.openGraph.publishedTime} />
210
+ {/if}
211
+ {#if metadata.openGraph.updatedTime}
212
+ <meta property="article:modified_time" content={metadata.openGraph.updatedTime} />
213
+ {/if}
214
+ <meta name="twitter:card" content={metadata.twitter.card} />
215
+ <meta name="twitter:title" content={metadata.twitter.title} />
216
+ <meta name="twitter:description" content={metadata.twitter.description} />
217
+ {#if metadata.twitter.image}
218
+ <meta name="twitter:image" content={metadata.twitter.image} />
219
+ {/if}
220
+ <script type="application/ld+json">{jsonLd}</script>
221
+ {/if}
222
+ </svelte:head>
223
+
224
+ <div class:sd-has-background-slot={showBackgroundSlot} class="sd-root" data-surface={surface} style={themeStyle}>
225
+ <a class="sd-skip" href="#content">Skip to content</a>
226
+ {#if showBackgroundSlot}
227
+ <div class="sd-background-slot" aria-hidden="true">
228
+ <slot name="background" />
229
+ </div>
230
+ {/if}
231
+ <header class:sd-mobile-menu-open={mobileMenuOpen} class="sd-topbar">
232
+ <a class="sd-brand" href={config.theme.brand.href}>
233
+ {#if config.theme.brand.logo}
234
+ <img class="sd-brand-logo" src={config.theme.brand.logo} alt="" draggable="false" />
235
+ {:else if config.theme.brand.mark !== false}
236
+ <span class="sd-brand-mark" aria-hidden="true"></span>
237
+ {/if}
238
+ <span>{config.theme.brand.label}</span>
239
+ </a>
240
+ <div id={mobileMenuId} class="sd-topbar-menu" class:sd-open={mobileMenuOpen}>
241
+ <nav class="sd-topnav" aria-label="Primary">
242
+ {#each config.theme.nav as item}
243
+ {@const active = isActiveNavItem(item)}
244
+ <a
245
+ class:sd-active={active}
246
+ href={item.href}
247
+ rel={linkRel(item)}
248
+ target={item.external ? '_blank' : undefined}
249
+ aria-current={active ? 'page' : undefined}
250
+ on:click={(event) => handleNavClick(event, item.href, item.external)}
251
+ >
252
+ {item.label}
253
+ </a>
254
+ {/each}
255
+ </nav>
256
+ <div class="sd-topbar-spacer" aria-hidden="true"></div>
257
+ <div class="sd-topbar-tools">
258
+ {#if config.search.enabled}
259
+ <SearchDialog records={search} loadRecords={loadSearch} scope={searchScope} provider={config.search.provider} buildMode={config.build.mode} />
260
+ {/if}
261
+ <ScopeSwitcher {page} {pages} locales={config.i18n.locales} />
262
+ </div>
263
+ {#if config.theme.social.length > 0}
264
+ <nav class="sd-socialnav" aria-label="Social links">
265
+ {#each config.theme.social as item}
266
+ <a href={item.href} rel={linkRel(item)} target={item.external ? '_blank' : undefined}>
267
+ {item.label}
268
+ </a>
269
+ {/each}
270
+ </nav>
271
+ {/if}
272
+ <ThemeToggle defaultMode={config.theme.defaultMode} />
273
+ {#if mobileTree.length > 0}
274
+ <nav class="sd-mobile-docnav" aria-label="Documentation">
275
+ <SidebarTree items={mobileTree} currentPath={mobileTreePath} />
276
+ </nav>
277
+ {/if}
278
+ </div>
279
+ <button
280
+ class="sd-menu-button"
281
+ type="button"
282
+ aria-label={mobileMenuOpen ? 'Close menu' : 'Open menu'}
283
+ aria-expanded={mobileMenuOpen}
284
+ aria-controls={mobileMenuId}
285
+ on:click={toggleMobileMenu}
286
+ >
287
+ <svg aria-hidden="true" viewBox="0 0 24 24">
288
+ {#if mobileMenuOpen}
289
+ <path d="M6 6l12 12M18 6 6 18" />
290
+ {:else}
291
+ <path d="M4 7h16M4 12h16M4 17h16" />
292
+ {/if}
293
+ </svg>
294
+ </button>
295
+ </header>
296
+ <slot />
297
+ {#if isDocsPage}
298
+ {#if config.ai.enabled}
299
+ <AskAiPanel {config} records={search} loadRecords={loadSearch} scope={aiScope} buildMode={config.build.mode} />
300
+ {/if}
301
+ <FloatingToolbar {config} />
302
+ {/if}
303
+ {#if config.theme.footer !== false && !isDocsPage}
304
+ <footer class="sd-footer">
305
+ <span>{config.theme.footer.text}</span>
306
+ {#if config.theme.footer.links.length > 0}
307
+ <nav aria-label="Footer">
308
+ {#each config.theme.footer.links as item}
309
+ {#if isGithubFooterLink(item)}
310
+ <a
311
+ class="sd-footer-icon"
312
+ href={item.href}
313
+ rel={linkRel(item)}
314
+ target={item.external ? '_blank' : undefined}
315
+ aria-label={item.label}
316
+ title={item.label}
317
+ >
318
+ <svg aria-hidden="true" viewBox="0 0 16 16" width="16" height="16">
319
+ <path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z" />
320
+ </svg>
321
+ </a>
322
+ {:else}
323
+ <a href={item.href} rel={linkRel(item)} target={item.external ? '_blank' : undefined}>{item.label}</a>
324
+ {/if}
325
+ {/each}
326
+ </nav>
327
+ {/if}
328
+ </footer>
329
+ {/if}
330
+ </div>
@@ -0,0 +1,40 @@
1
+ import type { SvedocsPage, SvedocsResolvedConfig, SvedocsSearchRecord, SvedocsTreeItem } from '../core/types.js';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
16
+ default: any;
17
+ } ? Props extends Record<string, never> ? any : {
18
+ children?: any;
19
+ } : {});
20
+ declare const RootLayout: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
21
+ config: SvedocsResolvedConfig;
22
+ page?: SvedocsPage | undefined;
23
+ pages?: SvedocsPage[];
24
+ search?: SvedocsSearchRecord[];
25
+ loadSearch?: (() => Promise<SvedocsSearchRecord[]>) | undefined;
26
+ mobileTree?: SvedocsTreeItem[];
27
+ mobileCurrentPath?: string;
28
+ hasBackgroundSlot?: boolean | undefined;
29
+ }, {
30
+ background: {};
31
+ default: {};
32
+ }>, {
33
+ [evt: string]: CustomEvent<any>;
34
+ }, {
35
+ background: {};
36
+ default: {};
37
+ }, {}, string>;
38
+ type RootLayout = InstanceType<typeof RootLayout>;
39
+ export default RootLayout;
40
+ //# sourceMappingURL=RootLayout.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RootLayout.svelte.d.ts","sourceRoot":"","sources":["../../src/theme/RootLayout.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAkUjH,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AACD,KAAK,gCAAgC,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,GACvD,CAAC,KAAK,SAAS;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,GACzB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACnC,GAAG,GACH;IAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;CAAE,GAClB,EAAE,CAAC,CAAC;AAId,QAAA,MAAM,UAAU;YAf0M,qBAAqB;WAAS,WAAW,GAAG,SAAS;YAAU,WAAW,EAAE;aAAW,mBAAmB,EAAE;iBAAe,CAAC,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,GAAG,SAAS;iBAAe,eAAe,EAAE;;wBAAoE,OAAO,GAAG,SAAS;;;;;;;;;cAezZ,CAAC;AACpF,KAAK,UAAU,GAAG,YAAY,CAAC,OAAO,UAAU,CAAC,CAAC;AACpD,eAAe,UAAU,CAAC"}
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import type { SvedocsLocale, SvedocsPage } from '../core/types.js';
4
+
5
+ export let page: SvedocsPage | undefined = undefined;
6
+ export let pages: SvedocsPage[] = [];
7
+ export let locales: SvedocsLocale[] = [];
8
+
9
+ let openMenu: 'locale' | undefined;
10
+ let root: HTMLDivElement;
11
+
12
+ $: localeOptions = createScopeOptions(
13
+ locales,
14
+ page?.locale,
15
+ (locale) => locale.code,
16
+ (locale) => locale.label,
17
+ (locale) => findScopedPage({ locale: locale.code })?.routePath
18
+ );
19
+ $: activeLocaleOption = localeOptions.find((option) => option.current);
20
+ $: activeLocaleLabel = activeLocaleOption?.label ?? 'Locale';
21
+ $: activeLocaleShortLabel = activeLocaleOption
22
+ ? createShortLocaleLabel(activeLocaleOption.value, activeLocaleOption.label)
23
+ : 'Lang';
24
+
25
+ function findScopedPage(scope: { locale?: string }): SvedocsPage | undefined {
26
+ if (!page) return undefined;
27
+ return pages.find((candidate) => (
28
+ candidate.scopePath === page.scopePath
29
+ && (scope.locale ? candidate.locale === scope.locale : candidate.locale === page.locale)
30
+ ));
31
+ }
32
+
33
+ function createScopeOptions<T>(
34
+ items: T[],
35
+ current: string | undefined,
36
+ getValue: (item: T) => string,
37
+ getLabel: (item: T) => string,
38
+ getPath: (item: T) => string | undefined
39
+ ) {
40
+ return items.map((item) => ({
41
+ value: getValue(item),
42
+ label: getLabel(item),
43
+ path: getPath(item),
44
+ current: getValue(item) === current
45
+ }));
46
+ }
47
+
48
+ function createShortLocaleLabel(value: string, label: string) {
49
+ const trimmedLabel = label.trim();
50
+ if ([...trimmedLabel].length <= 3) return trimmedLabel;
51
+
52
+ const trimmedValue = value.trim();
53
+ return trimmedValue ? trimmedValue.slice(0, 3).toUpperCase() : trimmedLabel.slice(0, 3);
54
+ }
55
+
56
+ function closeMenu() {
57
+ openMenu = undefined;
58
+ }
59
+
60
+ function toggleMenu(menu: 'locale') {
61
+ openMenu = openMenu === menu ? undefined : menu;
62
+ }
63
+
64
+ onMount(() => {
65
+ function closeOnPointer(event: PointerEvent) {
66
+ if (!root) return;
67
+ if (!root.contains(event.target as Node)) openMenu = undefined;
68
+ }
69
+
70
+ function closeOnEscape(event: KeyboardEvent) {
71
+ if (event.key === 'Escape') openMenu = undefined;
72
+ }
73
+
74
+ document.addEventListener('pointerdown', closeOnPointer);
75
+ document.addEventListener('keydown', closeOnEscape);
76
+ return () => {
77
+ document.removeEventListener('pointerdown', closeOnPointer);
78
+ document.removeEventListener('keydown', closeOnEscape);
79
+ };
80
+ });
81
+ </script>
82
+
83
+ {#if localeOptions.length > 1}
84
+ <div bind:this={root} class="sd-scope-switcher" role="group" aria-label="Documentation scope">
85
+ <div class:sd-open={openMenu === 'locale'} class="sd-scope-menu">
86
+ <button type="button" class="sd-scope-trigger" aria-label="Locale" aria-haspopup="menu" aria-expanded={openMenu === 'locale'} on:click={() => toggleMenu('locale')}>
87
+ <span class="sd-scope-label-full">{activeLocaleLabel}</span>
88
+ <span aria-hidden="true" class="sd-scope-label-short">{activeLocaleShortLabel}</span>
89
+ </button>
90
+ {#if openMenu === 'locale'}
91
+ <div class="sd-scope-options" role="menu" aria-label="Locale options">
92
+ {#each localeOptions as option}
93
+ {#if option.path}
94
+ <a href={option.path} role="menuitemradio" aria-checked={option.current} aria-current={option.current ? 'page' : undefined} on:click={closeMenu}>{option.label}</a>
95
+ {:else}
96
+ <span role="menuitemradio" aria-checked={option.current} aria-disabled="true">{option.label}</span>
97
+ {/if}
98
+ {/each}
99
+ </div>
100
+ {/if}
101
+ </div>
102
+ </div>
103
+ {/if}
@@ -0,0 +1,24 @@
1
+ import type { SvedocsLocale, SvedocsPage } from '../core/types.js';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: Props & {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const ScopeSwitcher: $$__sveltets_2_IsomorphicComponent<{
16
+ page?: SvedocsPage | undefined;
17
+ pages?: SvedocsPage[];
18
+ locales?: SvedocsLocale[];
19
+ }, {
20
+ [evt: string]: CustomEvent<any>;
21
+ }, {}, {}, string>;
22
+ type ScopeSwitcher = InstanceType<typeof ScopeSwitcher>;
23
+ export default ScopeSwitcher;
24
+ //# sourceMappingURL=ScopeSwitcher.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopeSwitcher.svelte.d.ts","sourceRoot":"","sources":["../../src/theme/ScopeSwitcher.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA4GnE,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,aAAa;WAVuD,WAAW,GAAG,SAAS;YAAU,WAAW,EAAE;cAAY,aAAa,EAAE;;;kBAUjD,CAAC;AACjF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}