feat: Implement category image management and display on the homepage, and streamline perfume feature rendering.
This commit is contained in:
parent
77c16168e3
commit
93d86a30c0
@ -5,13 +5,15 @@
|
|||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
use App\Traits\Datatable\WithConfiguration;
|
use App\Traits\Datatable\WithConfiguration;
|
||||||
use App\Traits\Datatable\WithPrependColumn;
|
use App\Traits\Datatable\WithPrependColumn;
|
||||||
|
use App\Traits\Media\WithMediaHandler;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
||||||
use Rappasoft\LaravelLivewireTables\Views\Column;
|
use Rappasoft\LaravelLivewireTables\Views\Column;
|
||||||
|
use Rappasoft\LaravelLivewireTables\Views\Columns\ImageColumn;
|
||||||
|
|
||||||
class CategoriesTable extends DataTableComponent
|
class CategoriesTable extends DataTableComponent
|
||||||
{
|
{
|
||||||
use WithConfiguration, WithPrependColumn;
|
use WithConfiguration, WithMediaHandler, WithPrependColumn;
|
||||||
|
|
||||||
protected $model = Category::class;
|
protected $model = Category::class;
|
||||||
|
|
||||||
@ -20,6 +22,13 @@ public function columns(): array
|
|||||||
return [
|
return [
|
||||||
Column::make('Nama', 'name')->searchable(),
|
Column::make('Nama', 'name')->searchable(),
|
||||||
|
|
||||||
|
ImageColumn::make('Gambar')
|
||||||
|
->location(fn ($row) => optional($row->getMedia('image')->first())->getUrl() ?? asset('assets/images/logo.png'))
|
||||||
|
->attributes(fn ($row) => [
|
||||||
|
'style' => 'width: 50px; height: 50px;',
|
||||||
|
'alt' => $row->name,
|
||||||
|
]),
|
||||||
|
|
||||||
Column::make('Aksi')
|
Column::make('Aksi')
|
||||||
->label(function ($row) {
|
->label(function ($row) {
|
||||||
$actions = '';
|
$actions = '';
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Livewire\Forms\Studio\Catalog;
|
namespace App\Livewire\Forms\Studio\Catalog;
|
||||||
|
|
||||||
use App\Models\Category;
|
use App\Models\Category;
|
||||||
|
use App\Traits\Media\WithMediaHandler;
|
||||||
use App\Traits\Utilities\WithSortOrder;
|
use App\Traits\Utilities\WithSortOrder;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
@ -10,7 +11,7 @@
|
|||||||
|
|
||||||
class CategoryForm extends Form
|
class CategoryForm extends Form
|
||||||
{
|
{
|
||||||
use WithSortOrder;
|
use WithMediaHandler, WithSortOrder;
|
||||||
|
|
||||||
public ?Category $category = null;
|
public ?Category $category = null;
|
||||||
|
|
||||||
@ -18,11 +19,14 @@ class CategoryForm extends Form
|
|||||||
|
|
||||||
public ?string $description = null;
|
public ?string $description = null;
|
||||||
|
|
||||||
|
public array $image = [];
|
||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => ['required', 'string', 'max:20', Rule::unique('categories', 'name')->whereNull('deleted_at')->ignore($this->category)],
|
'name' => ['required', 'string', 'max:20', Rule::unique('categories', 'name')->whereNull('deleted_at')->ignore($this->category)],
|
||||||
'description' => 'nullable',
|
'description' => 'nullable',
|
||||||
|
'image' => 'array',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +35,7 @@ public function validationAttributes(): array
|
|||||||
return [
|
return [
|
||||||
'name' => 'nama',
|
'name' => 'nama',
|
||||||
'description' => 'deskripsi',
|
'description' => 'deskripsi',
|
||||||
|
'image' => 'gambar',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +45,8 @@ public function setCategory(Category $category): void
|
|||||||
|
|
||||||
$this->name = $category->name;
|
$this->name = $category->name;
|
||||||
$this->description = $category->description;
|
$this->description = $category->description;
|
||||||
|
|
||||||
|
$this->image = $this->mapMediaCollection($category->getMedia('image'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(): void
|
public function store(): void
|
||||||
@ -50,11 +57,13 @@ public function store(): void
|
|||||||
// Increment all existing categories' sort_order
|
// Increment all existing categories' sort_order
|
||||||
Category::query()->increment('sort_order');
|
Category::query()->increment('sort_order');
|
||||||
|
|
||||||
Category::create([
|
$category = Category::create([
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'description' => $this->description,
|
'description' => $this->description,
|
||||||
'sort_order' => 1,
|
'sort_order' => 1,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->uploadMedia($this->image, $category, 'image');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,10 +71,15 @@ public function update(): void
|
|||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
|
|
||||||
$this->category->update([
|
DB::transaction(function () {
|
||||||
'name' => $this->name,
|
$this->category->update([
|
||||||
'description' => $this->description,
|
'name' => $this->name,
|
||||||
]);
|
'description' => $this->description,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->syncMedia($this->image, $this->category, 'image');
|
||||||
|
$this->uploadMedia($this->image, $this->category, 'image');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): void
|
public function delete(): void
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Livewire\Home;
|
namespace App\Livewire\Home;
|
||||||
|
|
||||||
use App\Models\Brand;
|
use App\Models\Brand;
|
||||||
|
use App\Models\Category;
|
||||||
use App\Models\ChooseUs;
|
use App\Models\ChooseUs;
|
||||||
use App\Models\Customer;
|
use App\Models\Customer;
|
||||||
use App\Models\Faq;
|
use App\Models\Faq;
|
||||||
@ -13,12 +14,15 @@
|
|||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Livewire\Attributes\Layout;
|
use Livewire\Attributes\Layout;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\WithPagination;
|
||||||
|
|
||||||
#[Layout('components.layouts.home', [
|
#[Layout('components.layouts.home', [
|
||||||
'title' => 'Beranda',
|
'title' => 'Beranda',
|
||||||
])]
|
])]
|
||||||
class Index extends Component
|
class Index extends Component
|
||||||
{
|
{
|
||||||
|
use WithPagination;
|
||||||
|
|
||||||
public array $bestSellingPerfumes = [];
|
public array $bestSellingPerfumes = [];
|
||||||
|
|
||||||
public array $brands = [];
|
public array $brands = [];
|
||||||
@ -65,13 +69,7 @@ public function mount(): void
|
|||||||
|
|
||||||
$this->whyChooseUs = ChooseUs::orderBy('sort_order')->get()->toArray();
|
$this->whyChooseUs = ChooseUs::orderBy('sort_order')->get()->toArray();
|
||||||
|
|
||||||
$this->perfumeFeatures = PerfumeFeature::orderBy('sort_order')
|
$this->perfumeFeatures = PerfumeFeature::orderBy('sort_order')->get()->toArray();
|
||||||
->get()
|
|
||||||
->map(fn (PerfumeFeature $perfumeFeature) => [
|
|
||||||
'name' => $perfumeFeature->name,
|
|
||||||
'description' => $perfumeFeature->description,
|
|
||||||
])
|
|
||||||
->toArray();
|
|
||||||
|
|
||||||
$this->faqs = Faq::orderBy('sort_order')
|
$this->faqs = Faq::orderBy('sort_order')
|
||||||
->get()
|
->get()
|
||||||
@ -100,6 +98,14 @@ public function render(): View
|
|||||||
{
|
{
|
||||||
return view('livewire.home.index', [
|
return view('livewire.home.index', [
|
||||||
'pageTitle' => 'Beranda',
|
'pageTitle' => 'Beranda',
|
||||||
|
'categories' => Category::orderBy('sort_order')
|
||||||
|
->paginate(12)
|
||||||
|
->through(function (Category $category) {
|
||||||
|
$category->image = $category->getFirstMediaUrl('image')
|
||||||
|
?: asset('assets/images/logo.png');
|
||||||
|
|
||||||
|
return $category;
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,13 +6,15 @@
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
use Spatie\Sluggable\HasSlug;
|
use Spatie\Sluggable\HasSlug;
|
||||||
use Spatie\Sluggable\SlugOptions;
|
use Spatie\Sluggable\SlugOptions;
|
||||||
use Veelasky\LaravelHashId\Eloquent\HashableId;
|
use Veelasky\LaravelHashId\Eloquent\HashableId;
|
||||||
|
|
||||||
class Category extends Model
|
class Category extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
use HasFactory, HashableId, HasSlug, SoftDeletes;
|
use HasFactory, HashableId, HasSlug, InteractsWithMedia, SoftDeletes;
|
||||||
|
|
||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,23 @@
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
transition: all .4s ease;
|
transition: all .4s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fadeUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-item {
|
||||||
|
opacity: 0;
|
||||||
|
animation: fadeUp 0.45s ease forwards;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@endassets
|
@endassets
|
||||||
|
|
||||||
@ -126,11 +143,34 @@ function animate() {
|
|||||||
link.addEventListener('click', e => {
|
link.addEventListener('click', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
links.forEach(l => l.classList.remove('bg-home-foreground'));
|
const targetPage = new URL(link.href).searchParams.get('page') || '1';
|
||||||
links.forEach(l => l.classList.add('bg-gray-400'));
|
|
||||||
|
|
||||||
e.target.classList.remove('bg-gray-400');
|
// Update all dots (mobile & desktop)
|
||||||
e.target.classList.add('bg-home-foreground');
|
links.forEach(l => {
|
||||||
|
const lPage = new URL(l.href).searchParams.get('page') || '1';
|
||||||
|
const isActive = lPage === targetPage;
|
||||||
|
|
||||||
|
const isMobile = l.closest('nav').classList.contains(
|
||||||
|
'lg:hidden');
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
l.classList.add('bg-home-primary');
|
||||||
|
if (isMobile) {
|
||||||
|
l.classList.add('w-8');
|
||||||
|
l.classList.remove('w-2', 'bg-gray-300');
|
||||||
|
} else {
|
||||||
|
l.classList.add('h-12');
|
||||||
|
l.classList.remove('h-6', 'bg-gray-200');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l.classList.remove('bg-home-primary', 'w-8', 'h-12');
|
||||||
|
if (isMobile) {
|
||||||
|
l.classList.add('bg-gray-300', 'w-2');
|
||||||
|
} else {
|
||||||
|
l.classList.add('bg-gray-200', 'h-6');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
fetch(link.href)
|
fetch(link.href)
|
||||||
.then(res => res.text())
|
.then(res => res.text())
|
||||||
|
|||||||
@ -1,77 +1,55 @@
|
|||||||
@php
|
|
||||||
$accordions = [
|
|
||||||
[
|
|
||||||
'title' => 'Aroma Premium Tahan Lama',
|
|
||||||
'content' =>
|
|
||||||
'Setiap varian dirancang menggunakan konsentrat berkualitas tinggi sehingga wanginya bertahan sepanjang hari, cocok dipakai kerja maupun aktivitas luar.',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'Formula Aman untuk Kulit',
|
|
||||||
'content' =>
|
|
||||||
'Parfum kami menggunakan bahan yang lebih lembut di kulit sehingga nyaman digunakan setiap hari tanpa rasa perih atau iritasi.',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'Pilihan Aroma Sangat Beragam',
|
|
||||||
'content' =>
|
|
||||||
'Mulai dari floral, fresh, woody, oriental hingga parfum harian — semua tersedia untuk menyesuaikan gaya dan kepribadianmu.',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'title' => 'Harga Terjangkau Kualitas Premium',
|
|
||||||
'content' =>
|
|
||||||
'Nikmati parfum berkelas tanpa perlu mengeluarkan biaya tinggi. Value terbaik untuk kebutuhan harian maupun koleksi pribadi.',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
<section class="bg-white py-16 lg:py-24 px-4 md:px-8 lg:px-24 xl:px-32 font-sans text-home-foreground overflow-hidden">
|
<section class="bg-white py-16 lg:py-24 px-4 md:px-8 lg:px-24 xl:px-32 font-sans text-home-foreground overflow-hidden">
|
||||||
<div class="max-w-7xl mx-auto">
|
<div class="max-w-7xl mx-auto">
|
||||||
<div class="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center">
|
<div class="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center">
|
||||||
|
|
||||||
<figure class="w-full relative order-2 lg:order-1">
|
<figure class="w-full relative order-2 lg:order-1">
|
||||||
<div class="absolute -inset-4 bg-home-primary/5 rounded-3xl -z-10 transform -rotate-2"></div>
|
<div class="absolute -inset-4 bg-home-primary/5 rounded-3xl -z-10 transform -rotate-2"></div>
|
||||||
<img src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?q=80"
|
<img src="https://images.pexels.com/photos/4659793/pexels-photo-4659793.jpeg" alt="Botol Parfum Elegan"
|
||||||
alt="Botol Parfum Elegan"
|
|
||||||
class="w-full h-[400px] lg:h-[600px] object-cover rounded-2xl shadow-lg">
|
class="w-full h-[400px] lg:h-[600px] object-cover rounded-2xl shadow-lg">
|
||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
<article class="space-y-8 order-1 lg:order-2" x-data="{ activeAccordion: 0 }">
|
<article class="space-y-8 order-1 lg:order-2" x-data="{ activeAccordion: 0 }">
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<h2 class="text-3xl md:text-4xl lg:text-5xl font-bold text-home-foreground leading-tight mb-6">
|
<h2 class="text-3xl md:text-4xl lg:text-5xl font-bold text-home-foreground leading-tight mb-6">
|
||||||
Keunggulan Produk Kami.
|
Keunggulan Produk Kami.
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-base md:text-lg text-home-foreground/70 leading-relaxed">
|
<p class="text-base md:text-lg text-home-foreground/70 leading-relaxed">
|
||||||
Setiap parfum dibuat dengan standar tinggi agar kamu mendapatkan kualitas terbaik dan pengalaman wangi yang tak terlupakan.
|
Setiap parfum dibuat dengan standar tinggi agar kamu mendapatkan kualitas terbaik dan pengalaman
|
||||||
|
wangi yang tak terlupakan.
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="bg-white rounded-2xl p-6 md:p-8 shadow-sm border border-gray-100">
|
<div class="bg-white rounded-2xl p-6 md:p-8 shadow-sm border border-gray-100">
|
||||||
@foreach ($accordions as $index => $acc)
|
@foreach ($perfumeFeatures as $index => $perfumeFeature)
|
||||||
<div class="border-b border-gray-100 last:border-0">
|
<div class="border-b border-gray-100 last:border-0">
|
||||||
<button
|
<button
|
||||||
@click="activeAccordion = (activeAccordion === {{ $index }} ? null : {{ $index }})"
|
@click="activeAccordion = (activeAccordion === {{ $index }} ? null : {{ $index }})"
|
||||||
class="w-full flex justify-between items-center py-5 text-left group focus:outline-none transition-all duration-300"
|
class="w-full flex justify-between items-center py-5 text-left group focus:outline-none transition-all duration-300"
|
||||||
:aria-expanded="activeAccordion === {{ $index }}">
|
:aria-expanded="activeAccordion === {{ $index }}">
|
||||||
|
|
||||||
<span class="text-lg font-bold transition-colors duration-300"
|
<span class="text-lg font-bold transition-colors duration-300"
|
||||||
:class="activeAccordion === {{ $index }} ? 'text-home-primary' : 'text-home-foreground group-hover:text-home-primary'">
|
:class="activeAccordion === {{ $index }} ? 'text-home-primary' :
|
||||||
{{ $acc['title'] }}
|
'text-home-foreground group-hover:text-home-primary'">
|
||||||
|
{{ $perfumeFeature['name'] }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="ml-4 flex-shrink-0 transition-transform duration-300 w-8 h-8 flex items-center justify-center rounded-full"
|
<span
|
||||||
:class="activeAccordion === {{ $index }} ? 'rotate-180 bg-home-primary text-white' : 'bg-gray-100 text-gray-400 group-hover:bg-home-primary/10 group-hover:text-home-primary'">
|
class="ml-4 flex-shrink-0 transition-transform duration-300 w-8 h-8 flex items-center justify-center rounded-full"
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
:class="activeAccordion === {{ $index }} ? 'rotate-180 bg-home-primary text-white' :
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
'bg-gray-100 text-gray-400 group-hover:bg-home-primary/10 group-hover:text-home-primary'">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none"
|
||||||
|
viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7" />
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div x-show="activeAccordion === {{ $index }}"
|
<div x-show="activeAccordion === {{ $index }}" x-collapse x-cloak
|
||||||
x-collapse
|
|
||||||
x-cloak
|
|
||||||
class="overflow-hidden text-home-foreground/70 text-base leading-relaxed">
|
class="overflow-hidden text-home-foreground/70 text-base leading-relaxed">
|
||||||
<div class="pb-5">
|
<div class="pb-5">
|
||||||
{{ $acc['content'] }}
|
{{ $perfumeFeature['description'] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -82,4 +60,4 @@ class="overflow-hidden text-home-foreground/70 text-base leading-relaxed">
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -1,38 +1,3 @@
|
|||||||
@php
|
|
||||||
$industries = [
|
|
||||||
['name' => 'AROMA FLORAL'],
|
|
||||||
['name' => 'AROMA FRESH'],
|
|
||||||
['name' => 'AROMA WOODY'],
|
|
||||||
['name' => 'AROMA ORIENTAL'],
|
|
||||||
['name' => 'PARFUM HARIAN'],
|
|
||||||
['name' => 'PARFUM KERJA'],
|
|
||||||
['name' => 'PARFUM MALAM'],
|
|
||||||
['name' => 'PARFUM PREMIUM'],
|
|
||||||
['name' => 'AROMA SWEET'],
|
|
||||||
['name' => 'AROMA FRUITY'],
|
|
||||||
['name' => 'AROMA MUSKY'],
|
|
||||||
['name' => 'LIMITED EDITION'],
|
|
||||||
['name' => 'AROMA CITRUS'],
|
|
||||||
['name' => 'AROMA AQUA'],
|
|
||||||
['name' => 'AROMA SPICY'],
|
|
||||||
['name' => 'PARFUM SPORT'],
|
|
||||||
['name' => 'PARFUM CLASSIC'],
|
|
||||||
['name' => 'AROMA GREEN'],
|
|
||||||
['name' => 'AROMA TEA'],
|
|
||||||
['name' => 'PARFUM SUMMER'],
|
|
||||||
['name' => 'AROMA TROPICAL'],
|
|
||||||
['name' => 'PARFUM LUXURY'],
|
|
||||||
['name' => 'AROMA EARTHY'],
|
|
||||||
];
|
|
||||||
|
|
||||||
$perPage = 12;
|
|
||||||
$page = request('page', 1);
|
|
||||||
$total = count($industries);
|
|
||||||
$start = ($page - 1) * $perPage;
|
|
||||||
$currentItems = array_slice($industries, $start, $perPage);
|
|
||||||
$totalPages = ceil($total / $perPage);
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
<section class="bg-home-foreground py-16 lg:py-24 px-4 md:px-8 lg:px-24 xl:px-32 relative overflow-hidden">
|
<section class="bg-home-foreground py-16 lg:py-24 px-4 md:px-8 lg:px-24 xl:px-32 relative overflow-hidden">
|
||||||
|
|
||||||
<div class="max-w-7xl mx-auto">
|
<div class="max-w-7xl mx-auto">
|
||||||
@ -51,23 +16,20 @@
|
|||||||
|
|
||||||
<div id="category-container" class="fade-enter-active">
|
<div id="category-container" class="fade-enter-active">
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
||||||
@foreach ($currentItems as $industry)
|
@foreach ($categories as $category)
|
||||||
<article
|
<article
|
||||||
class="group flex flex-col items-center justify-center py-10 px-4 bg-white rounded-2xl border border-gray-100 hover:border-home-primary hover:shadow-xl hover:shadow-home-primary/5 hover:-translate-y-1 transition-all duration-300 cursor-pointer h-full">
|
class="category-item group flex flex-col items-center justify-center py-10 px-4 bg-white rounded-2xl border border-gray-100 hover:border-home-primary hover:shadow-xl hover:shadow-home-primary/5 hover:-translate-y-1 transition-all duration-300 cursor-pointer h-full"
|
||||||
|
wire:key="category-{{ $category['id'] }}">
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="w-14 h-14 mb-4 rounded-full bg-gray-50 flex items-center justify-center group-hover:bg-home-primary transition-colors duration-300">
|
class="w-24 h-24 mb-4 rounded-full bg-gray-50 flex items-center justify-center group-hover:bg-home-primary transition-colors duration-300 overflow-hidden">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
<img src="{{ $category['image'] }}" alt="{{ $category['name'] }}"
|
||||||
stroke-width="1.5" stroke="currentColor"
|
class="w-full h-full object-cover transition-transform duration-300 group-hover:scale-110">
|
||||||
class="w-7 h-7 text-gray-400 group-hover:text-white transition-colors duration-300">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round"
|
|
||||||
d="M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3
|
<h3
|
||||||
class="text-[11px] md:text-xs font-bold tracking-widest text-gray-400 uppercase group-hover:text-home-primary transition-colors duration-300 text-center">
|
class="text-[11px] md:text-xs font-bold tracking-widest text-gray-400 uppercase group-hover:text-home-primary transition-colors duration-300 text-center">
|
||||||
{{ $industry['name'] }}
|
{{ $category['name'] }}
|
||||||
</h3>
|
</h3>
|
||||||
</article>
|
</article>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -76,18 +38,18 @@ class="text-[11px] md:text-xs font-bold tracking-widest text-gray-400 uppercase
|
|||||||
|
|
||||||
<nav class="mt-12 flex flex-col items-center space-y-4 lg:hidden" aria-label="Pagination Mobile">
|
<nav class="mt-12 flex flex-col items-center space-y-4 lg:hidden" aria-label="Pagination Mobile">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@for ($i = 1; $i <= $totalPages; $i++)
|
@for ($i = 1; $i <= $categories->lastPage(); $i++)
|
||||||
<a href="?page={{ $i }}" aria-label="Halaman {{ $i }}"
|
<a href="?page={{ $i }}" aria-label="Halaman {{ $i }}"
|
||||||
class="w-2 h-2 rounded-full transition-all duration-300 {{ $i == $page ? 'bg-home-primary w-8' : 'bg-gray-300 hover:bg-gray-400' }}"></a>
|
class="pagination-link w-2 h-2 rounded-full transition-all duration-300 {{ $i == $categories->currentPage() ? 'bg-home-primary w-8' : 'bg-gray-300 hover:bg-gray-400' }}"></a>
|
||||||
@endfor
|
@endfor
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<nav class="hidden lg:flex absolute top-0 -right-16 h-full items-center" aria-label="Pagination Desktop">
|
<nav class="hidden lg:flex absolute top-0 -right-16 h-full items-center" aria-label="Pagination Desktop">
|
||||||
<div class="flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
@for ($i = 1; $i <= $totalPages; $i++)
|
@for ($i = 1; $i <= $categories->lastPage(); $i++)
|
||||||
<a href="?page={{ $i }}" aria-label="Halaman {{ $i }}"
|
<a href="{{ $categories->url($i) }}"
|
||||||
class="w-1 rounded-full transition-all duration-300 {{ $i == $page ? 'bg-home-primary h-12' : 'bg-gray-200 h-6 hover:bg-gray-300' }}"></a>
|
class="pagination-link w-1 rounded-full transition-all duration-300 {{ $i == $categories->currentPage() ? 'bg-home-primary h-12' : 'bg-gray-200 h-6 hover:bg-gray-300' }}"></a>
|
||||||
@endfor
|
@endfor
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -47,6 +47,27 @@
|
|||||||
placeholder="Aromaterapi merupakan wewangian yang dapat membantu meredakan stress dan meredakan perasaan sakit kepala."
|
placeholder="Aromaterapi merupakan wewangian yang dapat membantu meredakan stress dan meredakan perasaan sakit kepala."
|
||||||
auotocomplete="off" class="**:data-[slot=content]:min-h-[100px]!" />
|
auotocomplete="off" class="**:data-[slot=content]:min-h-[100px]!" />
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="text-sm font-medium">Gambar</h3>
|
||||||
|
<div class="dropzone-wrapper">
|
||||||
|
<livewire:dropzone wire:model="form.image" :rules="['image', 'mimes:png,jpeg', 'max:10420']" :max-files="1" :key="'image'"
|
||||||
|
:files="$form->image ?? []" />
|
||||||
|
@error('form.image')
|
||||||
|
<div role="alert" aria-live="polite" aria-atomic="true"
|
||||||
|
class="mt-3 text-sm font-medium text-red-500 dark:text-red-400">
|
||||||
|
<svg class="shrink-0 [:where(&)]:size-5 inline" data-flux-icon=""
|
||||||
|
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"
|
||||||
|
aria-hidden="true" data-slot="icon">
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495ZM10 5a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 10 5Zm0 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"
|
||||||
|
clip-rule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
{{ $message }}
|
||||||
|
</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<flux:spacer />
|
<flux:spacer />
|
||||||
<flux:button variant="primary" class="sm:w-auto cursor-pointer" wire:click="{{ $method }}">
|
<flux:button variant="primary" class="sm:w-auto cursor-pointer" wire:click="{{ $method }}">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user