design: WorkoutPage Hevy-style redesign + AlternativeModal + backend API
- Add GET /api/exercises/:id/alternatives endpoint - Add GET /api/exercises/:id/last-workout endpoint - New AlternativeModal component for swapping exercises - WorkoutPage: single-tap logging, +/- buttons, rest timer - Updated Icons with new workout icons - Polish: card shadows, borders, micro-interactions - Tasks directory for project management
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { Icon } from './Icons'
|
||||
|
||||
function AlternativeModal({ exercise, alternatives, loading, error, onSelect, onClose }) {
|
||||
if (!exercise) return null
|
||||
|
||||
return (
|
||||
<div className="alternative-modal-overlay" onClick={onClose}>
|
||||
<div className="alternative-modal" onClick={(event) => event.stopPropagation()}>
|
||||
<div className="alternative-modal-header">
|
||||
<div>
|
||||
<h3>Alternativa övningar</h3>
|
||||
<p>För {exercise.name}</p>
|
||||
</div>
|
||||
<button className="alternative-modal-close" onClick={onClose} aria-label="Stäng">
|
||||
<Icon name="chevronDown" size={18} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{loading && (
|
||||
<div className="alternative-modal-state">Laddar alternativ...</div>
|
||||
)}
|
||||
|
||||
{!loading && error && (
|
||||
<div className="alternative-modal-state error">{error}</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && alternatives.length === 0 && (
|
||||
<div className="alternative-modal-state">Inga alternativ hittades.</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && alternatives.length > 0 && (
|
||||
<div className="alternative-list">
|
||||
{alternatives.map((alt) => (
|
||||
<div key={alt.id} className="alternative-item">
|
||||
<div className="alternative-info">
|
||||
<strong>{alt.name}</strong>
|
||||
<span>{alt.description || 'Ingen beskrivning tillgänglig.'}</span>
|
||||
</div>
|
||||
<button className="alternative-select-btn" onClick={() => onSelect(alt)}>
|
||||
Välj
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AlternativeModal
|
||||
@@ -62,6 +62,14 @@ export const Icons = {
|
||||
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||
</svg>
|
||||
),
|
||||
swap: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="7 7 3 11 7 15"/>
|
||||
<polyline points="17 9 21 13 17 17"/>
|
||||
<line x1="3" y1="11" x2="21" y2="11"/>
|
||||
<line x1="3" y1="13" x2="21" y2="13"/>
|
||||
</svg>
|
||||
),
|
||||
check: (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="20 6 9 17 4 12"/>
|
||||
|
||||
Reference in New Issue
Block a user