diff --git a/docs/superpowers/specs/2026-04-26-profile-devices-redesign.md b/docs/superpowers/specs/2026-04-26-profile-devices-redesign.md new file mode 100644 index 0000000..4df0962 --- /dev/null +++ b/docs/superpowers/specs/2026-04-26-profile-devices-redesign.md @@ -0,0 +1,136 @@ +# Profile & Devices Page Redesign + +## Goal +Revamp the profile page from a generic, narrow layout to a full-featured settings hub with password change, passkey management, account linking, and profile editing. Create the initial devices page with aggregated stats and charts. Remove profile photo from the navbar. + +## Architecture + +### Profile Page (`/profile`) +- Switch from `max-w-3xl` to `max-w-7xl` +- Remove profile photo/avatar from ProfileHeader (no image upload) +- Replace with initials-based avatar or just name display +- Settings tab gets 3 sub-tabs: Profile, Security, Linked Accounts +- Each settings section uses Better Auth's client-side API methods + +### Navbar +- Remove profile photo/icon from the authenticated dropdown trigger +- Show just "Profile" text link that opens the dropdown (Profile + Saved Games + Sign out) +- Mobile sidebar already uses text links, just remove avatar section + +### Devices Page (`/devices`) +- Grid of device cards with aggregated benchmark statistics +- Clicking a card navigates to `/devices/[slug]` for detailed view +- Detail page leverages existing EChartWrapper + chart components +- New API endpoints for aggregated hardware statistics + +### Devices Detail Page (`/devices/[slug]`) +- Hero header with device name, type, benchmark count +- Charts: Historical FPS, FPS Distribution (boxplot), Top Games, Game count by genre/proton status +- Uses same chart components and theme as game page + +## Tech Stack +- Better Auth client API (changePassword, updateUser, listAccounts, unlinkAccount, linkSocialAccount, passkey.addPasskey, passkey.deletePasskey, listPasskeys) +- ECharts (echarts-for-react) for device stats charts +- Existing chart components: EChartWrapper, HistoricalAreaChart, FpsBoxplot, DeviceDonut +- Framer Motion for animations (consistent with rest of app) +- Tailwind v4 with existing theme tokens + +## Profile Settings Details + +### Profile Sub-Tab +- Display name editing (Better Auth `updateUser`) +- Email display (read-only, with link to change email — future feature) +- Role and member since (read-only) + +### Security Sub-Tab +- **Password Section**: + - If user has password: "Change Password" form with current password + new password + confirm + - If user has no password (social-only): "Set Password" form + - Uses Better Auth `changePassword` (with currentPassword) or `setPassword` +- **Passkey Section**: + - List existing passkeys (name, device type, created date) + - "Add Passkey" button (Better Auth `addPasskey`) + - "Delete" button per passkey (Better Auth `deletePasskey`) + - "Rename" per passkey (Better Auth `updatePasskey`) + - Safety check: don't allow deleting last auth method + +### Linked Accounts Sub-Tab +- List linked providers (Google, Discord, password) + - Shows provider name, account ID/email, linked date + - "Unlink" button with confirmation (Better Auth `unlinkAccount`) + - Safety check: don't allow unlinking last auth method +- "Link Google" / "Link Discord" buttons (Better Auth `linkSocialAccount`) +- Show which providers are available vs already linked + +## Devices API + +### `GET /api/hardware/stats` +Returns array of all devices with aggregated stats: +```json +[ + { + "slug": "steam-deck-oled", + "name": "Steam Deck OLED", + "deviceType": "handheld", + "sortOrder": 0, + "totalBenchmarks": 150, + "avgFps": 45.2, + "gameCount": 35, + "verifiedCount": 20, + "bestGame": { "id": "...", "title": "...", "fpsAvg": 120 } + } +] +``` + +### `GET /api/hardware/:slug/stats` +Returns detailed stats for one device: +```json +{ + "slug": "steam-deck-oled", + "name": "Steam Deck OLED", + "deviceType": "handheld", + "totalBenchmarks": 150, + "avgFps": 45.2, + "verifiedCount": 20, + "gameCount": 35, + "boxplot": [...], + "historical": [...], + "topGames": [...], + "protonBreakdown": [...], + "fsrBreakdown": [...] +} +``` + +## Component File Structure + +### New Files +- `components/profile/settings-profile-tab.tsx` — Profile sub-tab +- `components/profile/settings-security-tab.tsx` — Security sub-tab (password + passkeys) +- `components/profile/settings-accounts-tab.tsx` — Linked Accounts sub-tab +- `app/devices/page.tsx` — Devices grid page (server component) +- `app/devices/page-client.tsx` — Devices grid client component +- `app/devices/[slug]/page.tsx` — Device detail page (server component) +- `app/devices/[slug]/device-detail-client.tsx` — Device detail client component +- `lib/api/hardware-stats.ts` — Hardware stats API routes + +### Modified Files +- `app/profile/page.tsx` — Redesign layout, widen to max-w-7xl, add settings sub-tabs +- `components/profile/profile-header.tsx` — Remove image/avatar, show name-centric layout +- `components/navbar.tsx` — Remove profile photo/icon from dropdown trigger, keep text-only "Profile" +- `lib/routes.ts` — Add /devices route +- `lib/api/hardware.ts` — May need minor updates for new stats endpoints + +## Design Patterns (from existing pages) +- **Game page** layout pattern: `max-w-7xl mx-auto` with `px-4 md:px-[10svw]` sections +- **Chart cards**: `rounded-xl border border-border bg-text/[0.03] p-4` +- **Stat cards**: Icon + label + value in `flex items-center gap-3` +- **Section headers**: `text-sm font-medium text-text/80 mb-2` +- **Tab style**: `border-b border-border` with active state `border-primary text-primary` +- **Animations**: `motion.div` with `initial={{ opacity: 0, y: 12 }}` and staggered delays + +## Edge Cases & Safety +1. Password section: Users with social-only accounts (no password) see "Set Password" not "Change Password" +2. Unlinking: Prevent removing the last authentication method (must always have at least one way to log in) +3. Passkey deletion: Same safety check — don't allow removing the only auth method +4. Device stats: Handle case where no benchmarks exist for a device (show empty state) +5. Mobile responsive: All new components must work on mobile (single-column layouts) \ No newline at end of file