228 lines
15 KiB
PHP
228 lines
15 KiB
PHP
<x-app-layout>
|
|||
|
|
<div class="min-h-screen bg-gradient-to-br from-amber-50 via-orange-50 to-red-50 dark:from-gray-900 dark:via-gray-800 dark:to-gray-900">
|
||
|
|
<!-- Hero Section -->
|
||
|
|
<div class="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm shadow-sm">
|
||
|
|
<div class="max-w-7xl mx-auto py-12 px-4 sm:px-6 lg:px-8">
|
||
|
|
<h1 class="text-4xl font-bold text-gray-900 dark:text-white mb-4">
|
||
|
|
Discover Delicious Recipes
|
||
|
|
</h1>
|
||
|
|
<p class="text-lg text-gray-600 dark:text-gray-300">
|
||
|
|
Explore our collection of homemade recipes, find your next favorite dish
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||
|
|
<div class="lg:grid lg:grid-cols-4 lg:gap-8">
|
||
|
|
<!-- Filters Sidebar -->
|
||
|
|
<div class="lg:col-span-1 mb-8 lg:mb-0">
|
||
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-6 sticky top-8">
|
||
|
|
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-6">Filters</h2>
|
||
|
|
|
||
|
|
<form method="GET" action="{{ route('recipes.index') }}" class="space-y-6">
|
||
|
|
<!-- Search -->
|
||
|
|
<div>
|
||
|
|
<label for="search" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||
|
|
Search
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
name="search"
|
||
|
|
id="search"
|
||
|
|
value="{{ request('search') }}"
|
||
|
|
placeholder="Search recipes..."
|
||
|
|
class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:border-orange-500 focus:ring-orange-500"
|
||
|
|
>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Category -->
|
||
|
|
<div>
|
||
|
|
<label for="category" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||
|
|
Category
|
||
|
|
</label>
|
||
|
|
<select
|
||
|
|
name="category"
|
||
|
|
id="category"
|
||
|
|
class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:border-orange-500 focus:ring-orange-500"
|
||
|
|
>
|
||
|
|
<option value="">All Categories</option>
|
||
|
|
@foreach($categories as $category)
|
||
|
|
<option value="{{ $category }}" {{ request('category') == $category ? 'selected' : '' }}>
|
||
|
|
{{ $category }}
|
||
|
|
</option>
|
||
|
|
@endforeach
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Cuisine -->
|
||
|
|
<div>
|
||
|
|
<label for="cuisine" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||
|
|
Cuisine
|
||
|
|
</label>
|
||
|
|
<select
|
||
|
|
name="cuisine"
|
||
|
|
id="cuisine"
|
||
|
|
class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:border-orange-500 focus:ring-orange-500"
|
||
|
|
>
|
||
|
|
<option value="">All Cuisines</option>
|
||
|
|
@foreach($cuisines as $cuisine)
|
||
|
|
<option value="{{ $cuisine }}" {{ request('cuisine') == $cuisine ? 'selected' : '' }}>
|
||
|
|
{{ $cuisine }}
|
||
|
|
</option>
|
||
|
|
@endforeach
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Difficulty -->
|
||
|
|
<div>
|
||
|
|
<label for="difficulty" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||
|
|
Difficulty
|
||
|
|
</label>
|
||
|
|
<select
|
||
|
|
name="difficulty"
|
||
|
|
id="difficulty"
|
||
|
|
class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:border-orange-500 focus:ring-orange-500"
|
||
|
|
>
|
||
|
|
<option value="">All Levels</option>
|
||
|
|
@foreach($difficulties as $difficulty)
|
||
|
|
<option value="{{ $difficulty }}" {{ request('difficulty') == $difficulty ? 'selected' : '' }}>
|
||
|
|
{{ $difficulty }}
|
||
|
|
</option>
|
||
|
|
@endforeach
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Sort -->
|
||
|
|
<div>
|
||
|
|
<label for="sort" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||
|
|
Sort By
|
||
|
|
</label>
|
||
|
|
<select
|
||
|
|
name="sort"
|
||
|
|
id="sort"
|
||
|
|
class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:border-orange-500 focus:ring-orange-500"
|
||
|
|
>
|
||
|
|
<option value="latest" {{ request('sort') == 'latest' ? 'selected' : '' }}>Latest</option>
|
||
|
|
<option value="popular" {{ request('sort') == 'popular' ? 'selected' : '' }}>Most Popular</option>
|
||
|
|
<option value="rated" {{ request('sort') == 'rated' ? 'selected' : '' }}>Highest Rated</option>
|
||
|
|
<option value="title" {{ request('sort') == 'title' ? 'selected' : '' }}>Alphabetical</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Buttons -->
|
||
|
|
<div class="flex gap-3">
|
||
|
|
<button
|
||
|
|
type="submit"
|
||
|
|
class="flex-1 bg-orange-600 hover:bg-orange-700 text-white font-medium py-2 px-4 rounded-lg transition duration-150"
|
||
|
|
>
|
||
|
|
Apply
|
||
|
|
</button>
|
||
|
|
<a
|
||
|
|
href="{{ route('recipes.index') }}"
|
||
|
|
class="flex-1 bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 font-medium py-2 px-4 rounded-lg text-center transition duration-150"
|
||
|
|
>
|
||
|
|
Clear
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Recipe Grid -->
|
||
|
|
<div class="lg:col-span-3">
|
||
|
|
@if($recipes->count() > 0)
|
||
|
|
<div class="grid md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||
|
|
@foreach($recipes as $recipe)
|
||
|
|
<a href="{{ route('recipes.show', $recipe->slug) }}" class="group">
|
||
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md overflow-hidden hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
|
||
|
|
<!-- Image -->
|
||
|
|
<div class="relative h-48 bg-gradient-to-br from-orange-200 to-red-200 dark:from-orange-900 dark:to-red-900 overflow-hidden">
|
||
|
|
@if($recipe->getRecipeImage())
|
||
|
|
<img
|
||
|
|
src="{{ $recipe->getRecipeImage() }}"
|
||
|
|
alt="{{ $recipe->title }}"
|
||
|
|
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-300"
|
||
|
|
>
|
||
|
|
@else
|
||
|
|
<div class="w-full h-full flex items-center justify-center text-6xl">
|
||
|
|
🍳
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
<!-- Difficulty Badge -->
|
||
|
|
@if($recipe->difficulty)
|
||
|
|
<div class="absolute top-3 right-3 bg-white/90 dark:bg-gray-800/90 backdrop-blur-sm px-3 py-1 rounded-full text-xs font-medium text-gray-700 dark:text-gray-300">
|
||
|
|
{{ $recipe->difficulty }}
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Content -->
|
||
|
|
<div class="p-5">
|
||
|
|
<h3 class="font-bold text-lg text-gray-900 dark:text-white mb-2 line-clamp-2 group-hover:text-orange-600 dark:group-hover:text-orange-400 transition-colors">
|
||
|
|
{{ $recipe->title }}
|
||
|
|
</h3>
|
||
|
|
|
||
|
|
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4 line-clamp-2">
|
||
|
|
{{ $recipe->description }}
|
||
|
|
</p>
|
||
|
|
|
||
|
|
<!-- Meta Info -->
|
||
|
|
<div class="flex items-center justify-between text-sm text-gray-500 dark:text-gray-400">
|
||
|
|
<div class="flex items-center space-x-4">
|
||
|
|
@if($recipe->prep_time || $recipe->cook_time)
|
||
|
|
<span class="flex items-center">
|
||
|
|
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||
|
|
</svg>
|
||
|
|
{{ ($recipe->prep_time ?? 0) + ($recipe->cook_time ?? 0) }}m
|
||
|
|
</span>
|
||
|
|
@endif
|
||
|
|
|
||
|
|
@if($recipe->rating_avg)
|
||
|
|
<span class="flex items-center">
|
||
|
|
<svg class="w-4 h-4 mr-1 text-yellow-400" fill="currentColor" viewBox="0 0 20 20">
|
||
|
|
<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"></path>
|
||
|
|
</svg>
|
||
|
|
{{ number_format($recipe->rating_avg, 1) }}
|
||
|
|
</span>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Tags -->
|
||
|
|
@if($recipe->tags->count() > 0)
|
||
|
|
<div class="mt-3 flex flex-wrap gap-1">
|
||
|
|
@foreach($recipe->tags->take(3) as $tag)
|
||
|
|
<span class="text-xs bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-300 px-2 py-1 rounded-full">
|
||
|
|
{{ $tag->name }}
|
||
|
|
</span>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</a>
|
||
|
|
@endforeach
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Pagination -->
|
||
|
|
<div class="mt-8">
|
||
|
|
{{ $recipes->links() }}
|
||
|
|
</div>
|
||
|
|
@else
|
||
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-md p-12 text-center">
|
||
|
|
<div class="text-6xl mb-4">🔍</div>
|
||
|
|
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">No recipes found</h3>
|
||
|
|
<p class="text-gray-600 dark:text-gray-400 mb-6">Try adjusting your filters to find what you're looking for</p>
|
||
|
|
<a href="{{ route('recipes.index') }}" class="inline-block bg-orange-600 hover:bg-orange-700 text-white font-medium py-2 px-6 rounded-lg transition duration-150">
|
||
|
|
Clear Filters
|
||
|
|
</a>
|
||
|
|
</div>
|
||
|
|
@endif
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</x-app-layout>
|