Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
8a7ce05
chore(builder): scaffold builder app
johnleider May 19, 2026
ea81d4b
chore(builder): add feature catalog and dependency resolver
johnleider May 19, 2026
d066159
chore(builder): add wizard UX and selection store
johnleider May 19, 2026
d5adf1f
chore(builder): add useStack and useRules to plugin catalog
johnleider May 20, 2026
7197fb6
chore(builder): add canonical plugin order and route metadata
johnleider May 20, 2026
905e9be
chore(builder): extend store with pluginConfig, selectedComponents, c…
johnleider May 20, 2026
17cf586
chore(builder): persist wizard state to localStorage
johnleider May 20, 2026
d3b88c4
chore(builder): add PluginConfigShell with prev/skip/save&next chrome
johnleider May 20, 2026
afd5f6e
chore(builder): refactor wizard into /builder routes with dynamic plu…
johnleider May 20, 2026
6266f64
chore(builder): add route guards for wizard navigation
johnleider May 20, 2026
eb66bfe
chore(builder): add Theme plugin config form
johnleider May 20, 2026
bbca413
chore(builder): add Breakpoints plugin config form
johnleider May 20, 2026
00c4713
chore(builder): add Locale plugin config form
johnleider May 20, 2026
20bc82b
chore(builder): add Rtl plugin config form
johnleider May 20, 2026
320a737
chore(builder): add Storage plugin config form
johnleider May 20, 2026
e75a21f
chore(builder): add Hydration confirm-only screen
johnleider May 20, 2026
6f301a8
chore(builder): add Logger plugin config form
johnleider May 20, 2026
6d2bea7
chore(builder): add Features plugin config form
johnleider May 20, 2026
2bce35c
chore(builder): add Permissions plugin config form
johnleider May 20, 2026
cf97c33
chore(builder): add Notifications plugin config form
johnleider May 20, 2026
87e71bb
chore(builder): add Date plugin config form
johnleider May 20, 2026
8dbfd4c
chore(builder): add Stack plugin config form (real options per scout)
johnleider May 20, 2026
763ccd0
chore(builder): add Rules plugin config form
johnleider May 20, 2026
1802757
chore(builder): thread per-plugin config into generated main.ts
johnleider May 20, 2026
c2258f1
chore(builder): add zip starter generator (fflate-based)
johnleider May 20, 2026
e5527d7
chore(builder): build review screen with playground + zip outputs
johnleider May 20, 2026
51f1b3f
chore(builder): add plugin-to-component recommendation mapping
johnleider May 20, 2026
7e6eb78
chore(builder): build smart-filter component selection page
johnleider May 20, 2026
2d7e902
chore(builder): fix adapter emission in generated main.ts
johnleider May 20, 2026
ee73c57
chore(builder): prefer toRef over computed per project style
johnleider May 20, 2026
b2204e6
chore(builder): use #v0 alias for cross-package imports
johnleider May 20, 2026
7d3de97
chore(builder): replace destructure-rest with explicit delete for sta…
johnleider May 20, 2026
0db744b
chore(builder): regenerate auto-imports + typed-router dts
johnleider May 20, 2026
c94c8e3
chore(builder): tighten exports and prune dead code
johnleider May 20, 2026
323320e
fix(builder): point playground handoff at v0play.vuetifyjs.com and dr…
johnleider May 21, 2026
278616e
chore(builder): swap native buttons for Button.Root in shared chrome
johnleider May 21, 2026
3fe793a
chore(builder): swap card-grid buttons for Button.Root in selection p…
johnleider May 21, 2026
41f42eb
chore(builder): refactor Theme form to v0 Select, Input, Checkbox com…
johnleider May 21, 2026
dacefc9
chore(builder): refactor Breakpoints form to v0 components
johnleider May 21, 2026
694a374
chore(builder): refactor Permissions form to v0 components
johnleider May 21, 2026
60c4532
chore(builder): refactor Storage form to v0 components
johnleider May 21, 2026
9cfc3a2
chore(builder): refactor Locale form to v0 components
johnleider May 21, 2026
fc3b85f
chore(builder): refactor Rtl form to v0 components
johnleider May 21, 2026
8f488e3
chore(builder): refactor Notifications form to v0 components
johnleider May 21, 2026
636fc29
chore(builder): refactor Logger form to v0 components
johnleider May 21, 2026
0a13bed
chore(builder): refactor Date form to v0 components
johnleider May 21, 2026
caa96d4
chore(builder): refactor Features form to v0 components
johnleider May 21, 2026
e9a5c7e
chore(builder): refactor Stack form to v0 components
johnleider May 21, 2026
21a14bf
chore(builder): refactor Rules form to v0 components
johnleider May 21, 2026
f7a446f
chore(builder): swap remaining native radios for Radio.Root in Breakp…
johnleider May 21, 2026
e5d55f7
fix(builder): use JSON clone instead of structuredClone for config hy…
johnleider May 22, 2026
7c8a4b0
chore(builder): live preview pane with draft channel
johnleider Jul 31, 2026
2992c33
chore(builder): align config screens with current v0 option shapes
johnleider Jul 31, 2026
09d68f3
chore(builder): regenerate working code from current v0 API
johnleider Jul 31, 2026
3f0c23b
chore(builder): pass resolved deps to zip so demos match playground
johnleider Jul 31, 2026
0b9e2c2
chore(builder): live preview modules for all configurable plugins
johnleider Jul 31, 2026
85b675c
chore(builder): emit new plugins, enforce install order for persist
johnleider Jul 31, 2026
e29b433
chore(builder): compile-time coverage for known rule aliases
johnleider Jul 31, 2026
214a538
chore(builder): preview fidelity fixes from QA pass
johnleider Jul 31, 2026
0d7c879
chore(builder): gate draft components and finish a11y from QA pass
johnleider Jul 31, 2026
b622fd9
chore(builder): style and configure generated output end to end
johnleider Jul 31, 2026
8e4e5b5
chore(builder): send saved plugin config to the playground payload
johnleider Jul 31, 2026
42300ac
chore(builder): design pass — one visual language across the wizard
johnleider Jul 31, 2026
670b826
chore(builder): survive undefined config values in codegen
johnleider Jul 31, 2026
bffca5f
chore(builder): omit unset config keys, in-grid rec chips, persist theme
johnleider Jul 31, 2026
8a0841d
chore(builder): two-column swatch grid on phones, no mid-word wraps
johnleider Jul 31, 2026
50a532f
chore(builder): drop dead exports flagged by knip
johnleider Jul 31, 2026
257709c
chore(builder): saved builds with auto-save, switcher, and migration
johnleider Jul 31, 2026
47dc005
chore(builder): registry invariants and demo import cross-checks
johnleider Jul 31, 2026
afbca6c
chore(builder): fix rename field focus, guard delete, purge unopened …
johnleider Jul 31, 2026
d7892ff
chore(builder): request-token switch guard, error contract, index rev
johnleider Jul 31, 2026
f0415cf
chore(builder): reactive build list, lazy create, honest delete
johnleider Jul 31, 2026
4f7d2f3
chore(builder): honest dependency graph and UI-registry guards
johnleider Jul 31, 2026
eb9eb0a
chore(builder): design-audit fixes — overflow, states, elevation, tokens
johnleider Jul 31, 2026
2b76708
chore(builder): fixed full-width step bar, tighter rhythm, live tweaks
johnleider Jul 31, 2026
dbb57d1
chore(builder): component info popovers on the picker
johnleider Jul 31, 2026
7267e17
chore(builder): theme config follows builder mode, rock-still preview
johnleider Jul 31, 2026
0b8fc49
chore(builder): add @paper/genesis dependency
johnleider Jul 31, 2026
ded64ef
chore(builder): step 1 category panels with live manifest aside
johnleider Jul 31, 2026
f0f35af
chore(builder): one-line plugin rows with About popovers
johnleider Jul 31, 2026
7ede831
chore(builder): manifest renders through GnDocsExampleCode with peek
johnleider Jul 31, 2026
f28bb71
chore(builder): blueprint dot grid and empty state for the manifest
johnleider Jul 31, 2026
2fbf77d
chore(builder): define on-background token for both themes
johnleider Jul 31, 2026
74ebbd2
chore(builder): customized chip means changed, not merely saved
johnleider Jul 31, 2026
985ef5d
chore(builder): final-review fixes for the step 1 manifest
johnleider Jul 31, 2026
8103bf4
chore(builder): step 1 aside polish — no mock app, fill-height code b…
johnleider Aug 1, 2026
abf9998
chore(builder): shiki highlighting for the live manifest
johnleider Aug 1, 2026
996cc2c
chore(builder): plugin picker back to compact card grid
johnleider Aug 3, 2026
1adb838
chore(builder): playing-card ratio for plugin cards
johnleider Aug 3, 2026
6fddfda
chore(builder): plugin card face — description and module count
johnleider Aug 3, 2026
410bcfa
chore(builder): plugin card icons + selected-state blueprint grid
johnleider Aug 3, 2026
cb78c1e
chore(builder): drop plugin card module count, fix grid row stretch
johnleider Aug 3, 2026
644275e
chore(builder): top-align plugin card content, fix button auto-centering
johnleider Aug 3, 2026
81ce4b1
chore(builder): info popovers open on hover
johnleider Aug 4, 2026
ecbcdbf
chore(builder): drop aside toolbar, dot grid blooms top left
johnleider Aug 4, 2026
38b985f
chore(builder): hide the manifest preview on step 1
johnleider Aug 4, 2026
31f466c
chore(builder): drop the empty blueprint panel on step 1
johnleider Aug 4, 2026
3d84ace
chore(builder): no aside on step 1
johnleider Aug 4, 2026
0ef8420
chore(builder): per-card blueprint variation on selected plugins
johnleider Aug 4, 2026
5b1e4f7
chore(builder): info popovers open above the trigger
johnleider Aug 4, 2026
1e59dd1
chore(builder): vuetify0 icon in the header
johnleider Aug 4, 2026
b10b936
chore(builder): stronger blueprint coverage on plugin cards
johnleider Aug 4, 2026
4336cc6
chore(builder): back chevron and progress move to the bottom bar
johnleider Aug 4, 2026
67bb077
chore(builder): hide the wizard progress on step 1
johnleider Aug 4, 2026
6c4e46c
chore(builder): add scroll-padding-bottom for fixed StepBar
cursoragent Sep 5, 2026
e0a6540
fix(builder): align review.vue statusFor with PreviewSummary customiz…
cursoragent Sep 5, 2026
ee6a01c
test(builder): update draft component list after DataGrid/DataTable p…
cursoragent Sep 5, 2026
885f4ec
chore(builder): fix lint issues
cursoragent Sep 5, 2026
32f8c72
feat(builder): add Vuetify One subscriber-gated requirements prompt
johnleider Sep 15, 2026
42d01f8
fix(builder): remove non-existent mdiSparkles import
johnleider Sep 15, 2026
ac95d43
fix(builder): remove unused getPluginInfo export
johnleider Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions apps/builder/build/generate-dependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url))
const ROOT = resolve(__dirname, '../../..')
const V0_SRC = resolve(ROOT, 'packages/0/src')

interface DependencyGraph {
composables: Record<string, string[]>
components: Record<string, string[]>
}

// Tests and benchmarks import far more than the feature itself needs — Dialog
// only reaches for Scrim in its browser test, useTheme only for useStorage in
// its unit test. Counting those makes the review sheet promise dependencies the
// generated starter deliberately never installs.
const EXCLUDED = /\.(?:test|browser\.test|ssr\.test|bench)\.ts$/

// `import type` is erased at build time, so a type-only edge is not a runtime
// dependency. Stripping the whole statement before scanning is simpler than
// trying to classify each specifier, and the brace form covers multi-line.
const TYPE_ONLY = /^[^\S\n]*(?:import|export)\s+type\s+(?:\{[^}]*\}|[^\n]*?)\s*from\s*['"][^'"]+['"]/gm

// The trailing group captures deep imports (`useTheme/adapters`,
// `createDataTable/columns`) which the specifier regex used to skip entirely.
const SPECIFIER = /from\s+['"]#v0\/(?:composables|components)\/(\w+)(?:\/[\w/]+)?['"]/g

function extractV0Imports (filePath: string): string[] {
if (EXCLUDED.test(filePath)) return []

let content: string
try {
content = readFileSync(filePath, 'utf8')
} catch {
return []
}

const runtime = content.replaceAll(TYPE_ONLY, '')
const imports = [...runtime.matchAll(SPECIFIER)].map(match => match[1])

return [...new Set(imports)]
}

// Recursive: a feature's real dependencies are not all at the top level.
// createDataTable reaches createFilter from adapters/adapter.ts, and a
// single-level scan reported that edge only by accident, via a type import in
// index.ts that is not a runtime dependency at all.
function collectFiles (dir: string): string[] {
const files: string[] = []

try {
for (const entry of readdirSync(dir)) {
const path = resolve(dir, entry)

if (statSync(path).isDirectory()) {
files.push(...collectFiles(path))
} else if (entry.endsWith('.ts') || entry.endsWith('.vue')) {
files.push(path)
}
}
} catch { /* empty */ }

return files
}

function scanDirectory (dir: string): Record<string, string[]> {
const entries = readdirSync(dir)
const graph: Record<string, string[]> = {}

for (const entry of entries) {
const entryPath = resolve(dir, entry)
if (!statSync(entryPath).isDirectory()) continue

const deps = collectFiles(entryPath).flatMap(file => extractV0Imports(file))

graph[entry] = [...new Set(deps)].filter(d => d !== entry).toSorted()
}

return graph
}

const graph: DependencyGraph = {
composables: scanDirectory(resolve(V0_SRC, 'composables')),
components: scanDirectory(resolve(V0_SRC, 'components')),
}

const outPath = resolve(__dirname, '../src/data/dependencies.json')
writeFileSync(outPath, JSON.stringify(graph, null, 2) + '\n')

console.log(
`Generated dependency graph: ${Object.keys(graph.composables).length} composables, ${Object.keys(graph.components).length} components`,
)
13 changes: 13 additions & 0 deletions apps/builder/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="https://cdn.vuetifyjs.com/docs/images/one/logos/vzero.svg" />
<title>v0 Framework Builder</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
33 changes: 33 additions & 0 deletions apps/builder/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@vuetify-private/builder",
"version": "1.0.0-alpha.0",
"private": true,
"type": "module",
"scripts": {
"generate": "tsx build/generate-dependencies.ts",
"dev": "pnpm generate && vite",
"build": "pnpm generate && vite build",
"preview": "vite preview"
},
"dependencies": {
"@mdi/js": "catalog:",
"@paper/genesis": "workspace:*",
"@shikijs/langs": "catalog:",
"@shikijs/themes": "catalog:",
"@vuetify/auth": "catalog:",
"@vuetify/v0": "workspace:*",
"fflate": "catalog:",
"pinia": "catalog:",
"shiki": "catalog:",
"vue": "catalog:",
"vue-router": "catalog:"
},
"devDependencies": {
"tsx": "catalog:",
"unocss": "catalog:",
"unplugin-vue": "catalog:",
"unplugin-vue-components": "catalog:",
"vite": "catalog:",
"vite-plugin-vue-layouts-next": "catalog:"
}
}
51 changes: 51 additions & 0 deletions apps/builder/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
// Components
import AppShell from '@/components/app/AppShell.vue'
import PreviewPane from '@/components/preview/PreviewPane.vue'

// Utilities
import { toRef } from 'vue'
import { RouterView, useRoute } from 'vue-router'

const route = useRoute()

const split = toRef(() => route.path.startsWith('/builder'))
</script>

<template>
<AppShell :split>
<RouterView />

<template #preview>
<PreviewPane />
</template>
</AppShell>
</template>

<style>
/* The fixed StepBar at the bottom is ~4rem + 1px; scroll-padding-bottom ensures
scroll-to targets (in-page anchors, router scrollBehavior) land above it, not
under. The 6rem matches the pb-24 content padding the stepped pages already use. */
html {
scroll-padding-bottom: 6rem;
}

/* Shiki (defaultColor: false, dual themes) writes each token's color as a pair of
--shiki-light/--shiki-dark custom properties on its own span rather than as a
`color` declaration — nothing consumes them without this rule. apps/docs' toggle
assumes a `.dark` ancestor class; this app only ever sets [data-theme] on <html>
(createThemePlugin, target: 'html'), so the toggle keys off that instead.
Background is forced transparent (not shiki's own light/dark bg) so the manifest's
own surface — GnDocsExampleCode's --v0-pre override — shows through underneath,
letting GnDotGrid read behind the code text instead of being covered by it. */
.shiki,
.shiki span {
color: var(--shiki-light);
background-color: transparent;
}

:root[data-theme='dark'] .shiki,
:root[data-theme='dark'] .shiki span {
color: var(--shiki-dark);
}
</style>
42 changes: 42 additions & 0 deletions apps/builder/src/components.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399

export {}

/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AppShell: typeof import('./components/app/AppShell.vue')['default']
BuildSwitcher: typeof import('./components/app/BuildSwitcher.vue')['default']
ComponentInfo: typeof import('./components/ComponentInfo.vue')['default']
Icon: typeof import('./components/app/Icon.vue')['default']
MiniFrame: typeof import('./components/preview/MiniFrame.vue')['default']
PluginConfigShell: typeof import('./components/PluginConfigShell.vue')['default']
PluginInfo: typeof import('./components/PluginInfo.vue')['default']
PreviewBreakpoints: typeof import('./components/preview/PreviewBreakpoints.vue')['default']
PreviewDate: typeof import('./components/preview/PreviewDate.vue')['default']
PreviewFeatures: typeof import('./components/preview/PreviewFeatures.vue')['default']
PreviewLocale: typeof import('./components/preview/PreviewLocale.vue')['default']
PreviewLogger: typeof import('./components/preview/PreviewLogger.vue')['default']
PreviewNotifications: typeof import('./components/preview/PreviewNotifications.vue')['default']
PreviewPane: typeof import('./components/preview/PreviewPane.vue')['default']
PreviewPermissions: typeof import('./components/preview/PreviewPermissions.vue')['default']
PreviewReducedMotion: typeof import('./components/preview/PreviewReducedMotion.vue')['default']
PreviewRtl: typeof import('./components/preview/PreviewRtl.vue')['default']
PreviewRules: typeof import('./components/preview/PreviewRules.vue')['default']
PreviewStack: typeof import('./components/preview/PreviewStack.vue')['default']
PreviewStorage: typeof import('./components/preview/PreviewStorage.vue')['default']
PreviewSummary: typeof import('./components/preview/PreviewSummary.vue')['default']
PreviewTheme: typeof import('./components/preview/PreviewTheme.vue')['default']
PreviewTooltip: typeof import('./components/preview/PreviewTooltip.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
StepBar: typeof import('./components/app/StepBar.vue')['default']
ThemeToggle: typeof import('./components/app/ThemeToggle.vue')['default']
}
}
Loading
Loading