@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 +152 -0
- package/bin/vue-site.mjs +355 -0
- package/dist/components/AppLayout.vue.d.ts +2 -0
- package/dist/components/DynamicIcon.vue.d.ts +6 -0
- package/dist/components/MarkdownView.vue.d.ts +5 -0
- package/dist/components/NavGroup.vue.d.ts +6 -0
- package/dist/components/NavItem.vue.d.ts +9 -0
- package/dist/components/PageView.vue.d.ts +2 -0
- package/dist/components/SideNav.vue.d.ts +2 -0
- package/dist/components/SiteExternalLinks.vue.d.ts +8 -0
- package/dist/components/ThemeSwitch.vue.d.ts +10 -0
- package/dist/components/TooltipOverlay.vue.d.ts +18 -0
- package/dist/components/TopPrimaryNav.vue.d.ts +2 -0
- package/dist/components/UiTooltip.vue.d.ts +35 -0
- package/dist/composables/useNavLayout.d.ts +5 -0
- package/dist/composables/useSiteConfig.d.ts +9 -0
- package/dist/composables/useTheme.d.ts +12 -0
- package/dist/create-app.d.ts +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.es.js +38146 -0
- package/dist/nav-utils.d.ts +8 -0
- package/dist/router.d.ts +3 -0
- package/dist/style.css +1 -0
- package/dist/theme/presets.d.ts +5 -0
- package/dist/theme/resolve-palettes.d.ts +6 -0
- package/dist/types.d.ts +106 -0
- package/package.json +58 -0
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
|
package/bin/vue-site.mjs
ADDED
|
@@ -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,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
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -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;
|