Design overhaul: Dark fitness theme, no emojis
CSS: - Dark background (#0a0a0f, #0d0d12, #15151b) - Orange accent (#ff6b35) - Muted text (#a1a1aa, #71717a) - Inter font from Google Fonts - Workout type colors (push/pull/legs/etc) Dashboard: - Calendar dots are CSS circles, not emoji - Coach avatar uses SVG icon - All emojis replaced with Icons.jsx SVGs - Navigation uses proper icons WorkoutPage: - Warmup exercises without emojis - Check icons instead of emoji checkmarks - Arrow icons for navigation - Fire icon for warmup section Professional fitness app aesthetic inspired by Nike/FITBOD
This commit is contained in:
+4
-1
@@ -4,9 +4,12 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name="theme-color" content="#1a1a2e" />
|
<meta name="theme-color" content="#0a0a0f" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<title>Gravl - Träning</title>
|
<title>Gravl - Träning</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
+40
-14
@@ -461,15 +461,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.coach-avatar {
|
.coach-avatar {
|
||||||
font-size: 2.5rem;
|
width: 52px;
|
||||||
width: 60px;
|
height: 52px;
|
||||||
height: 60px;
|
background: rgba(255,255,255,0.15);
|
||||||
background: rgba(255,255,255,0.2);
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
color: rgba(255,255,255,0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.coach-message {
|
.coach-message {
|
||||||
@@ -549,13 +549,6 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day.has-workout .day-dot {
|
|
||||||
color: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-day.today .day-dot {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.day-name {
|
.day-name {
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -574,10 +567,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.day-dot {
|
.day-dot {
|
||||||
font-size: 0.5rem;
|
width: 4px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--success);
|
||||||
margin-top: 0.25rem;
|
margin-top: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendar-day.today .day-dot {
|
||||||
|
background: rgba(255,255,255,0.8);
|
||||||
|
}
|
||||||
|
|
||||||
/* Today's Workout */
|
/* Today's Workout */
|
||||||
.todays-workout {
|
.todays-workout {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -731,6 +731,19 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stat-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Brand title with icon */
|
||||||
|
.brand-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* Upcoming Workouts */
|
/* Upcoming Workouts */
|
||||||
.upcoming-workouts h2 {
|
.upcoming-workouts h2 {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
@@ -818,6 +831,9 @@
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Page Main */
|
/* Page Main */
|
||||||
@@ -1242,7 +1258,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.warmup-icon {
|
.warmup-icon {
|
||||||
font-size: 1.5rem;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.warmup-title h2 {
|
.warmup-title h2 {
|
||||||
@@ -1260,7 +1278,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.expand-icon {
|
.expand-icon {
|
||||||
font-size: 0.75rem;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
transition: transform 0.2s;
|
transition: transform 0.2s;
|
||||||
}
|
}
|
||||||
@@ -1362,6 +1381,10 @@
|
|||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.warmup-done-btn:hover {
|
.warmup-done-btn:hover {
|
||||||
@@ -1573,6 +1596,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tip-badge {
|
.tip-badge {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.4rem;
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
padding: 0.5rem 0.75rem;
|
padding: 0.5rem 0.75rem;
|
||||||
|
|||||||
+38
-12
@@ -5,21 +5,43 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bg-primary: #0f0f1a;
|
/* Dark fitness palette */
|
||||||
--bg-secondary: #1a1a2e;
|
--bg-primary: #0a0a0f;
|
||||||
--bg-card: #16213e;
|
--bg-secondary: #0d0d12;
|
||||||
--bg-card-hover: #1f3460;
|
--bg-card: #15151b;
|
||||||
--text-primary: #eaeaea;
|
--bg-card-hover: #1a1a22;
|
||||||
--text-secondary: #a0a0a0;
|
--bg: #0a0a0f;
|
||||||
--accent: #e94560;
|
|
||||||
--accent-hover: #ff6b6b;
|
/* Text colors */
|
||||||
--success: #4ecca3;
|
--text-primary: #ffffff;
|
||||||
--warning: #ffd93d;
|
--text-secondary: #a1a1aa;
|
||||||
--border: #2a2a4a;
|
--text-muted: #71717a;
|
||||||
|
--text: #ffffff;
|
||||||
|
|
||||||
|
/* Accent - energetic orange */
|
||||||
|
--accent: #ff6b35;
|
||||||
|
--accent-hover: #ff8555;
|
||||||
|
|
||||||
|
/* Status colors */
|
||||||
|
--success: #22c55e;
|
||||||
|
--warning: #f59e0b;
|
||||||
|
--error: #ef4444;
|
||||||
|
|
||||||
|
/* Border */
|
||||||
|
--border: #1f1f28;
|
||||||
|
|
||||||
|
/* Workout type colors - muted, professional */
|
||||||
|
--workout-push: #ef4444;
|
||||||
|
--workout-pull: #3b82f6;
|
||||||
|
--workout-legs: #22c55e;
|
||||||
|
--workout-shoulders: #f59e0b;
|
||||||
|
--workout-upper: #8b5cf6;
|
||||||
|
--workout-lower: #06b6d4;
|
||||||
|
--workout-default: #ff6b35;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
||||||
background: var(--bg-primary);
|
background: var(--bg-primary);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
@@ -27,6 +49,10 @@ html, body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ function Dashboard({ onStartWorkout, onNavigate }) {
|
|||||||
>
|
>
|
||||||
<span className="day-name">{name}</span>
|
<span className="day-name">{name}</span>
|
||||||
<span className="day-date">{date.getDate()}</span>
|
<span className="day-date">{date.getDate()}</span>
|
||||||
{hasWorkout && <span className="day-dot"></span>}
|
{hasWorkout && <span className="day-dot" />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
|
import { Icon } from '../components/Icons'
|
||||||
|
|
||||||
// Uppvärmningsövningar baserat på muskelgrupp
|
// Uppvärmningsövningar baserat på muskelgrupp
|
||||||
const warmupExercises = {
|
const warmupExercises = {
|
||||||
general: [
|
general: [
|
||||||
{ name: 'Cykel eller roddmaskin', duration: '5 min', icon: '🚴' },
|
{ name: 'Cykel eller roddmaskin', duration: '5 min' },
|
||||||
{ name: 'Armcirklar', duration: '30 sek/riktning', icon: '🔄' },
|
{ name: 'Armcirklar', duration: '30 sek/riktning' },
|
||||||
{ name: 'Bensvingar (framåt/bakåt)', duration: '10 per ben', icon: '🦵' },
|
{ name: 'Bensvingar (framåt/bakåt)', duration: '10 per ben' },
|
||||||
{ name: 'Bensvingar (sidled)', duration: '10 per ben', icon: '🦵' },
|
{ name: 'Bensvingar (sidled)', duration: '10 per ben' },
|
||||||
{ name: 'Höftcirklar', duration: '10 per riktning', icon: '⭕' },
|
{ name: 'Höftcirklar', duration: '10 per riktning' },
|
||||||
],
|
],
|
||||||
specific: {
|
specific: {
|
||||||
'Bröst': [
|
'Bröst': [
|
||||||
@@ -97,7 +98,9 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
return (
|
return (
|
||||||
<div className="workout-page">
|
<div className="workout-page">
|
||||||
<header className="page-header">
|
<header className="page-header">
|
||||||
<button className="back-btn" onClick={onBack}>← Tillbaka</button>
|
<button className="back-btn" onClick={onBack}>
|
||||||
|
<Icon name="arrowLeft" size={16} /> Tillbaka
|
||||||
|
</button>
|
||||||
<div className="header-center">
|
<div className="header-center">
|
||||||
<h1>{day.name}</h1>
|
<h1>{day.name}</h1>
|
||||||
<span className="header-subtitle">Vecka {week} • Dag {day.day_number}</span>
|
<span className="header-subtitle">Vecka {week} • Dag {day.day_number}</span>
|
||||||
@@ -123,11 +126,13 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
onClick={() => setWarmupExpanded(!warmupExpanded)}
|
onClick={() => setWarmupExpanded(!warmupExpanded)}
|
||||||
>
|
>
|
||||||
<div className="warmup-title">
|
<div className="warmup-title">
|
||||||
<span className="warmup-icon">🔥</span>
|
<span className="warmup-icon"><Icon name="fire" size={20} /></span>
|
||||||
<h2>Uppvärmning</h2>
|
<h2>Uppvärmning</h2>
|
||||||
<span className="warmup-progress">{warmupProgress}/{totalWarmups}</span>
|
<span className="warmup-progress">{warmupProgress}/{totalWarmups}</span>
|
||||||
</div>
|
</div>
|
||||||
<span className={`expand-icon ${warmupExpanded ? 'expanded' : ''}`}>▼</span>
|
<span className={`expand-icon ${warmupExpanded ? 'expanded' : ''}`}>
|
||||||
|
<Icon name="chevronDown" size={16} />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{warmupExpanded && (
|
{warmupExpanded && (
|
||||||
@@ -143,9 +148,8 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
onClick={() => toggleWarmup(idx)}
|
onClick={() => toggleWarmup(idx)}
|
||||||
>
|
>
|
||||||
<span className="warmup-check">
|
<span className="warmup-check">
|
||||||
{completedWarmups.has(idx) ? '✓' : '○'}
|
{completedWarmups.has(idx) ? <Icon name="check" size={14} /> : ''}
|
||||||
</span>
|
</span>
|
||||||
<span className="warmup-item-icon">{warmup.icon}</span>
|
|
||||||
<span className="warmup-name">{warmup.name}</span>
|
<span className="warmup-name">{warmup.name}</span>
|
||||||
<span className="warmup-duration">{warmup.duration || warmup.reps}</span>
|
<span className="warmup-duration">{warmup.duration || warmup.reps}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -167,7 +171,7 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
onClick={() => toggleWarmup(globalIdx)}
|
onClick={() => toggleWarmup(globalIdx)}
|
||||||
>
|
>
|
||||||
<span className="warmup-check">
|
<span className="warmup-check">
|
||||||
{completedWarmups.has(globalIdx) ? '✓' : '○'}
|
{completedWarmups.has(globalIdx) ? <Icon name="check" size={14} /> : ''}
|
||||||
</span>
|
</span>
|
||||||
<span className="warmup-name">{warmup.name}</span>
|
<span className="warmup-name">{warmup.name}</span>
|
||||||
<span className="warmup-duration">{warmup.reps}</span>
|
<span className="warmup-duration">{warmup.reps}</span>
|
||||||
@@ -196,10 +200,10 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="warmup-check">
|
<span className="warmup-check">
|
||||||
{completedWarmups.has('prep') ? '✓' : '○'}
|
{completedWarmups.has('prep') ? <Icon name="check" size={14} /> : ''}
|
||||||
</span>
|
</span>
|
||||||
<span className="warmup-name">Lätta set {exercises[0].name}</span>
|
<span className="warmup-name">Lätta set {exercises[0].name}</span>
|
||||||
<span className="warmup-duration">2×10 @ 50%</span>
|
<span className="warmup-duration">2x10 @ 50%</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -209,7 +213,11 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
className={`warmup-done-btn ${warmupDone ? 'completed' : ''}`}
|
className={`warmup-done-btn ${warmupDone ? 'completed' : ''}`}
|
||||||
onClick={() => setWarmupDone(!warmupDone)}
|
onClick={() => setWarmupDone(!warmupDone)}
|
||||||
>
|
>
|
||||||
{warmupDone ? '✓ Uppvärmning klar!' : 'Markera uppvärmning som klar'}
|
{warmupDone ? (
|
||||||
|
<><Icon name="check" size={18} /> Uppvärmning klar</>
|
||||||
|
) : (
|
||||||
|
'Markera uppvärmning som klar'
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -239,7 +247,7 @@ function WorkoutPage({ day, week, logs, onLogSet, onBack, fetchProgression }) {
|
|||||||
onClick={onBack}
|
onClick={onBack}
|
||||||
>
|
>
|
||||||
{completedExercises === exercises.length
|
{completedExercises === exercises.length
|
||||||
? '🎉 Avsluta pass'
|
? 'Avsluta pass'
|
||||||
: `Avsluta pass (${completedExercises}/${exercises.length} klara)`}
|
: `Avsluta pass (${completedExercises}/${exercises.length} klara)`}
|
||||||
</button>
|
</button>
|
||||||
</main>
|
</main>
|
||||||
@@ -302,9 +310,9 @@ function ExerciseCard({ exercise, logs, progression, expanded, onToggle, onLogSe
|
|||||||
<div className="exercise-body">
|
<div className="exercise-body">
|
||||||
{progression && (
|
{progression && (
|
||||||
<div className="progression-hint">
|
<div className="progression-hint">
|
||||||
💡 {progression.reason}
|
{progression.reason}
|
||||||
{progression.suggestedWeight && (
|
{progression.suggestedWeight && (
|
||||||
<strong> → {progression.suggestedWeight} kg</strong>
|
<strong> {progression.suggestedWeight} kg</strong>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -338,7 +346,7 @@ function ExerciseCard({ exercise, logs, progression, expanded, onToggle, onLogSe
|
|||||||
className={`complete-btn ${input.completed ? 'done' : ''}`}
|
className={`complete-btn ${input.completed ? 'done' : ''}`}
|
||||||
onClick={() => handleComplete(setNum)}
|
onClick={() => handleComplete(setNum)}
|
||||||
>
|
>
|
||||||
{input.completed ? '✓' : '○'}
|
{input.completed ? <Icon name="check" size={18} /> : ''}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user