2025-09-03 16:05:08 +02:00
|
|
|
<script lang="ts">
|
|
|
|
|
import { onMount } from 'svelte';
|
|
|
|
|
import ExerciseField from './ExerciseField.svelte';
|
2025-09-03 18:20:08 +02:00
|
|
|
import { getTodayDateString, exampleWorkout, type WorkoutData, exercises } from '$lib/workout';
|
|
|
|
|
import { getTodaysWorkout, saveWorkout } from './workout.remote';
|
2025-09-03 19:10:17 +02:00
|
|
|
import { fade } from 'svelte/transition';
|
2025-09-03 16:05:08 +02:00
|
|
|
|
|
|
|
|
let todayDate = getTodayDateString();
|
|
|
|
|
|
|
|
|
|
// Form state
|
2025-09-03 19:10:17 +02:00
|
|
|
let form: WorkoutData = $state({
|
2025-09-03 16:05:08 +02:00
|
|
|
pushups: 0,
|
|
|
|
|
situps: 0,
|
|
|
|
|
plankSeconds: 0,
|
|
|
|
|
hangups: 0,
|
|
|
|
|
runKm: 0
|
2025-09-03 19:10:17 +02:00
|
|
|
});
|
2025-09-03 16:05:08 +02:00
|
|
|
|
|
|
|
|
onMount(async () => {
|
|
|
|
|
const result = await getTodaysWorkout();
|
|
|
|
|
form = result.data ?? form;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function loadExample() {
|
|
|
|
|
form = { ...exampleWorkout };
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<div class="mx-auto max-w-md rounded-lg bg-white p-6 shadow-lg">
|
|
|
|
|
<!-- Header -->
|
|
|
|
|
<header class="mb-6 text-center">
|
|
|
|
|
<h2 class="text-2xl font-bold text-gray-800">Log Today's Workout</h2>
|
|
|
|
|
<div class="mt-2 text-gray-600">📅 {todayDate}</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<!-- Main Form -->
|
|
|
|
|
<form {...saveWorkout}>
|
2025-09-03 18:20:08 +02:00
|
|
|
<!-- Exercise Fields -->
|
|
|
|
|
{#each exercises as { config, key }}
|
2025-09-03 19:10:17 +02:00
|
|
|
<ExerciseField {...config} bind:value={form[key]} />
|
2025-09-03 18:20:08 +02:00
|
|
|
{/each}
|
2025-09-03 16:05:08 +02:00
|
|
|
|
|
|
|
|
<!-- Action Buttons -->
|
|
|
|
|
<div class="mb-4 flex space-x-3">
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
class="flex-1 rounded-md bg-blue-600 px-4 py-2 font-medium text-white hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
|
|
>
|
2025-09-03 18:20:08 +02:00
|
|
|
{#if saveWorkout.pending !== 0}
|
|
|
|
|
Loading...
|
|
|
|
|
{:else}
|
|
|
|
|
💾 Save Workout
|
|
|
|
|
{/if}
|
2025-09-03 16:05:08 +02:00
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
<!-- Message Display -->
|
|
|
|
|
{#if saveWorkout.result?.success}
|
|
|
|
|
<div
|
2025-09-03 19:10:17 +02:00
|
|
|
transition:fade={{ duration: 300 }}
|
2025-09-03 16:05:08 +02:00
|
|
|
class="mb-4 rounded-md border border-green-200 bg-green-100 p-3 text-sm font-medium text-green-800"
|
|
|
|
|
role="alert"
|
|
|
|
|
>
|
|
|
|
|
{saveWorkout.result.message}
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<!-- Example Section -->
|
|
|
|
|
<section class="rounded-md bg-gray-50 p-4">
|
|
|
|
|
<h3 class="mb-2 text-sm font-medium text-gray-700">Quick Example:</h3>
|
|
|
|
|
<div class="space-y-1 text-sm text-gray-600">
|
|
|
|
|
<div>💪 Push-ups: {exampleWorkout.pushups}</div>
|
|
|
|
|
<div>🏋️ Sit-ups: {exampleWorkout.situps}</div>
|
|
|
|
|
<div>🧘 Plank: {exampleWorkout.plankSeconds} seconds</div>
|
|
|
|
|
<div>🏃 Running: {exampleWorkout.runKm} km</div>
|
|
|
|
|
<div>☕ Hangups: {exampleWorkout.hangups}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onclick={loadExample}
|
|
|
|
|
class="mt-2 rounded bg-gray-200 px-2 py-1 text-xs text-gray-700 hover:bg-gray-300 focus:ring-2 focus:ring-gray-500 focus:outline-none"
|
|
|
|
|
>
|
|
|
|
|
Load Example
|
|
|
|
|
</button>
|
|
|
|
|
</section>
|
|
|
|
|
</div>
|