feat(ui): complete Task 4 UI redesign — all sub-tasks 1-10
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 8m47s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 8m47s
- Implemented complete design system with 40+ CSS custom properties - Created 9 UI primitives (GameCard, SectionHeader, StatRow, ManaBar, ElementBadge, ValueDisplay, ActionButton, SkillRow, TooltipInfo) - Redesigned all tabs: Spire, Skills, Stats, Equipment, Crafting, Attunements, Golemancy, Spells, Loot, Achievements, Lab, Debug - Added toast notification system (GameToast) with success/warning/error/info types - Added confirmation dialogs for destructive actions - Removed all dev artifacts and component name labels - Added empty states to all tabs - Replaced emoji icons with Lucide React icons - Added enchantPower placeholder to StatsTab and EquipmentTab - Mobile audit passed at 375px viewport - Build passes with 0 errors, lint passes with 0 errors Sub-tasks completed: - ST1: Design System Implementation - ST2: Global Layout & Header - ST3: Left Panel (Mana Display & Action Area) - ST4: Skills Tab - ST5: Spire Tab & Spire Mode UI - ST6: Stats Tab - ST7: Equipment & Crafting Tabs - ST8: Attunements Tab - ST9: Remaining Tabs - ST10: Toast System & Confirmation Dialogs Documentation: 15+ files in docs/task4/
This commit is contained in:
@@ -0,0 +1,415 @@
|
||||
# Mana Loop - Design System
|
||||
|
||||
## Version: 1.0
|
||||
## Date: 2024-04-27
|
||||
|
||||
---
|
||||
|
||||
## 1. Visual Identity
|
||||
|
||||
### Theme: Ancient Arcane Grimoire
|
||||
|
||||
The Mana Loop UI should feel like an ancient spellbook infused with crystalline magic - not a generic dark mode SaaS application.
|
||||
|
||||
**Aesthetic References:**
|
||||
- Path of Exile passive tree (dark, arcane, intricate)
|
||||
- Slay the Spire card UI (clear, readable, atmospheric)
|
||||
- Hades menu screens (bold, high-contrast, mythological)
|
||||
|
||||
**Guiding Principles:**
|
||||
1. Every UI region should feel like it belongs in the world
|
||||
2. Restraint over decoration: one strong texture/treatment per region
|
||||
3. The UI must stay fast and readable - this is an idle game
|
||||
4. No generic purple-gradient-on-charcoal
|
||||
|
||||
**Key Visual Elements:**
|
||||
- Illuminated manuscript styling for headers (gold accents, serif fonts)
|
||||
- Crystalline magic effects for interactive elements
|
||||
- Subtle arcane patterns as background texture
|
||||
- High contrast for readability with muted atmospheric colors
|
||||
|
||||
---
|
||||
|
||||
## 2. Color Tokens
|
||||
|
||||
### 2a. Background Colors (Depth Levels)
|
||||
|
||||
```css
|
||||
--bg-base: #060811; /* Outermost / page - deep void black */
|
||||
--bg-surface: #0C1020; /* Panels, cards - dark navy */
|
||||
--bg-elevated: #111628; /* Dropdowns, tooltips, modals - medium dark */
|
||||
--bg-sunken: #181f35; /* Inset wells, progress track - lighter panel */
|
||||
```
|
||||
|
||||
### 2b. Border Colors
|
||||
|
||||
```css
|
||||
--border-subtle: #1e2a45; /* Barely-there separators */
|
||||
--border-default: #2a3a60; /* Standard card edges */
|
||||
--border-focus: #5B8FFF; /* Interactive focus rings */
|
||||
```
|
||||
|
||||
### 2c. Text Colors
|
||||
|
||||
```css
|
||||
--text-primary: #c8d8f8; /* Main text - light blue-white */
|
||||
--text-secondary: #7a92c0; /* Secondary text - muted blue-gray */
|
||||
--text-muted: #4a5f8a; /* Muted text - darker blue-gray */
|
||||
--text-disabled: #2a3a60; /* Disabled text - very muted */
|
||||
```
|
||||
|
||||
### 2d. Mana Element Colors
|
||||
|
||||
Each mana type has a distinct, semantic color that reflects its nature:
|
||||
|
||||
```css
|
||||
--mana-fire: #E8734A; /* Ember orange-red */
|
||||
--mana-water: #3BAFDA; /* Deep teal */
|
||||
--mana-air: #C8D8F8; /* Silver-white */
|
||||
--mana-earth: #B8860B; /* Warm ochre */
|
||||
--mana-light: #D4A843; /* Gold */
|
||||
--mana-dark: #4B0082; /* Deep indigo */
|
||||
--mana-death: #8B7D8B; /* Muted violet-grey */
|
||||
--mana-transfer: #00CED1; /* Cyan - the "tech mana" */
|
||||
--mana-metal: #708090; /* Cool steel */
|
||||
--mana-sand: #C2B280; /* Warm tan */
|
||||
--mana-lightning: #FFD700; /* Electric yellow */
|
||||
--mana-crystal: #B0E0E6; /* Pale ice blue */
|
||||
--mana-stellar: #FF8C00; /* Bright amber */
|
||||
--mana-void: #1A0A2E; /* Deep black-purple */
|
||||
```
|
||||
|
||||
### 2e. Semantic UI Colors
|
||||
|
||||
```css
|
||||
--color-success: #27AE60; /* Green */
|
||||
--color-warning: #F39C12; /* Orange */
|
||||
--color-danger: #C0392B; /* Red */
|
||||
--color-info: #3B6FE8; /* Blue */
|
||||
```
|
||||
|
||||
### 2f. Interactive Colors
|
||||
|
||||
```css
|
||||
--interactive-primary: #3B6FE8; /* Main CTA - Gather, Study, Climb */
|
||||
--interactive-primary-hover: #5B8FFF; /* Hover state */
|
||||
--interactive-secondary: #2a3a60; /* Secondary actions */
|
||||
--interactive-secondary-hover: #3a4a70; /* Secondary hover */
|
||||
--interactive-danger: #C0392B; /* Danger actions */
|
||||
--interactive-danger-hover: #E74C3C; /* Danger hover */
|
||||
--interactive-disabled: #1e2a45; /* Disabled state */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Typography
|
||||
|
||||
### 3a. Font Stack
|
||||
|
||||
```css
|
||||
--font-heading: 'Cinzel', serif; /* Fantasy-adjacent serif for headers */
|
||||
--font-body: 'Crimson Text', Georgia, serif; /* All body copy */
|
||||
--font-mono: 'JetBrains Mono', monospace; /* Numbers, values, timers */
|
||||
```
|
||||
|
||||
### 3b. Type Scale
|
||||
|
||||
| Size | Font Size | Line Height | Letter Spacing | Usage |
|
||||
|------|-----------|--------------|----------------|-------|
|
||||
| xs | 0.75rem (12px) | 1rem | 0.05em | Captions, labels |
|
||||
| sm | 0.875rem (14px) | 1.25rem | 0.025em | Secondary text |
|
||||
| base | 1rem (16px) | 1.5rem | normal | Body text |
|
||||
| lg | 1.125rem (18px) | 1.75rem | normal | Emphasized text |
|
||||
| xl | 1.25rem (20px) | 1.75rem | -0.025em | Subheaders |
|
||||
| 2xl | 1.5rem (24px) | 2rem | -0.05em | Section headers |
|
||||
| 3xl | 1.875rem (30px) | 2.25rem | -0.05em | Page titles |
|
||||
|
||||
**Heading Specifics:**
|
||||
- Font: `--font-heading` (Cinzel)
|
||||
- Letter spacing: 0.05em to 0.1em
|
||||
- Text transform: uppercase for game panel titles
|
||||
- Font weight: 600 or 700
|
||||
|
||||
---
|
||||
|
||||
## 4. Spacing & Layout
|
||||
|
||||
### 4a. Base Unit
|
||||
- **4px** (Tailwind default: 1 unit = 0.25rem)
|
||||
|
||||
### 4b. Border Radius
|
||||
```css
|
||||
--radius: 0.5rem; /* 8px - used everywhere for consistency */
|
||||
```
|
||||
|
||||
### 4c. Panel Inner Padding
|
||||
- All tabs/panels: `1.5rem` (24px / p-6 in Tailwind)
|
||||
- Card content: `1rem` (16px / p-4 in Tailwind)
|
||||
- Tight spacing: `0.75rem` (12px / p-3 in Tailwind)
|
||||
|
||||
### 4d. Gaps
|
||||
- Between cards: `1rem` (16px / gap-4)
|
||||
- Between elements: `0.5rem` (8px / gap-2)
|
||||
- Tight elements: `0.25rem` (4px / gap-1)
|
||||
|
||||
---
|
||||
|
||||
## 5. Component Primitives
|
||||
|
||||
### 5a. GameCard
|
||||
**Purpose:** All panel/section wrappers
|
||||
**Variants:** default, elevated, sunken, danger
|
||||
**Props:** `variant`, `className`, `children`
|
||||
|
||||
```typescript
|
||||
interface GameCardProps {
|
||||
variant?: 'default' | 'elevated' | 'sunken' | 'danger';
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- default: `--bg-surface` background, `--border-default` border
|
||||
- elevated: `--bg-elevated` background, stronger shadow
|
||||
- sunken: `--bg-sunken` background, inset appearance
|
||||
- danger: Red-tinted border for warning states
|
||||
|
||||
### 5b. SectionHeader
|
||||
**Purpose:** Consistent section titles with optional right-side action slot
|
||||
**Props:** `title`, `action`, `className`
|
||||
|
||||
```typescript
|
||||
interface SectionHeaderProps {
|
||||
title: string;
|
||||
action?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Font: `--font-heading`
|
||||
- Text transform: uppercase
|
||||
- Letter spacing: 0.1em
|
||||
- Color: `--text-primary`
|
||||
- Optional right-side action slot for buttons/badges
|
||||
|
||||
### 5c. StatRow
|
||||
**Purpose:** Label + value pair
|
||||
**Props:** `label`, `value`, `highlight`, `className`
|
||||
|
||||
```typescript
|
||||
interface StatRowProps {
|
||||
label: string;
|
||||
value: string | number;
|
||||
highlight?: 'default' | 'success' | 'warning' | 'danger' | 'mana-*';
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Label: `--text-secondary`, left-aligned
|
||||
- Value: `--text-primary`, right-aligned, `--font-mono`
|
||||
- Highlight colors change value text color
|
||||
|
||||
### 5d. ManaBar
|
||||
**Purpose:** Progress bar skinned per mana type
|
||||
**Props:** `value`, `max`, `manaType`, `className`
|
||||
|
||||
```typescript
|
||||
interface ManaBarProps {
|
||||
value: number;
|
||||
max: number;
|
||||
manaType?: keyof typeof MANA_COLORS;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Height: 8px (h-2)
|
||||
- Border radius: `--radius`
|
||||
- Fill uses appropriate `--mana-*` color
|
||||
- Transition: 300ms ease-out
|
||||
- Background: `--bg-sunken`
|
||||
|
||||
### 5e. ElementBadge
|
||||
**Purpose:** Pill badge for mana/element type with matching icon + color
|
||||
**Props:** `element`, `showIcon`, `size`, `className`
|
||||
|
||||
```typescript
|
||||
interface ElementBadgeProps {
|
||||
element: string;
|
||||
showIcon?: boolean;
|
||||
size?: 'sm' | 'md';
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Pill shape (rounded-full)
|
||||
- Background: `--mana-{type}` at 20% opacity
|
||||
- Border: `--mana-{type}` at 60% opacity
|
||||
- Text: `--mana-{type}` full color
|
||||
- Icon from Lucide icons matching element
|
||||
|
||||
### 5f. ValueDisplay
|
||||
**Purpose:** Animated numeric display for mana, DPS, etc.
|
||||
**Props:** `value`, `label`, `color`, `className`
|
||||
|
||||
```typescript
|
||||
interface ValueDisplayProps {
|
||||
value: number;
|
||||
label?: string;
|
||||
color?: string;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Font: `--font-mono`
|
||||
- Font feature: `tabular-nums` for aligned digits
|
||||
- Transition on value change (CSS only)
|
||||
- Optional label below in `--text-secondary`
|
||||
|
||||
### 5g. ActionButton
|
||||
**Purpose:** Primary game CTA
|
||||
**Variants:** primary, secondary, danger, ghost
|
||||
**Props:** `variant`, `size`, `disabled`, `children`, `className`
|
||||
|
||||
```typescript
|
||||
interface ActionButtonProps {
|
||||
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
disabled?: boolean;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- primary: `--interactive-primary` background
|
||||
- secondary: `--interactive-secondary` background
|
||||
- danger: `--interactive-danger` background
|
||||
- ghost: Transparent with border
|
||||
- Hover: 100ms ease transition
|
||||
- Disabled: `--interactive-disabled` with reduced opacity
|
||||
|
||||
### 5h. SkillRow
|
||||
**Purpose:** Standard skill entry row
|
||||
**Props:** `skill`, `onStudy`, `onUpgrade`, `children`, `className`
|
||||
|
||||
```typescript
|
||||
interface SkillRowProps {
|
||||
skill: Skill;
|
||||
onStudy?: () => void;
|
||||
onUpgrade?: () => void;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Name: `--text-primary`, `--font-heading`
|
||||
- Description: `--text-secondary`, `--font-body`
|
||||
- Cost: `--text-muted`, `--font-mono`
|
||||
- Level dots: Using `--mana-purple` for filled
|
||||
- Study button: ActionButton (secondary variant)
|
||||
|
||||
### 5i. TooltipInfo
|
||||
**Purpose:** Consistent tooltip triggered by `?` icon
|
||||
**Props:** `content`, `children`, `className`
|
||||
|
||||
```typescript
|
||||
interface TooltipInfoProps {
|
||||
content: string;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
```
|
||||
|
||||
**Styling:**
|
||||
- Trigger: `?` icon in circle, `--text-muted`
|
||||
- Content: `--bg-elevated` background, `--text-primary` text
|
||||
- Uses Radix Tooltip under the hood
|
||||
- Delay: 0ms (instant)
|
||||
|
||||
---
|
||||
|
||||
## 6. Animation Budget
|
||||
|
||||
| Category | Rule | Duration | Easing |
|
||||
|----------|------|----------|--------|
|
||||
| Mana bar fill | CSS transition | 300ms | ease-out |
|
||||
| Progress bars (study/cast) | CSS transition | linear | linear |
|
||||
| Tab switch | CSS transition | 150ms | fade-in |
|
||||
| Hover states | CSS transition | 100ms | ease |
|
||||
| Number changes | CSS `tabular-nums` | N/A | N/A |
|
||||
| Idle sparkle / glow | One subtle glow pulse on Gather button ONLY | 2s | ease-in-out, infinite |
|
||||
| Spire combat | Cast bar animates smoothly | 300ms | ease-out |
|
||||
|
||||
**Important Notes:**
|
||||
- NO framer-motion for layout shifts - CSS transitions only
|
||||
- All animations must be performant (idle game runs constantly)
|
||||
- Respect `prefers-reduced-motion` setting
|
||||
|
||||
---
|
||||
|
||||
## 7. Icon System
|
||||
|
||||
**Library:** Lucide React (already installed)
|
||||
|
||||
**Usage Guidelines:**
|
||||
- No emoji in UI - use Lucide icons only
|
||||
- Icons should match mana element colors when applicable
|
||||
- Standard sizes: 16px (sm), 20px (md), 24px (lg)
|
||||
- Stroke width: 2 (default)
|
||||
|
||||
**Common Icons:**
|
||||
- Mana: Zap, Flame, Droplet, Wind, Mountain, Sun, Moon, Skull, etc.
|
||||
- Actions: Play, Pause, RotateCcw, ChevronRight, etc.
|
||||
- UI: Settings, Info, AlertTriangle, Check, X, etc.
|
||||
|
||||
---
|
||||
|
||||
## 8. Z-Index Scale
|
||||
|
||||
| Layer | Value | Usage |
|
||||
|-------|-------|-------|
|
||||
| Base | 0 | Normal content |
|
||||
| Dropdown | 50 | Select, dropdown menus |
|
||||
| Sticky | 100 | Sticky headers |
|
||||
| Overlay | 200 | Modals, dialogs |
|
||||
| Toast | 300 | Toast notifications |
|
||||
| Tooltip | 400 | Tooltips |
|
||||
|
||||
---
|
||||
|
||||
## 9. Shadow System
|
||||
|
||||
```css
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
|
||||
--shadow-glow-gold: 0 0 15px rgba(212, 168, 67, 0.4);
|
||||
--shadow-glow-purple: 0 0 15px rgba(124, 92, 191, 0.4);
|
||||
--shadow-glow-accent: 0 0 15px rgba(60, 111, 232, 0.4);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Implementation Checklist
|
||||
|
||||
- [ ] Update `src/app/globals.css` with all CSS custom properties
|
||||
- [ ] Create `src/components/ui/game-card.tsx`
|
||||
- [ ] Create `src/components/ui/section-header.tsx`
|
||||
- [ ] Create `src/components/ui/stat-row.tsx`
|
||||
- [ ] Create `src/components/ui/mana-bar.tsx`
|
||||
- [ ] Create `src/components/ui/element-badge.tsx`
|
||||
- [ ] Create `src/components/ui/value-display.tsx`
|
||||
- [ ] Create `src/components/ui/action-button.tsx` (or update existing button.tsx)
|
||||
- [ ] Create `src/components/ui/skill-row.tsx`
|
||||
- [ ] Create `src/components/ui/tooltip-info.tsx`
|
||||
- [ ] Update `src/components/ui/index.ts` with all exports
|
||||
- [ ] Search and remove component name labels
|
||||
- [ ] Create all sub-task documentation files
|
||||
- [ ] Run final lint verification
|
||||
Reference in New Issue
Block a user