first commit

This commit is contained in:
2025-10-02 22:52:13 +03:00
commit 5d8d08d2f4
137 changed files with 18187 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
<x-app-layout>
<section class="bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-8">
<div class="flex items-start justify-between flex-col lg:flex-row gap-6">
<div>
<h1 class="text-2xl sm:text-3xl font-extrabold tracking-tight text-gray-900 dark:text-white">Browse Exercises</h1>
<p class="mt-2 text-gray-600 dark:text-gray-300">Explore the full FitAtlas library. Filter by body part, muscle, or equipment.</p>
</div>
</div>
</div>
</section>
<section class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-6">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- Filters -->
<aside class="lg:col-span-12">
<form action="{{ route('exercises.index') }}" method="GET" class="space-y-4 lg:space-y-0 lg:flex lg:flex-wrap lg:items-end lg:gap-4 bg-white dark:bg-gray-800 rounded-2xl p-4 ring-1 ring-gray-200 dark:ring-gray-700">
<div class="w-full lg:w-72">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Search</label>
<input type="text" name="q" value="{{ $filters['q'] ?? '' }}" placeholder="Search by name or instruction" class="mt-1 w-full rounded-xl border-gray-300 dark:border-gray-700 bg-white/80 dark:bg-gray-900 text-gray-900 dark:text-gray-100 placeholder-gray-400 focus:border-indigo-500 focus:ring-indigo-500 px-3 py-2">
</div>
<div class="w-full lg:w-56">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Body Part</label>
<select name="bodypart" class="mt-1 w-full rounded-xl border-gray-300 dark:border-gray-700 bg-white/80 dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:border-indigo-500 focus:ring-indigo-500 px-3 py-2">
<option value="">Any</option>
@foreach($bodyParts as $bp)
<option value="{{ $bp->slug }}" @selected(($filters['bodypart'] ?? '') === $bp->slug)>{{ $bp->name }}</option>
@endforeach
</select>
</div>
<div class="w-full lg:w-56">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Muscle</label>
<select name="muscle" class="mt-1 w-full rounded-xl border-gray-300 dark:border-gray-700 bg-white/80 dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:border-indigo-500 focus:ring-indigo-500 px-3 py-2">
<option value="">Any</option>
@foreach($muscles as $m)
<option value="{{ $m->slug }}" @selected(($filters['muscle'] ?? '') === $m->slug)>{{ $m->name }}</option>
@endforeach
</select>
</div>
<div class="w-full lg:w-56">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">Equipment</label>
<select name="equipment" class="mt-1 w-full rounded-xl border-gray-300 dark:border-gray-700 bg-white/80 dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:border-indigo-500 focus:ring-indigo-500 px-3 py-2">
<option value="">Any</option>
@foreach($equipments as $e)
<option value="{{ $e->slug }}" @selected(($filters['equipment'] ?? '') === $e->slug)>{{ $e->name }}</option>
@endforeach
</select>
</div>
<div class="w-full lg:w-auto flex items-center justify-between lg:justify-end gap-2 lg:ml-auto">
<a href="{{ route('exercises.index') }}" class="text-sm text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white">Reset</a>
<button type="submit" class="inline-flex items-center rounded-xl bg-gradient-to-r from-fuchsia-600 to-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow hover:from-fuchsia-500 hover:to-indigo-500">Apply Filters</button>
</div>
</form>
</aside>
<!-- Results -->
<div class="lg:col-span-12">
<div class="flex items-center justify-between mb-4">
<p class="text-sm text-gray-600 dark:text-gray-300">Showing <span class="font-medium">{{ $exercises->total() }}</span> exercises</p>
<div class="flex items-center gap-2">
<label class="text-sm text-gray-600 dark:text-gray-300">Per page</label>
<select name="per_page" form="per-page-form" class="rounded-lg border-gray-300 dark:border-gray-700 bg-white/80 dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:border-indigo-500 focus:ring-indigo-500 px-2 py-1">
@foreach([12, 24, 36] as $n)
<option value="{{ $n }}" @selected(($filters['per_page'] ?? 12) == $n)>{{ $n }}</option>
@endforeach
</select>
<form id="per-page-form" action="{{ route('exercises.index') }}" method="GET" class="hidden">
@foreach(request()->except('per_page') as $k => $v)
<input type="hidden" name="{{ $k }}" value="{{ $v }}">
@endforeach
<input type="hidden" name="per_page" value="{{ $filters['per_page'] ?? 12 }}">
</form>
<script>
document.addEventListener('change', (e) => {
if (e.target && e.target.name === 'per_page') {
const form = document.getElementById('per-page-form');
form.querySelector('input[name="per_page"]').value = e.target.value;
form.submit();
}
});
</script>
</div>
</div>
@if($exercises->count() === 0)
<div class="rounded-2xl border border-dashed border-gray-300 dark:border-gray-700 p-8 text-center text-gray-600 dark:text-gray-300">No exercises found. Try adjusting your filters.</div>
@else
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
@php $badgePalette = ['bg-rose-100 text-rose-700','bg-amber-100 text-amber-700','bg-emerald-100 text-emerald-700','bg-sky-100 text-sky-700','bg-violet-100 text-violet-700']; @endphp
@foreach($exercises as $exercise)
<a href="{{ route('exercises.show', $exercise->slug) }}" class="group rounded-3xl overflow-hidden bg-white dark:bg-gray-800 ring-1 ring-gray-200 dark:ring-gray-700 shadow-sm hover:shadow-xl transition">
<div class="relative aspect-[16/9] overflow-hidden">
<img src="{{ $exercise->gif_url ?: 'https://images.unsplash.com/photo-1517836357463-d25dfeac3438?q=80&w=1200&auto=format&fit=crop' }}" alt="{{ $exercise->name }}" class="h-full w-full object-cover transition-transform duration-500 group-hover:scale-105">
<div class="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent"></div>
<div class="absolute bottom-3 left-3 inline-flex items-center rounded-full bg-white/90 px-3 py-1 text-xs font-semibold text-gray-900 shadow">{{ $exercise->name }}</div>
</div>
<div class="p-4">
<div class="mt-1 flex flex-wrap gap-2">
@foreach($exercise->targetMuscles->take(2) as $i => $m)
<span class="inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium {{ $badgePalette[$i % count($badgePalette)] }}">{{ $m->name }}</span>
@endforeach
@if($exercise->bodyParts->count())
<span class="inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-200">{{ $exercise->bodyParts->first()->name }}</span>
@endif
</div>
</div>
</a>
@endforeach
</div>
<div class="mt-6">{{ $exercises->links() }}</div>
@endif
</div>
</div>
</section>
</x-app-layout>
+75
View File
@@ -0,0 +1,75 @@
<x-app-layout>
<section class="relative overflow-hidden">
<div class="absolute inset-0">
<img src="{{ $exercise->gif_url ?: 'https://images.unsplash.com/photo-1517836357463-d25dfeac3438?q=80&w=1920&auto=format&fit=crop' }}" alt="{{ $exercise->name }}" class="h-full w-full object-cover">
<div class="absolute inset-0 bg-gradient-to-b from-indigo-900/70 via-indigo-800/60 to-transparent"></div>
</div>
<div class="relative mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-16 sm:py-24">
<a href="{{ url()->previous() ?? route('exercises.index') }}" class="inline-flex items-center text-sm font-medium text-white/90 hover:text-white">
&#8592; Back
</a>
<h1 class="mt-3 text-3xl sm:text-5xl font-extrabold tracking-tight text-white drop-shadow">{{ $exercise->name }}</h1>
<div class="mt-4 flex flex-wrap items-center gap-2">
@foreach($exercise->bodyParts as $bp)
<span class="inline-flex items-center rounded-full bg-white/90 px-3 py-1 text-xs font-semibold text-gray-900 shadow">{{ $bp->name }}</span>
@endforeach
@foreach($exercise->targetMuscles as $m)
<span class="inline-flex items-center rounded-full bg-emerald-100 text-emerald-700 px-2.5 py-1 text-xs font-semibold">Target: {{ $m->name }}</span>
@endforeach
@foreach($exercise->secondaryMuscles as $m)
<span class="inline-flex items-center rounded-full bg-sky-100 text-sky-700 px-2.5 py-1 text-xs font-semibold">Secondary: {{ $m->name }}</span>
@endforeach
@foreach($exercise->equipments as $e)
<span class="inline-flex items-center rounded-full bg-amber-100 text-amber-700 px-2.5 py-1 text-xs font-semibold">{{ ucfirst($e->name) }}</span>
@endforeach
</div>
</div>
</section>
<section class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-10">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-8">
<div class="lg:col-span-8">
<div class="rounded-3xl overflow-hidden ring-1 ring-gray-200 dark:ring-gray-700 bg-white dark:bg-gray-800">
<div class="relative aspect-[16/9] bg-black">
<img src="{{ $exercise->gif_url ?: 'https://images.unsplash.com/photo-1517836357463-d25dfeac3438?q=80&w=1600&auto=format&fit=crop' }}" alt="{{ $exercise->name }} demo" class="h-full w-full object-cover">
</div>
<div class="p-6">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">How to perform</h2>
<div class="prose prose-indigo dark:prose-invert max-w-none mt-3">
@php $instructions = trim((string) $exercise->instructions); @endphp
@if($instructions !== '')
@foreach(preg_split('/\r?\n+/', $instructions) as $line)
@if(trim($line) !== '')<p>{{ $line }}</p>@endif
@endforeach
@else
<p>No instructions available.</p>
@endif
</div>
</div>
</div>
</div>
<div class="lg:col-span-4">
<div class="rounded-2xl p-5 ring-1 ring-gray-200 dark:ring-gray-700 bg-white dark:bg-gray-800">
<h3 class="text-sm font-semibold text-gray-900 dark:text-white">Exercise Info</h3>
<dl class="mt-3 space-y-2 text-sm text-gray-700 dark:text-gray-300">
@if($exercise->bodyParts->count())
<div class="flex justify-between"><dt>Body Part</dt><dd>{{ $exercise->bodyParts->pluck('name')->join(', ') }}</dd></div>
@endif
@if($exercise->targetMuscles->count())
<div class="flex justify-between"><dt>Target Muscles</dt><dd>{{ $exercise->targetMuscles->pluck('name')->join(', ') }}</dd></div>
@endif
@if($exercise->secondaryMuscles->count())
<div class="flex justify-between"><dt>Secondary Muscles</dt><dd>{{ $exercise->secondaryMuscles->pluck('name')->join(', ') }}</dd></div>
@endif
@if($exercise->equipments->count())
<div class="flex justify-between"><dt>Equipment</dt><dd>{{ $exercise->equipments->pluck('name')->join(', ') }}</dd></div>
@endif
</dl>
<div class="mt-5">
<a href="{{ route('workouts.builder') }}" class="inline-flex items-center rounded-xl bg-gradient-to-r from-fuchsia-600 to-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow hover:from-fuchsia-500 hover:to-indigo-500">Add to Workout</a>
</div>
</div>
</div>
</div>
</section>
</x-app-layout>