Skip to content

feat: apply AppFoundation Screens design to the Identity UI#82

Merged
andregoepel merged 18 commits into
mainfrom
feat/appfoundation-theme
Jul 6, 2026
Merged

feat: apply AppFoundation Screens design to the Identity UI#82
andregoepel merged 18 commits into
mainfrom
feat/appfoundation-theme

Conversation

@andregoepel

@andregoepel andregoepel commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Imports the AppFoundation Screens Claude Design project and applies it as the target design across the Blazor Identity UI and the Aspire sample host. Because the app is built on Radzen, the theme is applied by remapping Radzen's --rz-* variables onto the AppFoundation emerald palette rather than rewriting each component; distinctive screens get bespoke markup.

What's included

Theme foundation

  • wwwroot/css/appfoundation.css — light + dark tokens, Radzen variable remap, Manrope / Space Grotesk / JetBrains Mono fonts, plus shell/login/control classes.
  • wwwroot/js/appfoundation-theme.js — no-flash auto/light/dark switch persisted to localStorage.

App shell (Aspire sample)

  • Replaced the top header with the AppFoundation sidebar shell: brand, Home, ACCOUNT nav, role-gated ADMINISTRATION nav, topbar with theme toggle and user chip.

Auth screens (login card)

  • LoginLayout rebuilt as the centered login card.
  • Login, Register, Forgot password, Resend confirmation, Two-factor, and Recovery code: heading + subtitle, label-above full-width fields, stacked full-width sentence-case buttons, outline passkey button, and a centered footer link.

Account & admin forms

  • Replaced Radzen's floating-label RadzenFormField (the watermark that jumps to the top line) with a static RadzenLabel above each field, and unwrapped RadzenFieldset groupings, so Profile, Manage Email, Change Password, Set Password, Enable Authenticator, Two-Factor, Rename Passkey, Delete Personal Data, and User Cleanup match the flat card design.

Verification

  • Full solution builds (0 warnings / 0 errors).
  • All 97 Blazor tests pass.

Notes

🤖 Generated with Claude Code

andregoepel and others added 6 commits July 6, 2026 15:39
Import the "AppFoundation Screens" Claude Design project and use it as the
target design for the Blazor Identity UI and the Aspire sample host.

- Add a design-token stylesheet that remaps Radzen's --rz-* variables onto
  the emerald AppFoundation palette, with matching light + dark themes and
  Manrope / Space Grotesk / JetBrains Mono fonts (RCL wwwroot).
- Add a no-flash theme switcher (auto/light/dark) persisted to localStorage.
- Rebuild LoginLayout as the centered login card; restyle the Login heading.
- Replace the sample host header with the AppFoundation app shell: sidebar
  nav (Home, Account, role-gated Administration), topbar page title, theme
  toggle and user chip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bring every login-card auth screen in line with the updated AppFoundation
Screens design (heading + subtitle, label-above full-width fields, stacked
full-width sentence-case buttons, centered footer link):

- Login: inline forgot-password on the password row, outline passkey button,
  "Don't have an account? Create account" / "Resend confirmation" footer.
- Register, Forgot password, Resend confirmation, Two-factor, Recovery code:
  vertical label/field layout, heading + subtitle, and a centered footer link
  back to log in (or to the alternate 2FA method).
- appfoundation.css: login form/control/button rules and an outline passkey
  variant targeted via data-af.
- Update the LoginTests register-link constant to the new "Create account" copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The library's Login/LoginForm pages don't self-declare a render mode but
require interactivity: SignInHandoff performs the cookie handoff to /login in
OnAfterRenderAsync (JS), and the Radzen "Remember me" checkbox only binds
interactively. The sample rendered <Routes> statically, so sign-in silently
failed (fields cleared, no cookie) and Remember me was always false.

- App.razor: apply global InteractiveServer render mode to <HeadOutlet> and
  <Routes>. RCL pages that redeclare the same mode coexist fine (verified).
- Home.razor: also serve /dashboard, the cookie middleware's DefaultRedirect
  after a no-ReturnUrl login, so a successful sign-in no longer 404s.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lationToken in RoleStore

- Relocate the identity feature-flag types (IdentityFeature, IdentityFeatureFlags,
  IIdentityFeatureProvider, OptionsIdentityFeatureProvider, the gate middleware and
  its app-builder extension) into the AndreGoepel.Marten.Identity.Blazor.Features
  namespace, updating Login.razor, Initialization, MartenIdentityBlazorOptions and
  the affected tests accordingly.
- RoleStore: pass the ambient CancellationToken into GetCurrentUserIdAsync on the
  create/change/delete/restore paths instead of dropping it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
UseMartenIdentityFeatureGate moved to the .Features namespace; add the
matching using so the Aspire sample compiles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace Radzen's floating-label RadzenFormField (watermark that jumps to
the top line) with a static RadzenLabel above each field, and unwrap the
RadzenFieldset groupings, so the account and admin forms match the flat
AppFoundation card design used by the login screens.

Covers Profile, Manage Email, Change Password, Set Password, Enable
Authenticator, Two-Factor, Rename Passkey, Delete Personal Data, and the
admin User Cleanup page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@andregoepel
andregoepel force-pushed the feat/appfoundation-theme branch from 8a61358 to 79d0a5f Compare July 6, 2026 07:48
@andregoepel
andregoepel changed the base branch from feat/aspire-identity-sample to main July 6, 2026 07:48
andregoepel and others added 12 commits July 6, 2026 16:15
Verified in the running Aspire sample against the AppFoundation design:

- Suppress the focus ring Blazor's FocusOnNavigate paints on page headings
  (the stray box around each card title).
- Global sentence-case buttons (Radzen's Material theme upper-cased them).
- Card footer actions: a bordered, natural-width action row (af-card-actions),
  right-aligned for forms and left-aligned for Personal Data — replacing the
  centered / full-width button stacks on Profile, Change Password, Manage Email,
  Set Password, Enable Authenticator, Delete Personal Data, Rename Passkey,
  Personal Data, and User Cleanup.
- Soften Radzen's filled alerts into the design's tinted banners (correct
  .rz-alert.rz-{info,warning,danger,success} selectors); the 2FA "disabled"
  notice now uses the amber warning tone.
- Two-Factor: fieldset replaced by a flat sub-heading, and the lone action
  button no longer stretches full width (af-actions-inline).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three design-detail refinements verified in the running sample:

- Manage Email: show a "✓ Confirmed" status pill beside the current-email
  field instead of plain green text.
- Change Password: lay New password / Confirm new password out in a
  two-column grid (collapses to one column on narrow viewports).
- Roles grid: replace the plain Deleted True/False column with a Status
  badge (Active / Deleted).

Adds shared .af-badge / .af-form-grid styles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tables

Addresses design-review feedback, verified in the running sample:

- Buttons: force the dark on-accent text colour (Radzen forced white in dark
  mode); tighten to the design's 13px. Labels are now 12.5px / 600 / muted
  globally, not just inside the login card.
- Theme toggle: reorder to light / auto / dark with crisp sun / monitor / moon
  SVG icons to match the design pill.
- Two-Factor: move the status banner outside (above) the card.
- Passkeys: move the register action into the page header (top-right) and use a
  dashed empty-state card instead of an info alert.
- Personal Data: buttons pick up the dark on-accent text and danger-soft styling.
- Users / Roles grids: merge the id under the name/email (mono, muted), add
  Status / Confirmed badges, drop the per-column filter funnels, and uppercase
  the column headers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ow menu

Further design-review fixes, verified in the running sample (dark mode):

- Disabled/read-only inputs now read as greyed out (hover bg, muted text) —
  define --rz-input-disabled-background and style .rz-textbox[readonly].
- Danger buttons use the design's danger-soft tint + red text (Radzen's filled
  danger forced a solid red; overridden with !important).
- Data-grid row hover uses the dark --af-hover (Radzen's white grid-hover var
  broke dark mode); grids fill the card and no longer overflow horizontally
  (auto table layout, id truncated with ellipsis).
- Users / Roles actions: keep the primary action (Users / Roles) visible and
  move Delete / Restore behind a compact "⋯" overflow menu (ContextMenuService);
  rows are no longer selectable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add DESIGN.md documenting how to build components that fit the AppFoundation
theme — tokens, typography, page/form/card/table/alert recipes, the af-* helper
classes, and the Radzen overrides to be aware of — and link it from the Blazor
project README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Alerts: tint the icon to the status colour (was white), shrink it, and set
  the banner text to 13px — matching the design's tinted banners.
- Two-Factor: the "Authenticator app" description now uses the muted secondary
  colour instead of the bright body colour.
- Sample sidebar: rename account nav items to the design's labels (Email,
  Password, Two-factor authentication, Personal data).
- DESIGN.md: document the muted-description and alert-icon conventions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Sidebar brand now shows the configured application name (AppName config,
  default "Marten Identity") and its initial, instead of a hard-coded label;
  footer follows suit.
- Topbar shows a Section / Page breadcrumb derived from the current route
  (e.g. "Account / Email") instead of a static title.
- Row overflow (⋯) menus: dark, readable hover (Radzen's default was a white
  block that erased the text in dark mode), and the Delete item now has a trash
  icon and the danger red colour (icon + text). Restore gets a restore icon.
- Sample: add AppName to appsettings; sentence-case the "User cleanup" nav item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Radzen fills the sharp-cornered menu-item wrapper near-white on hover, which
showed through the four rounded corners of the dark item highlight. Force the
wrapper/item hover background transparent so only the rounded --af-hover link
shows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Override Radzen's compact-density cells (4px/8px) with the design's roomier
  padding — 12px 20px headers, 13px 20px rows — so cell text has breathing room
  in the Users/Roles grids.
- Render .af-badge as inline-flex so its padding and rounded corners show as a
  clean pill instead of a cramped inline box.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Users/Roles grids: add the design's in-card toolbar — a live filter box
  (client-side, matches name/email or id) and an "X of Y" row count.
- User Cleanup: narrow the retention (140px) and cron (240px, monospace) inputs
  to match the design, and render "Next scheduled run" as a soft info box
  (af-info-box) instead of plain text.
- DESIGN.md: document the new toolbar and info-box helper classes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Translate the design's isCompact/isMobile behaviour into real CSS media queries
plus a tiny toggle script:

- <=1000px: the sidebar becomes a fixed off-canvas drawer toggled by a topbar
  hamburger, with a dimming backdrop. State is data-nav-open on .af-shell,
  flipped by appfoundation-nav.js (also closes on Escape / after a nav link).
- <=700px: tighter padding, the user email is hidden, af-form-grid collapses to
  one column, and data grids get a min-width + horizontal scroll.

Adds appfoundation-nav.js, the hamburger/backdrop to the sample MainLayout, and
documents the breakpoints in DESIGN.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap the long RoleDeleted/RoleRestored constructor calls so `dotnet csharpier
check .` (the CI format gate) passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@andregoepel
andregoepel merged commit 47c45ec into main Jul 6, 2026
3 checks passed
andregoepel added a commit that referenced this pull request Jul 6, 2026
Address the PR #82 review comments on the AppFoundation shell:

- Breadcrumb is now defined per page, not by a central route→label map. Add a
  cascading BreadcrumbState (owned by the shell layout) and an optional
  Breadcrumb parameter on IdentityPageTitle; each shell page declares its own
  crumb. Drops the 15-entry dictionary + Breadcrumb()/Humanize() from MainLayout.
  EnableAuthenticator gains a document title it was missing.

- Theme-toggle SVGs move out of ThemeToggle into a reusable AppIcon component
  (<AppIcon Name="sun" />); adding a glyph is one dictionary entry.

- Fonts are self-hosted: vendor Manrope / Space Grotesk / JetBrains Mono
  (latin + latin-ext variable woff2) into the RCL wwwroot with a generated
  fonts.css, and load that instead of fonts.googleapis.com. Nothing is fetched
  from Google at runtime (GDPR / offline / reliability). Regenerate via
  scripts/fetch-fonts.py.

DESIGN.md documents all three.
@andregoepel
andregoepel deleted the feat/appfoundation-theme branch July 18, 2026 01:54
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