redesign(ui): полный реворк в стиле Apple iOS/macOS
Ветка для нового интерфейса; main с предыдущим Strava-дизайном
не тронут — можно вернуться через checkout main.
== Design system (foundation) ==
- Шрифты: Geist (sans, display) + Geist Mono (HUD числа) +
Instrument Serif (hero titles) — все через Google Fonts. Близки
к SF Pro / SF Mono.
- Палитра: Apple Human Interface Guidelines
* accent: 255 107 53 (Apple Fitness Move orange)
* success: 52 199 89 (systemGreen — для switch)
* destructive: 255 59 48 (systemRed)
* info: 0 122 255 (systemBlue)
* warning: 255 159 10
* Light bg: 242 242 247 (iOS systemGroupedBackground)
* Dark bg: true black 0 0 0 (OLED-friendly), elevation через
28/44/56 grey steps как в iOS Settings
- Утилиты: .vibrancy (macOS Big Sur sidebar), .hairline-b/-t (0.5px
iOS-стиль), .shadow-card (soft layered), .font-display/-serif/-mono-num
== UI primitives ==
- Button: filled / tinted / plain / destructive / success (iOS UIButton);
active:scale-[0.97] press feedback. Старые имена primary/secondary/
ghost/danger/victory маппятся через legacyMap для совместимости.
- Switch: настоящий iOS UISwitch 51x31, spring физика knob, success
цвет on.
- Modal: центрированный sheet с rounded-3xl (22px), backdrop blur,
spring scale-in. Header с font-display, X в circle.
- Card + Row + SectionHeader: iOS grouped list — белая поверхность,
hairline-b dividers между rows, last={true} убирает последний.
== App frame ==
- Sidebar: vibrancy (semi-transparent + backdrop-blur saturate 180%),
font-serif лого, tinted icon-plaques на каждом пункте (как в iOS
Settings), плавный hover. Drawer на mobile со spring slide.
- Titlebar: центрированный title, window controls без glow, hamburger
только на <md.
- App.tsx: AnimatePresence cross-fade между маршрутами.
== Pages ==
- Dashboard: hero с font-serif Large Title + датой. 3-card Hero panel
(Apple Fitness style) с tinted icon squares. ExerciseCard теперь с
progress-ring вокруг иконки + появляющейся "Готово" pill только при
due. Three-dot menu (iOS-style popover).
- Exercises: групированный список iOS, разделение Активные/Выключенные,
chevron-right на каждом row.
- Challenges: тот же групированный паттерн + warning banner если игр
нет, formula preview карточка в редакторе с big number в accent.
- Games: cards в новом стиле, статус-чипы pulse-dot для LIVE, dev
кнопки в pill-стиле.
- Settings: классические iOS Settings секции с ToggleRow и SelectRow
inside Card. UpdaterCard полностью переработан под Cell pattern.
== Reminder window ==
- iOS action sheet: большая иконка в accent-circle сверху, font-serif
название упражнения, гигантское моноширинное число reps. Кнопки
стопкой: primary Готово full-width, потом snooze + skip в grid.
Хоткеи Enter/Space/Esc сохранены.
- Match summary: tone-цветной icon plaque (success/destructive/accent),
ChallengeRow с pill-shaped check button.
== Анимации ==
- Spring физика везде где layout (Switch knob, Modal, Sidebar drawer,
карточки)
- active:scale-[0.97] на всех интерактивных элементах (iOS touch feel)
- Cross-fade между страницами через AnimatePresence
- Никаких glow / pulse-ring — apple style это сдержанность
Verified: typecheck OK, 23 tests pass, build 36.35 KB CSS (на 6 KB
меньше предыдущего HUD-стиля), 1.56 MB JS.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -5,60 +5,77 @@ export default {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
// iOS semantic palette
|
||||
accent: 'rgb(var(--accent) / <alpha-value>)',
|
||||
'accent-soft': 'rgb(var(--accent-soft) / <alpha-value>)',
|
||||
'accent-2': 'rgb(var(--accent-2) / <alpha-value>)',
|
||||
victory: 'rgb(var(--victory) / <alpha-value>)',
|
||||
defeat: 'rgb(var(--defeat) / <alpha-value>)',
|
||||
xp: 'rgb(var(--xp) / <alpha-value>)',
|
||||
success: 'rgb(var(--success) / <alpha-value>)',
|
||||
warning: 'rgb(var(--warning) / <alpha-value>)',
|
||||
destructive: 'rgb(var(--destructive) / <alpha-value>)',
|
||||
info: 'rgb(var(--info) / <alpha-value>)',
|
||||
|
||||
// Surfaces
|
||||
bg: 'rgb(var(--bg) / <alpha-value>)',
|
||||
'bg-deep': 'rgb(var(--bg-deep) / <alpha-value>)',
|
||||
surface: 'rgb(var(--surface) / <alpha-value>)',
|
||||
'surface-2': 'rgb(var(--surface-2) / <alpha-value>)',
|
||||
'surface-elevated': 'rgb(var(--surface-elevated) / <alpha-value>)',
|
||||
border: 'rgb(var(--border) / <alpha-value>)',
|
||||
|
||||
// Text & lines
|
||||
text: 'rgb(var(--text) / <alpha-value>)',
|
||||
muted: 'rgb(var(--muted) / <alpha-value>)'
|
||||
muted: 'rgb(var(--muted) / <alpha-value>)',
|
||||
hairline: 'rgb(var(--hairline) / <alpha-value>)',
|
||||
border: 'rgb(var(--border) / <alpha-value>)',
|
||||
|
||||
// Legacy aliases (so unchanged pages still compile)
|
||||
victory: 'rgb(var(--victory) / <alpha-value>)',
|
||||
defeat: 'rgb(var(--defeat) / <alpha-value>)',
|
||||
xp: 'rgb(var(--xp) / <alpha-value>)'
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'Segoe UI Variable', 'Segoe UI', 'system-ui', 'sans-serif'],
|
||||
display: ['Rajdhani', 'Inter', 'Segoe UI Variable', 'sans-serif'],
|
||||
mono: ['JetBrains Mono', 'ui-monospace', 'Cascadia Code', 'Menlo', 'monospace']
|
||||
sans: [
|
||||
'Geist',
|
||||
'-apple-system',
|
||||
'SF Pro Text',
|
||||
'Segoe UI Variable Text',
|
||||
'Segoe UI',
|
||||
'system-ui',
|
||||
'sans-serif'
|
||||
],
|
||||
display: [
|
||||
'Geist',
|
||||
'-apple-system',
|
||||
'SF Pro Display',
|
||||
'Segoe UI Variable Display',
|
||||
'system-ui',
|
||||
'sans-serif'
|
||||
],
|
||||
serif: [
|
||||
'Instrument Serif',
|
||||
'Iowan Old Style',
|
||||
'Apple Garamond',
|
||||
'Georgia',
|
||||
'serif'
|
||||
],
|
||||
mono: [
|
||||
'Geist Mono',
|
||||
'ui-monospace',
|
||||
'SF Mono',
|
||||
'Cascadia Code',
|
||||
'Menlo',
|
||||
'monospace'
|
||||
]
|
||||
},
|
||||
borderRadius: {
|
||||
// iOS-specific radii
|
||||
xl: '14px',
|
||||
'2xl': '18px',
|
||||
'3xl': '22px'
|
||||
},
|
||||
boxShadow: {
|
||||
soft: '0 8px 30px -12px rgb(0 0 0 / 0.35)',
|
||||
glow: '0 0 0 1px rgb(var(--accent) / 0.4), 0 8px 24px -8px rgb(var(--accent) / 0.55)',
|
||||
'glow-lg':
|
||||
'0 0 0 1px rgb(var(--accent) / 0.45), 0 18px 48px -12px rgb(var(--accent) / 0.7)',
|
||||
'glow-victory':
|
||||
'0 0 0 1px rgb(var(--victory) / 0.45), 0 12px 32px -10px rgb(var(--victory) / 0.55)',
|
||||
hud: '0 1px 0 rgb(var(--text) / 0.04) inset, 0 0 0 1px rgb(var(--border) / 0.8), 0 18px 40px -20px rgb(0 0 0 / 0.4)'
|
||||
},
|
||||
backgroundImage: {
|
||||
'gradient-brand':
|
||||
'linear-gradient(135deg, rgb(var(--accent)) 0%, rgb(var(--accent-2)) 100%)',
|
||||
'gradient-victory':
|
||||
'linear-gradient(135deg, rgb(var(--victory)) 0%, rgb(var(--accent)) 100%)',
|
||||
'gradient-defeat':
|
||||
'linear-gradient(135deg, rgb(var(--defeat)) 0%, rgb(var(--accent-2)) 100%)'
|
||||
},
|
||||
animation: {
|
||||
'pulse-ring': 'pulse-ring 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
shimmer: 'shimmer 2.5s linear infinite',
|
||||
'neon-shift': 'neon-shift 6s linear infinite'
|
||||
},
|
||||
keyframes: {
|
||||
'pulse-ring': {
|
||||
'0%, 100%': { transform: 'scale(1)', opacity: '0.7' },
|
||||
'50%': { transform: 'scale(1.1)', opacity: '0.25' }
|
||||
},
|
||||
shimmer: {
|
||||
'0%': { backgroundPosition: '-200% 0' },
|
||||
'100%': { backgroundPosition: '200% 0' }
|
||||
},
|
||||
'neon-shift': {
|
||||
'0%': { backgroundPosition: '0% 50%' },
|
||||
'100%': { backgroundPosition: '200% 50%' }
|
||||
}
|
||||
ios: '0 0.5px 0 rgb(0 0 0 / 0.04), 0 1px 2px rgb(0 0 0 / 0.05), 0 4px 12px rgb(0 0 0 / 0.04)',
|
||||
sheet:
|
||||
'0 1px 2px rgb(0 0 0 / 0.06), 0 20px 50px -16px rgb(0 0 0 / 0.4)'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user