nexus/.planning/phases/31-puter.js-zero-config-cloud/31-UI-SPEC.md
2026-04-04 03:55:49 +00:00

258 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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, 281283, 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:
```
<p className="text-sm text-destructive bg-destructive/10 rounded-md px-3 py-2">
{errorMessage}
</p>
```
### Keyboard and Accessibility
- All provider option cards are `<button type="button">` elements (matching ModeSelector pattern) — keyboard navigable, focus ring via `--ring`.
- Risk warning callout uses `role="alert"` so screen readers announce it immediately when the Google option is selected.
- Auth buttons have `aria-busy="true"` during loading states.
- Skip button has accessible label: "Skip provider setup for now".
---
## Copywriting Contract
| Element | Copy |
|---------|------|
| Step heading (provider step) | "Choose a provider" |
| Step subheading | "No API keys needed for the zero-config path." |
| Primary CTA — Puter | "Continue with Puter" |
| Primary CTA — Google | "Sign in with Google" |
| Primary CTA — API key | "Save API key" |
| Primary CTA — generic Continue | "Continue" |
| Skip action | "Skip for now" |
| Puter card label | "Puter — free, zero-config" |
| Puter card description | "Free AI powered by your Puter.com account. No API key needed." |
| Puter cost attribution note | "Usage is billed to your Puter account, not to Nexus." |
| Google card label | "Google — Gemini free tier" |
| Google card description | "Sign in with Google to access Gemini via your Google account." |
| Google risk warning heading | "Policy risk — read before continuing" |
| Google risk warning body | "Google has suspended accounts that used third-party apps with Gemini credentials. This may affect your Gmail and Workspace access. Use a Google AI Studio API key instead if you want to avoid this risk." |
| Google safe alternative hint | "Safer option: enter a Gemini API key from Google AI Studio below." |
| API key card label | "API key — subscription provider" |
| API key card description | "Use your own OpenAI, Anthropic, or Groq API key." |
| Puter connected success | "Puter connected — Continue" |
| Google connected success | "Google connected — Continue" |
| Empty state (no provider selected, user tries to continue without skipping) | Not applicable — "Skip for now" is always available; no blocking empty state. |
| Error: Puter popup blocked | "Puter sign-in was blocked. Click 'Continue with Puter' directly — do not use keyboard shortcuts." |
| Error: Puter auth failed | "Puter sign-in failed. Check your Puter.com account and try again." |
| Error: Google auth failed | "Google sign-in failed. Try again or use an API key instead." |
| Error: API key save failed | "Could not save API key. Check the key is valid and try again." |
| Error: generic setup failure | "Setup failed. Please try again." |
| Puter auth button loading | "Connecting to Puter…" |
| Google auth button loading | "Signing in…" |
| API key submit loading | "Saving…" |
| Auto-detected tool badge | "{ToolName} detected" (e.g. "Hermes detected", "Claude Code detected") |
| Step indicator | "Step {N} of 4" |
Destructive actions: None in this phase. The Google OAuth risk warning is a caution, not a destructive action confirmation (no data is deleted).
---
## Registry Safety
| Registry | Blocks Used | Safety Gate |
|----------|-------------|-------------|
| shadcn official (ui.shadcn.com) | button, input, label, skeleton, dialog | not required |
| Third-party | none | not applicable |
No third-party shadcn registry blocks are used in this phase. `@heyputer/puter.js` is an npm package loaded via CDN script tag at runtime (not a shadcn registry block) — registry vetting gate does not apply.
---
## Notes for Executor
1. **Wizard step count:** Update the "Step N of 3" indicator to "Step N of 4" in `NexusOnboardingWizard.tsx`. The existing step counter is a plain string — a one-line change.
2. **Puter CDN load:** Load `https://js.puter.com/v2/` dynamically via `loadScript()` helper only when the user clicks "Continue with Puter" — not on wizard open. This avoids loading a large third-party script unnecessarily.
3. **Google risk warning timing gate:** The "Sign in with Google" button must remain disabled for 3 seconds after the Google card is selected to prevent accidental clicks. Use a `useEffect` with a `setTimeout` keyed to the selected card state.
4. **Provider card pre-detection:** Run `agentsApi.probeAdapter()` for `claude_local`, `hermes_local`, and `openclaw_gateway` when the wizard opens (parallel, fire-and-forget). Detected tools surface as a `text-xs text-primary` badge inside the card ("Hermes detected"). Non-detected tools show nothing extra.
5. **Skip-all valid state:** When the user skips Step 3 entirely, the wizard must still complete Step 4 (root directory) and create at least one working agent. The existing `defaultAdapter` probe result handles this — if hermes_local was detected, it's used; otherwise claude_local.
6. **No new shadcn components needed:** All required UI elements are covered by the existing component inventory (button, input, label, skeleton). Do not install additional shadcn components for this phase.
---
## Checker Sign-Off
- [ ] Dimension 1 Copywriting: PASS
- [ ] Dimension 2 Visuals: PASS
- [ ] Dimension 3 Color: PASS
- [ ] Dimension 4 Typography: PASS
- [ ] Dimension 5 Spacing: PASS
- [ ] Dimension 6 Registry Safety: PASS
**Approval:** pending