@bndynet/vue-site 0.1.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 ADDED
@@ -0,0 +1,152 @@
1
+ # @bndynet/vue-site
2
+
3
+ Configurable Vue 3 site framework: one package, `site.config.ts`, and Markdown pages — sidebar, syntax-highlighted code, light/dark themes. No hand-written `main.ts`, `index.html`, or `vite.config.ts`.
4
+
5
+ ## Features
6
+
7
+ - Config-driven nav (Lucide icon names)
8
+ - Markdown (`?raw`) or Vue pages
9
+ - highlight.js, light/dark theme + localStorage
10
+ - Project `README.md` as Home
11
+ - Full TypeScript types
12
+
13
+ ## Quick start
14
+
15
+ **Install**
16
+
17
+ ```bash
18
+ npm install @bndynet/vue-site
19
+ ```
20
+
21
+ **`site.config.ts`**
22
+
23
+ ```typescript
24
+ import { defineConfig } from '@bndynet/vue-site'
25
+
26
+ export default defineConfig({
27
+ title: 'My Project',
28
+ nav: [
29
+ { label: 'Home', icon: 'home', page: () => import('./README.md?raw') },
30
+ { label: 'Guide', icon: 'book-open', page: () => import('./pages/guide.md?raw') },
31
+ ],
32
+ })
33
+ ```
34
+
35
+ **Layout**
36
+
37
+ ```
38
+ my-site/
39
+ package.json
40
+ site.config.ts
41
+ README.md
42
+ pages/guide.md
43
+ ```
44
+
45
+ **CLI** (`vue-site` and `vs` are the same)
46
+
47
+ ```bash
48
+ npx vue-site dev
49
+ npx vue-site build
50
+ npx vue-site preview
51
+ ```
52
+
53
+ Add `"dev": "vue-site dev"` (or `vs dev`) in `package.json` scripts if you like.
54
+
55
+ ## Config reference
56
+
57
+ ### `SiteConfig`
58
+
59
+ | Property | Description |
60
+ |----------|-------------|
61
+ | `title` | Site title (sidebar + tab) |
62
+ | `nav` | `NavItem[]` |
63
+ | `logo` | Logo URL or imported image |
64
+ | `theme` | See `ThemeConfig` below |
65
+ | `footer` | Footer text |
66
+ | `readme` | Raw Home content if no `README.md` |
67
+ | `links` | Header links: Lucide `icon` + `link`, optional `title` |
68
+ | `packageRepository` | Usually set by CLI from `package.json`; omit when using `createSiteApp` alone |
69
+ | `env` | Dev/build options — see below |
70
+
71
+ ### `NavItem`
72
+
73
+ | Property | Description |
74
+ |----------|-------------|
75
+ | `label` | Sidebar text |
76
+ | `icon` | [Lucide](https://lucide.dev/icons) name |
77
+ | `page` | `() => import('./page.md?raw')` or `() => import('./Page.vue')` |
78
+ | `path` | Route path (derived from `label` if omitted) |
79
+ | `children` | Nested group |
80
+
81
+ ### `ThemeConfig`
82
+
83
+ | Property | Default | Description |
84
+ |----------|---------|-------------|
85
+ | `default` | `light` | `light`, `dark`, or an `extraThemes[].id` |
86
+ | `colors` | — | Global CSS variable overrides |
87
+ | `palettes` | — | Partial overrides for built-in light/dark only |
88
+ | `extraThemes` | — | Extra themes: `id`, `label`, `icon`, optional `basedOn`, `palette`; import `builtinThemePalettes` for full defaults |
89
+
90
+ ## `env` (`SiteEnvConfig`)
91
+
92
+ | Property | Description |
93
+ |----------|-------------|
94
+ | `port` | Dev server port |
95
+ | `outDir` | Build output (relative to site root; default `{folder}-dist`) |
96
+ | `customElements` | Tag prefixes for custom elements (e.g. `['chat-', 'i-']`) |
97
+ | `watchPackages` | Local packages: package name string, or `{ name, entryPath }` for source HMR |
98
+ | `vite` | Vite overrides (not `root`); framework merges aliases, `server.fs.allow`, `build.outDir`, etc. |
99
+
100
+ ## Library mode
101
+
102
+ Own `index.html` + Vite setup:
103
+
104
+ ```typescript
105
+ import { createSiteApp } from '@bndynet/vue-site'
106
+ import '@bndynet/vue-site/style.css'
107
+ import config from './site.config'
108
+
109
+ createSiteApp(config).mount('#app')
110
+ ```
111
+
112
+ Exports: `createSiteApp`, `defineConfig`, `useTheme`, `useSiteConfig`. Types: `SiteConfig`, `SiteEnvConfig`, `SiteViteConfig`, `SiteExternalLink`, `NavItem`, `ThemeConfig`, `ThemeOption`, `ThemePaletteVars`, `ResolvedNavItem`.
113
+
114
+ ### Theme in Vue pages (`useTheme`)
115
+
116
+ Import `useTheme` from `@bndynet/vue-site`. It returns a reactive `theme` ref (the active theme id, e.g. `light`, `dark`, or an `extraThemes[].id`) plus `setTheme` and `toggleTheme`. The root layout also sets `document.documentElement` attribute `data-theme` and applies CSS variables, so you can style with `var(--color-*)` without JavaScript.
117
+
118
+ ```vue
119
+ <script setup lang="ts">
120
+ import { watch } from 'vue'
121
+ import { useTheme } from '@bndynet/vue-site'
122
+
123
+ const { theme, setTheme, toggleTheme } = useTheme()
124
+
125
+ watch(theme, (next, prev) => {
126
+ if (prev !== undefined) console.log('theme:', prev, '→', next)
127
+ })
128
+ </script>
129
+
130
+ <template>
131
+ <p>Current theme: {{ theme }}</p>
132
+ </template>
133
+ ```
134
+
135
+ ## Upgrade
136
+
137
+ ```bash
138
+ npm update @bndynet/vue-site
139
+ ```
140
+
141
+ ## Developing this repo
142
+
143
+ ```bash
144
+ git clone https://github.com/bndynet/vue-site.git && cd vue-site
145
+ npm install
146
+ npm run dev # watch-build lib + example site
147
+ npm run build # `dist/` + `example/example-dist`
148
+ ```
149
+
150
+ ## License
151
+
152
+ MIT
@@ -0,0 +1,355 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createServer, build, preview, mergeConfig } from 'vite'
4
+ import vue from '@vitejs/plugin-vue'
5
+ import { resolve, dirname, basename } from 'path'
6
+ import { fileURLToPath, pathToFileURL } from 'url'
7
+ import { createRequire } from 'module'
8
+ import { transform } from 'esbuild'
9
+ import fs from 'fs'
10
+
11
+ const __filename = fileURLToPath(import.meta.url)
12
+ const __dirname = dirname(__filename)
13
+ const pkgDir = resolve(__dirname, '..')
14
+ const require = createRequire(import.meta.url)
15
+
16
+ function resolvePkgDir(pkg) {
17
+ return dirname(require.resolve(`${pkg}/package.json`))
18
+ }
19
+
20
+ const vuePath = resolvePkgDir('vue')
21
+ const vueRouterPath = resolvePkgDir('vue-router')
22
+ const cwd = process.cwd()
23
+ const command = process.argv[2] || 'dev'
24
+
25
+ const configCandidates = [
26
+ 'site.config.ts',
27
+ 'site.config.js',
28
+ 'site.config.mts',
29
+ 'site.config.mjs',
30
+ ]
31
+ const foundConfig = configCandidates.find((f) => fs.existsSync(resolve(cwd, f)))
32
+ if (!foundConfig) {
33
+ console.error(
34
+ '\x1b[31mError: No site.config.ts found in the current directory.\x1b[0m\n\n' +
35
+ 'Create a site.config.ts file:\n\n' +
36
+ ' import type { SiteConfig } from \'@bndynet/vue-site\'\n\n' +
37
+ ' export default {\n' +
38
+ ' title: \'My Site\',\n' +
39
+ ' nav: [\n' +
40
+ ' { label: \'Home\', icon: \'home\', page: () => import(\'./README.md?raw\') },\n' +
41
+ ' ],\n' +
42
+ ' } satisfies SiteConfig\n'
43
+ )
44
+ process.exit(1)
45
+ }
46
+
47
+ const VIRTUAL_ENTRY = 'virtual:vue-site-entry'
48
+ const RESOLVED_ENTRY = '\0' + VIRTUAL_ENTRY
49
+ const VIRTUAL_PACKAGE = 'virtual:vue-site-package'
50
+ const RESOLVED_PACKAGE = '\0' + VIRTUAL_PACKAGE
51
+
52
+ function parseRepositoryUrl(pkg) {
53
+ const r = pkg.repository
54
+ if (!r) return null
55
+ let url = typeof r === 'string' ? r : r.url
56
+ if (!url) return null
57
+ const ssh = /^git@([^:]+):(.+?)(\.git)?$/i.exec(url)
58
+ if (ssh) {
59
+ const host = ssh[1]
60
+ const path = ssh[2]
61
+ return `https://${host}/${path.replace(/\.git$/i, '')}`
62
+ }
63
+ url = url.replace(/^git\+/i, '')
64
+ url = url.replace(/\.git$/i, '')
65
+ if (/^github:/i.test(url)) {
66
+ return 'https://github.com/' + url.replace(/^github:/i, '')
67
+ }
68
+ if (/^gist:/i.test(url)) {
69
+ return 'https://gist.github.com/' + url.replace(/^gist:/i, '')
70
+ }
71
+ if (/^bitbucket:/i.test(url)) {
72
+ return 'https://bitbucket.org/' + url.replace(/^bitbucket:/i, '')
73
+ }
74
+ if (/^gitlab:/i.test(url)) {
75
+ return 'https://gitlab.com/' + url.replace(/^gitlab:/i, '')
76
+ }
77
+ if (url.startsWith('git:')) {
78
+ url = 'https:' + url.slice(4)
79
+ }
80
+ return url || null
81
+ }
82
+
83
+ function tryReadRepositoryFromDir(dir) {
84
+ try {
85
+ const pkgPath = resolve(dir, 'package.json')
86
+ if (!fs.existsSync(pkgPath)) return null
87
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
88
+ return parseRepositoryUrl(pkg)
89
+ } catch {
90
+ return null
91
+ }
92
+ }
93
+
94
+ /** Prefer parent directory's `repository`, then the site root (`cwd`) package.json. */
95
+ function readPackageRepositoryUrl() {
96
+ const parentDir = resolve(cwd, '..')
97
+ const fromParent = tryReadRepositoryFromDir(parentDir)
98
+ if (fromParent) return fromParent
99
+ return tryReadRepositoryFromDir(cwd)
100
+ }
101
+
102
+ const entryCode = [
103
+ `import { createSiteApp } from '${pkgDir.replace(/\\/g, '/')}/dist/index.es.js'`,
104
+ `import '${pkgDir.replace(/\\/g, '/')}/dist/style.css'`,
105
+ `import siteConfig from '/${foundConfig}'`,
106
+ `import { repositoryUrl } from '${VIRTUAL_PACKAGE}'`,
107
+ `createSiteApp({ ...siteConfig, packageRepository: repositoryUrl }).mount('#app')`,
108
+ ].join('\n')
109
+
110
+ const htmlTemplate = `<!DOCTYPE html>
111
+ <html lang="en">
112
+ <head>
113
+ <meta charset="UTF-8" />
114
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
115
+ <title></title>
116
+ </head>
117
+ <body>
118
+ <div id="app"></div>
119
+ <script type="module" src="/@id/__x00__${VIRTUAL_ENTRY}"></script>
120
+ </body>
121
+ </html>`
122
+
123
+ async function loadSiteConfig() {
124
+ const configPath = resolve(cwd, foundConfig)
125
+ const raw = fs.readFileSync(configPath, 'utf-8')
126
+
127
+ const isTs = /\.m?ts$/.test(foundConfig)
128
+ const { code } = await transform(raw, {
129
+ loader: isTs ? 'ts' : 'js',
130
+ format: 'esm',
131
+ })
132
+
133
+ const stubbed = code.replace(
134
+ /import\s*\{[^}]*defineConfig[^}]*\}\s*from\s*['"][^'"]*['"]\s*;?/g,
135
+ 'const defineConfig = (c) => c;',
136
+ )
137
+
138
+ const tmpFile = resolve(cwd, `.site-config.${Date.now()}.tmp.mjs`)
139
+ fs.writeFileSync(tmpFile, stubbed)
140
+
141
+ try {
142
+ const mod = await import(pathToFileURL(tmpFile).href)
143
+ return mod.default || {}
144
+ } catch (e) {
145
+ console.warn(
146
+ `[vue-site] Could not pre-load site config from ${foundConfig}: ${e.message}`,
147
+ )
148
+ return {}
149
+ } finally {
150
+ try {
151
+ fs.unlinkSync(tmpFile)
152
+ } catch {}
153
+ }
154
+ }
155
+
156
+ function vueSitePlugin() {
157
+ return [
158
+ {
159
+ name: 'vue-site:virtual-entry',
160
+ resolveId(id) {
161
+ if (id === VIRTUAL_ENTRY) return RESOLVED_ENTRY
162
+ if (id === VIRTUAL_PACKAGE) return RESOLVED_PACKAGE
163
+ },
164
+ load(id) {
165
+ if (id === RESOLVED_ENTRY) return entryCode
166
+ if (id === RESOLVED_PACKAGE) {
167
+ const url = readPackageRepositoryUrl()
168
+ return `export const repositoryUrl = ${JSON.stringify(url)}`
169
+ }
170
+ },
171
+ },
172
+ {
173
+ name: 'vue-site:html',
174
+ configureServer(server) {
175
+ return () => {
176
+ server.middlewares.use(async (req, res, next) => {
177
+ if (req.url === '/' || req.url === '/index.html') {
178
+ const html = await server.transformIndexHtml(
179
+ req.url,
180
+ htmlTemplate,
181
+ )
182
+ res.writeHead(200, { 'Content-Type': 'text/html' })
183
+ res.end(html)
184
+ return
185
+ }
186
+ next()
187
+ })
188
+ }
189
+ },
190
+ },
191
+ ]
192
+ }
193
+
194
+ async function buildViteConfig() {
195
+ const siteConfig = await loadSiteConfig()
196
+ const {
197
+ port,
198
+ outDir,
199
+ customElements = [],
200
+ watchPackages = [],
201
+ vite: userVite = {},
202
+ } = siteConfig.env || {}
203
+ const { vue: userVueOpts = {}, plugins: userPlugins, ...userViteRest } =
204
+ userVite
205
+
206
+ const vueOpts = { ...userVueOpts }
207
+ if (customElements.length) {
208
+ vueOpts.template = {
209
+ ...vueOpts.template,
210
+ compilerOptions: {
211
+ ...vueOpts.template?.compilerOptions,
212
+ isCustomElement: (tag) =>
213
+ customElements.some((prefix) => tag.startsWith(prefix)),
214
+ },
215
+ }
216
+ }
217
+
218
+ if (watchPackages.length) {
219
+ const excludeNames = []
220
+ const watchPatterns = []
221
+ const localAliases = {}
222
+ const fsAllowPaths = []
223
+
224
+ for (const pkg of watchPackages) {
225
+ if (typeof pkg === 'string') {
226
+ excludeNames.push(pkg)
227
+ watchPatterns.push(`!**/node_modules/${pkg}/**`)
228
+ } else {
229
+ const entryAbs = resolve(cwd, pkg.entryPath)
230
+ const entryDir = entryAbs.replace(/\/[^/]+$/, '')
231
+ excludeNames.push(pkg.name)
232
+ localAliases[pkg.name] = entryAbs
233
+ watchPatterns.push(`!${entryDir}/**`)
234
+ fsAllowPaths.push(entryDir)
235
+ }
236
+ }
237
+
238
+ userViteRest.optimizeDeps = {
239
+ ...userViteRest.optimizeDeps,
240
+ exclude: [
241
+ ...(userViteRest.optimizeDeps?.exclude || []),
242
+ ...excludeNames,
243
+ ],
244
+ }
245
+ userViteRest.server = {
246
+ ...userViteRest.server,
247
+ watch: {
248
+ ...userViteRest.server?.watch,
249
+ ignored: [
250
+ ...(userViteRest.server?.watch?.ignored || []),
251
+ ...watchPatterns,
252
+ ],
253
+ },
254
+ }
255
+ if (Object.keys(localAliases).length) {
256
+ userViteRest.resolve = {
257
+ ...userViteRest.resolve,
258
+ alias: { ...userViteRest.resolve?.alias, ...localAliases },
259
+ }
260
+ }
261
+ if (fsAllowPaths.length) {
262
+ userViteRest.server = {
263
+ ...userViteRest.server,
264
+ fs: {
265
+ ...userViteRest.server?.fs,
266
+ allow: [
267
+ ...(userViteRest.server?.fs?.allow || []),
268
+ ...fsAllowPaths,
269
+ ],
270
+ },
271
+ }
272
+ }
273
+ }
274
+
275
+ const baseConfig = {
276
+ root: cwd,
277
+ plugins: [vue(vueOpts), ...vueSitePlugin(), ...(userPlugins || [])],
278
+ resolve: {
279
+ alias: {
280
+ vue: resolve(vuePath, 'dist/vue.runtime.esm-bundler.js'),
281
+ 'vue-router': resolve(vueRouterPath, 'dist/vue-router.mjs'),
282
+ },
283
+ },
284
+ server: {
285
+ open: true,
286
+ ...(port != null && { port }),
287
+ fs: {
288
+ allow: [cwd, pkgDir],
289
+ },
290
+ },
291
+ build: {
292
+ outDir: resolve(cwd, outDir || `${basename(cwd)}-dist`),
293
+ emptyOutDir: true,
294
+ },
295
+ }
296
+
297
+ return mergeConfig(userViteRest, baseConfig)
298
+ }
299
+
300
+ async function run() {
301
+ const viteConfig = await buildViteConfig()
302
+
303
+ if (command === 'dev') {
304
+ const server = await createServer(viteConfig)
305
+ await server.listen()
306
+ server.printUrls()
307
+ server.bindCLIShortcuts({ print: true })
308
+ } else if (command === 'build') {
309
+ const tempHtml = resolve(cwd, 'index.html')
310
+ const hadHtml = fs.existsSync(tempHtml)
311
+
312
+ if (!hadHtml) {
313
+ const buildHtml = `<!DOCTYPE html>
314
+ <html lang="en">
315
+ <head>
316
+ <meta charset="UTF-8" />
317
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
318
+ <title></title>
319
+ </head>
320
+ <body>
321
+ <div id="app"></div>
322
+ <script type="module">
323
+ import { createSiteApp } from '${pkgDir.replace(/\\/g, '/')}/dist/index.es.js'
324
+ import '${pkgDir.replace(/\\/g, '/')}/dist/style.css'
325
+ import siteConfig from './${foundConfig}'
326
+ import { repositoryUrl } from '${VIRTUAL_PACKAGE}'
327
+ createSiteApp({ ...siteConfig, packageRepository: repositoryUrl }).mount('#app')
328
+ </script>
329
+ </body>
330
+ </html>`
331
+ fs.writeFileSync(tempHtml, buildHtml)
332
+ }
333
+
334
+ try {
335
+ await build(viteConfig)
336
+ } finally {
337
+ if (!hadHtml) {
338
+ fs.unlinkSync(tempHtml)
339
+ }
340
+ }
341
+ } else if (command === 'preview') {
342
+ const server = await preview(
343
+ mergeConfig(viteConfig, { preview: { open: true } }),
344
+ )
345
+ server.printUrls()
346
+ } else {
347
+ console.log('Usage: vue-site|vs <dev|build|preview>')
348
+ process.exit(1)
349
+ }
350
+ }
351
+
352
+ run().catch((err) => {
353
+ console.error(err)
354
+ process.exit(1)
355
+ })
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
2
+ export default _default;
@@ -0,0 +1,6 @@
1
+ type __VLS_Props = {
2
+ name: string;
3
+ size?: number;
4
+ };
5
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
6
+ export default _default;
@@ -0,0 +1,5 @@
1
+ type __VLS_Props = {
2
+ content: string;
3
+ };
4
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
5
+ export default _default;
@@ -0,0 +1,6 @@
1
+ import { ResolvedNavItem } from '../types';
2
+ type __VLS_Props = {
3
+ item: ResolvedNavItem;
4
+ };
5
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
6
+ export default _default;
@@ -0,0 +1,9 @@
1
+ import { ResolvedNavItem } from '../types';
2
+ type __VLS_Props = {
3
+ item: ResolvedNavItem;
4
+ indent?: boolean;
5
+ };
6
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
7
+ indent: boolean;
8
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
9
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLElement>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ type __VLS_Props = {
2
+ /** Smaller hit targets for sidebar footer */
3
+ compact?: boolean;
4
+ };
5
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
6
+ compact: boolean;
7
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
8
+ export default _default;
@@ -0,0 +1,10 @@
1
+ type __VLS_Props = {
2
+ compact?: boolean;
3
+ };
4
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
5
+ compact: boolean;
6
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
7
+ detailsRef: HTMLDetailsElement;
8
+ summaryRef: HTMLElement;
9
+ }, HTMLDetailsElement>;
10
+ export default _default;
@@ -0,0 +1,18 @@
1
+ type __VLS_Props = {
2
+ /** Matches `aria-describedby` on the trigger */
3
+ id: string;
4
+ open: boolean;
5
+ text: string;
6
+ /** Trigger element (pass a template ref; it unwraps to the DOM node) */
7
+ anchor: HTMLElement | null;
8
+ placement?: 'top' | 'bottom';
9
+ };
10
+ declare function measure(): void;
11
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {
12
+ measure: typeof measure;
13
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
14
+ placement: "top" | "bottom";
15
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
16
+ tipRef: HTMLDivElement;
17
+ }, any>;
18
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLElement>;
2
+ export default _default;
@@ -0,0 +1,35 @@
1
+ type __VLS_Props = {
2
+ /** Tooltip text (empty hides tooltip behavior) */
3
+ label: string;
4
+ placement?: 'top' | 'bottom';
5
+ /** Hover delay before showing (ms) */
6
+ showDelay?: number;
7
+ };
8
+ declare function __VLS_template(): {
9
+ attrs: Partial<{}>;
10
+ slots: {
11
+ default?(_: {
12
+ describedBy: string | undefined;
13
+ }): any;
14
+ };
15
+ refs: {
16
+ root: HTMLSpanElement;
17
+ };
18
+ rootEl: HTMLSpanElement;
19
+ };
20
+ type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
21
+ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {
22
+ open: import('vue').Ref<boolean, boolean>;
23
+ }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
24
+ placement: "top" | "bottom";
25
+ showDelay: number;
26
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
27
+ root: HTMLSpanElement;
28
+ }, HTMLSpanElement>;
29
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
30
+ export default _default;
31
+ type __VLS_WithTemplateSlots<T, S> = T & {
32
+ new (): {
33
+ $slots: S;
34
+ };
35
+ };
@@ -0,0 +1,5 @@
1
+ export declare function useNavLayout(): {
2
+ tieredNav: import('vue').ComputedRef<boolean>;
3
+ sidebarNav: import('vue').ComputedRef<import('..').ResolvedNavItem[]>;
4
+ showSidebar: import('vue').ComputedRef<boolean>;
5
+ };
@@ -0,0 +1,9 @@
1
+ import { InjectionKey } from 'vue';
2
+ import { SiteConfig, ResolvedNavItem } from '../types';
3
+ export interface SiteContext {
4
+ config: SiteConfig;
5
+ resolvedNav: ResolvedNavItem[];
6
+ }
7
+ export declare const siteContextKey: InjectionKey<SiteContext>;
8
+ export declare function provideSiteConfig(context: SiteContext): void;
9
+ export declare function useSiteConfig(): SiteContext;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @param defaultMode — used when nothing valid is in localStorage
3
+ * @param themeIds — full list of allowed ids (built-in `light`/`dark` plus any `extraThemes`)
4
+ * @param palettes — resolved CSS variable maps per id
5
+ * @param overlay — optional `:root` overrides applied after the active palette
6
+ */
7
+ export declare function initTheme(defaultMode?: string, themeIds?: readonly string[], palettes?: Record<string, Record<string, string>>, overlay?: Record<string, string>): void;
8
+ export declare function useTheme(): {
9
+ theme: import('vue').Ref<string, string>;
10
+ setTheme: (mode: string) => void;
11
+ toggleTheme: () => void;
12
+ };
@@ -0,0 +1,2 @@
1
+ import { SiteConfig } from './types';
2
+ export declare function createSiteApp(config: SiteConfig): import('vue').App<Element>;
@@ -0,0 +1,7 @@
1
+ import { SiteConfig } from './types';
2
+ export { createSiteApp } from './create-app';
3
+ export { useTheme } from './composables/useTheme';
4
+ export { useSiteConfig } from './composables/useSiteConfig';
5
+ export { builtinThemePalettes } from './theme/presets';
6
+ export type { SiteConfig, SiteEnvConfig, SiteViteConfig, SiteExternalLink, NavItem, ThemeConfig, ThemeOption, ThemePaletteVars, ResolvedNavItem, } from './types';
7
+ export declare function defineConfig(config: SiteConfig): SiteConfig;