feat: Implement dynamic brand display, product type filtering, and custom Livewire pagination, and refactor header navigation.
This commit is contained in:
parent
a2042c918d
commit
2c84184bf9
@ -38,10 +38,11 @@ public function mount(): void
|
||||
{
|
||||
$this->brands = Brand::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn (Brand $brand) => [
|
||||
'name' => $brand->name,
|
||||
'image' => $brand->getFirstMediaUrl('image') ? Storage::url($brand->getFirstMediaUrl('image')) : asset('assets/images/logo.png'),
|
||||
])
|
||||
->map(function (Brand $brand) {
|
||||
$brand->image = $brand->getFirstMediaUrl('image') ? $brand->getFirstMediaUrl('image') : asset('assets/images/dark-logo.png');
|
||||
|
||||
return $brand;
|
||||
})
|
||||
->toArray();
|
||||
|
||||
$this->perfumeFeatures = PerfumeFeature::orderBy('sort_order')
|
||||
|
||||
@ -2,33 +2,65 @@
|
||||
|
||||
namespace App\Livewire\Home\Product;
|
||||
|
||||
use App\Models\Perfume;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
#[Layout('components.layouts.home', [
|
||||
'title' => 'Product',
|
||||
'title' => 'Produk',
|
||||
])]
|
||||
class Index extends Component
|
||||
{
|
||||
public bool $isDetail = false;
|
||||
use WithPagination;
|
||||
|
||||
public ?string $slug = null;
|
||||
public string $productType = 'perfume';
|
||||
|
||||
public function mount(?string $slug = null): void
|
||||
public array $recommendations = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
if ($slug) {
|
||||
$this->isDetail = true;
|
||||
$this->slug = $slug;
|
||||
}
|
||||
$this->recommendations = Perfume::with(['brand', 'categories', 'items'])
|
||||
->withCount('items')
|
||||
->orderBy('items_count', 'desc')
|
||||
->take(5)
|
||||
->get()
|
||||
->map(function ($perfume) {
|
||||
return [
|
||||
'id' => $perfume->id,
|
||||
'name' => $perfume->name,
|
||||
'category' => $perfume->categories->first()?->name,
|
||||
'price' => $perfume->sale_price,
|
||||
'image' => $perfume->getFirstMediaUrl() ?: 'https://placehold.co/400x500/png?text='.urlencode($perfume->name),
|
||||
'rating' => 4.5,
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
return view(
|
||||
$this->isDetail
|
||||
? 'livewire.home.product.show'
|
||||
: 'livewire.home.product.index'
|
||||
);
|
||||
$perfumes = Perfume::with(['brand', 'categories', 'items'])
|
||||
->latest()
|
||||
->paginate(9)
|
||||
->through(function ($perfume) {
|
||||
return [
|
||||
'id' => $perfume->id,
|
||||
'name' => $perfume->name,
|
||||
'category' => $perfume->categories->first()?->name,
|
||||
'price' => $perfume->sale_price,
|
||||
'image' => $perfume->getFirstMediaUrl() ?: 'https://placehold.co/400x500/png?text='.urlencode($perfume->name),
|
||||
'rating' => 4.5,
|
||||
'reviews' => $perfume->items->count(),
|
||||
'is_new' => $perfume->created_at->diffInDays(now()) <= 30,
|
||||
'colors' => ['#78350f', '#1f2937'],
|
||||
];
|
||||
});
|
||||
|
||||
return view('livewire.home.product.index', [
|
||||
'pageTitle' => 'Produk',
|
||||
'perfumes' => $perfumes,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,25 +305,9 @@ public function boot(): void
|
||||
],
|
||||
[
|
||||
'title' => 'Produk',
|
||||
'type' => 'dropdown',
|
||||
'action' => 'goToProduct',
|
||||
'items' => [
|
||||
[
|
||||
'title' => 'Parfum',
|
||||
'route' => 'product.perfume.index',
|
||||
'match' => 'product.perfume.*',
|
||||
],
|
||||
[
|
||||
'title' => 'Botol',
|
||||
'route' => 'product.bottle.index',
|
||||
'match' => 'product.bottle.*',
|
||||
],
|
||||
[
|
||||
'title' => 'Arabian',
|
||||
'route' => 'product.arabian.index',
|
||||
'match' => 'product.arabian.*',
|
||||
],
|
||||
],
|
||||
'type' => 'link',
|
||||
'route' => 'product.index',
|
||||
'match' => 'product.*',
|
||||
],
|
||||
[
|
||||
'title' => 'Voucher',
|
||||
|
||||
@ -19,7 +19,7 @@ class="size-6 text-white hidden transition-transform duration-300">
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<a href="/" class="flex items-center ml-8 lg:ml-0 z-50">
|
||||
<a href="{{ route('homepage') }}" wire:navigate class="flex items-center ml-8 lg:ml-0 z-50">
|
||||
<img src="{{ asset('assets/images/logo.png') }}" alt="Logo"
|
||||
class="w-10 h-8 lg:w-16 lg:h-12 transition-all duration-200">
|
||||
</a>
|
||||
@ -38,8 +38,8 @@ class="{{ request()->routeIs($item['route']) ? 'font-bold text-home-primary' : '
|
||||
|
||||
@if ($item['type'] === 'dropdown')
|
||||
<div class="relative group">
|
||||
<button wire:click="{{ $item['action'] }}"
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity">
|
||||
<button
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity {{ request()->routeIs($item['match']) ? 'font-bold text-home-primary' : 'hover:opacity-80' }}">
|
||||
<span>{{ $item['title'] }}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
@ -51,8 +51,8 @@ class="size-4 group-hover:rotate-180 transition-transform duration-300">
|
||||
<div class="absolute left-0 top-full hidden group-hover:block pt-2 w-40">
|
||||
<div class="bg-white/95 backdrop-blur-md shadow-lg rounded-lg py-2 border border-gray-200">
|
||||
@foreach ($item['items'] as $sub)
|
||||
<a href="{{ $sub['route'] }}"
|
||||
class="block px-4 py-2 hover:bg-gray-50 transition-colors">
|
||||
<a href="{{ route($sub['route']) }}" wire:navigate
|
||||
class="{{ request()->routeIs($sub['match']) ? 'font-bold text-home-primary' : 'hover:opacity-80' }} block px-4 py-2 hover:bg-gray-50 transition-colors">
|
||||
{{ $sub['title'] }}
|
||||
</a>
|
||||
@endforeach
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class="relative min-h-screen">
|
||||
@include('livewire.home.partials.jumbotron')
|
||||
@include('livewire.home.partials.partners')
|
||||
@include('livewire.home.partials.brands')
|
||||
@include('livewire.home.partials.why')
|
||||
@include('livewire.home.partials.categories')
|
||||
@include('livewire.home.partials.benefits')
|
||||
|
||||
12
resources/views/livewire/home/partials/brands.blade.php
Normal file
12
resources/views/livewire/home/partials/brands.blade.php
Normal file
@ -0,0 +1,12 @@
|
||||
<section class="overflow-hidden relative pt-4 bg-home-foreground" id="brand-slider" aria-label="Brand Slider">
|
||||
<div class="flex gap-6 items-center cursor-grab active:cursor-grabbing" id="brand-track" style="touch-action: pan-y;">
|
||||
@foreach ($brands as $brand)
|
||||
<div class="flex flex-col items-center flex-shrink-0 py-5">
|
||||
<img src="{{ $brand['image'] }}" alt="{{ $brand['name'] }}" class="w-12 h-12 object-contain rounded-xl">
|
||||
<h3 class="mt-1 text-base font-bold text-center text-white">
|
||||
{{ $brand['name'] }}
|
||||
</h3>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
@ -31,7 +31,7 @@ class="border-2 border-home-background w-8 h-8 lg:w-10 lg:h-10 rounded-full over
|
||||
</p>
|
||||
|
||||
<div class="flex items-center">
|
||||
<a href="{{ route('product.perfume') }}" wire:navigate
|
||||
<a href="{{ route('product.index') }}" wire:navigate
|
||||
class="bg-home-primary text-home-background py-3 px-6 rounded-full hover:shadow-lg hover:shadow-home-primary/30 transition-all font-medium">
|
||||
Jelajahi Toko
|
||||
</a>
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
<section class="overflow-hidden relative pt-4 bg-home-foreground" id="brand-slider" aria-label="Brand Slider">
|
||||
<div class="flex gap-6 items-center whitespace-nowrap will-change-transform cursor-grab active:cursor-grabbing"
|
||||
id="brand-track" style="touch-action: pan-y;">
|
||||
<img src="https://images.seeklogo.com/logo-png/44/2/next-js-logo-png_seeklogo-449824.png" alt="Next.js"
|
||||
class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://logo.svgcdn.com/devicon/laravel-original-wordmark.png" alt="Laravel"
|
||||
class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://brandlogos.net/wp-content/uploads/2023/11/tailwind_css-logo_brandlogos.net_v91ni.png"
|
||||
alt="Tailwind CSS" class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://raw.githubusercontent.com/livewire/livewire/main/art/readme_logo.png" alt="Livewire"
|
||||
class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://logo.svgcdn.com/devicon/laravel-original-wordmark.png" alt="Laravel"
|
||||
class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://images.seeklogo.com/logo-png/44/2/next-js-logo-png_seeklogo-449824.png" alt="Next.js"
|
||||
class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://raw.githubusercontent.com/livewire/livewire/main/art/readme_logo.png" alt="Livewire"
|
||||
class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
<img src="https://brandlogos.net/wp-content/uploads/2023/11/tailwind_css-logo_brandlogos.net_v91ni.png"
|
||||
alt="Tailwind CSS" class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
</div>
|
||||
</section>
|
||||
@ -1,106 +1,3 @@
|
||||
@php
|
||||
$products = [
|
||||
[
|
||||
'name' => 'Oud Royal Premium',
|
||||
'category' => 'Luxury',
|
||||
'price' => 1200000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Oud+Royal',
|
||||
'rating' => 5.0,
|
||||
'reviews' => 120,
|
||||
'is_new' => true,
|
||||
'colors' => ['#78350f', '#1f2937'],
|
||||
],
|
||||
[
|
||||
'name' => 'Rose Velvet',
|
||||
'category' => 'Floral',
|
||||
'price' => 450000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Rose+Velvet',
|
||||
'rating' => 4.8,
|
||||
'reviews' => 85,
|
||||
'is_new' => false,
|
||||
'colors' => ['#be123c', '#fce7f3'],
|
||||
],
|
||||
[
|
||||
'name' => 'Ocean Breeze',
|
||||
'category' => 'Fresh',
|
||||
'price' => 320000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Ocean+Breeze',
|
||||
'rating' => 4.9,
|
||||
'reviews' => 200,
|
||||
'is_new' => false,
|
||||
'colors' => ['#0ea5e9', '#e0f2fe'],
|
||||
],
|
||||
[
|
||||
'name' => 'Vanilla Sky',
|
||||
'category' => 'Sweet',
|
||||
'price' => 350000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Vanilla+Sky',
|
||||
'rating' => 4.7,
|
||||
'reviews' => 150,
|
||||
'is_new' => true,
|
||||
'colors' => ['#d4d4d8', '#71717a'],
|
||||
],
|
||||
[
|
||||
'name' => 'Midnight Musk',
|
||||
'category' => 'Musky',
|
||||
'price' => 550000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Midnight+Musk',
|
||||
'rating' => 4.6,
|
||||
'reviews' => 90,
|
||||
'is_new' => false,
|
||||
'colors' => ['#1f2937', '#000000'],
|
||||
],
|
||||
[
|
||||
'name' => 'Citrus Energy',
|
||||
'category' => 'Fresh',
|
||||
'price' => 280000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Citrus+Energy',
|
||||
'rating' => 4.5,
|
||||
'reviews' => 60,
|
||||
'is_new' => false,
|
||||
'colors' => ['#eab308', '#fef08a'],
|
||||
],
|
||||
];
|
||||
|
||||
$recommendations = [
|
||||
[
|
||||
'name' => 'Golden Amber',
|
||||
'category' => 'Oriental',
|
||||
'price' => 890000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Golden+Amber',
|
||||
'rating' => 4.9,
|
||||
],
|
||||
[
|
||||
'name' => 'Spring Blossom',
|
||||
'category' => 'Floral',
|
||||
'price' => 380000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Spring+Blossom',
|
||||
'rating' => 4.7,
|
||||
],
|
||||
[
|
||||
'name' => 'Woody Intense',
|
||||
'category' => 'Woody',
|
||||
'price' => 650000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Woody+Intense',
|
||||
'rating' => 4.8,
|
||||
],
|
||||
[
|
||||
'name' => 'Aqua Marine',
|
||||
'category' => 'Fresh',
|
||||
'price' => 420000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Aqua+Marine',
|
||||
'rating' => 4.6,
|
||||
],
|
||||
[
|
||||
'name' => 'Spicy Leather',
|
||||
'category' => 'Leather',
|
||||
'price' => 750000,
|
||||
'image' => 'https://placehold.co/400x500/png?text=Spicy+Leather',
|
||||
'rating' => 4.9,
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<div class="flex flex-col min-h-screen bg-white font-sans">
|
||||
|
||||
{{-- Hero Section --}}
|
||||
@ -114,9 +11,23 @@
|
||||
|
||||
{{-- Content --}}
|
||||
<div class="relative z-10 container mx-auto px-6 text-center">
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">Koleksi Parfum</h1>
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold text-white mb-6">
|
||||
@if ($productType === 'perfume')
|
||||
Koleksi Parfum
|
||||
@elseif($productType === 'bottle')
|
||||
Koleksi Botol
|
||||
@else
|
||||
Koleksi Arabian
|
||||
@endif
|
||||
</h1>
|
||||
<p class="text-white/80 text-lg md:text-xl max-w-2xl mx-auto mb-10">
|
||||
Temukan aroma khas yang mencerminkan kepribadian dan gaya Anda.
|
||||
@if ($productType === 'perfume')
|
||||
Temukan aroma khas yang mencerminkan kepribadian dan gaya Anda.
|
||||
@elseif($productType === 'bottle')
|
||||
Pilihan botol berkualitas untuk parfum Anda.
|
||||
@else
|
||||
Koleksi produk Arabian eksklusif dan mewah.
|
||||
@endif
|
||||
</p>
|
||||
|
||||
{{-- Search Bar --}}
|
||||
@ -140,6 +51,23 @@ class="absolute right-2 top-2 bottom-2 w-10 h-10 bg-home-primary rounded-full fl
|
||||
|
||||
<aside class="hidden lg:block lg:col-span-1 space-y-8">
|
||||
<div class="bg-white rounded-2xl border border-home-foreground/10 p-6 shadow-sm sticky top-32">
|
||||
{{-- Filter Jenis Produk --}}
|
||||
<h3 class="font-bold text-home-primary mb-6 border-b border-home-foreground/10 pb-4">Jenis Produk
|
||||
</h3>
|
||||
<div class="space-y-4">
|
||||
@foreach ([['value' => 'perfume', 'label' => 'Parfum'], ['value' => 'bottle', 'label' => 'Botol'], ['value' => 'arabian', 'label' => 'Arabian']] as $type)
|
||||
<label class="flex items-center cursor-pointer group">
|
||||
<input type="radio" name="productType" value="{{ $type['value'] }}"
|
||||
wire:model.live="productType" {{ $productType === $type['value'] ? 'checked' : '' }}
|
||||
class="w-5 h-5 border-home-foreground/20 text-home-primary focus:ring-home-primary cursor-pointer accent-home-primary">
|
||||
<span
|
||||
class="ml-3 text-home-foreground/70 group-hover:text-home-primary transition-colors text-sm font-medium {{ $productType === $type['value'] ? 'font-bold text-home-primary' : '' }}">{{ $type['label'] }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<div class="border-t border-home-foreground/10 my-8"></div>
|
||||
|
||||
<h3 class="font-bold text-home-primary mb-6 border-b border-home-foreground/10 pb-4">Kategori</h3>
|
||||
<div class="space-y-4">
|
||||
@foreach (['Pria', 'Wanita', 'Unisex', 'Luxury', 'Best Seller', 'New Arrival'] as $cat)
|
||||
@ -189,17 +117,17 @@ class="w-full appearance-none px-6 py-3 pr-10 rounded-xl border border-home-fore
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
@foreach ($products as $item)
|
||||
@foreach ($perfumes as $perfume)
|
||||
<article
|
||||
class="group bg-white rounded-2xl border border-home-foreground/10 overflow-hidden hover:shadow-xl hover:shadow-home-primary/5 hover:border-home-primary/30 hover:-translate-y-1 transition-all duration-300 flex flex-col h-full relative">
|
||||
|
||||
@if ($item['is_new'])
|
||||
@if ($perfume['is_new'])
|
||||
<span
|
||||
class="absolute top-4 left-4 bg-home-primary text-white text-[10px] uppercase tracking-wider font-bold px-3 py-1 rounded-full z-10 shadow-md">New</span>
|
||||
@endif
|
||||
|
||||
<div class="relative h-72 overflow-hidden bg-home-primary/5">
|
||||
<img src="{{ $item['image'] }}" alt="{{ $item['name'] }}"
|
||||
<img src="{{ $perfume['image'] }}" alt="{{ $perfume['name'] }}"
|
||||
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500">
|
||||
|
||||
<div
|
||||
@ -230,29 +158,31 @@ class="w-10 h-10 bg-white rounded-full flex items-center justify-center text-hom
|
||||
<div class="p-5 flex flex-col flex-grow">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<span
|
||||
class="text-[10px] font-bold tracking-widest text-home-primary uppercase bg-home-primary/10 px-2 py-1 rounded">{{ $item['category'] }}</span>
|
||||
class="text-[10px] font-bold tracking-widest text-home-primary uppercase bg-home-primary/10 px-2 py-1 rounded">{{ $perfume['category'] }}</span>
|
||||
<div class="flex items-center gap-1">
|
||||
<svg class="w-3 h-3 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" />
|
||||
</svg>
|
||||
<span
|
||||
class="text-xs font-bold text-home-foreground">{{ $item['rating'] }}</span>
|
||||
<span class="text-xs text-home-foreground/40">({{ $item['reviews'] }})</span>
|
||||
class="text-xs font-bold text-home-foreground">{{ $perfume['rating'] }}</span>
|
||||
<span
|
||||
class="text-xs text-home-foreground/40">({{ $perfume['reviews'] }})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3
|
||||
class="text-lg font-bold text-home-foreground group-hover:text-home-primary transition-colors mb-4 line-clamp-1">
|
||||
{{ $item['name'] }}</h3>
|
||||
{{ $perfume['name'] }}</h3>
|
||||
|
||||
<div
|
||||
class="mt-auto pt-4 border-t border-home-foreground/5 flex items-center justify-between">
|
||||
<span class="text-xl font-bold text-home-primary">Rp
|
||||
{{ number_format($item['price'], 0, ',', '.') }}</span>
|
||||
{{ number_format($perfume['price'], 0, ',', '.') }}</span>
|
||||
<button
|
||||
class="w-10 h-10 rounded-lg bg-home-foreground text-white flex items-center justify-center hover:bg-home-primary transition-colors shadow-md">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor"
|
||||
viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 4v16m8-8H4"></path>
|
||||
</svg>
|
||||
@ -264,29 +194,7 @@ class="w-10 h-10 rounded-lg bg-home-foreground text-white flex items-center just
|
||||
</div>
|
||||
|
||||
<div class="mt-16 flex justify-center">
|
||||
<nav class="flex items-center gap-2">
|
||||
<button
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full border border-home-foreground/10 text-home-foreground/30 cursor-not-allowed hover:bg-transparent">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full bg-home-primary text-white font-bold shadow-lg shadow-home-primary/20 transition-all">1</button>
|
||||
<button
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full text-home-foreground hover:bg-home-primary/5 transition-all font-medium">2</button>
|
||||
<button
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full text-home-foreground hover:bg-home-primary/5 transition-all font-medium">3</button>
|
||||
<span class="w-10 h-10 flex items-center justify-center text-home-foreground/40">...</span>
|
||||
<button
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full border border-home-foreground/10 text-home-foreground hover:border-home-primary hover:text-home-primary transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
{{ $perfumes->links('vendor.livewire.custom-pagination') }}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
66
resources/views/vendor/livewire/custom-pagination.blade.php
vendored
Normal file
66
resources/views/vendor/livewire/custom-pagination.blade.php
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
<div>
|
||||
@if ($paginator->hasPages())
|
||||
<nav class="flex items-center gap-2">
|
||||
{{-- Previous Page Link --}}
|
||||
@if ($paginator->onFirstPage())
|
||||
<button disabled
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full border border-home-foreground/10 text-home-foreground/30 cursor-not-allowed hover:bg-transparent">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
@else
|
||||
<button wire:click="previousPage" wire:loading.attr="disabled"
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full border border-home-foreground/10 text-home-foreground hover:border-home-primary hover:text-home-primary transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
@endif
|
||||
|
||||
{{-- Pagination Elements --}}
|
||||
@foreach ($elements as $element)
|
||||
{{-- "Three Dots" Separator --}}
|
||||
@if (is_string($element))
|
||||
<span
|
||||
class="w-10 h-10 flex items-center justify-center text-home-foreground/40">{{ $element }}</span>
|
||||
@endif
|
||||
|
||||
{{-- Array Of Links --}}
|
||||
@if (is_array($element))
|
||||
@foreach ($element as $page => $url)
|
||||
@if ($page == $paginator->currentPage())
|
||||
<button wire:click="gotoPage({{ $page }})"
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full bg-home-primary text-white font-bold shadow-lg shadow-home-primary/20 transition-all">
|
||||
{{ $page }}
|
||||
</button>
|
||||
@else
|
||||
<button wire:click="gotoPage({{ $page }})"
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full text-home-foreground hover:bg-home-primary/5 transition-all font-medium">
|
||||
{{ $page }}
|
||||
</button>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
{{-- Next Page Link --}}
|
||||
@if ($paginator->hasMorePages())
|
||||
<button wire:click="nextPage" wire:loading.attr="disabled"
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full border border-home-foreground/10 text-home-foreground hover:border-home-primary hover:text-home-primary transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
@else
|
||||
<button disabled
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full border border-home-foreground/10 text-home-foreground/30 cursor-not-allowed hover:bg-transparent">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
@endif
|
||||
</nav>
|
||||
@endif
|
||||
</div>
|
||||
@ -5,7 +5,7 @@
|
||||
use App\Livewire\Home\Faq\Index as FaqComponent;
|
||||
use App\Livewire\Home\Index as HomeComponent;
|
||||
use App\Livewire\Home\Outlet as OutletComponent;
|
||||
use App\Livewire\Home\Product\Index as ProductComponent;
|
||||
use App\Livewire\Home\Product\Index as ProductIndex;
|
||||
use App\Livewire\Home\Voucher as VoucherComponent;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@ -13,12 +13,7 @@
|
||||
|
||||
Route::get('/outlets', OutletComponent::class)->name('outlet');
|
||||
|
||||
Route::prefix('products')
|
||||
->name('product.')
|
||||
->group(function () {
|
||||
Route::get('perfumes/{slug?}', ProductComponent::class)
|
||||
->name('perfume');
|
||||
});
|
||||
Route::get('/products', ProductIndex::class)->name('product.index');
|
||||
|
||||
Route::get('/vouchers', VoucherComponent::class)->name('voucher');
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user