refactor(home): membuat layouting
- memperbaiki custom js - menyimpan menu untuk header di view service dan di foreach - menghapus file yang tidak berguna - membuat halaman outlet
This commit is contained in:
parent
358ca2d932
commit
1aa8f3da42
@ -27,7 +27,7 @@ public function mount()
|
||||
{
|
||||
$this->brands = Brand::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn(Brand $brand) => [
|
||||
->map(fn (Brand $brand) => [
|
||||
'name' => $brand->name,
|
||||
'image' => $brand->getFirstMediaUrl('image') ? Storage::url($brand->getFirstMediaUrl('image')) : asset('assets/images/logo.png'),
|
||||
])
|
||||
@ -35,7 +35,7 @@ public function mount()
|
||||
|
||||
$this->perfumeFeatures = PerfumeFeature::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn(PerfumeFeature $perfumeFeature) => [
|
||||
->map(fn (PerfumeFeature $perfumeFeature) => [
|
||||
'name' => $perfumeFeature->name,
|
||||
'description' => $perfumeFeature->description,
|
||||
])
|
||||
@ -43,7 +43,7 @@ public function mount()
|
||||
|
||||
$this->faqs = Faq::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn(Faq $faq) => [
|
||||
->map(fn (Faq $faq) => [
|
||||
'question' => $faq->question,
|
||||
'answer' => $faq->answer,
|
||||
])
|
||||
@ -51,7 +51,7 @@ public function mount()
|
||||
|
||||
$this->whyChooseUs = ChooseUs::orderBy('sort_order')
|
||||
->get()
|
||||
->map(fn(ChooseUs $chooseUs) => [
|
||||
->map(fn (ChooseUs $chooseUs) => [
|
||||
'name' => $chooseUs->name,
|
||||
'description' => $chooseUs->description,
|
||||
])
|
||||
@ -64,7 +64,7 @@ public function render()
|
||||
'pageTitle' => 'Beranda',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function goToProduct()
|
||||
{
|
||||
return redirect('/product');
|
||||
|
||||
17
app/Livewire/Home/Outlet.php
Normal file
17
app/Livewire/Home/Outlet.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Livewire\Home;
|
||||
|
||||
use Livewire\Attributes\Layout;
|
||||
use Livewire\Component;
|
||||
|
||||
#[Layout('components.layouts.home', [
|
||||
'title' => 'Outlet',
|
||||
])]
|
||||
class Outlet extends Component
|
||||
{
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.home.outlets');
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,6 @@
|
||||
])]
|
||||
class Index extends Component
|
||||
{
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.home.product.index');
|
||||
|
||||
@ -262,7 +262,65 @@ public function boot(): void
|
||||
],
|
||||
];
|
||||
|
||||
$view->with('sidebar', $sidebar);
|
||||
$header = [
|
||||
[
|
||||
'title' => 'Beranda',
|
||||
'type' => 'link',
|
||||
'route' => 'homepage',
|
||||
'match' => 'homepage',
|
||||
],
|
||||
[
|
||||
'title' => 'Outlet',
|
||||
'type' => 'link',
|
||||
'route' => 'outlet',
|
||||
'match' => 'outlet',
|
||||
],
|
||||
[
|
||||
'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.*',
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'title' => 'Voucher',
|
||||
'type' => 'link',
|
||||
'route' => 'voucher.index',
|
||||
'match' => 'voucher.*',
|
||||
],
|
||||
[
|
||||
'title' => 'Artikel',
|
||||
'type' => 'link',
|
||||
'route' => 'article.index',
|
||||
'match' => 'article.*',
|
||||
],
|
||||
[
|
||||
'title' => 'FAQ',
|
||||
'type' => 'link',
|
||||
'route' => 'faq',
|
||||
'match' => 'faq',
|
||||
],
|
||||
];
|
||||
|
||||
$view->with([
|
||||
'sidebar' => $sidebar,
|
||||
'header' => $header,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,20 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
@include('components.partials.home._meta')
|
||||
@include('components.partials.home._css')
|
||||
</head>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ $title }} | {{ config('app.name') }}</title>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@fluxAppearance
|
||||
<link rel="icon" type="image/png" href="{{ asset('assets/images/logo.png') }}">
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=inter:400,500,600&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body>
|
||||
@include('components.partials.home._header')
|
||||
|
||||
@include("components.partials.home._header")
|
||||
|
||||
{{ $slot }}
|
||||
|
||||
@include("components.partials.home._footer")
|
||||
|
||||
@include('components.partials.home._js')
|
||||
</body>
|
||||
@persist('toast')
|
||||
<flux:toast position="bottom end" class="ps-6" />
|
||||
@endpersist
|
||||
|
||||
{{ $slot }}
|
||||
@fluxScripts
|
||||
|
||||
<script>
|
||||
document.addEventListener('livewire:navigated', () => {
|
||||
const navbar = document.getElementById('navbar');
|
||||
const navLinks = document.getElementById('nav-links');
|
||||
const cart = document.getElementById('cart');
|
||||
const login = document.getElementById('login');
|
||||
const profile = document.getElementById('profile');
|
||||
const cartIcon = document.getElementById('cart-icon');
|
||||
const cartSvg = document.getElementById('cart-svg');
|
||||
const profileIcon = document.getElementById('profile-icon');
|
||||
const profileSvg = document.getElementById('profile-svg');
|
||||
|
||||
const mobileBtn = document.getElementById('mobile-menu-btn');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const hamburgerIcon = document.getElementById('hamburger-icon');
|
||||
const closeIcon = document.getElementById('close-icon');
|
||||
|
||||
function setIconsLight() {
|
||||
cartIcon.classList.remove('bg-black', 'bg-gray-100');
|
||||
cartIcon.classList.add('bg-white');
|
||||
cartSvg.classList.remove('text-white', 'text-gray-800');
|
||||
cartSvg.classList.add('text-black');
|
||||
|
||||
profileIcon.classList.remove('bg-black', 'bg-gray-100');
|
||||
profileIcon.classList.add('bg-white');
|
||||
profileSvg.classList.remove('text-white', 'text-gray-800');
|
||||
profileSvg.classList.add('text-black');
|
||||
}
|
||||
|
||||
function setIconsDark() {
|
||||
cartIcon.classList.add('bg-black');
|
||||
cartIcon.classList.remove('bg-white', 'bg-gray-100');
|
||||
cartSvg.classList.add('text-white');
|
||||
cartSvg.classList.remove('text-black', 'text-gray-800');
|
||||
|
||||
profileIcon.classList.add('bg-black');
|
||||
profileIcon.classList.remove('bg-white', 'bg-gray-100');
|
||||
profileSvg.classList.add('text-white');
|
||||
profileSvg.classList.remove('text-black', 'text-gray-800');
|
||||
}
|
||||
|
||||
function setIconsScrolled() {
|
||||
cartIcon.classList.add('bg-gray-100');
|
||||
cartIcon.classList.remove('bg-black', 'bg-white');
|
||||
cartSvg.classList.add('text-gray-800');
|
||||
cartSvg.classList.remove('text-white', 'text-black');
|
||||
|
||||
profileIcon.classList.add('bg-gray-100');
|
||||
profileIcon.classList.remove('bg-black', 'bg-white');
|
||||
profileSvg.classList.add('text-gray-800');
|
||||
profileSvg.classList.remove('text-white', 'text-black');
|
||||
}
|
||||
|
||||
mobileBtn.addEventListener('click', () => {
|
||||
const isClosed = mobileMenu.classList.contains('hidden');
|
||||
|
||||
if (isClosed) {
|
||||
mobileMenu.classList.remove('hidden');
|
||||
void mobileMenu.offsetWidth;
|
||||
mobileMenu.classList.remove('opacity-0');
|
||||
mobileMenu.classList.add('opacity-100');
|
||||
|
||||
hamburgerIcon.classList.add('hidden');
|
||||
closeIcon.classList.remove('hidden');
|
||||
mobileBtn.setAttribute('aria-expanded', 'true');
|
||||
|
||||
navbar.classList.remove('bg-white/40', 'backdrop-blur-md', 'shadow-sm',
|
||||
'border-gray-200');
|
||||
navbar.classList.add('bg-transparent');
|
||||
|
||||
setIconsLight();
|
||||
|
||||
} else {
|
||||
mobileMenu.classList.remove('opacity-100');
|
||||
mobileMenu.classList.add('opacity-0');
|
||||
|
||||
setTimeout(() => {
|
||||
mobileMenu.classList.add('hidden');
|
||||
}, 500);
|
||||
|
||||
hamburgerIcon.classList.remove('hidden');
|
||||
closeIcon.classList.add('hidden');
|
||||
mobileBtn.setAttribute('aria-expanded', 'false');
|
||||
|
||||
const scrolled = window.scrollY > 10;
|
||||
if (scrolled) {
|
||||
navbar.classList.add('bg-white/40', 'backdrop-blur-md', 'shadow-sm',
|
||||
'border-gray-200');
|
||||
navbar.classList.remove('bg-transparent');
|
||||
setIconsScrolled();
|
||||
} else {
|
||||
navbar.classList.add('bg-transparent');
|
||||
navbar.classList.remove('bg-white/40', 'backdrop-blur-md', 'shadow-sm',
|
||||
'border-gray-200');
|
||||
setIconsDark();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
const isMenuOpen = !mobileMenu.classList.contains('hidden');
|
||||
if (isMenuOpen) return;
|
||||
|
||||
const scrolled = window.scrollY > 10;
|
||||
|
||||
if (scrolled) {
|
||||
navbar.classList.add('bg-white/40', 'backdrop-blur-md', 'shadow-sm', 'border-gray-200');
|
||||
navbar.classList.remove('bg-transparent');
|
||||
|
||||
navLinks.classList.add('bg-white', 'border-gray-300', 'text-black');
|
||||
navLinks.classList.remove('bg-transparent', 'border-black', 'text-black');
|
||||
|
||||
cart.classList.add('border-gray-300', 'bg-white');
|
||||
cart.classList.remove('border-black');
|
||||
cart.querySelector('span').classList.add('text-gray-800');
|
||||
|
||||
login.classList.add('border-gray-300', 'text-gray-800', 'bg-white');
|
||||
login.classList.remove('border-black', 'text-black');
|
||||
|
||||
profile.classList.add('border-gray-300');
|
||||
profile.classList.remove('border-black');
|
||||
|
||||
setIconsScrolled();
|
||||
} else {
|
||||
navbar.classList.add('bg-transparent');
|
||||
navbar.classList.remove('bg-white/40', 'backdrop-blur-md', 'shadow-sm', 'border-b',
|
||||
'border-gray-200');
|
||||
|
||||
navLinks.classList.add('bg-transparent', 'border-black', 'text-black');
|
||||
navLinks.classList.remove('bg-white', 'border-gray-300');
|
||||
|
||||
cart.classList.add('border-black');
|
||||
cart.classList.remove('border-gray-300', 'bg-white');
|
||||
cart.querySelector('span').classList.remove('text-gray-800');
|
||||
cart.querySelector('span').classList.add('text-black');
|
||||
|
||||
login.classList.add('border-black', 'text-black');
|
||||
login.classList.remove('border-gray-300', 'text-gray-800', 'bg-white');
|
||||
|
||||
profile.classList.add('border-black');
|
||||
profile.classList.remove('border-gray-300');
|
||||
|
||||
setIconsDark();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
{{-- <link rel="shortcut icon" href="{{ asset('assets/img/favicon.png') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/plugins.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/style.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('assets/css/colors/grape.css') }}">
|
||||
<link rel="preload" href="{{ asset('assets/css/fonts/space.css') }}" as="style" onload="this.rel='stylesheet'"> --}}
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@ -26,27 +26,38 @@ class="w-10 h-8 lg:w-16 lg:h-12 transition-all duration-500">
|
||||
<nav id="nav-links"
|
||||
class="hidden lg:flex items-center gap-6 font-medium px-8 py-3 rounded-full transition-all duration-500 border"
|
||||
aria-label="Main Navigation">
|
||||
<a href="#" class="hover:opacity-80 transition-opacity">Beranda</a>
|
||||
<a href="#" class="hover:opacity-80 transition-opacity">Outlet</a>
|
||||
<div class="relative group">
|
||||
<button wire:click="goToProduct" class="flex items-center gap-2 hover:opacity-80 transition-opacity">
|
||||
<span>Produk</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" class="size-4 group-hover:rotate-180 transition-transform duration-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
<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">
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-50 transition-colors">Parfum</a>
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-50 transition-colors">Botol</a>
|
||||
<a href="#" class="block px-4 py-2 hover:bg-gray-50 transition-colors">Arabian</a>
|
||||
@foreach ($header as $item)
|
||||
@if ($item['type'] === 'link')
|
||||
<a href="{{ route($item['route']) }}" class="hover:opacity-80 transition-opacity" wire:navigate>
|
||||
{{ $item['title'] }}
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@if ($item['type'] === 'dropdown')
|
||||
<div class="relative group">
|
||||
<button wire:click="{{ $item['action'] }}"
|
||||
class="flex items-center gap-2 hover:opacity-80 transition-opacity">
|
||||
<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"
|
||||
class="size-4 group-hover:rotate-180 transition-transform duration-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<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">
|
||||
{{ $sub['title'] }}
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a wire:click="goToVoucher" class="hover:opacity-80 transition-opacity cursor-pointer">Voucher</a>
|
||||
<a href="#" class="hover:opacity-80 transition-opacity">Artikel</a>
|
||||
<a href="#" class="hover:opacity-80 transition-opacity">FAQ</a>
|
||||
@endif
|
||||
@endforeach
|
||||
</nav>
|
||||
|
||||
<section class="flex items-center lg:gap-3 z-50">
|
||||
@ -110,151 +121,3 @@ class="mt-8 px-8 py-3 bg-white text-black font-bold rounded-full hover:bg-gray-1
|
||||
</button>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const navbar = document.getElementById('navbar');
|
||||
const navLinks = document.getElementById('nav-links');
|
||||
const cart = document.getElementById('cart');
|
||||
const login = document.getElementById('login');
|
||||
const profile = document.getElementById('profile');
|
||||
const cartIcon = document.getElementById('cart-icon');
|
||||
const cartSvg = document.getElementById('cart-svg');
|
||||
const profileIcon = document.getElementById('profile-icon');
|
||||
const profileSvg = document.getElementById('profile-svg');
|
||||
|
||||
const mobileBtn = document.getElementById('mobile-menu-btn');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
const hamburgerIcon = document.getElementById('hamburger-icon');
|
||||
const closeIcon = document.getElementById('close-icon');
|
||||
|
||||
function setIconsLight() {
|
||||
cartIcon.classList.remove('bg-black', 'bg-gray-100');
|
||||
cartIcon.classList.add('bg-white');
|
||||
cartSvg.classList.remove('text-white', 'text-gray-800');
|
||||
cartSvg.classList.add('text-black');
|
||||
|
||||
profileIcon.classList.remove('bg-black', 'bg-gray-100');
|
||||
profileIcon.classList.add('bg-white');
|
||||
profileSvg.classList.remove('text-white', 'text-gray-800');
|
||||
profileSvg.classList.add('text-black');
|
||||
}
|
||||
|
||||
function setIconsDark() {
|
||||
cartIcon.classList.add('bg-black');
|
||||
cartIcon.classList.remove('bg-white', 'bg-gray-100');
|
||||
cartSvg.classList.add('text-white');
|
||||
cartSvg.classList.remove('text-black', 'text-gray-800');
|
||||
|
||||
profileIcon.classList.add('bg-black');
|
||||
profileIcon.classList.remove('bg-white', 'bg-gray-100');
|
||||
profileSvg.classList.add('text-white');
|
||||
profileSvg.classList.remove('text-black', 'text-gray-800');
|
||||
}
|
||||
|
||||
function setIconsScrolled() {
|
||||
cartIcon.classList.add('bg-gray-100');
|
||||
cartIcon.classList.remove('bg-black', 'bg-white');
|
||||
cartSvg.classList.add('text-gray-800');
|
||||
cartSvg.classList.remove('text-white', 'text-black');
|
||||
|
||||
profileIcon.classList.add('bg-gray-100');
|
||||
profileIcon.classList.remove('bg-black', 'bg-white');
|
||||
profileSvg.classList.add('text-gray-800');
|
||||
profileSvg.classList.remove('text-white', 'text-black');
|
||||
}
|
||||
|
||||
mobileBtn.addEventListener('click', () => {
|
||||
const isClosed = mobileMenu.classList.contains('hidden');
|
||||
|
||||
if (isClosed) {
|
||||
mobileMenu.classList.remove('hidden');
|
||||
void mobileMenu.offsetWidth;
|
||||
mobileMenu.classList.remove('opacity-0');
|
||||
mobileMenu.classList.add('opacity-100');
|
||||
|
||||
hamburgerIcon.classList.add('hidden');
|
||||
closeIcon.classList.remove('hidden');
|
||||
mobileBtn.setAttribute('aria-expanded', 'true');
|
||||
|
||||
navbar.classList.remove('bg-white/40', 'backdrop-blur-md', 'shadow-sm',
|
||||
'border-gray-200');
|
||||
navbar.classList.add('bg-transparent');
|
||||
|
||||
setIconsLight();
|
||||
|
||||
} else {
|
||||
mobileMenu.classList.remove('opacity-100');
|
||||
mobileMenu.classList.add('opacity-0');
|
||||
|
||||
setTimeout(() => {
|
||||
mobileMenu.classList.add('hidden');
|
||||
}, 500);
|
||||
|
||||
hamburgerIcon.classList.remove('hidden');
|
||||
closeIcon.classList.add('hidden');
|
||||
mobileBtn.setAttribute('aria-expanded', 'false');
|
||||
|
||||
const scrolled = window.scrollY > 10;
|
||||
if (scrolled) {
|
||||
navbar.classList.add('bg-white/40', 'backdrop-blur-md', 'shadow-sm',
|
||||
'border-gray-200');
|
||||
navbar.classList.remove('bg-transparent');
|
||||
setIconsScrolled();
|
||||
} else {
|
||||
navbar.classList.add('bg-transparent');
|
||||
navbar.classList.remove('bg-white/40', 'backdrop-blur-md', 'shadow-sm',
|
||||
'border-gray-200');
|
||||
setIconsDark();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
const isMenuOpen = !mobileMenu.classList.contains('hidden');
|
||||
if (isMenuOpen) return;
|
||||
|
||||
const scrolled = window.scrollY > 10;
|
||||
|
||||
if (scrolled) {
|
||||
navbar.classList.add('bg-white/40', 'backdrop-blur-md', 'shadow-sm', 'border-gray-200');
|
||||
navbar.classList.remove('bg-transparent');
|
||||
|
||||
navLinks.classList.add('bg-white', 'border-gray-300', 'text-black');
|
||||
navLinks.classList.remove('bg-transparent', 'border-black', 'text-black');
|
||||
|
||||
cart.classList.add('border-gray-300', 'bg-white');
|
||||
cart.classList.remove('border-black');
|
||||
cart.querySelector('span').classList.add('text-gray-800');
|
||||
|
||||
login.classList.add('border-gray-300', 'text-gray-800', 'bg-white');
|
||||
login.classList.remove('border-black', 'text-black');
|
||||
|
||||
profile.classList.add('border-gray-300');
|
||||
profile.classList.remove('border-black');
|
||||
|
||||
setIconsScrolled();
|
||||
} else {
|
||||
navbar.classList.add('bg-transparent');
|
||||
navbar.classList.remove('bg-white/40', 'backdrop-blur-md', 'shadow-sm', 'border-b',
|
||||
'border-gray-200');
|
||||
|
||||
navLinks.classList.add('bg-transparent', 'border-black', 'text-black');
|
||||
navLinks.classList.remove('bg-white', 'border-gray-300');
|
||||
|
||||
cart.classList.add('border-black');
|
||||
cart.classList.remove('border-gray-300', 'bg-white');
|
||||
cart.querySelector('span').classList.remove('text-gray-800');
|
||||
cart.querySelector('span').classList.add('text-black');
|
||||
|
||||
login.classList.add('border-black', 'text-black');
|
||||
login.classList.remove('border-gray-300', 'text-gray-800', 'bg-white');
|
||||
|
||||
profile.classList.add('border-black');
|
||||
profile.classList.remove('border-gray-300');
|
||||
|
||||
setIconsDark();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
{{-- <script src="{{ asset('assets/js/plugins.js') }}"></script>
|
||||
<script src="{{ asset('assets/js/theme.js') }}"></script> --}}
|
||||
@ -1,8 +0,0 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description"
|
||||
content="An impressive and flawless site template that includes various UI elements and countless features, attractive ready-made blocks and rich pages, basically everything you need to create a unique and professional website.">
|
||||
<meta name="keywords"
|
||||
content="bootstrap 5, business, corporate, creative, gulp, marketing, minimal, modern, multipurpose, one page, responsive, saas, sass, seo, startup, html5 template, site template">
|
||||
<meta name="author" content="elemis">
|
||||
<title>{{ $title }} - {{ config('app.name') }}</title>
|
||||
@ -15,32 +15,39 @@
|
||||
['id' => 4, 'q' => 'Bagaimana kebijakan pengembalian barang?', 'a' => 'Pengembalian dalam 30 hari dengan syarat barang belum digunakan, segel utuh, dan menyertakan video unboxing.'],
|
||||
['id' => 5, 'q' => 'Metode pembayaran apa saja yang tersedia?', 'a' => 'Kami menerima Transfer bank (BCA, Mandiri), Kartu Kredit, E-wallet (GoPay, OVO), dan cicilan 0%.'],
|
||||
['id' => 6, 'q' => 'Bagaimana cara menggunakan voucher?', 'a' => 'Masukkan kode voucher pada halaman checkout di kolom "Kode Promo", diskon akan otomatis terpotong.'],
|
||||
] as $faq)
|
||||
<article
|
||||
] as $index => $faq)
|
||||
<article x-data="{ open: null }"
|
||||
class="bg-white rounded-2xl border border-home-foreground/10 overflow-hidden break-inside-avoid mb-6 shadow-sm">
|
||||
<button
|
||||
class="w-full px-6 py-5 flex items-center justify-between hover:bg-home-foreground/5 transition-colors accordion-trigger"
|
||||
data-accordion="{{ $faq['id'] }}" aria-expanded="false"
|
||||
aria-controls="faq-content-{{ $faq['id'] }}">
|
||||
|
||||
<button @click="open === {{ $index }} ? open = null : open = {{ $index }}"
|
||||
:aria-expanded="open === {{ $index }}"
|
||||
class="w-full px-6 py-5 flex items-center justify-between hover:bg-home-foreground/5 transition-colors">
|
||||
|
||||
<h3 class="text-lg font-bold text-home-foreground text-left pr-4">
|
||||
{{ $faq['q'] }}
|
||||
</h3>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
class="w-6 h-6 text-home-foreground accordion-icon transition-transform duration-300 flex-shrink-0"
|
||||
fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||
class="w-6 h-6 text-home-foreground transition-transform duration-300"
|
||||
:class="{ 'rotate-180': open === {{ $index }} }" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="2" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
|
||||
<div id="faq-content-{{ $faq['id'] }}"
|
||||
class="accordion-content hidden px-6 py-5 border-t border-home-foreground/10"
|
||||
data-content="{{ $faq['id'] }}">
|
||||
<p class="text-home-foreground/70 leading-relaxed">{{ $faq['a'] }}</p>
|
||||
<div x-show="open === {{ $index }}" x-collapse
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
class="px-6 pb-5 border-t border-home-foreground/10 text-home-foreground/70">
|
||||
<p class="leading-relaxed">
|
||||
{{ $faq['a'] }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-10 bg-home-foreground/5 rounded-2xl border border-home-foreground/10 p-8 text-center">
|
||||
@ -53,38 +60,3 @@ class="bg-home-foreground text-white font-bold px-8 py-3 rounded-lg hover:opacit
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.querySelectorAll('.accordion-trigger').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const id = btn.dataset.accordion;
|
||||
const content = document.querySelector(`[data-content="${id}"]`);
|
||||
const icon = btn.querySelector('.accordion-icon');
|
||||
|
||||
document.querySelectorAll('.accordion-content').forEach(el => {
|
||||
if (el.dataset.content !== id) {
|
||||
el.classList.add('hidden');
|
||||
const otherBtn = document.querySelector(
|
||||
`[data-accordion="${el.dataset.content}"]`);
|
||||
if (otherBtn) {
|
||||
otherBtn.setAttribute('aria-expanded', 'false');
|
||||
otherBtn.querySelector('.accordion-icon').style.transform =
|
||||
'rotate(0deg)';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
content.classList.toggle('hidden');
|
||||
|
||||
if (content.classList.contains('hidden')) {
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
btn.setAttribute('aria-expanded', 'false');
|
||||
} else {
|
||||
icon.style.transform = 'rotate(180deg)';
|
||||
btn.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -6,3 +6,104 @@
|
||||
@include('livewire.home.partials.benefits')
|
||||
@include('livewire.home.partials.cta')
|
||||
</div>
|
||||
|
||||
@assets
|
||||
<style>
|
||||
#brand-slider img {
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.6;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#brand-slider img:hover {
|
||||
filter: grayscale(0%);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fade-enter {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
.fade-enter-active {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition: all .4s ease;
|
||||
}
|
||||
</style>
|
||||
@endassets
|
||||
|
||||
@script
|
||||
<script>
|
||||
document.addEventListener('livewire:navigated', () => {
|
||||
// brand slider
|
||||
const track = document.getElementById('brand-track');
|
||||
const originalChildren = Array.from(track.children);
|
||||
const originalHTML = track.innerHTML;
|
||||
|
||||
if (originalChildren.length === 0) return;
|
||||
|
||||
const itemWidth = originalChildren[0].offsetWidth;
|
||||
const gapStyle = window.getComputedStyle(track).gap;
|
||||
const gap = parseFloat(gapStyle) || 0;
|
||||
|
||||
const singleSetWidth = (itemWidth + gap) * originalChildren.length;
|
||||
|
||||
let currentWidth = singleSetWidth;
|
||||
while (currentWidth < window.innerWidth + singleSetWidth * 2) {
|
||||
track.innerHTML += originalHTML;
|
||||
currentWidth
|
||||
+= singleSetWidth;
|
||||
}
|
||||
let position = 0;
|
||||
const speed = 1;
|
||||
|
||||
function animate() {
|
||||
position -= speed;
|
||||
if (Math.abs(position) >=
|
||||
singleSetWidth) {
|
||||
position = 0;
|
||||
}
|
||||
|
||||
track.style.transform = `translateX(${position}px)`;
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
animate();
|
||||
|
||||
// category pagination
|
||||
const links = document.querySelectorAll('.pagination-link');
|
||||
const container = document.getElementById('category-container');
|
||||
|
||||
links.forEach(link => {
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
|
||||
links.forEach(l => l.classList.remove('bg-black'));
|
||||
links.forEach(l => l.classList.add('bg-gray-400'));
|
||||
|
||||
e.target.classList.remove('bg-gray-400');
|
||||
e.target.classList.add('bg-black');
|
||||
|
||||
fetch(link.href)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const newContent = doc.querySelector('#category-container')
|
||||
.innerHTML;
|
||||
|
||||
container.classList.add('fade-enter');
|
||||
setTimeout(() => {
|
||||
container.innerHTML = newContent;
|
||||
container.classList.remove('fade-enter');
|
||||
container.classList.add('fade-enter-active');
|
||||
}, 120);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endscript
|
||||
|
||||
3
resources/views/livewire/home/outlets.blade.php
Normal file
3
resources/views/livewire/home/outlets.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="">
|
||||
Outlet
|
||||
</div>
|
||||
@ -23,74 +23,42 @@
|
||||
];
|
||||
@endphp
|
||||
|
||||
<section class="bg-white py-20 px-6 lg:px-48 relative overflow-hidden font-sans text-home-foreground">
|
||||
<div class="absolute top-24 left-[40%] w-4 h-4 bg-gray-200 rounded-full opacity-50"></div>
|
||||
<div class="absolute top-32 left-[30%] w-2 h-2 bg-orange-200 rounded-full opacity-50"></div>
|
||||
<div class="absolute bottom-10 right-[20%] w-2 h-2 bg-red-200 rounded-full opacity-50"></div>
|
||||
|
||||
<div class="grid lg:grid-cols-2 gap-12 mb-20 items-start">
|
||||
<section class="bg-white py-20 px-6 lg:px-48 font-sans text-home-foreground">
|
||||
<div class="grid lg:grid-cols-2 gap-12 items-start">
|
||||
<figure class="w-full">
|
||||
<img src="https://images.unsplash.com/photo-1523275335684-37898b6baf30?q=80"
|
||||
class="w-full h-[500px] object-cover rounded-2xl shadow" alt="Parfum Premium">
|
||||
class="w-full h-[500px] object-cover rounded-2xl shadow">
|
||||
</figure>
|
||||
|
||||
<article class="space-y-4 mt-4 lg:mt-0">
|
||||
<h2 class="text-4xl leading-tight mb-6 text-home-foreground">
|
||||
Keunggulan Produk Kami.
|
||||
</h2>
|
||||
<article class="space-y-4">
|
||||
<h2 class="text-4xl leading-tight mb-6">Keunggulan Produk Kami.</h2>
|
||||
<p class="text-gray-700 mb-8 max-w-3xl leading-relaxed">
|
||||
Setiap parfum dibuat dengan standar tinggi agar kamu mendapatkan kualitas terbaik.
|
||||
Dan kalau kamu ingin pengalaman yang lebih eksklusif, ada paket membership yang bikin kamu jauh lebih
|
||||
hemat dan leluasa mencoba banyak aroma.
|
||||
</p>
|
||||
|
||||
@foreach ($accordions as $acc)
|
||||
<div class="border-b border-gray-200 pb-4 accordion-item">
|
||||
<button class="w-full flex justify-between items-center py-2 text-left group focus:outline-none"
|
||||
onclick="toggleAccordion(this)" aria-expanded="false">
|
||||
@foreach ($accordions as $index => $acc)
|
||||
<div x-data="{ open: null }" class="border-b border-gray-200 pb-4 accordion-item">
|
||||
<button @click="open === {{ $index }} ? open = null : open = {{ $index }}"
|
||||
class="w-full flex justify-between items-center py-2 text-left group focus:outline-none"
|
||||
:aria-expanded="open === {{ $index }}">
|
||||
<span class="text-lg font-semibold text-home-foreground group-hover:text-gray-600 transition">
|
||||
{{ $acc['title'] }}
|
||||
</span>
|
||||
<span
|
||||
class="text-xl font-light text-gray-400 transition-transform duration-300 icon-plus">+</span>
|
||||
|
||||
<span class="icon-plus text-xl font-light text-gray-400 transition-transform duration-300"
|
||||
:class="{ 'rotate-45': open === {{ $index }} }">
|
||||
+
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
class="max-h-0 overflow-hidden transition-all duration-500 ease-in-out content text-gray-700 text-sm leading-relaxed">
|
||||
<div class="pt-2 pb-2">{{ $acc['content'] }}</div>
|
||||
<div x-show="open === {{ $index }}" x-collapse
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
class="min-h-0 content overflow-hidden text-gray-700 text-sm leading-relaxed">
|
||||
<div class="pt-2 pb-2">
|
||||
{{ $acc['content'] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function toggleAccordion(button) {
|
||||
const content = button.nextElementSibling;
|
||||
const icon = button.querySelector('.icon-plus');
|
||||
|
||||
document.querySelectorAll('.accordion-item').forEach(item => {
|
||||
const otherBtn = item.querySelector('button');
|
||||
const otherContent = item.querySelector('.content');
|
||||
const otherIcon = item.querySelector('.icon-plus');
|
||||
|
||||
if (otherBtn !== button) {
|
||||
otherContent.style.maxHeight = null;
|
||||
otherIcon.textContent = '+';
|
||||
otherIcon.style.transform = 'rotate(0deg)';
|
||||
otherBtn.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
if (content.style.maxHeight) {
|
||||
content.style.maxHeight = null;
|
||||
icon.textContent = '+';
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
button.setAttribute('aria-expanded', 'false');
|
||||
} else {
|
||||
content.style.maxHeight = content.scrollHeight + 'px';
|
||||
icon.style.transform = 'rotate(45deg)';
|
||||
button.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -95,51 +95,3 @@ class="w-[3px] h-10 rounded-full pagination-link transition duration-300 {{ $i =
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.fade-enter {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
.fade-enter-active {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transition: all .4s ease;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const links = document.querySelectorAll('.pagination-link');
|
||||
const container = document.getElementById('category-container');
|
||||
|
||||
links.forEach(link => {
|
||||
link.addEventListener('click', e => {
|
||||
e.preventDefault();
|
||||
|
||||
links.forEach(l => l.classList.remove('bg-black'));
|
||||
links.forEach(l => l.classList.add('bg-gray-400'));
|
||||
|
||||
e.target.classList.remove('bg-gray-400');
|
||||
e.target.classList.add('bg-black');
|
||||
|
||||
fetch(link.href)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const newContent = doc.querySelector('#category-container')
|
||||
.innerHTML;
|
||||
|
||||
container.classList.add('fade-enter');
|
||||
setTimeout(() => {
|
||||
container.innerHTML = newContent;
|
||||
container.classList.remove('fade-enter');
|
||||
container.classList.add('fade-enter-active');
|
||||
}, 120);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<section class="overflow-hidden relative pt-4" id="brand-slider" aria-label="Teknologi yang digunakan">
|
||||
<section class="overflow-hidden relative pt-4" id="brand-slider" aria-label="Brand Slider">
|
||||
<div class="flex gap-6 items-center whitespace-nowrap will-change-transform" id="brand-track">
|
||||
|
||||
<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"
|
||||
@ -17,59 +16,5 @@ class="w-32 h-32 object-contain rounded-xl flex-shrink-0">
|
||||
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>
|
||||
|
||||
<style>
|
||||
#brand-slider img {
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.6;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#brand-slider img:hover {
|
||||
filter: grayscale(0%);
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const track = document.getElementById('brand-track');
|
||||
const originalChildren = Array.from(track.children);
|
||||
const originalHTML = track.innerHTML;
|
||||
|
||||
if (originalChildren.length === 0) return;
|
||||
|
||||
const itemWidth = originalChildren[0].offsetWidth;
|
||||
const gapStyle = window.getComputedStyle(track).gap;
|
||||
const gap = parseFloat(gapStyle) || 0;
|
||||
|
||||
const singleSetWidth = (itemWidth + gap) * originalChildren.length;
|
||||
|
||||
let currentWidth = singleSetWidth;
|
||||
while (currentWidth < window.innerWidth + singleSetWidth * 2) {
|
||||
track.innerHTML += originalHTML;
|
||||
currentWidth += singleSetWidth;
|
||||
}
|
||||
|
||||
let position = 0;
|
||||
const speed = 1;
|
||||
|
||||
function animate() {
|
||||
position -= speed;
|
||||
|
||||
if (Math.abs(position) >= singleSetWidth) {
|
||||
position = 0;
|
||||
}
|
||||
|
||||
track.style.transform = `translateX(${position}px)`;
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
animate();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -1,15 +1,37 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\Home\Index as HomeComponent;
|
||||
use App\Livewire\Home\Product\Index as ProductComponent;
|
||||
use App\Livewire\Home\Voucher\Index as VoucherComponent;
|
||||
use App\Livewire\Home\Article\Index as ArticleComponent;
|
||||
use App\Livewire\Home\Article\Index as ArticleIndex;
|
||||
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\Voucher\Index as VoucherIndex;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', HomeComponent::class)->name('homepage');
|
||||
Route::get('/product', ProductComponent::class)->name('product');
|
||||
Route::get('/voucher', VoucherComponent::class)->name('voucher');
|
||||
Route::get('/article', ArticleComponent::class)->name('article');
|
||||
|
||||
Route::get('/outlets', OutletComponent::class)->name('outlet');
|
||||
|
||||
Route::prefix('products')
|
||||
->name('product.')
|
||||
->group(function () {
|
||||
Route::prefix('perfumes')
|
||||
->name('perfume.')
|
||||
->group(function () {
|
||||
Route::get('/', ProductComponent::class)->name('index');
|
||||
});
|
||||
});
|
||||
|
||||
Route::prefix('vouchers')
|
||||
->name('voucher.')
|
||||
->group(function () {
|
||||
Route::get('/', VoucherIndex::class)->name('index');
|
||||
});
|
||||
|
||||
Route::prefix('articles')
|
||||
->name('article.')
|
||||
->group(function () {
|
||||
Route::get('/', ArticleIndex::class)->name('index');
|
||||
});
|
||||
|
||||
Route::get('/faq', FaqComponent::class)->name('faq');
|
||||
// Route::get('/', HomeComponent::class)->name('produk');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user