feat: Builder car-configurator wizard#241
Open
johnleider wants to merge 34 commits into
Open
Conversation
Bootstrap apps/builder workspace package modeled on apps/playground but without the playground-specific deps (vue-repl, shiki, markdown). Same tsconfig + vite config patterns so the oxc transformer resolves tsconfig cleanly.
Carried forward from the deleted feature/framework-builder branch via
docs/builder-seed/:
- data/features.ts: curated catalog with name, summary, useCases, tags,
icon over the generated dep graph
- data/dependencies.json: generated by build/generate-dependencies.ts
on every `pnpm generate` (runs before vite via the dev script)
- data/questions.ts: 11 plugins across 5 categories (appearance, i18n,
infrastructure, access, utilities) - the only surface upfront config
needs to ask about
- engine/resolve.ts: pure function that walks the dep graph and reports
{ selected, autoIncluded, reasons, warnings }
- engine/manifest.ts: encodes selection into a fflate-compressed hash
for handoff to apps/playground
- main.ts wires Pinia + router + v0 plugins (hydration, breakpoints,
storage, theme) with light/dark color tokens
- pages/index.vue lands users with a one-paragraph explainer and a
single CTA to /wizard
- pages/wizard.vue runs the wizard in two phases via a plain
shallowRef<'plugins' | 'review'>:
- plugins phase renders the questions.ts taxonomy as a category-
grouped toggle grid
- review phase shows selected + auto-included dependencies + any
warnings, pulled from the engine/resolve output
- stores/builder.ts holds the selection Set and exposes resolved as a
toRef derived from the dep graph
Deliberately skipped from the previous branch: IntentCard + multi-
intent flow (only component-library exists), mode cards, the stepper
integration, breadcrumb sync, Free Pick and AI pages.
Add generateMainTs() and generatePluginCalls() to manifest.ts. The
generator iterates a FACTORY map covering all 13 plugins and emits
`app.use(createXPlugin(config))` calls. When the stored config is
empty/absent, the call is no-arg. The useDate special-case always
emits `{ adapter: new V0DateAdapter() }` since the plugin throws
when the adapter is missing.
New engine/zip.ts exports generateZip(manifest) and downloadZip(manifest) producing a downloadable starter project. The archive includes package.json, vite.config.ts, tsconfig.json, uno.config.ts, index.html, README.md, .gitignore, App.vue, src/pages/index.vue, and main.ts generated by manifest.ts so per-plugin config is threaded through.
Replace the Wave 1 placeholder with the real review screen. Shows selected plugins with customized/defaults/(no config) status, selected components, auto-included deps, and any resolver warnings. Two action buttons: "Open in Playground" (encodes a FrameworkManifest via toPlaygroundUrl) and "Download starter (.zip)" (calls downloadZip). Footer offers Reset all and Back.
Date / Logger / Notifications / Features plugins save the adapter as a
string in their config (e.g. 'V0DateAdapter', 'KnockNotificationsAdapter').
The generator was JSON-stringifying the whole config object, producing
broken TypeScript like `createDatePlugin({ adapter: "V0DateAdapter" })`
where the plugin expects a class INSTANCE.
The existing useDate sentinel trick also didn't work because the spread
order overwrote the placeholder.
Introduce a per-plugin ADAPTER_HANDLERS table that:
- Maps each adapter string to a raw TS expression (e.g. `new V0DateAdapter()`)
- Returns the v0 class names that need to be added to the import list
- Returns `null` to omit the adapter field entirely (e.g. 'none' for
Notifications / Features)
Imports are now collected per-plugin and merged into the @vuetify/v0
import list so adapter classes always travel alongside their factory.
useDate always emits an adapter (it's required); 'custom' emits a
TODO-flagged `new CustomDateAdapter()` for the user to fill in.
…le config cleanup
- Add apps/builder workspace entry to knip.json - Drop dead Feature/FeatureMeta types and the unused features.ts seed catalog (components page uses maturity.json directly) - Un-export PLUGIN_TO_COMPONENTS, generatePluginCalls, encodeHash, generateZip — internal-only
|
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Builds out
apps/builder/into a car-configurator-style wizard for assembling a v0-based Vue app from selectable plugins + components./builder/<slug>(Theme, Breakpoints, Locale, Rtl, Storage, Hydration, Logger, Stack, Features, Permissions, Date, Notifications, Rules) — each with its own form body component anddefaults.ts. HybridPluginConfigShellwrapper handles chrome (Prev / Skip / Save & Next) so the body components only declare fields./builder/components— recommended subset derived from selected plugins, full catalog grouped by category. Reads the component list frompackages/0/src/maturity.json./builder/review:play.vuetifyjs.com#….package.json,vite.config.ts,tsconfig.*,uno.config.ts,index.html,src/main.tswith all selected plugins wired with their saved configs).generateMainTs()source-of-truth feeds both outputs.useStorageunder namespacebuilder.v1(Set ↔ array conversion at the boundary). Resume across reloads.apps/builder/src/router/guards.tsfor/builder/configureredirect-to-first-selected and rejecting orphan plugin slugs.Adapter handling in generated main.ts
useDate,useLogger,useNotifications,useFeaturessave their adapter as a string in the form (e.g.'V0DateAdapter'). The generator strips that field, injectsnew V0DateAdapter()as raw TS, and adds the class to the v0 import list.'none'omits the field;'custom'for Date emits a// TODO: implementplaceholder.Scope cuts (v1)
messageseditor and Rules custom-rule editor are JSON textareas — tree/visual editors are their own projects.component-libraryintent supported.What's not in this PR