Skip to content

Commit 554c8fc

Browse files
authored
feat(ui): redesign every module page to the HiFi design system + add Doctor page (#131)
* feat(ui): redesign every module page to the SimpleModulePython HiFi system Implements the emerald + teal design system from the Claude Design HiFi mock across the full surface — public, auth, and authenticated pages — and adds a new admin Doctor page that mirrors `sm doctor`. Design system primitives in packages/ui: - StatCard, SectionTitle, FilterPills (new) - PageShell, AuthCardShell, ErrorScreen (refreshed) - TONE map at packages/ui/src/lib/tone.ts — single source for semantic badge / chrome class triplets - Globals: emerald primary scale (oklch hue 158), Sora display font Pages redesigned: - Landing — mesh blobs, gradient hero, terminal CTA, 6-feature grid, quickstart split with terminal, gradient CTA strip, light footer - Auth (Login / Register / Forgot / Reset / AcceptInvite / VerifyEmail) — light glass card on emerald mesh blobs, simple_module / python lockup - Dashboard Home — 4 stat cards, system module grid, demo activity panels gated to `import.meta.env.DEV` - Doctor (NEW, /dashboard/doctor) — admin-only page with stat cards, static checks, recent migrations, dev server, sm CLI runner, env vars, installed modules. Wired into AdminLayout sidebar - Users Index — workspace-wide aggregate stat cards (active/pending), search + filters, avatar table with status badges; Roles tab with role cards - Users Edit / Invite — section cards with gradient accent bars, role pill picker, alert-dialog confirmation on Disable + reset-link - Permissions UserEdit / RoleEdit — 3 stat cards, search, per-module switch grid with proper grid borders for odd-length lists - Settings Browse / Create / Edit / ModulesEdit — uniform PageShell + Card forms; module navigator with search - Profile — gradient avatar, verified badge, role pills - Error (403/404/500) — gradient HTTP numerals + accent badge per status Backend additions: - UserService.count_user_states() — workspace-wide active/unverified counts served as `aggregates` prop so stat cards reflect totals not the page slice - Dashboard module registers Doctor in ADMIN_SIDEBAR; doctor route slimmed to only system_info + module_count Notable fixes from the simplify pass: - Reset-link generation requires AlertDialog confirmation (was firing on click) - ForgotPassword keeps anti-enumeration WHY comment - useMemo Sets / reduce / filter in permission editors (was rebuilt per keystroke in the search box) - Lookup table replaces ternary chains in Doctor CheckRow - Grid border math corrected for odd-length permission lists - Manage permissions link from User Edit now goes to /edit (was 405) - Vite dev port reflected as 5050 in README * test(e2e): update settings smoke test for redesigned auth labels The public landing nav and login form both relabeled in the redesign: - Public nav: "Get Started" → "Log in" / "Sign up" - Login form submit: "Sign in" → "Log in" Update the e2e _login helper to match the new role-based selectors.
1 parent d95c3b0 commit 554c8fc

45 files changed

Lines changed: 2764 additions & 1614 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ A modular-monolith framework for Python. Each feature lives in its own self-cont
66

77
- **Backend:** Python 3.12, FastAPI, SQLModel (SQLAlchemy async + Pydantic), Alembic
88
- **Frontend:** Inertia.js + React + Tailwind CSS 4, Vite HMR
9+
- **UI:** shadcn/ui primitives + emerald/teal design tokens, Sora display font, DM Sans body, JetBrains Mono code
910
- **Auth:** Local user management (email+password, cookie-based sessions) via fastapi-users
1011
- **Tooling:** uv workspaces, Ruff, ty, Biome, pytest
1112

@@ -44,7 +45,7 @@ make migrate
4445
make dev
4546
```
4647

47-
Hit `http://localhost:8000` — you land on the public page. `/users/login` is the email+password login, `/dashboard` is the authenticated home.
48+
Hit `http://localhost:8000` — you land on the public page. `/users/login` is the email+password login, `/dashboard/` is the authenticated home, and `/dashboard/doctor` is the admin-only "sm doctor" panel (static checks, migrations, dev server, modules).
4849

4950
## Create a new module
5051

@@ -80,7 +81,8 @@ host/
8081
client_app/ # Vite + React client app
8182
migrations/ # Alembic migrations
8283
packages/
83-
ui/ # shared shadcn/ui components & layouts
84+
ui/ # shared shadcn/ui components, layouts, and design-system primitives
85+
i18n/ # generated i18n keys + translation runtime
8486
scripts/
8587
new_module.py # module scaffolder (called by `make new-module`)
8688
docs/
@@ -100,7 +102,7 @@ docs/
100102
| `make migrate` | Apply pending Alembic migrations |
101103
| `make migration msg="..."` | Autogenerate a new migration |
102104
| `make new-module name=<name>` | Scaffold a new module |
103-
| `make kill` | Stop any running dev servers (ports 8000, 5173) |
105+
| `make kill` | Stop any running dev servers (ports 8000, 5050, 5173) |
104106
| `make docker-up` / `docker-down` | Manage the Postgres container (SQLite needs no Docker) |
105107

106108
## Configuration
@@ -112,7 +114,7 @@ Local deployments only need one env var — everything else has sensible default
112114
| `SM_DATABASE_URL` | `sqlite+aiosqlite:///./app.db` | Yes — async URL. Postgres: `postgresql+asyncpg://...` |
113115
| `SM_ENVIRONMENT` | `development` | No — any value other than `development`, `test`, `testing` triggers strict discovery and placeholder-secret checks |
114116
| `SM_SECRET_KEY` | `change-me-in-production` | No in dev; **must** be overridden in production |
115-
| `SM_VITE_DEV_URL` | `http://localhost:5050` | Dev only |
117+
| `SM_VITE_DEV_URL` | `http://localhost:5050` | Dev only — Vite HMR origin |
116118

117119
Power users can still override the following bootstrap knobs via env if needed: `SM_DB_POOL_SIZE`, `SM_DB_MAX_OVERFLOW`, `SM_DB_POOL_PRE_PING`, `SM_DB_POOL_RECYCLE`, `SM_DEBUG`, `SM_LOG_LEVEL`, `SM_LOG_FORMAT`, `SM_MODULES_ENABLED`. These are needed before the DB connection is open.
118120

@@ -128,6 +130,32 @@ to seed DB overrides from the current `SM_*` environment.
128130
129131
See `framework-conventions.md` for the settings-per-module convention.
130132

133+
## UI & design system
134+
135+
The frontend uses an emerald + teal design system mirrored as Tailwind 4 tokens. Module pages should compose from a small set of shared primitives so they stay visually consistent without duplication.
136+
137+
**Shared primitives** (in `packages/ui/src/`):
138+
139+
| Component | When to use |
140+
|---|---|
141+
| `PageShell` | Every authenticated page. Wraps title + description + actions header and a max-width content area. |
142+
| `StatCard` | Top-of-page KPI tiles — icon, value, label, optional delta badge. Used on Dashboard, Users, Doctor. |
143+
| `SectionTitle` | Card section headings with the gradient accent bar. |
144+
| `FilterPills` | Segmented filter chips for status/tab-style toggles. |
145+
| `AuthCardShell` | Login / register / forgot / accept-invite / verify — light glass card on emerald mesh blobs. |
146+
| `ErrorScreen` | 403 / 404 / 500 — gradient HTTP numerals + accent badge per status. |
147+
148+
**Design tokens** live in `packages/ui/src/styles/globals.css` under the `@theme` block — primary emerald scale (`--color-primary-50…900`), display/sans/mono families, semantic shadcn tokens. Override the CSS variables to rebrand without touching component code.
149+
150+
**Module pages** should:
151+
152+
- Wrap in `PageShell` with `title`, optional `description`, and `actions`.
153+
- Use `Card` + `CardContent` from `@simple-module-py/ui/components/ui/card` for content blocks.
154+
- Reach for `StatCard` / `SectionTitle` / `FilterPills` before rolling new layouts.
155+
- Use lucide-react icons (already a dependency) and the existing `Badge` / `Button` variants — emerald primary for the main CTA, outline / ghost for secondary actions.
156+
157+
The 300-line file cap (enforced by CI) usually pushes you to factor row-level components into `pages/components/` — see `modules/users/users/components/UserRow.tsx` and `modules/dashboard/dashboard/pages/components/doctor-data.ts` for the pattern.
158+
131159
## User management
132160

133161
### Creating the first admin

‎host/client_app/pages/Error.tsx‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Link } from '@inertiajs/react';
22
import { keys, useT } from '@simple-module-py/i18n';
33
import { ErrorScreen } from '@simple-module-py/ui/components/ErrorScreen';
44
import { Button } from '@simple-module-py/ui/components/ui/button';
5+
import { Home, LifeBuoy } from 'lucide-react';
56

67
interface Props {
78
status: number;
@@ -23,15 +24,25 @@ function ErrorPage({ status, message }: Props) {
2324
500: t(keys.host.error.server_error_description),
2425
};
2526

27+
const accents: Record<number, 'primary' | 'warning' | 'destructive'> = {
28+
403: 'warning',
29+
404: 'primary',
30+
500: 'destructive',
31+
};
32+
2633
const title = titles[status] || t(keys.host.error.generic_title);
2734
const description = message || descriptions[status] || t(keys.host.error.generic_description);
2835

2936
return (
30-
<ErrorScreen hero={status} title={title} description={description}>
31-
<Button asChild>
32-
<Link href="/">{t(keys.host.error.go_home)}</Link>
37+
<ErrorScreen hero={status} title={title} description={description} accent={accents[status]}>
38+
<Button asChild className="gap-1.5">
39+
<Link href="/">
40+
<Home className="h-4 w-4" />
41+
{t(keys.host.error.go_home)}
42+
</Link>
3343
</Button>
34-
<Button variant="outline" onClick={() => window.history.back()}>
44+
<Button variant="outline" onClick={() => window.history.back()} className="gap-1.5">
45+
<LifeBuoy className="h-4 w-4" />
3546
{t(keys.host.error.go_back)}
3647
</Button>
3748
</ErrorScreen>

0 commit comments

Comments
 (0)