Rename in 91045a1 was only partially reverted by later commits, leaving
~20 UI spots calling the project entity "Client" while table headers
already said "Project". Reverted all of them plus the /clients/:id
route (now /projects/:id canonical again, nothing was live yet).
Also: stop tracking .env.backfill (had a live admin password/token
committed - rotate those credentials), remove stale pre-redesign
layout.md superseded by REDESIGN-LAYOUT2.md.
11 KiB
Layout2 — Redesign Tracker
Visual redesign only. Functions stay identical. No data flow, query, route, or behavior changes. If a change touches logic, it does not belong in Layout2.
- Branch:
redesign - Dev: http://localhost:5173/ (Vite HMR, no rebuild)
- Live: untouched — nothing deploys until explicitly approved. No
vercel --prodduring Layout2. - Started: 2026-06-23
Rules
- Redesign = layout, spacing, hierarchy, components' visual form. No prop/state/handler edits.
- Keep every element that exists today (buttons, fields, badges) — reposition/restyle, don't remove function.
- Preserve all routes, role gates (
team/external/client), and conditional rendering as-is. - Reuse design tokens (below). Add new tokens rather than hard-coding values.
- Commit per page/section with
redesign:prefix so it's revertible.
Direction
- Background: solid 95% black
#0d0d0d, no gradient, no animation. - Cards: solid gray
#1a1a1a(5% lighter than bg); elevated/hover#242424. - Font: Inter (Google Fonts, weights 300–700) — modern, readable, app-wide. Brand
Fourgefont retired from UI text; logo is an image, unaffected.
Control panel (single source of truth — src/index.css :root)
Change one line, every card/page across all roles updates.
| Knob | Token / line | Scope |
|---|---|---|
| Background | --bg |
whole app |
| Card fill | --card-bg (+ --card-bg-2 elevated/hover) |
every card |
| Card border | --card-border (1px solid transparent = off) |
every card |
| Card radius | --card-radius |
every card |
| Font | body font-family (Inter) |
whole app |
| Accent / gold | --accent (+ --accent-hover) |
all gold UI |
| Status: error | --danger (+ --danger-strong) |
all red |
| Status: success | --success (+ --success-strong) |
success greens |
| Money/positive | --positive |
dashboard/positive green |
| Info | --info |
blue |
| Violet | --violet |
purple |
| Warning | --warning |
amber |
Tints pull from the same token: color-mix(in srgb, var(--accent) 15%, transparent).
All semantic colors are theme-independent (badge light palette stays in index.css).
~168 hardcoded hex/rgba across 15 JSX files were swept to these tokens (zero visual change).
Cards = elements with var(--card-bg); their frame uses var(--card-border). The menu/sidebar
also uses --card-border + --card-radius. Inputs/tables/toolbar dividers keep their own --border
and are intentionally NOT card-controlled.
Theming: tokens live in :root (dark defaults); [data-theme="light"] overrides values.
Same token name site-wide, one value per theme. --card-border is set in both themes
(dark #262626, light rgba(0,0,0,0.08)); --card-radius is shared (color-free).
Full token chart (canonical — src/index.css)
All in :root (dark); [data-theme="light"] overrides where noted. Same token name site-wide,
one value per theme. Solids = var(--x); tints = color-mix(in srgb, var(--x) N%, transparent).
Surfaces
| Token | Dark | Light |
|---|---|---|
--bg |
#1a1a1a |
#ffffff |
--card-bg |
#1f1f1f |
rgba(0,0,0,.02) |
--card-bg-2 |
#262626 |
rgba(0,0,0,.08) |
--surface-sunken |
#141414 |
#f5f5f5 |
--popup-bg |
var(--card-bg) (= #1f1f1f) |
rgba(255,255,255,.92) (opaque; light card-bg is translucent) |
Borders
| Token | Dark | Light |
|---|---|---|
--border |
rgba(245,165,35,.15) |
rgba(0,0,0,.1) |
--card-border |
1px solid #262626 |
1px solid rgba(0,0,0,.08) |
--card-radius |
8px |
shared |
--interactive-hover-border |
rgba(245,165,35,.3) |
rgba(0,0,0,.2) |
Text
| Token | Dark | Light |
|---|---|---|
--text-primary |
#ffffff |
#0d0d0d |
--text-secondary |
#a8a8a8 |
rgba(0,0,0,.6) |
--text-muted |
#666666 |
rgba(0,0,0,.38) |
--text-on-accent |
#000000 |
shared |
Brand & status (theme-independent)
| Token | Value |
|---|---|
--accent / --accent-hover |
#F5A523 / #e09510 |
--danger / --danger-strong |
#ef4444 / #dc2626 |
--success / --success-strong |
#22c55e / #16a34a |
--positive |
#4ade80 |
--info |
#60a5fa |
--violet |
#a78bfa |
--warning |
#f59e0b |
Data / categorical (charts, file-type chips — by hue)
| Token | Value | Token | Value |
|---|---|---|---|
--data-blue |
#3b82f6 |
--data-indigo |
#2563eb |
--data-purple |
#8b5cf6 |
--data-purple-soft |
#c084fc |
--data-pink |
#ec4899 |
--data-pink-soft |
#f472b6 |
--data-orange |
#f97316 |
--data-orange-soft |
#fb923c |
--data-emerald |
#10b981 |
--data-emerald-soft |
#34d399 |
--data-gray |
#6b7280 |
Utility / misc
| Token | Dark | Light |
|---|---|---|
--overlay-scrim |
rgba(0,0,0,.58) |
rgba(255,255,255,.72) |
--popup-shadow |
0 24px 64px rgba(0,0,0,.5) |
lighter |
--avatar-inner-ring |
#111111 |
#ffffff |
--sidebar-* |
bg #0d0d0d, text #888, active #fff/#1a1a1a |
inverted |
| motion | --motion-fast 160ms, --motion-base 220ms, ease cubic-bezier(0.22,1,0.36,1) |
|
| buttons | h 22px, radius 8px, font 11px/500, tracking 0.8px |
Intentionally NOT tokenized (must stay literal):
- Canvas/PDF export colors (
BrandBook.jsx,Converters.jsx—ctx.fillStyle), white logo backgrounds. PayInvoice.jsx— public printable invoice, standalone light styling, must not follow app theme.
Established patterns (from memory):
- Card label color
rgba(255,255,255,0.8). - Filter/tab layout: dropdowns outside card, tab buttons inside card above table. Canonical:
Tasks.jsx(Requests).
Shared shell / components
| Item | File | Status |
|---|---|---|
| App shell / sidebar / nav | src/components/Layout.jsx |
⬜ |
| Global tokens & base CSS | src/index.css |
⬜ |
| StatusBadge | src/components/StatusBadge.jsx |
⬜ |
| FilterDropdown | src/components/FilterDropdown.jsx |
⬜ |
| SortTh (table headers) | src/components/SortTh.jsx |
⬜ |
| ProfileAvatar | src/components/ProfileAvatar.jsx |
⬜ |
| LoadingButton / PageLoader | src/components/{LoadingButton,PageLoader}.jsx |
⬜ |
| RequestForm | src/components/RequestForm.jsx |
⬜ |
| Invoice popups / tables | InvoiceDetailPopup, InvoicePopupTable |
⬜ |
| Subcontractor invoice form/view | SubcontractorInvoice{Form,DetailView}.jsx |
⬜ |
| FileAttachment | src/components/FileAttachment.jsx |
⬜ |
Pages
| Route | Page | Roles | Status |
|---|---|---|---|
/ |
Login | all | ⬜ |
/dashboard |
team/TeamDashboard.jsx |
team/external/client | ⬜ |
/tasks |
Tasks.jsx (Requests) |
team/external/client | ⬜ |
/tasks/:id |
TaskDetail.jsx |
team/external/client | ⬜ |
/projects/:id |
ProjectDetail.jsx |
team/external/client | ⬜ |
/company |
Companies.jsx |
team/client | ⬜ |
/company/:id |
CompanyDetail.jsx |
team/client | ⬜ |
/finances |
team/TeamInvoices.jsx |
team | ⬜ |
/finances/:id |
team/TeamInvoiceDetail.jsx |
team | ⬜ |
/subcontractor-pos/new |
team/TeamCreateSubcontractorPO.jsx |
team | ⬜ |
/subcontractor-pos/:id |
team/TeamSubcontractorPODetail.jsx |
team | ⬜ |
/sub-invoices/:id |
team/TeamSubInvoiceDetail.jsx |
team | ⬜ |
/reports |
team/TeamReports.jsx |
team | ⬜ |
/fourge-passwords |
team/TeamFourgePasswords.jsx |
team | ⬜ |
/survey-maker |
SurveyMaker.jsx |
team/external | ⬜ |
/brand-book |
BrandBook.jsx |
team/external | ⬜ |
/converters |
Converters.jsx |
team/external | ⬜ |
/my-purchase-orders |
external/ExternalMyPurchaseOrders.jsx |
external | ⬜ |
/subs-invoices |
external/ExternalMyInvoices.jsx |
external | ⬜ |
/subs-invoices/new |
external/ExternalMyInvoiceCreate.jsx |
external | ⬜ |
/subs-invoices/:id |
external/ExternalMyInvoiceDetail.jsx |
external | ⬜ |
/client-invoices |
client/ClientMyInvoices.jsx |
client | ⬜ |
/profile, /profile/:id |
Profile.jsx |
all | ⬜ |
/pay/:id |
PayInvoice.jsx |
public | ⬜ |
Legend: ⬜ todo · 🔄 in progress · ✅ done
Log
- 2026-06-23 — Doc created,
redesignbranch cut, dev on 5173. - 2026-06-23 — Base tokens: solid
#0d0d0dbg, killed animated grid; cards#1a1a1a/#242424. Font → Inter. - 2026-06-23 — bg →
#1a1a1a(90% K), cards#1f1f1f/#262626(88% K), solid/no transparency. - 2026-06-23 — Tokenized cards: added
--card-border(off) +--card-radius; swept 28 inline card frames +.cardclass to the tokens. All cards now controllable from one line. - 2026-06-23 — Card border on at
#262626(85% K); light-mode--card-border=rgba(0,0,0,0.08); menu/sidebar routed to--card-border/--card-radius. - 2026-06-23 — Color system: added
--positive/--info/--violet/--warning/--danger-strong/--success-strong; swept 168 hardcoded colors across 15 JSX files to tokens +color-mixtints. Site/role/page colors now single-source. - 2026-06-23 — Completed palette: added
--data-*(hue-named) categorical set,--surface-sunken,--text-on-accent. Swept file-type chips + chart colors + surface neutrals to tokens. Remaining literals are canvas/PDF exports + PayInvoice (intentional). Full chart documented above. - 2026-06-23 — Popups single-source:
--popup-bgnow =var(--card-bg)(dark); stripped 8 inlinebackground: var(--card-bg)overrides onpopupSurfaceStyleso loader/modals/menus all use the token. Light stays opaque white. - 2026-06-23 — Dashboard reflow: row2 = To Do (fluid) + Calendar (280px); row3 = Activity / In-Progress / Team Perf. New
.dash-row-todo/.dash-row-trioclasses; responsive (trio 2-up ≤1200, all stack ≤768). Retired bottomCardsHeight viewport-fill hack. Mobile-friendly is now a standing requirement for Layout2. - 2026-06-23 — Perf sweep: root cause = ~400–770ms/query server cold-start (compute tier, infra). Code fixes: added FK/filter index migration (pushed to DB); removed redundant client/external scope waterfall in Tasks + Dashboard (rely on RLS, verified
has_company_access/project_membersparity); embedded submitter-profiles + deliveries into the Tasks submissions query (−2 round trips all roles). Test client/external dashboards on 5173. - 2026-07-15 — Naming cleanup: the
91045a1Project→Client rename was only partially walked back by later commits, leaving the project entity mislabeled "Client" in ~20 spots (Add Project modal, filters, PO/report/dashboard columns, etc.) while table headers already said "Project". Confirmed with user: Company = the customer org (e.g. "Public Storage"), Project = a job within that company — "Client" was a leftover label, not a third entity. Reverted all mislabeled text to "Project"; reverted the/clients/:idroute back to canonical/projects/:id(nothing deployed to prod yet, so no live URLs broke). Also: removed stale pre-redesignlayout.md(superseded by this doc), stopped tracking.env.backfill(had a live admin password/token committed — rotate those credentials separately).