go-htmx-gsd #1
1 changed files with 256 additions and 0 deletions
256
.planning/phases/08-social-sign-in/08-UI-SPEC.md
Normal file
256
.planning/phases/08-social-sign-in/08-UI-SPEC.md
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
---
|
||||
phase: 8
|
||||
slug: social-sign-in
|
||||
status: approved
|
||||
shadcn_initialized: false
|
||||
preset: none
|
||||
created: 2026-05-15
|
||||
---
|
||||
|
||||
# Phase 8 — UI Design Contract
|
||||
|
||||
> Visual and interaction contract for the Social Sign-in phase. This phase changes the login/signup surfaces and adds a minimal linked-providers account view. It should stay functional and restrained; the user will provide a more polished UI later.
|
||||
|
||||
---
|
||||
|
||||
## Design System
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Tool | none |
|
||||
| Preset | not applicable |
|
||||
| Component library | local templ components in `backend/internal/web/ui` |
|
||||
| Icon library | none required for Phase 8 |
|
||||
| Font | inherited app font |
|
||||
|
||||
### Existing Surface To Preserve
|
||||
|
||||
- Keep the centered auth card layout used by `LoginPage` and `SignupPage`.
|
||||
- Keep the current card width: `w-full max-w-sm`.
|
||||
- Keep the current card padding: `px-6 py-8`.
|
||||
- Keep existing form labels, inputs, and validation error patterns.
|
||||
- Do not introduce a marketing-style auth page, hero area, decorative background, split layout, or large illustration.
|
||||
|
||||
---
|
||||
|
||||
## Interaction Contract
|
||||
|
||||
### Login and Signup Pages
|
||||
|
||||
Both `/login` and `/signup` must show:
|
||||
|
||||
1. Page heading
|
||||
2. Equal-prominence Google and Apple provider buttons
|
||||
3. A visual separator between provider buttons and the email/password form
|
||||
4. Existing email/password form
|
||||
5. Existing inline validation/error rendering behavior
|
||||
|
||||
Provider buttons:
|
||||
|
||||
- Google and Apple are peers; neither is styled as primary over the other.
|
||||
- Buttons link to provider start routes when configured.
|
||||
- Buttons render disabled when required provider config is missing.
|
||||
- Disabled state must be visible and non-clickable.
|
||||
- Disabled state copy must be short and plain, not diagnostic.
|
||||
- Provider buttons must not submit the email/password form.
|
||||
|
||||
Successful social sign-in redirects to `/`; no provider-specific welcome page.
|
||||
|
||||
### Linked Providers View
|
||||
|
||||
Add a protected, minimal linked-providers status view.
|
||||
|
||||
Required content:
|
||||
|
||||
- Heading: `Linked providers`
|
||||
- One row for Google
|
||||
- One row for Apple
|
||||
- Each row shows one of:
|
||||
- `Connected`
|
||||
- `Not connected`
|
||||
- If connected, show the stored provider email.
|
||||
- No unlink action in Phase 8.
|
||||
- No add-password UI in Phase 8.
|
||||
|
||||
The view may live at `/account` or `/account/providers`; planner decides route naming.
|
||||
|
||||
---
|
||||
|
||||
## Spacing Scale
|
||||
|
||||
Declared values (must be multiples of 4):
|
||||
|
||||
| Token | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| xs | 4px | Provider button inner gaps if icons are later added |
|
||||
| sm | 8px | Button stack gap, inline provider row gap |
|
||||
| md | 16px | Default form/provider group spacing |
|
||||
| lg | 24px | Auth section separator margin |
|
||||
| xl | 32px | Page card inner section breaks |
|
||||
| 2xl | 48px | Account page section spacing |
|
||||
| 3xl | 64px | Existing auth page top spacing equivalent |
|
||||
|
||||
Exceptions: none
|
||||
|
||||
Auth card layout:
|
||||
|
||||
- Heading margin-bottom: 24px (`mb-6`) remains acceptable.
|
||||
- Form/provider section gap: 20px (`space-y-5`) remains acceptable because it already exists; do not introduce additional non-4px spacing.
|
||||
- Provider button stack gap: 8px.
|
||||
- Separator vertical margin: 16px above and below.
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
| Role | Size | Weight | Line Height |
|
||||
|------|------|--------|-------------|
|
||||
| Body | 16px | 400 | 1.5 |
|
||||
| Label | 14px | 500 | 1.25 |
|
||||
| Helper / status | 14px | 400 | 1.4 |
|
||||
| Heading | 24px | 600 | 1.25 |
|
||||
| Account section heading | 20px | 600 | 1.3 |
|
||||
|
||||
Rules:
|
||||
|
||||
- Do not use viewport-scaled font sizes.
|
||||
- Do not use negative letter spacing.
|
||||
- Keep provider button labels at 16px / 600 if using `ui.Button`, matching existing primary button weight.
|
||||
- Disabled explanatory copy uses 14px normal weight.
|
||||
|
||||
---
|
||||
|
||||
## Color
|
||||
|
||||
| Role | Value | Usage |
|
||||
|------|-------|-------|
|
||||
| Dominant (60%) | `#ffffff` | Auth card and account content surfaces |
|
||||
| Secondary (30%) | `#f8fafc` | Page background or subtle status surfaces |
|
||||
| Text | `#0f172a` | Primary headings/body |
|
||||
| Muted text | `#64748b` | Helper text, disabled provider explanation |
|
||||
| Border | `#e2e8f0` | Provider buttons, separators, provider status rows |
|
||||
| Accent (10%) | `#2563eb` | Existing primary email/password submit button and focus ring only |
|
||||
| Destructive | `#b91c1c` | Error text or future destructive actions only |
|
||||
|
||||
Accent reserved for:
|
||||
|
||||
- Existing primary email/password submit button
|
||||
- Focus rings
|
||||
- Links if needed
|
||||
|
||||
Provider buttons:
|
||||
|
||||
- Use neutral/outline styling rather than blue primary styling.
|
||||
- Background: `#ffffff`
|
||||
- Border: `#e2e8f0`
|
||||
- Text: `#0f172a`
|
||||
- Hover when enabled: `#f8fafc`
|
||||
- Disabled background: `#f1f5f9`
|
||||
- Disabled text: `#94a3b8`
|
||||
|
||||
---
|
||||
|
||||
## Copywriting Contract
|
||||
|
||||
| Element | Copy |
|
||||
|---------|------|
|
||||
| Google button | `Continue with Google` |
|
||||
| Apple button | `Continue with Apple` |
|
||||
| Disabled Google button | `Google sign-in not configured` |
|
||||
| Disabled Apple button | `Apple sign-in not configured` |
|
||||
| Auth separator | `or` |
|
||||
| Provider callback generic error | `Could not sign you in with this provider. Try another sign-in method.` |
|
||||
| Unverified email error | `This provider did not return a verified email. Try another sign-in method.` |
|
||||
| Social-only signup conflict | `An account already exists for this email. Sign in with your provider.` |
|
||||
| Linked providers heading | `Linked providers` |
|
||||
| Connected status | `Connected` |
|
||||
| Not connected status | `Not connected` |
|
||||
| No unlink copy | No visible copy needed; simply omit unlink controls |
|
||||
|
||||
Error copy rules:
|
||||
|
||||
- Do not expose provider tokens, codes, claim names, key IDs, or raw OAuth errors in the UI.
|
||||
- Server logs may contain structured error categories, but UI copy stays generic unless the user can act on it.
|
||||
|
||||
---
|
||||
|
||||
## Component Contract
|
||||
|
||||
### Provider Button
|
||||
|
||||
Create a provider button pattern rather than reusing the solid blue primary submit button.
|
||||
|
||||
Acceptable implementation options:
|
||||
|
||||
- Extend `ui.Button` with neutral outline/disabled support.
|
||||
- Add a small auth-local provider button templ component.
|
||||
|
||||
Required behavior:
|
||||
|
||||
- Full width inside the auth card.
|
||||
- Stable height of at least 44px.
|
||||
- Does not resize based on provider config.
|
||||
- Uses native disabled semantics for button form controls, or `aria-disabled="true"` plus no actionable `href` for links.
|
||||
- Keyboard focus ring is visible when enabled.
|
||||
|
||||
### Separator
|
||||
|
||||
Use a simple horizontal rule pattern:
|
||||
|
||||
- Left line
|
||||
- Center text `or`
|
||||
- Right line
|
||||
|
||||
No decorative icons or large text.
|
||||
|
||||
### Linked Provider Row
|
||||
|
||||
Each row:
|
||||
|
||||
- Provider name on the left.
|
||||
- Status and email on the right or below on small screens.
|
||||
- Bordered row or subtle card row.
|
||||
- Minimum row height 44px.
|
||||
- No nested cards inside cards.
|
||||
|
||||
---
|
||||
|
||||
## Responsive Contract
|
||||
|
||||
- Auth card remains centered and no wider than `max-w-sm`.
|
||||
- Provider buttons are stacked vertically on all viewports in Phase 8; do not use a two-column button layout.
|
||||
- Linked providers view uses a single column on mobile.
|
||||
- Text must not overflow provider buttons; if future localization makes labels long, allow wrapping before reducing font size.
|
||||
- No horizontal scrolling.
|
||||
|
||||
---
|
||||
|
||||
## Accessibility Contract
|
||||
|
||||
- Provider buttons must be reachable by keyboard.
|
||||
- Disabled provider controls must communicate disabled state to assistive tech.
|
||||
- Separator `or` must not be announced as a form control.
|
||||
- Error messages must be associated with the relevant auth surface and visible near the provider/form area.
|
||||
- Connected provider rows should expose status text as real text, not only color.
|
||||
|
||||
---
|
||||
|
||||
## Registry Safety
|
||||
|
||||
| Registry | Blocks Used | Safety Gate |
|
||||
|----------|-------------|-------------|
|
||||
| shadcn official | none | not required |
|
||||
| third-party blocks | none | not allowed for Phase 8 |
|
||||
|
||||
---
|
||||
|
||||
## Checker Sign-Off
|
||||
|
||||
- [x] Dimension 1 Copywriting: PASS
|
||||
- [x] Dimension 2 Visuals: PASS
|
||||
- [x] Dimension 3 Color: PASS
|
||||
- [x] Dimension 4 Typography: PASS
|
||||
- [x] Dimension 5 Spacing: PASS
|
||||
- [x] Dimension 6 Registry Safety: PASS
|
||||
|
||||
**Approval:** approved 2026-05-15
|
||||
Loading…
Reference in a new issue