diff --git a/.planning/phases/31-puter.js-zero-config-cloud/31-UI-SPEC.md b/.planning/phases/31-puter.js-zero-config-cloud/31-UI-SPEC.md new file mode 100644 index 00000000..a98805c5 --- /dev/null +++ b/.planning/phases/31-puter.js-zero-config-cloud/31-UI-SPEC.md @@ -0,0 +1,258 @@ +--- +phase: 31 +slug: puter.js-zero-config-cloud +status: draft +shadcn_initialized: true +preset: new-york / neutral / cssVariables +created: 2026-04-02 +--- + +# Phase 31 — UI Design Contract + +> Visual and interaction contract for Phase 31: Puter.js Zero-Config Cloud. +> Generated by gsd-ui-researcher. Verified by gsd-ui-checker. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | shadcn | +| Preset | new-york, baseColor: neutral, cssVariables: true, style: new-york | +| Component library | Radix UI (via shadcn) | +| Icon library | lucide-react | +| Font | System UI (inherited from body; no custom font declared in index.css) | + +Source: `/opt/nexus/ui/components.json` + `/opt/nexus/ui/src/index.css` + +--- + +## Spacing Scale + +Declared values (must be multiples of 4): + +| Token | Value | Usage | +|-------|-------|-------| +| xs | 4px | Icon gaps (`gap-1`), inline badge padding | +| sm | 8px | Compact element spacing (`gap-2`), within-form row gaps | +| md | 16px | Default element spacing (`gap-4`), form field gaps | +| lg | 24px | Section padding (`p-6`), card interior padding | +| xl | 32px | Layout gaps (`p-8`) — matches existing wizard card `p-8` | +| 2xl | 48px | Major section breaks — not used in wizard context | +| 3xl | 64px | Page-level spacing — not used in wizard context | + +Exceptions: +- Touch targets: `min-height: 44px` enforced globally via `@media (pointer: coarse)` in `index.css` — no per-component override required. +- Provider option cards: `p-4` (16px) interior padding, matching `ModeSelector` card pattern. +- Warning callout (Google OAuth risk): `px-3 py-2` (12px/8px) — compact inline alert pattern matching existing error state style. + +Source: existing `NexusOnboardingWizard.tsx` uses `p-8`, `gap-6`, `gap-4`, `gap-2`. ModeSelector uses `p-4`, `gap-3`, `gap-1`. + +--- + +## Typography + +| Role | Size | Weight | Line Height | +|------|------|--------|-------------| +| Body | 14px (0.875rem) | 400 | 1.5 | +| Heading | 24px (1.5rem / text-2xl) | 600 | 1.2 | +| Caption / muted | 12px (0.75rem / text-xs) | 400 | 1.4 | + +Notes: +- Heading size matches existing wizard `h1` (`text-2xl font-semibold`) — locked by Phase 30 component pattern. +- Label size matches existing form label pattern (`text-sm font-medium`). +- Body size matches existing paragraph + description pattern (`text-sm`). +- Caption is used for step indicator (`text-xs text-muted-foreground`), provider descriptions, and warning footnotes. +- No display-size text (>24px) is needed in this phase — the wizard card is constrained to `max-w-md`. + +Source: `NexusOnboardingWizard.tsx` lines 214, 245, 281–283, 294. + +--- + +## Color + +All values are shadcn CSS custom properties resolved from `/opt/nexus/ui/src/index.css`. +Both light (Catppuccin Latte) and dark (Catppuccin Mocha) themes are supported. + +| Role | Light value | Dark value | Usage | +|------|-------------|------------|-------| +| Dominant (60%) | `--background` (#eff1f5) | `--background` (#1e1e2e) | Wizard backdrop, page background | +| Secondary (30%) | `--card` (#e6e9ef) | `--card` (#181825) | Wizard card surface, provider option cards | +| Accent (10%) | `--primary` (#1e66f5) | `--primary` (#89b4fa) | Selected provider card border + tint, primary CTA button | +| Destructive | `--destructive` (#d20f39) | `--destructive` (#f38ba8) | Google OAuth policy-risk warning text; error state text | + +Accent reserved for: +1. The currently selected provider option card border (`border-primary`) and tint (`bg-primary/5`) +2. The primary CTA button ("Continue with Puter", "Continue", "Get Started") +3. The focus ring on interactive inputs and buttons (`--ring`) + +Do NOT use accent on: provider logos, status badges, neutral labels, section headings. + +Source: `index.css` CSS custom properties; `ModeSelector.tsx` selected-state pattern (`border-primary bg-primary/5`). + +--- + +## Component Inventory + +New components introduced in this phase: + +| Component | File | Reuses | +|-----------|------|--------| +| `ProviderSelectionStep` | `ui/src/components/onboarding/ProviderSelectionStep.tsx` | `Button`, `cn`, NexusOnboardingWizard card patterns | +| `PuterAuthButton` | `ui/src/components/onboarding/PuterAuthButton.tsx` | `Button` (variant default), lucide `LogIn` icon | +| `GoogleOAuthButton` | `ui/src/components/onboarding/GoogleOAuthButton.tsx` | `Button` (variant outline), lucide `AlertTriangle` icon for warning | +| `ApiKeyEntryForm` | `ui/src/components/onboarding/ApiKeyEntryForm.tsx` | `Input`, `Label`, `Button` | +| `ProviderRiskWarning` | inline in `GoogleOAuthButton` | styled `div` with `text-destructive` + `bg-destructive/10` — matches existing error block | + +Existing components consumed without modification: + +| Component | Source | +|-----------|--------| +| `Button` | `@/components/ui/button` | +| `Input` | `@/components/ui/input` | +| `Label` | `@/components/ui/label` | +| `Skeleton` | `@/components/ui/skeleton` | +| `NexusOnboardingWizard` | `@/components/NexusOnboardingWizard` — extended with new Step 4 | + +--- + +## Interaction Contract + +### Wizard Step Extension + +The existing 3-step wizard becomes a 4-step wizard for users without a detected local adapter: + +``` +Step 1: Hardware Detection → Step 2: Mode Selection → Step 3: Provider Selection (NEW) → Step 4: Root Directory +``` + +For users with a detected local adapter (hermes_local or claude_local), Step 3 is shown but pre-populated with the detected provider highlighted and a "Continue" shortcut. + +Step indicator text: "Step {N} of 4" (updated from current "Step {N} of 3"). + +### Provider Selection Step Layout + +Three option cards in a vertical stack (matching `ModeSelector` grid pattern): + +1. **Puter (free, zero-config)** — primary recommendation when no local AI and no API key + - Card border: `border-primary bg-primary/5` when selected + - Action: "Continue with Puter" button appears below cards when Puter is selected + - Auth state: button shows spinner during `puter.auth.signIn()` popup + - Post-auth state: button label changes to "Puter connected — Continue", icon: `CheckCircle` (lucide), border stays `border-primary` + +2. **Google (Gemini free tier)** — shown with risk callout + - Risk callout: amber/destructive inline alert (see Copywriting section) rendered inside the card when this option is selected — always visible before the "Sign in with Google" button is enabled + - Action: "Sign in with Google" (disabled until risk callout has been displayed for 3 seconds — anti-accidental-click gate) + - Post-auth state: "Google connected — Continue" + +3. **API Key (subscription providers)** — manual entry + - When selected: inline form expands below card (no new page) with provider select dropdown + API key input + - Supported providers listed in dropdown: OpenAI, Anthropic, Groq (extensible) + +4. **Skip for now** — ghost button below the three cards, always visible + - Does not require a selection; proceeds to Step 4 with the probed default adapter + +### Loading States + +| State | Treatment | +|-------|-----------| +| Puter auth popup in progress | Button disabled, spinner icon (h-4 w-4 animate-spin), label "Connecting to Puter…" | +| Google OAuth in progress | Button disabled, spinner, label "Signing in…" | +| API key saving | Submit button disabled, spinner, label "Saving…" | +| Adapter probe in progress | Provider cards render with `Skeleton` placeholders where pre-detected tool badges would appear; probe is fire-and-forget (cards still interactive) | + +### Error States + +All errors render inline below the triggering element using the existing error block pattern: +``` +

+ {errorMessage} +

+``` + +### Keyboard and Accessibility + +- All provider option cards are `