fix(frontend): sprint 4 design-review — slab token + UsersAdmin alignment + dark hairlines + badge contrast
- bump dark hairline from #374151 → #4b5563 for visible table borders - topbar header bg-canvas → bg-paper for dark-mode lift vs canvas body - UsersAdminPage create-form: Option A structural 3-row grid (labels / inputs / hints) to fix AC-17.3 alignment; removes FormField wrapper that caused row-height misalignment - EngagementsListPage: replace text "+ New" with lucide Plus icon per design spec Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -111,43 +111,56 @@ export function UsersAdminPage(): JSX.Element {
|
||||
<section className="card-product flex flex-col gap-md">
|
||||
<h2 className="text-[20px] font-medium">Create account</h2>
|
||||
{/*
|
||||
items-start so each cell top-aligns; the button is wrapped in a flex column
|
||||
that pushes it to align with the input row (label + 4px gap = ~22px offset).
|
||||
Option A structural fix (AC-17.3): labels / inputs / hints in 3 explicit grid rows
|
||||
so the browser can never misalign them by collapsing different-height cells.
|
||||
grid-rows-[auto_auto_auto] ensures row 1 = labels, row 2 = inputs, row 3 = hints.
|
||||
*/}
|
||||
<form onSubmit={onCreate} className="grid grid-cols-1 md:grid-cols-4 gap-md items-start">
|
||||
<FormField label="Username" htmlFor="new-username" required>
|
||||
<TextInput
|
||||
id="new-username"
|
||||
value={createForm.username}
|
||||
onChange={(e) => setCreateForm({ ...createForm, username: e.target.value })}
|
||||
required
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="Password" htmlFor="new-password" required hint="≥ 8 characters">
|
||||
<TextInput
|
||||
id="new-password"
|
||||
type="password"
|
||||
value={createForm.password}
|
||||
onChange={(e) => setCreateForm({ ...createForm, password: e.target.value })}
|
||||
required
|
||||
minLength={8}
|
||||
/>
|
||||
</FormField>
|
||||
<FormField label="Role" htmlFor="new-role" required>
|
||||
<Select
|
||||
id="new-role"
|
||||
value={createForm.role}
|
||||
onChange={(e) => setCreateForm({ ...createForm, role: e.target.value as Role })}
|
||||
options={ROLE_OPTIONS}
|
||||
/>
|
||||
</FormField>
|
||||
{/* Button column: spacer matches label row height so input + button baselines align */}
|
||||
<div className="flex flex-col gap-xs">
|
||||
<div className="h-[22px]" aria-hidden="true" />
|
||||
<button type="submit" className="btn-primary w-full" disabled={createMutation.isPending}>
|
||||
{createMutation.isPending ? 'Creating…' : 'Create'}
|
||||
</button>
|
||||
</div>
|
||||
<form
|
||||
onSubmit={onCreate}
|
||||
className="grid grid-cols-1 md:grid-cols-4 md:grid-rows-[auto_auto_auto] gap-x-md gap-y-xs"
|
||||
>
|
||||
{/* Row 1 — labels */}
|
||||
<label htmlFor="new-username" className="text-[14px] font-medium text-ink">
|
||||
Username <span className="text-bloom-deep">*</span>
|
||||
</label>
|
||||
<label htmlFor="new-password" className="text-[14px] font-medium text-ink">
|
||||
Password <span className="text-bloom-deep">*</span>
|
||||
</label>
|
||||
<label htmlFor="new-role" className="text-[14px] font-medium text-ink">
|
||||
Role <span className="text-bloom-deep">*</span>
|
||||
</label>
|
||||
<div aria-hidden="true" />
|
||||
|
||||
{/* Row 2 — inputs + button (all same height = h-11) */}
|
||||
<TextInput
|
||||
id="new-username"
|
||||
value={createForm.username}
|
||||
onChange={(e) => setCreateForm({ ...createForm, username: e.target.value })}
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
id="new-password"
|
||||
type="password"
|
||||
value={createForm.password}
|
||||
onChange={(e) => setCreateForm({ ...createForm, password: e.target.value })}
|
||||
required
|
||||
minLength={8}
|
||||
/>
|
||||
<Select
|
||||
id="new-role"
|
||||
value={createForm.role}
|
||||
onChange={(e) => setCreateForm({ ...createForm, role: e.target.value as Role })}
|
||||
options={ROLE_OPTIONS}
|
||||
/>
|
||||
<button type="submit" className="btn-primary w-full" disabled={createMutation.isPending}>
|
||||
{createMutation.isPending ? 'Creating…' : 'Create'}
|
||||
</button>
|
||||
|
||||
{/* Row 3 — hints */}
|
||||
<div aria-hidden="true" />
|
||||
<span className="text-[12px] text-graphite">≥ 8 characters</span>
|
||||
<div aria-hidden="true" />
|
||||
<div aria-hidden="true" />
|
||||
</form>
|
||||
{createError ? (
|
||||
<div role="alert" className="text-[14px] text-bloom-deep">
|
||||
|
||||
Reference in New Issue
Block a user