Redesign v2: Solar Momentum — bold, bright, energetic

Design philosophy informed by skills review:
- canvas-design: Named aesthetic movement, craftsmanship emphasis
- frontend-design: Bold direction, distinctive typography, avoid AI slop
- frontend-patterns: Component composition, proper hooks
- theme-factory: Focused 4-color palettes with clear hierarchy

Changes:
- Palette: Deep orange (#FF5722) + vivid green (#00C853) + electric blue + purple
- Typography: Outfit (display, 900 weight) + Plus Jakarta Sans (body)
- Background: Warm gradient (peach → cream → light blue)
- Gate banner: 2.8rem hero numbers, thick gradient progress bars
- Activity checklist: Colored icon badges per category
- Cards: Larger radius (20px), warm shadows, tinted section backgrounds
- Login: Bold gradient hero (orange → dark), fire emoji brand
- Navigation: Orange active indicator bar, frosted glass backdrop
- Week view: Purple-themed hero with large stats
- Buttons: More shadow depth, active press scale animation
- All CSS variables renamed to semantic system (--orange, --green, --text-2)
- Zero orphaned old variable references
This commit is contained in:
claude 2026-03-15 11:11:23 +00:00
parent 22f5e8fae3
commit 080b7856b7
9 changed files with 566 additions and 552 deletions

View file

@ -6,66 +6,84 @@ export default function WeekView() {
const [loading, setLoading] = useState(true)
useEffect(() => { load() }, [])
async function load() {
try {
const data = await api.week()
setWeek(data)
} catch (err) { console.error(err) }
try { setWeek(await api.week()) }
catch (err) { console.error(err) }
finally { setLoading(false) }
}
if (loading) return <div className="page"><div className="loading">Loading...</div></div>
if (!week) return <div className="page"><div className="error-msg">Failed to load</div></div>
const dayNames = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
const pct = week.weekly_target > 0 ? Math.min(100, Math.round((week.total_points_earned / week.weekly_target) * 100)) : 0
const today = new Date().toISOString().split('T')[0]
return (
<div className="page">
<h1 className="page-title">📊 This Week</h1>
<h1 className="page-title">This Week</h1>
{/* Week summary */}
<div className="card" style={{ textAlign: 'center' }}>
<div style={{ fontSize: '2rem', fontWeight: 800 }}>{week.total_points_earned}</div>
<div style={{ color: 'var(--text-muted)', marginBottom: '8px' }}>/ {week.weekly_target} pts</div>
<div className="progress-bar">
<div className="progress-bar-fill" style={{ width: `${pct}%`, background: week.hit_weekly_target ? 'var(--success)' : 'var(--accent)' }} />
{/* Summary hero */}
<div className="card" style={{ textAlign: 'center', background: 'var(--purple-ghost)' }}>
<div className="section-label">Weekly Total</div>
<div style={{ fontFamily: 'var(--font-display)', fontSize: '2.6rem', fontWeight: 900, letterSpacing: '-0.03em' }}>
{week.total_points_earned}
</div>
<div style={{ color: 'var(--text-3)', fontWeight: 600, fontSize: '0.88rem', marginBottom: '12px' }}>
/ {week.weekly_target} pts
</div>
<div className="progress-bar" style={{ height: '12px' }}>
<div className="progress-bar-fill" style={{
width: `${pct}%`,
background: week.hit_weekly_target ? 'linear-gradient(90deg, #00C853, #69F0AE)' : 'linear-gradient(90deg, #7C4DFF, #B388FF)',
}} />
</div>
{week.hit_weekly_target && (
<div style={{ marginTop: '8px', color: 'var(--success)', fontWeight: 600 }}>
🏆 Weekly target hit! +{week.weekly_bonus_earned} bonus pts
<div style={{ marginTop: '10px', color: 'var(--green-dark)', fontWeight: 700, fontSize: '0.9rem' }}>
🏆 Target hit! +{week.weekly_bonus_earned} bonus
</div>
)}
<div style={{ display: 'flex', justifyContent: 'center', gap: '24px', marginTop: '12px', fontSize: '0.85rem' }}>
<div><span style={{ fontWeight: 700 }}>{week.active_days}</span> <span style={{ color: 'var(--text-muted)' }}>active days</span></div>
<div><span style={{ fontWeight: 700 }}>{week.gate_passed_days}</span> <span style={{ color: 'var(--text-muted)' }}>rewards earned</span></div>
<div style={{ display: 'flex', justifyContent: 'center', gap: '28px', marginTop: '14px' }}>
<div>
<div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: '1.3rem' }}>{week.active_days}</div>
<div style={{ fontSize: '0.72rem', color: 'var(--text-3)', fontWeight: 600 }}>active days</div>
</div>
<div>
<div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: '1.3rem' }}>{week.gate_passed_days}</div>
<div style={{ fontSize: '0.72rem', color: 'var(--text-3)', fontWeight: 600 }}>rewards earned</div>
</div>
</div>
</div>
{/* Daily breakdown */}
<div className="card">
<div style={{ fontWeight: 700, marginBottom: '12px' }}>Daily Breakdown</div>
<div className="section-label">Daily Breakdown</div>
{week.daily_breakdown.map((day, i) => {
const dayPct = day.daily_minimum > 0 ? Math.min(100, Math.round((day.points_earned / day.daily_minimum) * 100)) : 0
const isToday = day.date === new Date().toISOString().split('T')[0]
const isToday = day.date === today
return (
<div key={day.date} style={{ display: 'flex', alignItems: 'center', gap: '10px', padding: '8px 0', borderBottom: i < 6 ? '1px solid var(--border)' : 'none' }}>
<div style={{ width: '40px', fontWeight: isToday ? 700 : 400, color: isToday ? 'var(--accent)' : 'var(--text)' }}>
{dayNames[i]}
<div key={day.date} style={{
display: 'flex', alignItems: 'center', gap: '10px', padding: '10px 0',
borderBottom: i < 6 ? '1px solid var(--divider)' : 'none',
}}>
<div style={{
width: '38px', fontWeight: isToday ? 800 : 600, fontSize: '0.85rem',
color: isToday ? 'var(--orange)' : 'var(--text)',
}}>
{days[i]}
</div>
<div style={{ flex: 1 }}>
<div className="progress-bar" style={{ height: '6px' }}>
<div className="progress-bar" style={{ height: '8px' }}>
<div className="progress-bar-fill" style={{
width: `${dayPct}%`,
background: day.gate_passed ? 'var(--success)' : day.points_earned > 0 ? 'var(--warning)' : 'var(--border)',
background: day.gate_passed ? 'var(--green)' : day.points_earned > 0 ? 'var(--amber)' : 'transparent',
}} />
</div>
</div>
<div style={{ width: '50px', textAlign: 'right', fontSize: '0.85rem', fontWeight: 600 }}>
<div style={{ width: '46px', textAlign: 'right', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: '0.9rem' }}>
{day.points_earned}
</div>
<div style={{ width: '24px', textAlign: 'center' }}>
<div style={{ width: '22px', textAlign: 'center', fontSize: '0.9rem' }}>
{day.gate_passed ? '✅' : day.points_earned > 0 ? '🟡' : '⬜'}
</div>
</div>