feat(design): design system v2 — new components, refreshed tokens#210
Merged
Conversation
Refresh tokens and ship six new shared components used across all pages.
Tokens (packages/SimpleModule.Theme.Default/theme.css)
- OKLCH palette across both modes; warm graphite dark mode (was cold slate)
- Fraunces (display) + Geist (body) + JetBrains Mono
- Layered shadow scale, motion durations + easings, z-index, opacity
- Removed all linear-gradient surface treatments; primary is now flat
- Base table styles: proper cell padding, header bar, row hover, .num
helper for tabular-num right-aligned columns
UI components (packages/SimpleModule.UI/components/)
- Stat: dashboard tile metric (value/unit/label/trend/change)
- EmptyState: icon + title + description + primary/secondary action
- SearchInput: leading search icon + optional kbd shortcut suffix
- NumberInput: input with - / + steppers, clamps min/max
- FilterBar: data-grid toolbar (search / controls / actions slots)
- Kbd: small inline key cap
Component upgrades that fan out
- DataGridPage now renders EmptyState internally
- Button primary variant: solid emerald, no gradient
- AuditLogs KpiCard: thin wrapper around Stat
Pages migrated to EmptyState
- AuditLogs/Browse, Email/History, Email/Templates
Layouts / inline gradients removed
- app-layout, public-layout, public-layout-mobile, user-dropdown,
page-header, section, registry templates
Design system reference
- docs/design-system/ — 43-section live preview, mobile-friendly,
wired into Tailwind via @source in template/SimpleModule.Host/Styles/app.css
Verified: all 14 modules build successfully (npm run build:dev).
Replaces three hand-rolled empty-state blocks with the new EmptyState
component shipped in the previous commit. Consistent icon size, copy
hierarchy, spacing, and theme-aware text colors.
- modules/RateLimiting/components/ActivePoliciesTable
- modules/RateLimiting/components/RulesTable
- modules/Settings/Pages/MenuManager (×2 — list + editor empty state)
Other audited surfaces:
- Email/Dashboard.tsx "TopErrorsEmpty" is an inline tile message,
intentionally lighter than EmptyState — left as is.
12 findings from a high-effort recall review; commits resolve all
bug-level issues and several visual/a11y regressions.
NumberInput (packages/SimpleModule.UI/components/number-input.tsx)
- Track internal display string so users can clear the field; commit
onChange only when the parsed value is valid. Restore min/0 on blur
if left empty. Adds optional `emptyFallback` prop.
- Decrement icon picks up matching strokeLinejoin for consistency.
Stat (packages/SimpleModule.UI/components/stat.tsx)
- When onClick is provided the component now renders as a <button>,
auto-promoting to a keyboard-accessible element with proper role.
- Auto-enables `interactive` when onClick is set so callers can't
accidentally ship a clickable tile without the hover affordance.
- New `lift` prop gates the translate-y hover micro-motion, defaulting
to off so KpiCard preserves its old shadow-only hover.
EmptyState (packages/SimpleModule.UI/components/empty-state.tsx)
- Default heading level changed from h3 to h2 — EmptyState commonly
sits directly under a PageShell h1, and h1→h2 keeps the document
outline contiguous. New `headingLevel` prop overrides when needed.
- Icon bubble shrunk from w-14 h-14 (56px) to w-11 h-11 (44px) so the
22px SVGs we ship don't float in oversized circles.
- Title now uses the `font-display` Tailwind utility (driven by the
--font-display token) instead of an inline style — keeps with the
Tailwind-only directive.
SearchInput (packages/SimpleModule.UI/components/search-input.tsx)
- Suppress the native webkit search cancel button so it doesn't
overlap the Kbd shortcut suffix.
Overlays — z-index migration
- Dialog overlay + content: z-50 → z-[60] (matches --z-modal)
- Sheet overlay + content: z-50 → z-[60]
- Tooltip content: z-50 → z-[90] (matches --z-tooltip)
- Resolves the contradiction where Dialog/Dropdown both rendered at
z-50 despite the theme advertising a layered stack.
theme.css
- Table row hover moved behind `[data-interactive]` opt-in so
read-only tables (recovery codes, audit results, RateLimiting
policies, dashboard error lists) don't pick up an interactive cue.
- Dropped the explicit `border-collapse: collapse` — restores default
behavior to avoid border-merge artifacts in two-tone cells.
Verified: all 14 modules build successfully (npm run build:dev).
Found by Stage 4 of /vf: - EmptyStateProps must Omit 'title' from React.HTMLAttributes because the HTML title attribute is typed as string | undefined but the component repurposes title as React.ReactNode. - docs/design-system/index.html is a static reference page with intentional inline styles from earlier iterations; add it to biome's includes ignore list so repo-wide lint runs clean.
Deploying simplemodule-website with
|
| Latest commit: |
22350c8
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://663bccee.simplemodule-website.pages.dev |
| Branch Preview URL: | https://worktree-design-refresh.simplemodule-website.pages.dev |
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
linear-gradientsurface treatmentsStat,EmptyState,SearchInput,NumberInput,FilterBar,Kbd— exported from@simplemodule/uiEmptyState;DataGridPage+Button+KpiCardrefactored so every consumer inherits the new systemdocs/design-system/reference site (43 sections, mobile-friendly, wired into Tailwind via@source)Verification
worktree-design-refresh, up to date withorigin/main/Identity/Account/Login: page renders, Fraunces<h1>"Welcome back", Geist body, OKLCH primaryoklch(0.62 0.16 158), dark mode toggles to warm graphiteoklch(0.205 0.006 60)dotnet build -warnaserror(0 warnings, 0 errors)Test plan
EmptyStaterenders correctly (AuditLogs/Browse, Email/History, Email/Templates, Settings/MenuManager, RateLimiting tables)NumberInput(if you add one) can be cleared without snapping back to the prior numeric valueStatis reachable via Tab and activates on Enter/Space (a11y)Notes
This PR was assembled in 5 commits:
feat(design): refresh design system + new components— tokens, components, layouts, design-system previewrefactor(pages): migrate remaining empty states to shared EmptyState— RateLimiting tables + MenuManagerfix(ui): address code review findings on design-system components— 12 review findings (NumberInput clear, Stat keyboard a11y, EmptyState heading hierarchy, SearchInput overlap, z-index migration, table hover scope, etc.)fix(ui): EmptyState title type + biome ignore docs/design-system— Stage 4 typecheck + lint fixeschore: add verification screenshot