Skip to content

djangobuilder5 — Milestone 1: redesigned UI vertical slice (React + Vite + Tailwind + shadcn) - #263

Open
mmcardle wants to merge 53 commits into
masterfrom
feat/djangobuilder5-redesign
Open

djangobuilder5 — Milestone 1: redesigned UI vertical slice (React + Vite + Tailwind + shadcn)#263
mmcardle wants to merge 53 commits into
masterfrom
feat/djangobuilder5-redesign

Conversation

@mmcardle

@mmcardle mmcardle commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

Introduces a new front-end package packages/djangobuilder5 — a slick, modern, dark-first redesign of Django Builder — as a look-locking Milestone 1 vertical slice. Nothing in djangobuilder.io or djangobuilder4 is touched; this is purely additive.

  • Stack: React 19 + Vite 6 + TypeScript + Tailwind v4 + shadcn-style owned components (class-variance-authority + clsx + tailwind-merge).
  • Design system: dark-first tokens + light variant with a persisted theme toggle, emerald #3ECF8E accent, and a coding palette exposed as first-class tokens (highlight.js theme is driven by those tokens, so the code colours follow the theme switch).
  • Splash: hero + live generated-models.py preview with a Copy helper.
  • Model builder: three-pane IDE — apps/models tree · inline field & relationship editor · live generated code with file tabs, per-file Copy, and Download .tar. Editing regenerates the code live.
  • Engine reuse: all Django generation + the .tar come from @djangobuilder/core, unchanged, isolated behind a single src/domain/ adapter. State is local (Zustand + immer + localStorage) — no Firebase in M1.
  • Workspace: adds dev5 / build_v5 / lint_v5 / test_v5 and folds lint_v5/test_v5 into the aggregate lint/test.

Design artifacts: docs/superpowers/specs/2026-07-05-djangobuilder5-ui-redesign-design.md and docs/superpowers/plans/2026-07-05-djangobuilder5-milestone-1.md.

Deliberate choices / deviations

  • highlight.js (not Shiki): token-driven theme, synchronous, switches instantly with the theme toggle; matches repo precedent.
  • Native styled <select> for M1 (Radix Select can replace later).
  • Right pane uses fixed file tabs (renderAppFile) rather than the full asTree explorer (deferred).
  • A whole-implementation code review was run and its findings applied (id-based relationship-owner wiring to prevent mis-wiring under duplicate model names; a clipboard guard for non-secure origins).

Out of scope (later milestones)

  • M2: Firebase auth + Firestore persistence, projects dashboard.
  • M3: optional canvas/ERD view mode (state model already shaped for it), production routing/deploy (/db5/ base + hosting), Radix-backed Select/Dialog/Toast.

Test Plan

  • bun install && bun run test_v5 → 30 tests pass (real generator + real store + a live-edit integration test).
  • bun run build_v5tsc --noEmit + vite build succeed.
  • bun run lint && bun run test (aggregate, all packages) pass.
  • bun run dev5 → splash shows live models.py + Copy; /build three-pane editor; edit a field → right-pane code regenerates; Download .tar downloads the project; theme toggle flips dark/light and the code palette follows.

🤖 Generated with Claude Code

https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo

mmcardle and others added 30 commits July 5, 2026 20:21
Design doc for a new React + Vite + Tailwind + shadcn/ui front-end package
(djangobuilder5) replacing the dated Vuetify UI. Milestone 1 is the
look-locking vertical slice: design system (dark-first, emerald accent),
app shell, hero splash with live code preview, and the three-pane IDE model
builder. Uses @djangobuilder/core unchanged; local state, Firebase deferred.

Also gitignore .superpowers/ (visual-companion brainstorm output).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
14-task TDD plan for the look-locking vertical slice: package scaffold,
Tailwind v4 design tokens (dark+light), shadcn foundation, theme toggle,
core domain adapter (@djangobuilder/core), generation + tar, CodeBlock with
token-driven highlighting + copy, Zustand store, app shell, hero splash, and
the three-pane IDE model builder with live regeneration and .tar download.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Adds djangobuilder5 dev/build/lint/test scripts and folds lint_v5/test_v5
into the aggregate lint/test. Leaves the deploy-oriented build (io+v4)
unchanged; db5 is not deployed in Milestone 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
…uard

- buildCoreProject: pass 2 now wires relationships onto the core model
  produced in pass 1 by identity (paired list) instead of re-looking up the
  owner by name, so duplicate model names can no longer mis-wire a
  relationship. Removes two non-null assertions. Adds a regression test.
- CodeBlock.copy: guard missing navigator.clipboard and wrap writeText in
  try/catch so copy fails silently on non-secure origins (e.g. LAN IP) instead
  of throwing an unhandled rejection.

Both from the Milestone 1 final code review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
- Hero column is now top-aligned (items-start) instead of vertically centered
  against the tall code preview, so "Design your models." starts at the top.
- Wider container (max-w-7xl) with a capped text column (~28rem) and a code
  column that grows to fill the remaining space (minmax-based grid), so the
  generated-code panel is wider and responsive — long lines like the
  ForeignKey no longer get clipped.

Addresses layout feedback on the Milestone 1 splash.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
The nav Docs link now uses target="_blank" + rel="noopener noreferrer" and
shows a small external-link icon so it's visually clear it leaves the app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Mirrors how djangobuilder4 is served under /db4/:
- db5 build scripts now use --base=/db5/ (+ development/staging/build-only
  variants), and the router uses BrowserRouter basename=import.meta.env.BASE_URL
  so client routing works under the subpath ("/" in dev).
- Root aggregate build/build_development/build_staging/build_production now
  include build_v5(_development/_staging/_production).
- firebase.json rewrites db5/** -> /db5/index.html.
- script/deploy.sh and the Makefile deploy target build db5 and copy its dist
  into the db5/ subdir of the deploy root.

Verified: built index.html emits /db5/assets/..., and the bundle boots and
client-routes correctly when served under /db5/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
The code pane was a fixed w-[380px] while the editor took all remaining
space. Give it flex-1 (with a 360px floor) so it and the editor split the
space ~50/50 and both scale with the viewport — the generated code is no
longer cramped and the editor no longer hogs the width.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Design for M2: share the live Firebase backend + 5-collection owner-stamped
schema (via a pure flatten/re-nest mapper), auto-save write-through builder,
full email auth + anonymous, and an A+C projects dashboard (code-thumbnail
cards). Keeps MAX_PROJECTS=3, drops the local-only postgres field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
11-task TDD plan for auth + Firestore persistence + dashboard: firebase init,
pure renest/summary mapper, auth/data/write services (owner-stamped, cascade),
auth store + firestore-backed write-through project store, builder wiring
(route :id, debounced edits, anon try-it), auth screens, A+C dashboard with
MAX_PROJECTS, and auth-gated routing. Service layer tested with mocked
firebase; dev project is the manual e2e gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
…on try-it

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
mmcardle and others added 23 commits July 6, 2026 21:10
…ession

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
… auto-select

From the Milestone 2 code review + live e2e findings:
- DebouncedInput: cancel the pending commit on unmount (no updateDoc against a
  deleted doc) and only adopt an external value when not focused (no clobbering
  in-progress keystrokes).
- projectStore: route every write-through op through guardWrite/reportWriteError
  so failed saves log instead of becoming silent unhandled rejections;
  createProject/deleteProject catch too.
- BuilderPage: auto-select the first model once a project's collections load
  (openProject can run before the models snapshot arrives), and add a short
  grace period so a freshly-created project shows Loading rather than flashing
  "Project not found".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Deploy db5 under /db5/ to the development Firebase project, after fixing the
subpath auth continue-URL + favicon and the four deferred M2 review minors
(snapshot-handler log-not-throw, all-collections-loaded guard, unverified
reload button, atomic batched addModel). Inline execution; staging/prod later.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
- Email action-code continue URL uses import.meta.env.BASE_URL so verified/reset
  users return to /db5/login under the deployed subpath (not the root app).
- Add an inline SVG favicon (kills the 404).
- snapshotErrorHandler logs instead of throwing into onSnapshot's async machinery.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
subscribeAll now reports allLoaded (true once every collection's initial
snapshot has arrived); the store sets dataLoaded from it. Fixes the
cascade-delete race window, the brief "Project not found" flash, and makes
first-model auto-select reliable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Add reloadUser() and an "I've verified — refresh" button that reloads the user
from the server, pushes it into the auth store, and navigates to /projects when
verified — no manual page reload needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
addModel now writes the model doc, the app-map link, and the two default
DateTimeField fields (created/last_updated) in a single writeBatch — atomic
and one round-trip instead of four sequential writes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jUxCijreThyiaGzxyieYo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
…t, responsive

Closes the five parity gaps vs the current system:
- Project files: CodePane now renders the full project file tree
  (renderer.asTree) — project/app/model files, click to view — not just the
  five app files. Adds projectFileTree + renderNodeByPath to domain/generate;
  exports DjangoProjectFileResource from core.
- Description + settings: new ProjectHeader (name, description, version/HTMX/
  Channels chips) + ProjectSettingsDialog (edit name/description/version/flags
  write-through, delete project). Adds store setDescription.
- About: new /about route + AboutView + TopNav link.
- Responsive: new BuilderShell — 3-pane on lg+, tree drawer + Edit/Code tab
  switcher below lg.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Replace the four-column builder (models tree | editor | file tree | code)
with a two-column tabbed workspace: a persistent models tree plus a main
area that tabs between Design (model editor) and Code (file tree + code).
Only one content pane shows at a time, at every width, so nothing is cramped.
Makes the existing mobile tab pattern the layout at all breakpoints.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Collapse the builder to a single navigation tree (the generated file tree)
plus the code view; move all model editing into a per-app modal.

- Remove the models panel (TreePane) and the Design/Code tabs (EditorPane,
  CodePane deleted). BuilderShell is now: file tree (persistent lg / drawer
  below lg) + CodeView, with a per-app ModelsModal.
- ModelsModal lists every model in an app (ModelEditor each: name, abstract,
  fields, relationships, delete), plus Add model and Delete app. Opened from
  the tree's edit control on models.py or the code header's 'Edit models'.
- FileTree gains a '+ App' input and a per-models.py edit control.
- Add app-level creation to the tree; add store updateModel + removeApp
  (writes.removeApp cascade); drop the now-unused select/selectedModelId.
- Promote DebouncedInput to a shared ui component.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
- core: add DJANGO6 = 6.0 to the DjangoVersion enum (additive; db4 unaffected).
- db5: DjangoVersionNumber 3|4|5|6; toVersionNumber(6)->6.0; fromVersion default 6;
  buildCoreProject maps 6 -> DJANGO6; LocalProject/ProjectSummary version types.
- dialogs: add 'Django 6' option, preselected by default, in New-project + Settings.

Note: the numeric enum renders the pin as 'Django==6' (pip resolves to 6.0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
…de, built-in targets, consent/analytics

Closes the High + Medium gaps vs djangobuilder.io:
- Import from models.py: core ModelImporter wrapped in domain/import.ts;
  writes.importModels batches parsed models+fields+rels; ImportModelsDialog
  (paste -> parse -> select -> add) opened from the models modal.
- Model inheritance/parents: LocalModel.parents in the shared Firestore format
  ({class,type:django} | {app,model,type:user}); mapper reads + filters dangling;
  buildCoreProject resolves django + user parents; ModelEditor 'Inherits from' UI.
- Move model between apps: writes.moveModel re-parents via the app maps; a
  'Move to…' select in the model editor.
- Anonymous -> registered upgrade: auth.upgradeAnonymous (linkWithCredential),
  UpgradeAccountDialog, 'Save your account' in the nav — same uid, data kept.
- Extra built-in targets: auth.AbstractUser/AbstractBaseUser/Group as relationship
  targets; buildCoreProject resolves any built-in; shared builtInTargets.
- Analytics + consent + privacy: consentStore, gated gtag loader, ConsentSnackbar,
  /privacy PrivacyPolicy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
At >=1536px the per-app models editor renders as a right-rail side panel
next to the live code (edit + watch models.py regenerate together) instead
of a centered overlay; below that width it stays the modal.

- extract ModelsPanel (the editor content) from ModelsModal; ModelsModal is
  now a thin overlay wrapper around it.
- add a matchMedia-based useMediaQuery hook (+ jsdom mock in test setup).
- BuilderShell docks ModelsPanel (right rail) when the 2xl query matches,
  else renders the ModelsModal overlay.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
The relationship row had a fixed-width name input plus two intrinsic-width
selects (type + target) and no flex-1 absorber, so its min content width
(~548px) exceeded the narrow docked panel (~469px) and spilled past the edge.
Make both selects min-w-0 flex-1 so they share the row and shrink (like the
field row's args input). Verified live: row now fits its container exactly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RakQgqBxYPYUY37gvxrtG7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant