Backend (FastAPI + SQLAlchemy + SQLite): - JWT auth with access/refresh tokens, bcrypt password hashing - User model with member/organizer/admin roles, auto-approve members - Championship, Registration, ParticipantList, Notification models - Alembic async migrations, seed data with test users - Registration endpoint returns tokens for members, pending for organizers - /registrations/my returns championship title/date/location via eager loading - Admin endpoints: list users, approve/reject organizers Mobile (React Native + Expo + TypeScript): - Zustand auth store, Axios client with token refresh interceptor - Role-based registration (Member vs Organizer) with contextual form labels - Tab navigation with Ionicons, safe area headers, admin tab for admin role - Championships list with status badges, detail screen with registration progress - My Registrations with championship title, progress bar, and tap-to-navigate - Admin panel with pending/all filter, approve/reject with confirmation - Profile screen with role badge, Ionicons info rows, sign out - Password visibility toggle (Ionicons), keyboard flow hints (returnKeyType) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
259 lines
7.3 KiB
Markdown
259 lines
7.3 KiB
Markdown
# DanceChamp — Design System
|
||
|
||
## Theme: Dark Luxury
|
||
|
||
The app has a premium dark aesthetic. Think high-end dance competition branding — elegant, minimal, confident.
|
||
|
||
---
|
||
|
||
## Colors
|
||
|
||
### Core Palette
|
||
```
|
||
Background: #08070D (near-black with slight purple)
|
||
Card: #12111A (elevated surface)
|
||
Card Hover: #1A1926 (pressed/active state)
|
||
Border: #1F1E2E (subtle separator)
|
||
Text Primary: #F2F0FA (off-white)
|
||
Text Dim: #5E5C72 (labels, placeholders)
|
||
Text Mid: #8F8DA6 (secondary info)
|
||
```
|
||
|
||
### Accent Colors
|
||
```
|
||
Pink (Primary): #D4145A ← Member app + Org app default
|
||
Purple: #7C3AED ← Secondary accent (styles, alt champ branding)
|
||
Indigo: #6366F1 ← Admin panel accent
|
||
```
|
||
|
||
### Semantic Colors
|
||
```
|
||
Green: #10B981 (success, passed, active, confirmed)
|
||
Yellow: #F59E0B (warning, pending, draft)
|
||
Red: #EF4444 (error, failed, blocked, danger)
|
||
Blue: #60A5FA (info, links, video)
|
||
Orange: #F97316 (warned status, awaiting review)
|
||
```
|
||
|
||
### Transparent Variants
|
||
Each semantic color has a 10% opacity background:
|
||
```
|
||
Green Soft: rgba(16,185,129,0.10)
|
||
Yellow Soft: rgba(245,158,11,0.10)
|
||
Red Soft: rgba(239,68,68,0.10)
|
||
Blue Soft: rgba(96,165,250,0.10)
|
||
Purple Soft: rgba(139,92,246,0.10)
|
||
```
|
||
|
||
For accent overlays use 15% opacity: `${color}15`
|
||
For accent borders use 30% opacity: `${color}30`
|
||
|
||
### Per-Championship Branding
|
||
Each championship can have its own accent color:
|
||
- Zero Gravity: `#D4145A` (pink)
|
||
- Pole Star: `#7C3AED` (purple)
|
||
|
||
This color is used for the championship's tab highlights, buttons, and member tags.
|
||
|
||
---
|
||
|
||
## Typography
|
||
|
||
### Font Stack
|
||
```
|
||
Display: 'Playfair Display', Georgia, serif ← Headings, numbers, titles
|
||
Body: 'DM Sans', 'Segoe UI', sans-serif ← Body text, labels, buttons
|
||
Mono: 'JetBrains Mono', monospace ← Badges, timestamps, codes, small labels
|
||
```
|
||
|
||
### Sizes & Usage
|
||
```
|
||
Screen title: Playfair Display, 20px, 700 weight
|
||
Section title: Playfair Display, 14px, 700 weight, Text Mid color
|
||
Card title: DM Sans, 14-16px, 600 weight
|
||
Body text: DM Sans, 12-13px, 400 weight
|
||
Small label: JetBrains Mono, 9-10px, 500 weight, uppercase, letter-spacing 0.3-0.5
|
||
Badge: JetBrains Mono, 8px, 700 weight, uppercase, letter-spacing 0.8
|
||
Stat number: Playfair Display, 16-20px, 700 weight
|
||
```
|
||
|
||
---
|
||
|
||
## Components
|
||
|
||
### Card
|
||
```
|
||
Background: #12111A
|
||
Border: 1px solid #1F1E2E
|
||
Border Radius: 14px
|
||
Padding: 16px
|
||
```
|
||
|
||
### Status Badge
|
||
Small pill with semantic color + soft background.
|
||
```
|
||
Font: JetBrains Mono, 8px, 700 weight, uppercase
|
||
Padding: 3px 8px
|
||
Border Radius: 4px
|
||
```
|
||
|
||
Status mappings:
|
||
| Status | Label | Color | Background |
|
||
|---|---|---|---|
|
||
| active / live | ACTIVE / LIVE | Green | Green Soft |
|
||
| pending | PENDING | Yellow | Yellow Soft |
|
||
| pending_approval | AWAITING REVIEW | Orange | Orange Soft |
|
||
| draft | DRAFT | Dim | Dim 15% |
|
||
| blocked | BLOCKED | Red | Red Soft |
|
||
| warned | WARNED | Orange | Orange Soft |
|
||
| passed | PASSED | Green | Green Soft |
|
||
| failed | FAILED | Red | Red Soft |
|
||
|
||
### Tab Bar (in-screen tabs, not bottom nav)
|
||
```
|
||
Container: horizontal scroll, no scrollbar, gap 3px
|
||
Tab: JetBrains Mono, 9px, 600 weight
|
||
Active: accent color text, accent 15% bg, accent 30% border
|
||
Inactive: Dim color text, transparent bg
|
||
Border Radius: 16px (pill shape)
|
||
Padding: 5px 10px
|
||
```
|
||
|
||
Configurable tabs have a status dot (6px circle):
|
||
- Green dot = section configured ✓
|
||
- Yellow dot = section pending
|
||
|
||
### Input Field
|
||
```
|
||
Background: #08070D (same as page bg)
|
||
Border: 1px solid #1F1E2E
|
||
Border Radius: 10px
|
||
Padding: 10px 12px
|
||
Font: DM Sans, 13px
|
||
Label: JetBrains Mono, 9px, uppercase, Dim color, 6px margin bottom
|
||
```
|
||
|
||
### Action Button
|
||
Two variants:
|
||
- **Filled**: solid background, white text (for primary actions)
|
||
- **Outline**: transparent bg, colored border 30%, colored text (for secondary/danger)
|
||
|
||
```
|
||
Padding: 8px 14px
|
||
Border Radius: 8px
|
||
Font: DM Sans, 11px, 700 weight
|
||
```
|
||
|
||
### Tag Editor
|
||
For lists of editable items (rules, levels, styles):
|
||
```
|
||
Tag: DM Sans 11px, colored bg 10%, colored border 25%, 4px 10px padding, 16px radius
|
||
Remove (×): 10px, Dim color
|
||
Add input: same as Input Field but smaller (8px 12px, 12px font)
|
||
Add button: colored bg, white "+" text, 8px 14px
|
||
```
|
||
|
||
### Header
|
||
```
|
||
Padding: 14px 20px 6px
|
||
Title: Playfair Display, 20px, 700
|
||
Subtitle: DM Sans, 11px, Dim color
|
||
Back button: 32×32px, Card bg, Border, 8px radius, "←" centered
|
||
```
|
||
|
||
### Bottom Navigation
|
||
```
|
||
Border top: 1px solid #1F1E2E
|
||
Padding: 10px 0 8px
|
||
Items: flex, space-around
|
||
Icon: 18px emoji
|
||
Label: JetBrains Mono, 8px, letter-spacing 0.3
|
||
Active: opacity 1
|
||
Inactive: opacity 0.35
|
||
```
|
||
|
||
---
|
||
|
||
## Patterns
|
||
|
||
### Progress/Setup Checklist
|
||
For configurable tabs on org side:
|
||
```
|
||
Each row:
|
||
[Checkbox 22×22] [Label capitalize] [Configure › or ✓]
|
||
|
||
Checkbox: 6px radius, 2px border
|
||
Done: Green border, Green Soft bg, "✓" inside
|
||
Pending: Yellow border, transparent bg
|
||
|
||
Label done: Dim color, line-through
|
||
Label pending: Text Primary, clickable → navigates to tab
|
||
```
|
||
|
||
### Readiness Bar (dashboard cards)
|
||
```
|
||
Track: 4px height, Border color bg, 2px radius
|
||
Fill: accent color, width = (done/total * 100)%
|
||
Below: list of section names with ✓ (green) or ○ (yellow)
|
||
```
|
||
|
||
### Member Card
|
||
```
|
||
Container: Card style, 12px padding
|
||
Name: DM Sans 13px, 600 weight
|
||
Instagram: JetBrains Mono 10px, accent color
|
||
Tags: DM Sans 9px, Mid color, Mid 10% bg, 2px 7px padding, 10px radius
|
||
Status badge: top-right corner
|
||
```
|
||
|
||
### Stat Box
|
||
```
|
||
Container: Card style, 10px 6px padding, centered
|
||
Number: Playfair Display, 16-20px, 700 weight, semantic color
|
||
Label: JetBrains Mono, 7px, uppercase, Dim color
|
||
```
|
||
|
||
---
|
||
|
||
## Phone Frame (for prototypes)
|
||
|
||
```
|
||
Width: 375px
|
||
Height: 740px
|
||
Border Radius: 36px
|
||
Border: 1.5px solid #1F1E2E
|
||
Shadow: 0 0 80px rgba(accent, 0.06), 0 20px 40px rgba(0,0,0,0.5)
|
||
|
||
Status bar: 8px 24px padding
|
||
Time: JetBrains Mono 11px, Dim
|
||
Notch: 100×28px black, 14px radius
|
||
Indicators: "●●●" JetBrains Mono 11px, Dim
|
||
```
|
||
|
||
---
|
||
|
||
## React Native Adaptation
|
||
|
||
The prototypes use inline styles. For React Native:
|
||
|
||
| Prototype | React Native |
|
||
|---|---|
|
||
| `div` | `View` |
|
||
| `span`, `p`, `h1` | `Text` |
|
||
| `input` | `TextInput` |
|
||
| `onClick` | `onPress` (via `Pressable` or `TouchableOpacity`) |
|
||
| `overflow: auto` | `ScrollView` or `FlatList` |
|
||
| `cursor: pointer` | Not needed |
|
||
| `border: 1px solid` | `borderWidth: 1, borderColor:` |
|
||
| `fontFamily: 'DM Sans'` | Loaded via `expo-font` |
|
||
| `gap` | Use `marginBottom` on children (gap not fully supported) |
|
||
| `overflowX: auto` with scrollbar hidden | `ScrollView horizontal showsHorizontalScrollIndicator={false}` |
|
||
|
||
### Fonts Loading (Expo)
|
||
```typescript
|
||
import { useFonts } from 'expo-font';
|
||
import { PlayfairDisplay_700Bold } from '@expo-google-fonts/playfair-display';
|
||
import { DMSans_400Regular, DMSans_500Medium, DMSans_600SemiBold } from '@expo-google-fonts/dm-sans';
|
||
import { JetBrainsMono_400Regular, JetBrainsMono_500Medium, JetBrainsMono_700Bold } from '@expo-google-fonts/jetbrains-mono';
|
||
```
|