|
| 1 | +<script lang="ts"> |
| 2 | + import * as Card from '$lib/components/ui/card'; |
| 3 | + import { Badge } from '$lib/components/ui/badge'; |
| 4 | + import { Separator } from '$lib/components/ui/separator'; |
| 5 | + import { Dumbbell, Info, Calendar } from 'lucide-svelte'; |
| 6 | + import * as Accordion from '$lib/components/ui/accordion'; |
| 7 | +
|
| 8 | + type WorkoutPlan = { |
| 9 | + fitness_level: string; |
| 10 | + plan_name: string; |
| 11 | + general_guidelines: string; |
| 12 | + weekly_schedule: Array<{ |
| 13 | + day: string; |
| 14 | + focus: string; |
| 15 | + exercises: Array<{ |
| 16 | + name: string; |
| 17 | + sets: number; |
| 18 | + reps: string; |
| 19 | + load: string; |
| 20 | + rest: string; |
| 21 | + tips: string; |
| 22 | + }>; |
| 23 | + cooldown: string; |
| 24 | + }>; |
| 25 | + days_per_week: number; |
| 26 | + }; |
| 27 | +
|
| 28 | + let { workoutPlan } = $props<{ workoutPlan: WorkoutPlan }>(); |
| 29 | +
|
| 30 | + function capitalize(str: string): string { |
| 31 | + return str |
| 32 | + .split('_') |
| 33 | + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) |
| 34 | + .join(' '); |
| 35 | + } |
| 36 | +</script> |
| 37 | + |
| 38 | +<Card.Root class="w-full overflow-hidden bg-card/95 backdrop-blur-sm border-primary/10"> |
| 39 | + <Card.Header class="bg-muted/30"> |
| 40 | + <div class="flex items-center justify-between"> |
| 41 | + <div class="space-y-1.5"> |
| 42 | + <Card.Title class="text-xl font-bold bg-gradient-to-br from-primary to-primary-foreground bg-clip-text text-transparent"> |
| 43 | + {workoutPlan.plan_name} |
| 44 | + </Card.Title> |
| 45 | + <Card.Description> |
| 46 | + <div class="flex items-center gap-2"> |
| 47 | + <Badge variant="secondary" class="bg-primary/10 text-primary hover:bg-primary/20"> |
| 48 | + {capitalize(workoutPlan.fitness_level)} Level |
| 49 | + </Badge> |
| 50 | + <Badge variant="outline" class="gap-1"> |
| 51 | + <Calendar class="h-3 w-3" /> |
| 52 | + {workoutPlan.days_per_week} days/week |
| 53 | + </Badge> |
| 54 | + </div> |
| 55 | + </Card.Description> |
| 56 | + </div> |
| 57 | + <div class="rounded-full bg-primary/10 p-3 ring-1 ring-primary/20"> |
| 58 | + <Dumbbell class="h-6 w-6 text-primary" /> |
| 59 | + </div> |
| 60 | + </div> |
| 61 | + </Card.Header> |
| 62 | + |
| 63 | + <Card.Content class="space-y-6 p-6"> |
| 64 | + <div class="space-y-2"> |
| 65 | + <div class="flex items-center gap-2 text-sm font-medium text-primary"> |
| 66 | + <Info class="h-4 w-4" /> |
| 67 | + General Guidelines |
| 68 | + </div> |
| 69 | + <p class="whitespace-pre-line text-sm text-muted-foreground leading-relaxed"> |
| 70 | + {workoutPlan.general_guidelines} |
| 71 | + </p> |
| 72 | + </div> |
| 73 | + |
| 74 | + <Separator class="bg-primary/10" /> |
| 75 | + |
| 76 | + <Accordion.Root class="w-full" type="single"> |
| 77 | + {#each workoutPlan.weekly_schedule as day} |
| 78 | + <Accordion.Item value={day.day} class="border-primary/10"> |
| 79 | + <Accordion.Trigger class="hover:bg-muted/50"> |
| 80 | + <div class="flex items-center gap-4"> |
| 81 | + <span class="font-medium text-primary">{day.day}</span> |
| 82 | + <Badge variant="outline" class="bg-background/50">{day.focus}</Badge> |
| 83 | + </div> |
| 84 | + </Accordion.Trigger> |
| 85 | + <Accordion.Content> |
| 86 | + <div class="space-y-4 p-4"> |
| 87 | + <div class="grid gap-4"> |
| 88 | + {#each day.exercises as exercise} |
| 89 | + <div class="rounded-lg border border-primary/10 bg-card/50 p-4 hover:bg-muted/30 transition-colors"> |
| 90 | + <div class="flex items-center justify-between"> |
| 91 | + <h4 class="font-medium text-primary">{exercise.name}</h4> |
| 92 | + <Badge class="bg-primary/10 text-primary hover:bg-primary/20">{exercise.load}</Badge> |
| 93 | + </div> |
| 94 | + <div class="mt-2 grid grid-cols-3 gap-2 text-sm text-muted-foreground"> |
| 95 | + <div> |
| 96 | + <span class="font-medium text-foreground">Sets:</span> |
| 97 | + {exercise.sets} |
| 98 | + </div> |
| 99 | + <div> |
| 100 | + <span class="font-medium text-foreground">Reps:</span> |
| 101 | + {exercise.reps} |
| 102 | + </div> |
| 103 | + <div> |
| 104 | + <span class="font-medium text-foreground">Rest:</span> |
| 105 | + {exercise.rest} |
| 106 | + </div> |
| 107 | + </div> |
| 108 | + {#if exercise.tips} |
| 109 | + <p class="mt-2 text-xs text-muted-foreground">💡 {exercise.tips}</p> |
| 110 | + {/if} |
| 111 | + </div> |
| 112 | + {/each} |
| 113 | + </div> |
| 114 | + <div class="rounded-lg bg-muted/30 p-3 text-sm border border-primary/10"> |
| 115 | + <span class="font-medium text-primary">Cooldown:</span> |
| 116 | + <span class="text-muted-foreground"> {day.cooldown}</span> |
| 117 | + </div> |
| 118 | + </div> |
| 119 | + </Accordion.Content> |
| 120 | + </Accordion.Item> |
| 121 | + {/each} |
| 122 | + </Accordion.Root> |
| 123 | + </Card.Content> |
| 124 | +</Card.Root> |
0 commit comments