popular product, brand
This commit is contained in:
parent
6117a3580a
commit
3b91c813da
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ComponentController extends Controller
|
||||||
|
{
|
||||||
|
public function load(Request $request, $component)
|
||||||
|
{
|
||||||
|
$template = $request->get('template');
|
||||||
|
|
||||||
|
// Map component names to their blade views
|
||||||
|
$componentMap = [
|
||||||
|
'home-popular-products' => 'components.home.home-popular-products',
|
||||||
|
'product-highlight' => 'components.home.product-highlight',
|
||||||
|
'new-arrivals' => 'components.home.new-arrivals',
|
||||||
|
'brand-home' => 'components.home.brand-home-' . ($template ?? 'fashion-v1'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$view = $componentMap[$component] ?? null;
|
||||||
|
|
||||||
|
if (!$view) {
|
||||||
|
return response()->json(['error' => 'Component not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For brand-home component, we need to pass the template parameter
|
||||||
|
if ($component === 'brand-home') {
|
||||||
|
return view($view, ['template' => $template]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view($view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -174,6 +174,98 @@ class ProductController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function brands(Request $request)
|
||||||
|
{
|
||||||
|
$brandRepository = new \App\Repositories\Catalog\BrandRepository;
|
||||||
|
$brands = $brandRepository->getList([]);
|
||||||
|
|
||||||
|
// Render brand HTML
|
||||||
|
$brandHtml = '';
|
||||||
|
foreach ($brands as $brand) {
|
||||||
|
$brandHtml .= '<a class="swiper-slide text-body" href="' . route('product.index', ['brand' => $brand->slug]) . '" aria-label="' . $brand->name . '">';
|
||||||
|
$brandHtml .= '<img src="' . $brand->image_url . '" alt="' . $brand->name . '" class="object-fit-contain">';
|
||||||
|
$brandHtml .= '</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'brands' => $brandHtml
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function highlights(Request $request)
|
||||||
|
{
|
||||||
|
$type = $request->input('type', 'new');
|
||||||
|
$limit = 8;
|
||||||
|
|
||||||
|
$user = auth()->user();
|
||||||
|
$userId = $user ? $user->id : 0;
|
||||||
|
[$location_id, $is_consignment] = Cache::remember('employee_user_'.$userId, 60 * 60 * 24, function () use ($user) {
|
||||||
|
|
||||||
|
if ($user == null) {
|
||||||
|
return [10, false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$employee = @$user->employee;
|
||||||
|
$location_id = @$employee->location_id;
|
||||||
|
$location = @$employee->location;
|
||||||
|
$is_consignment = (bool) @$location->is_consignment;
|
||||||
|
|
||||||
|
return [$location_id, $is_consignment];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$productRepository = new ProductRepository;
|
||||||
|
|
||||||
|
// Set parameters based on type
|
||||||
|
$params = [
|
||||||
|
'limit' => $limit,
|
||||||
|
'location_id' => $location_id,
|
||||||
|
'is_consignment' => $is_consignment,
|
||||||
|
];
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'best_sellers':
|
||||||
|
$params['sort'] = 'random';
|
||||||
|
break;
|
||||||
|
case 'new_arrivals':
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
case 'sale_items':
|
||||||
|
$params['event'] = 'special-offer';
|
||||||
|
break;
|
||||||
|
case 'top_rated':
|
||||||
|
$params['sort'] = 'random';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$params['sort'] = 'new';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$products = $productRepository->getList($params);
|
||||||
|
|
||||||
|
// Render product cards HTML
|
||||||
|
$productHtml = '';
|
||||||
|
if (count($products) == 0) {
|
||||||
|
$productHtml = '<div class="col-12 text-center py-4">';
|
||||||
|
$productHtml .= 'No products found';
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
} else {
|
||||||
|
foreach ($products as $product) {
|
||||||
|
$productHtml .= '<div class="col mb-2 mb-sm-3 mb-md-0">';
|
||||||
|
$productHtml .= view('components.home.product-card', ['product' => $product])->render();
|
||||||
|
$productHtml .= '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'products' => $productHtml,
|
||||||
|
'count' => count($products),
|
||||||
|
'type' => $type
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function detail($slug, Request $request, ProductRepository $productRepository)
|
public function detail($slug, Request $request, ProductRepository $productRepository)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,24 +9,16 @@ use Illuminate\View\Component;
|
||||||
|
|
||||||
class BrandHome extends Component
|
class BrandHome extends Component
|
||||||
{
|
{
|
||||||
public $brands;
|
|
||||||
|
|
||||||
public $template = 'fashion-v1';
|
public $template = 'fashion-v1';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new component instance.
|
* Create a new component instance.
|
||||||
*/
|
*/
|
||||||
public function __construct(BrandRepository $brandRepository)
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->brands = $brandRepository->getList([]);
|
|
||||||
|
|
||||||
if ($this->brands->count() < 9) {
|
|
||||||
// Ensure we have at least 9 brands by duplicating if necessary
|
|
||||||
while ($this->brands->count() < 9) {
|
|
||||||
$this->brands = $this->brands->concat($this->brands);
|
|
||||||
}
|
|
||||||
$this->brands = $this->brands->take(9);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components\Home;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class HomePopularProducts extends Component
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the view / contents that represent the component.
|
||||||
|
*/
|
||||||
|
public function render(): View|Closure|string
|
||||||
|
{
|
||||||
|
return view('components.home.home-popular-products');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components\Home;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
|
class HomeSlider extends Component
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the view / contents that represent the component.
|
||||||
|
*/
|
||||||
|
public function render(): View|Closure|string
|
||||||
|
{
|
||||||
|
return view('components.home.home-slider');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,14 +9,11 @@ use Illuminate\View\Component;
|
||||||
|
|
||||||
class ProductHighlight extends Component
|
class ProductHighlight extends Component
|
||||||
{
|
{
|
||||||
public $products;
|
|
||||||
|
|
||||||
public function __construct(ProductRepository $productRepository)
|
|
||||||
|
public function __construct()
|
||||||
{
|
{
|
||||||
$params = [
|
|
||||||
'sort' => 'new',
|
|
||||||
];
|
|
||||||
$this->products = $productRepository->getList($params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -34,4 +34,4 @@ import './components/binded-label'
|
||||||
import './components/image-zoom'
|
import './components/image-zoom'
|
||||||
import './components/code-highlight'
|
import './components/code-highlight'
|
||||||
import './components/copy-text'
|
import './components/copy-text'
|
||||||
import './components/chart'
|
import './components/chart'
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<section class="container pb-5 mb-1 mb-sm-3 mb-lg-4 mb-xl-5">
|
<section class="container pb-5 mb-1 mb-sm-3 mb-lg-4 mb-xl-5" id="brand-home-section">
|
||||||
<div class="swiper my-md-3"
|
<div class="swiper my-md-3"
|
||||||
data-swiper='{
|
data-swiper='{
|
||||||
"slidesPerView": 2,
|
"slidesPerView": 2,
|
||||||
"pagination": {
|
"pagination": {
|
||||||
"el": ".swiper-pagination",
|
"el": ".swiper-pagination",
|
||||||
|
|
@ -24,21 +24,80 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}'>
|
}'>
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper" id="brand-container">
|
||||||
|
<!-- Brands will be loaded via AJAX -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination (Bullets) -->
|
||||||
|
<div class="swiper-pagination position-static mt-3"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Item -->
|
<!-- Loading state -->
|
||||||
@foreach($brands as $brand)
|
<div class="text-center py-5 d-none" id="brand-loading">
|
||||||
<a class="swiper-slide text-body" href="#!" aria-label="{{ $brand->name }}">
|
<div class="swiper my-md-3">
|
||||||
<img src="{{ $brand->image_url }}" alt="{{ $brand->name }}" class="object-fit-contain">
|
<div class="swiper-wrapper">
|
||||||
</a>
|
@for ($i = 1; $i <= 6; $i++)
|
||||||
|
<div class="swiper-slide text-body">
|
||||||
@endforeach
|
<div class="shimmer-wrapper">
|
||||||
|
<div class="shimmer">
|
||||||
</div>
|
<div class="shimmer-content rounded">
|
||||||
|
<div class="shimmer-line shimmer-image rounded"
|
||||||
<!-- Pagination (Bullets) -->
|
style="height: 60px; width: 100%; background-color: rgba(0, 0, 0, 0.1);">
|
||||||
<div class="swiper-pagination position-static mt-3"></div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endfor
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const brandContainer = document.getElementById('brand-container');
|
||||||
|
const loadingSpinner = document.getElementById('brand-loading');
|
||||||
|
const section = document.getElementById('brand-home-section');
|
||||||
|
|
||||||
|
if (!brandContainer || !loadingSpinner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load brands on page load
|
||||||
|
loadBrands();
|
||||||
|
|
||||||
|
function loadBrands() {
|
||||||
|
// Show loading spinner
|
||||||
|
loadingSpinner.classList.remove('d-none');
|
||||||
|
|
||||||
|
// Make AJAX request for brands
|
||||||
|
fetch('{{ route("product.ajax.brands") }}')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success && data.brands) {
|
||||||
|
brandContainer.innerHTML = data.brands;
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
brandContainer.innerHTML = '<div class="swiper-slide text-center py-4">Error loading brands</div>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading brands:', error);
|
||||||
|
brandContainer.innerHTML = '<div class="swiper-slide text-center py-4">Error loading brands</div>';
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
// Hide loading spinner
|
||||||
|
loadingSpinner.classList.add('d-none');
|
||||||
|
|
||||||
|
// Re-initialize Swiper
|
||||||
|
if (window.Swiper) {
|
||||||
|
const swiper = section.querySelector('.swiper');
|
||||||
|
if (swiper && swiper.swiper) {
|
||||||
|
swiper.swiper.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,248 @@
|
||||||
|
<section class="container py-5 my-2 my-sm-3 my-lg-4 my-xl-5" id="popular-products-section">
|
||||||
|
<div class="row align-items-lg-center py-xxl-3">
|
||||||
|
|
||||||
|
<!-- Products -->
|
||||||
|
<div class="col-md-6 col-xl-5 offset-xl-1 order-md-2 mb-4 mb-md-0">
|
||||||
|
<div class="ps-md-3 ps-lg-4 ps-xl-0">
|
||||||
|
<div class="d-flex align-items-center justify-content-between pb-4 mb-md-1 mb-lg-2 mb-xl-3">
|
||||||
|
<h2 class="me-3 mb-0">Popular products</h2>
|
||||||
|
|
||||||
|
<!-- Slider prev/next buttons -->
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-icon btn-outline-secondary animate-slide-start rounded-circle me-1"
|
||||||
|
id="popularPrev" aria-label="Prev">
|
||||||
|
<i class="ci-chevron-left fs-lg animate-target"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-icon btn-outline-secondary animate-slide-end rounded-circle"
|
||||||
|
id="popularNext" aria-label="Next">
|
||||||
|
<i class="ci-chevron-right fs-lg animate-target"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Products master slider -->
|
||||||
|
<div class="swiper"
|
||||||
|
data-swiper='{
|
||||||
|
"spaceBetween": 24,
|
||||||
|
"loop": true,
|
||||||
|
"speed": 400,
|
||||||
|
"controlSlider": "#sliderImages",
|
||||||
|
"navigation": {
|
||||||
|
"prevEl": "#popularPrev",
|
||||||
|
"nextEl": "#popularNext"
|
||||||
|
}
|
||||||
|
}'>
|
||||||
|
<div class="swiper-wrapper" id="popular-products-container">
|
||||||
|
<!-- Products will be loaded via AJAX -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Images -->
|
||||||
|
<div class="col-md-6 col-xl-5 order-md-1">
|
||||||
|
<div class="position-relative">
|
||||||
|
<div class="ratio d-none d-md-block" style="--cz-aspect-ratio: calc(720 / 636 * 100%)">
|
||||||
|
</div>
|
||||||
|
<div class="ratio ratio-4x3 d-md-none"></div>
|
||||||
|
<div class="swiper position-absolute top-0 start-0 w-100 h-100 user-select-none"
|
||||||
|
id="sliderImages"
|
||||||
|
data-swiper='{
|
||||||
|
"allowTouchMove": false,
|
||||||
|
"loop": true,
|
||||||
|
"effect": "fade",
|
||||||
|
"fadeEffect": {
|
||||||
|
"crossFade": true
|
||||||
|
}
|
||||||
|
}'>
|
||||||
|
<div class="swiper-wrapper" id="popular-images-container">
|
||||||
|
<!-- Images will be loaded via AJAX -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading state -->
|
||||||
|
<div class="text-center py-5 d-none" id="popular-products-loading">
|
||||||
|
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 gy-4 gy-md-5 pb-xxl-3">
|
||||||
|
@for ($i = 1; $i <= 6; $i++)
|
||||||
|
<div class="col mb-2 mb-sm-3 mb-md-0">
|
||||||
|
<div class="shimmer-wrapper">
|
||||||
|
<div class="shimmer">
|
||||||
|
<div class="shimmer-content rounded">
|
||||||
|
<div class="shimmer-line shimmer-image rounded mb-3"
|
||||||
|
style="height: 0; padding-bottom: 100%; position: relative;">
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.1); border-radius: 4px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="shimmer-line shimmer-title rounded mb-2"
|
||||||
|
style="height: 20px; width: 80%;"></div>
|
||||||
|
<div class="shimmer-line shimmer-price rounded" style="height: 16px; width: 60%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endfor
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const productsContainer = document.getElementById('popular-products-container');
|
||||||
|
const imagesContainer = document.getElementById('popular-images-container');
|
||||||
|
const loadingSpinner = document.getElementById('popular-products-loading');
|
||||||
|
const section = document.getElementById('popular-products-section');
|
||||||
|
|
||||||
|
if (!productsContainer || !imagesContainer || !loadingSpinner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load popular products on page load
|
||||||
|
loadPopularProducts();
|
||||||
|
|
||||||
|
function loadPopularProducts() {
|
||||||
|
// Show loading spinner
|
||||||
|
if (loadingSpinner) {
|
||||||
|
loadingSpinner.classList.remove('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make AJAX request for popular products
|
||||||
|
fetch('{{ route("product.ajax.highlights") }}?type=best_sellers&limit=6')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success && data.products) {
|
||||||
|
// Parse the HTML to extract individual product cards
|
||||||
|
const tempDiv = document.createElement('div');
|
||||||
|
tempDiv.innerHTML = data.products;
|
||||||
|
|
||||||
|
const productCards = tempDiv.querySelectorAll('.col');
|
||||||
|
const productsArray = Array.from(productCards);
|
||||||
|
|
||||||
|
// Split products into two slides (3 products each)
|
||||||
|
const slide1 = productsArray.slice(0, 3);
|
||||||
|
const slide2 = productsArray.slice(3, 6);
|
||||||
|
|
||||||
|
// Create slides with product lists
|
||||||
|
productsContainer.innerHTML = '';
|
||||||
|
|
||||||
|
[slide1, slide2].forEach((slide, index) => {
|
||||||
|
const slideDiv = document.createElement('div');
|
||||||
|
slideDiv.className = 'swiper-slide';
|
||||||
|
|
||||||
|
const listDiv = document.createElement('div');
|
||||||
|
listDiv.className = 'd-flex flex-column gap-3 gap-lg-4';
|
||||||
|
|
||||||
|
slide.forEach(product => {
|
||||||
|
// Convert product card to list item format
|
||||||
|
const productImg = product.querySelector('img');
|
||||||
|
const productLink = product.querySelector('a');
|
||||||
|
const productPrice = product.querySelector('.h6, .price');
|
||||||
|
|
||||||
|
const listItem = document.createElement('div');
|
||||||
|
listItem.className = 'd-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline';
|
||||||
|
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = productImg ? productImg.src : '/img/shop/fashion/thumbs/0' + (index * 3 + slide.indexOf(product) + 1) + '.png';
|
||||||
|
img.width = 110;
|
||||||
|
img.alt = 'Thumbnail';
|
||||||
|
|
||||||
|
const navDiv = document.createElement('div');
|
||||||
|
navDiv.className = 'nav flex-column gap-2 min-w-0 p-3';
|
||||||
|
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.className = 'nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0';
|
||||||
|
link.href = productLink ? productLink.href : '#';
|
||||||
|
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.className = 'animate-target text-truncate';
|
||||||
|
span.textContent = productLink ? productLink.textContent.trim() : 'Product Name';
|
||||||
|
|
||||||
|
const price = document.createElement('div');
|
||||||
|
price.className = 'h6 mb-0';
|
||||||
|
price.textContent = productPrice ? productPrice.textContent : '$0.00';
|
||||||
|
|
||||||
|
link.appendChild(span);
|
||||||
|
navDiv.appendChild(link);
|
||||||
|
navDiv.appendChild(price);
|
||||||
|
listItem.appendChild(img);
|
||||||
|
listItem.appendChild(navDiv);
|
||||||
|
listDiv.appendChild(listItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
slideDiv.appendChild(listDiv);
|
||||||
|
productsContainer.appendChild(slideDiv);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load corresponding images
|
||||||
|
loadPopularImages();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
productsContainer.innerHTML = '<div class="swiper-slide"><div class="text-center py-4">Error loading products</div></div>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading popular products:', error);
|
||||||
|
productsContainer.innerHTML = '<div class="swiper-slide"><div class="text-center py-4">Error loading products</div></div>';
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
// Hide loading spinner
|
||||||
|
if (loadingSpinner) {
|
||||||
|
loadingSpinner.classList.add('d-none');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-initialize Swiper
|
||||||
|
if (window.Swiper) {
|
||||||
|
const swiperElements = section.querySelectorAll('.swiper');
|
||||||
|
swiperElements.forEach(element => {
|
||||||
|
if (element.swiper) {
|
||||||
|
element.swiper.update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPopularImages() {
|
||||||
|
// Load images for the slider
|
||||||
|
const images = [
|
||||||
|
'/img/home/fashion/v1/popular/01.jpg',
|
||||||
|
'/img/home/fashion/v1/popular/02.jpg'
|
||||||
|
];
|
||||||
|
|
||||||
|
imagesContainer.innerHTML = '';
|
||||||
|
|
||||||
|
images.forEach((src, index) => {
|
||||||
|
const slideDiv = document.createElement('div');
|
||||||
|
slideDiv.className = 'swiper-slide';
|
||||||
|
|
||||||
|
const ratioDiv = document.createElement('div');
|
||||||
|
ratioDiv.className = index === 0 ? 'ratio d-none d-md-block' : 'ratio d-none d-md-block';
|
||||||
|
ratioDiv.style.setProperty('--cz-aspect-ratio', 'calc(720 / 636 * 100%)');
|
||||||
|
|
||||||
|
const mobileRatioDiv = document.createElement('div');
|
||||||
|
mobileRatioDiv.className = 'ratio ratio-4x3 d-md-none';
|
||||||
|
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = src;
|
||||||
|
img.className = 'position-absolute top-0 start-0 w-100 h-100 object-fit-cover rounded-5';
|
||||||
|
img.alt = 'Image';
|
||||||
|
|
||||||
|
if (index === 1) {
|
||||||
|
img.style.objectPosition = 'center top';
|
||||||
|
}
|
||||||
|
|
||||||
|
slideDiv.appendChild(ratioDiv);
|
||||||
|
slideDiv.appendChild(mobileRatioDiv);
|
||||||
|
slideDiv.appendChild(img);
|
||||||
|
imagesContainer.appendChild(slideDiv);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
<section class="bg-body-tertiary">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<!-- Titles master slider -->
|
||||||
|
<div class="col-md-6 col-lg-5 d-flex flex-column">
|
||||||
|
<div class="py-4 mt-auto">
|
||||||
|
<div class="swiper pb-1 pt-3 pt-sm-4 py-md-4 py-lg-3"
|
||||||
|
data-swiper='{
|
||||||
|
"spaceBetween": 24,
|
||||||
|
"loop": true,
|
||||||
|
"speed": 400,
|
||||||
|
"controlSlider": "#heroImages",
|
||||||
|
"pagination": {
|
||||||
|
"el": "#sliderBullets",
|
||||||
|
"clickable": true
|
||||||
|
},
|
||||||
|
"autoplay": {
|
||||||
|
"delay": 5500,
|
||||||
|
"disableOnInteraction": false
|
||||||
|
}
|
||||||
|
}'>
|
||||||
|
<div class="swiper-wrapper align-items-center">
|
||||||
|
|
||||||
|
<!-- Item -->
|
||||||
|
<div class="swiper-slide text-center text-md-start">
|
||||||
|
<p class="fs-xl mb-2 mb-lg-3 mb-xl-4">The new warm collection</p>
|
||||||
|
<h2 class="display-4 text-uppercase mb-4 mb-xl-5">New fall <br
|
||||||
|
class="d-none d-md-inline">season 2024</h2>
|
||||||
|
<a class="btn btn-lg btn-outline-dark" href="{{ route('second', ['shop', 'catalog-fashion']) }}">
|
||||||
|
Shop now
|
||||||
|
<i class="ci-arrow-up-right fs-lg ms-2 me-n1"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Item -->
|
||||||
|
<div class="swiper-slide text-center text-md-start">
|
||||||
|
<p class="fs-xl mb-2 mb-lg-3 mb-xl-4">Ready for the party?</p>
|
||||||
|
<h2 class="display-4 text-uppercase mb-4 mb-xl-5">Choose outfits for parties</h2>
|
||||||
|
<a class="btn btn-lg btn-outline-dark" href="{{ route('second', ['shop', 'catalog-fashion']) }}">
|
||||||
|
Shop now
|
||||||
|
<i class="ci-arrow-up-right fs-lg ms-2 me-n1"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Item -->
|
||||||
|
<div class="swiper-slide text-center text-md-start">
|
||||||
|
<p class="fs-xl mb-2 mb-lg-3 mb-xl-4">Shades of gray for your look</p>
|
||||||
|
<h2 class="display-4 text-uppercase mb-4 mb-xl-5">-50% on gray Collection</h2>
|
||||||
|
<a class="btn btn-lg btn-outline-dark" href="{{ route('second', ['shop', 'catalog-fashion']) }}">
|
||||||
|
Shop now
|
||||||
|
<i class="ci-arrow-up-right fs-lg ms-2 me-n1"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Slider bullets (pagination) -->
|
||||||
|
<div
|
||||||
|
class="d-flex justify-content-center justify-content-md-start pb-4 pb-xl-5 mt-n1 mt-md-auto mb-md-3 mb-lg-4">
|
||||||
|
<div class="swiper-pagination position-static w-auto pb-1" id="sliderBullets"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Linked images (controlled slider) -->
|
||||||
|
<div class="col-md-6 col-lg-7 align-self-end">
|
||||||
|
<div class="position-relative ms-md-n4">
|
||||||
|
<div class="ratio" style="--cz-aspect-ratio: calc(662 / 770 * 100%)"></div>
|
||||||
|
<div class="swiper position-absolute top-0 start-0 w-100 h-100 user-select-none"
|
||||||
|
id="heroImages"
|
||||||
|
data-swiper='{
|
||||||
|
"allowTouchMove": false,
|
||||||
|
"loop": true,
|
||||||
|
"effect": "fade",
|
||||||
|
"fadeEffect": {
|
||||||
|
"crossFade": true
|
||||||
|
}
|
||||||
|
}'>
|
||||||
|
<div class="swiper-wrapper">
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img src="/img/home/fashion/v1/hero-slider/01.png" class="rtl-flip"
|
||||||
|
alt="Image">
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img src="/img/home/fashion/v1/hero-slider/02.png" class="rtl-flip"
|
||||||
|
alt="Image">
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img src="/img/home/fashion/v1/hero-slider/03.png" class="rtl-flip"
|
||||||
|
alt="Image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
<span class="text-truncate">{{ $product->name }}</span>
|
<span class="text-truncate">{{ $product->name }}</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="h6 mb-0">{{ number_format($product->price, 0, ',', '.') }}</div>
|
<div class="h6 mb-0">Rp {{ number_format($product->display_price, 0, ',', '.') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,204 @@
|
||||||
<section class="container pb-5 mb-2 mb-sm-3 mb-lg-4 mb-xl-5">
|
<style>
|
||||||
<h2 class="text-center pb-2 pb-sm-3">{{ __('weeks_highlights.this_weeks_highlights') }}</h2>
|
.shimmer-wrapper-highlight {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
<!-- Nav pills -->
|
.shimmer-wrapper-highlight .shimmer {
|
||||||
<div class="row g-0 overflow-x-auto pb-2 pb-sm-3 mb-3">
|
position: relative;
|
||||||
<div class="col-auto pb-1 pb-sm-0 mx-auto">
|
overflow: hidden;
|
||||||
<ul class="nav nav-pills flex-nowrap text-nowrap">
|
}
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link active" aria-current="page" href="#!">{{ __('weeks_highlights.best_sellers') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#!">{{ __('weeks_highlights.new_arrivals') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#!">{{ __('weeks_highlights.sale_items') }}</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#!">{{ __('weeks_highlights.top_rated') }}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Products grid -->
|
.shimmer-wrapper-highlight .shimmer::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
rgba(255, 255, 255, 0) 0%,
|
||||||
|
rgba(255, 255, 255, 0.3) 50%,
|
||||||
|
rgba(255, 255, 255, 0) 100%);
|
||||||
|
animation: shimmer-wrapper-highlight-shimmer 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer-wrapper-highlight-shimmer {
|
||||||
|
0% {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shimmer-wrapper-highlight .shimmer-line {
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shimmer-wrapper-highlight .shimmer-content {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<section class="container pb-5 mb-2 mb-sm-3 mb-lg-4 mb-xl-5" id="product-highlights-section">
|
||||||
|
<h2 class="text-center pb-2 pb-sm-3">{{ __('weeks_highlights.this_weeks_highlights') }}</h2>
|
||||||
|
|
||||||
|
<div class="row g-0 overflow-x-auto pb-2 pb-sm-3 mb-3">
|
||||||
|
<div class="col-auto pb-1 pb-sm-0 mx-auto">
|
||||||
|
<ul class="nav nav-pills flex-nowrap text-nowrap" id="product-highlights-tabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="#" data-type="best_sellers"
|
||||||
|
data-url="{{ route('product.ajax.highlights') }}">
|
||||||
|
{{ __('weeks_highlights.best_sellers') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#" data-type="new_arrivals"
|
||||||
|
data-url="{{ route('product.ajax.highlights') }}">
|
||||||
|
{{ __('weeks_highlights.new_arrivals') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#" data-type="sale_items"
|
||||||
|
data-url="{{ route('product.ajax.highlights') }}">
|
||||||
|
{{ __('weeks_highlights.sale_items') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#" data-type="top_rated"
|
||||||
|
data-url="{{ route('product.ajax.highlights') }}">
|
||||||
|
{{ __('weeks_highlights.top_rated') }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="position-relative">
|
||||||
|
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 gy-4 gy-md-5 pb-xxl-3" id="product-highlights-container">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center py-5 d-none" id="product-highlights-loading">
|
||||||
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 gy-4 gy-md-5 pb-xxl-3">
|
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 gy-4 gy-md-5 pb-xxl-3">
|
||||||
|
@for ($i = 1; $i <= 8; $i++)
|
||||||
<!-- Item -->
|
<div class="col-6 col-md-4 mb-2 mb-sm-3 mb-md-0">
|
||||||
@foreach ($products as $key => $product)
|
<div class="shimmer-wrapper-highlight">
|
||||||
<div class="col mb-2 mb-sm-3 mb-md-0">
|
<div class="shimmer">
|
||||||
<x-home.product-card :product="$product" />
|
<div class="shimmer-content rounded">
|
||||||
</div>
|
<div class="shimmer-line shimmer-image rounded mb-3"
|
||||||
@endforeach
|
style="height: 0; padding-bottom: 100%; position: relative;">
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.1); border-radius: 4px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="shimmer-line shimmer-title rounded mb-2"
|
||||||
|
style="height: 20px; width: 80%;"></div>
|
||||||
|
<div class="shimmer-line shimmer-price rounded" style="height: 16px; width: 60%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endfor
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/*!
|
||||||
|
* Product Highlights AJAX functionality
|
||||||
|
* Handles tab switching and AJAX loading for product highlights section
|
||||||
|
*/
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const tabsContainer = document.getElementById('product-highlights-tabs');
|
||||||
|
const productsContainer = document.getElementById('product-highlights-container');
|
||||||
|
const loadingSpinner = document.getElementById('product-highlights-loading');
|
||||||
|
|
||||||
|
if (!tabsContainer || !productsContainer || !loadingSpinner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load first tab content on page load
|
||||||
|
const firstTab = tabsContainer.querySelector('.nav-link.active');
|
||||||
|
if (firstTab) {
|
||||||
|
const type = firstTab.dataset.type;
|
||||||
|
const url = firstTab.dataset.url;
|
||||||
|
if (type && url) {
|
||||||
|
loadProductHighlights(type, url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle tab clicks
|
||||||
|
tabsContainer.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const tab = e.target.closest('.nav-link');
|
||||||
|
if (!tab) return;
|
||||||
|
|
||||||
|
// Get the type and URL from data attributes
|
||||||
|
const type = tab.dataset.type;
|
||||||
|
const url = tab.dataset.url;
|
||||||
|
|
||||||
|
if (!type || !url) return;
|
||||||
|
|
||||||
|
// Update active tab
|
||||||
|
tabsContainer.querySelectorAll('.nav-link').forEach(t => t.classList.remove('active'));
|
||||||
|
tab.classList.add('active');
|
||||||
|
|
||||||
|
// Load products via AJAX
|
||||||
|
loadProductHighlights(type, url);
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadProductHighlights(type, url) {
|
||||||
|
// Show loading spinner
|
||||||
|
productsContainer.style.display = 'none';
|
||||||
|
loadingSpinner.classList.remove('d-none');
|
||||||
|
|
||||||
|
// Build URL with parameters
|
||||||
|
const requestUrl = `${url}?type=${type}`;
|
||||||
|
|
||||||
|
// Make AJAX request
|
||||||
|
fetch(requestUrl)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
// Update products container with new HTML
|
||||||
|
productsContainer.innerHTML = data.products;
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
productsContainer.innerHTML =
|
||||||
|
'<div class="col-12 text-center py-4">Error loading products</div>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading product highlights:', error);
|
||||||
|
productsContainer.innerHTML =
|
||||||
|
'<div class="col-12 text-center py-4">Error loading products</div>';
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
// Hide loading spinner and show products
|
||||||
|
loadingSpinner.classList.add('d-none');
|
||||||
|
productsContainer.style.display = 'flex';
|
||||||
|
|
||||||
|
// Re-initialize any components that might be needed for the new products
|
||||||
|
if (window.bootstrap && window.bootstrap.Tooltip) {
|
||||||
|
const tooltipTriggerList = [].slice.call(productsContainer.querySelectorAll(
|
||||||
|
'[data-bs-toggle="tooltip"]'));
|
||||||
|
tooltipTriggerList.map(function(tooltipTriggerEl) {
|
||||||
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -8,267 +8,11 @@
|
||||||
<main class="content-wrapper">
|
<main class="content-wrapper">
|
||||||
|
|
||||||
<!-- Hero slider -->
|
<!-- Hero slider -->
|
||||||
<section class="bg-body-tertiary">
|
<x-home.home-slider />
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
|
|
||||||
<!-- Titles master slider -->
|
|
||||||
<div class="col-md-6 col-lg-5 d-flex flex-column">
|
|
||||||
<div class="py-4 mt-auto">
|
|
||||||
<div class="swiper pb-1 pt-3 pt-sm-4 py-md-4 py-lg-3"
|
|
||||||
data-swiper='{
|
|
||||||
"spaceBetween": 24,
|
|
||||||
"loop": true,
|
|
||||||
"speed": 400,
|
|
||||||
"controlSlider": "#heroImages",
|
|
||||||
"pagination": {
|
|
||||||
"el": "#sliderBullets",
|
|
||||||
"clickable": true
|
|
||||||
},
|
|
||||||
"autoplay": {
|
|
||||||
"delay": 5500,
|
|
||||||
"disableOnInteraction": false
|
|
||||||
}
|
|
||||||
}'>
|
|
||||||
<div class="swiper-wrapper align-items-center">
|
|
||||||
|
|
||||||
<!-- Item -->
|
|
||||||
<div class="swiper-slide text-center text-md-start">
|
|
||||||
<p class="fs-xl mb-2 mb-lg-3 mb-xl-4">The new warm collection</p>
|
|
||||||
<h2 class="display-4 text-uppercase mb-4 mb-xl-5">New fall <br
|
|
||||||
class="d-none d-md-inline">season 2024</h2>
|
|
||||||
<a class="btn btn-lg btn-outline-dark" href="{{ route('second', ['shop', 'catalog-fashion']) }}">
|
|
||||||
Shop now
|
|
||||||
<i class="ci-arrow-up-right fs-lg ms-2 me-n1"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Item -->
|
|
||||||
<div class="swiper-slide text-center text-md-start">
|
|
||||||
<p class="fs-xl mb-2 mb-lg-3 mb-xl-4">Ready for the party?</p>
|
|
||||||
<h2 class="display-4 text-uppercase mb-4 mb-xl-5">Choose outfits for parties</h2>
|
|
||||||
<a class="btn btn-lg btn-outline-dark" href="{{ route('second', ['shop', 'catalog-fashion']) }}">
|
|
||||||
Shop now
|
|
||||||
<i class="ci-arrow-up-right fs-lg ms-2 me-n1"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Item -->
|
|
||||||
<div class="swiper-slide text-center text-md-start">
|
|
||||||
<p class="fs-xl mb-2 mb-lg-3 mb-xl-4">Shades of gray for your look</p>
|
|
||||||
<h2 class="display-4 text-uppercase mb-4 mb-xl-5">-50% on gray Collection</h2>
|
|
||||||
<a class="btn btn-lg btn-outline-dark" href="{{ route('second', ['shop', 'catalog-fashion']) }}">
|
|
||||||
Shop now
|
|
||||||
<i class="ci-arrow-up-right fs-lg ms-2 me-n1"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Slider bullets (pagination) -->
|
|
||||||
<div
|
|
||||||
class="d-flex justify-content-center justify-content-md-start pb-4 pb-xl-5 mt-n1 mt-md-auto mb-md-3 mb-lg-4">
|
|
||||||
<div class="swiper-pagination position-static w-auto pb-1" id="sliderBullets"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Linked images (controlled slider) -->
|
|
||||||
<div class="col-md-6 col-lg-7 align-self-end">
|
|
||||||
<div class="position-relative ms-md-n4">
|
|
||||||
<div class="ratio" style="--cz-aspect-ratio: calc(662 / 770 * 100%)"></div>
|
|
||||||
<div class="swiper position-absolute top-0 start-0 w-100 h-100 user-select-none"
|
|
||||||
id="heroImages"
|
|
||||||
data-swiper='{
|
|
||||||
"allowTouchMove": false,
|
|
||||||
"loop": true,
|
|
||||||
"effect": "fade",
|
|
||||||
"fadeEffect": {
|
|
||||||
"crossFade": true
|
|
||||||
}
|
|
||||||
}'>
|
|
||||||
<div class="swiper-wrapper">
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img src="/img/home/fashion/v1/hero-slider/01.png" class="rtl-flip"
|
|
||||||
alt="Image">
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img src="/img/home/fashion/v1/hero-slider/02.png" class="rtl-flip"
|
|
||||||
alt="Image">
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img src="/img/home/fashion/v1/hero-slider/03.png" class="rtl-flip"
|
|
||||||
alt="Image">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Popular products carousel -->
|
<!-- Popular products carousel -->
|
||||||
<section class="container py-5 my-2 my-sm-3 my-lg-4 my-xl-5">
|
<x-home.home-popular-products />
|
||||||
<div class="row align-items-lg-center py-xxl-3">
|
|
||||||
|
|
||||||
<!-- Products -->
|
|
||||||
<div class="col-md-6 col-xl-5 offset-xl-1 order-md-2 mb-4 mb-md-0">
|
|
||||||
<div class="ps-md-3 ps-lg-4 ps-xl-0">
|
|
||||||
<div class="d-flex align-items-center justify-content-between pb-4 mb-md-1 mb-lg-2 mb-xl-3">
|
|
||||||
<h2 class="me-3 mb-0">Popular products</h2>
|
|
||||||
|
|
||||||
<!-- Slider prev/next buttons -->
|
|
||||||
<div class="d-flex gap-2">
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-icon btn-outline-secondary animate-slide-start rounded-circle me-1"
|
|
||||||
id="popularPrev" aria-label="Prev">
|
|
||||||
<i class="ci-chevron-left fs-lg animate-target"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="btn btn-icon btn-outline-secondary animate-slide-end rounded-circle"
|
|
||||||
id="popularNext" aria-label="Next">
|
|
||||||
<i class="ci-chevron-right fs-lg animate-target"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Products master slider -->
|
|
||||||
<div class="swiper"
|
|
||||||
data-swiper='{
|
|
||||||
"spaceBetween": 24,
|
|
||||||
"loop": true,
|
|
||||||
"speed": 400,
|
|
||||||
"controlSlider": "#sliderImages",
|
|
||||||
"navigation": {
|
|
||||||
"prevEl": "#popularPrev",
|
|
||||||
"nextEl": "#popularNext"
|
|
||||||
}
|
|
||||||
}'>
|
|
||||||
<div class="swiper-wrapper">
|
|
||||||
|
|
||||||
<!-- Products list slide -->
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<div class="d-flex flex-column gap-3 gap-lg-4">
|
|
||||||
<div
|
|
||||||
class="d-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline">
|
|
||||||
<img src="/img/shop/fashion/thumbs/01.png" width="110" alt="Thumbnail">
|
|
||||||
<div class="nav flex-column gap-2 min-w-0 p-3">
|
|
||||||
<a class="nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0"
|
|
||||||
href="{{ route('second', ['shop', 'product-fashion']) }}">
|
|
||||||
<span class="animate-target text-truncate">Short jacket in long-pile
|
|
||||||
faux fur</span>
|
|
||||||
</a>
|
|
||||||
<div class="h6 mb-0">$218.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline">
|
|
||||||
<img src="/img/shop/fashion/thumbs/02.png" width="110" alt="Thumbnail">
|
|
||||||
<div class="nav flex-column gap-2 min-w-0 p-3">
|
|
||||||
<a class="nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0"
|
|
||||||
href="{{ route('second', ['shop', 'product-fashion']) }}">
|
|
||||||
<span class="animate-target text-truncate">Women's walking shoes tennis
|
|
||||||
sneakers</span>
|
|
||||||
</a>
|
|
||||||
<div class="h6 mb-0">$54.99</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline">
|
|
||||||
<img src="/img/shop/fashion/thumbs/03.png" width="110" alt="Thumbnail">
|
|
||||||
<div class="nav flex-column gap-2 min-w-0 p-3">
|
|
||||||
<a class="nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0"
|
|
||||||
href="{{ route('second', ['shop', 'product-fashion']) }}">
|
|
||||||
<span class="animate-target text-truncate">Classic aviator sunglasses
|
|
||||||
for women</span>
|
|
||||||
</a>
|
|
||||||
<div class="h6 mb-0">$76.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Products list slide -->
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<div class="d-flex flex-column gap-3 gap-lg-4">
|
|
||||||
<div
|
|
||||||
class="d-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline">
|
|
||||||
<img src="/img/shop/fashion/thumbs/04.png" width="110" alt="Thumbnail">
|
|
||||||
<div class="nav flex-column gap-2 min-w-0 p-3">
|
|
||||||
<a class="nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0"
|
|
||||||
href="{{ route('second', ['shop', 'product-fashion']) }}">
|
|
||||||
<span class="animate-target text-truncate">Vintage oversized wool
|
|
||||||
blazer jacket</span>
|
|
||||||
</a>
|
|
||||||
<div class="h6 mb-0">$174.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline">
|
|
||||||
<img src="/img/shop/fashion/thumbs/05.png" width="110" alt="Thumbnail">
|
|
||||||
<div class="nav flex-column gap-2 min-w-0 p-3">
|
|
||||||
<a class="nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0"
|
|
||||||
href="{{ route('second', ['shop', 'product-fashion']) }}">
|
|
||||||
<span class="animate-target text-truncate">Classic pilot style
|
|
||||||
polarized sunglasses</span>
|
|
||||||
</a>
|
|
||||||
<div class="h6 mb-0">$93.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="d-flex align-items-center position-relative bg-body-tertiary rounded overflow-hidden animate-underline">
|
|
||||||
<img src="/img/shop/fashion/thumbs/06.png" width="110" alt="Thumbnail">
|
|
||||||
<div class="nav flex-column gap-2 min-w-0 p-3">
|
|
||||||
<a class="nav-link text-dark-emphasis stretched-link w-100 min-w-0 p-0"
|
|
||||||
href="{{ route('second', ['shop', 'product-fashion']) }}">
|
|
||||||
<span class="animate-target text-truncate">Cotton dress straight-leg
|
|
||||||
pants</span>
|
|
||||||
</a>
|
|
||||||
<div class="h6 mb-0">$65.00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Complete look images (controlled slider) -->
|
|
||||||
<div class="col-md-6 order-md-1">
|
|
||||||
<div class="swiper user-select-none" id="sliderImages"
|
|
||||||
data-swiper='{
|
|
||||||
"allowTouchMove": false,
|
|
||||||
"loop": true,
|
|
||||||
"effect": "fade",
|
|
||||||
"fadeEffect": {
|
|
||||||
"crossFade": true
|
|
||||||
}
|
|
||||||
}'>
|
|
||||||
<div class="swiper-wrapper">
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<div class="ratio d-none d-md-block" style="--cz-aspect-ratio: calc(720 / 636 * 100%)">
|
|
||||||
</div>
|
|
||||||
<div class="ratio ratio-4x3 d-md-none"></div>
|
|
||||||
<img src="/img/home/fashion/v1/popular/01.jpg"
|
|
||||||
class="position-absolute top-0 start-0 w-100 h-100 object-fit-cover rounded-5"
|
|
||||||
alt="Image">
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<div class="ratio d-none d-md-block" style="--cz-aspect-ratio: calc(720 / 636 * 100%)">
|
|
||||||
</div>
|
|
||||||
<div class="ratio ratio-4x3 d-md-none"></div>
|
|
||||||
<img src="/img/home/fashion/v1/popular/02.jpg"
|
|
||||||
class="position-absolute top-0 start-0 w-100 h-100 object-fit-cover rounded-5"
|
|
||||||
style="object-position: center top" alt="Image">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Featured products -->
|
<!-- Featured products -->
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use App\Http\Controllers\LocationController;
|
||||||
use App\Http\Controllers\LocaleController;
|
use App\Http\Controllers\LocaleController;
|
||||||
use App\Http\Controllers\ProductController;
|
use App\Http\Controllers\ProductController;
|
||||||
use App\Http\Controllers\SearchController;
|
use App\Http\Controllers\SearchController;
|
||||||
|
use App\Http\Controllers\ComponentController;
|
||||||
|
|
||||||
Route::group(['prefix' => '/dummy'], function () {
|
Route::group(['prefix' => '/dummy'], function () {
|
||||||
Route::get('', [RoutingController::class, 'index'])->name('root');
|
Route::get('', [RoutingController::class, 'index'])->name('root');
|
||||||
|
|
@ -26,9 +27,14 @@ Route::get('/', [HomeController::class, 'index'])->name('home');
|
||||||
|
|
||||||
Route::get('/products',[ProductController::class, 'index'])->name('product.index');
|
Route::get('/products',[ProductController::class, 'index'])->name('product.index');
|
||||||
Route::get('/products/ajax',[ProductController::class, 'ajax'])->name('product.ajax');
|
Route::get('/products/ajax',[ProductController::class, 'ajax'])->name('product.ajax');
|
||||||
|
Route::get('/products/ajax/highlights',[ProductController::class, 'highlights'])->name('product.ajax.highlights');
|
||||||
|
Route::get('/products/ajax/brands',[ProductController::class, 'brands'])->name('product.ajax.brands');
|
||||||
Route::get('/products/ajax/categories',[ProductController::class, 'categories'])->name('product.ajax.categories');
|
Route::get('/products/ajax/categories',[ProductController::class, 'categories'])->name('product.ajax.categories');
|
||||||
Route::get('/products/ajax/genders',[ProductController::class, 'genders'])->name('product.ajax.genders');
|
Route::get('/products/ajax/genders',[ProductController::class, 'genders'])->name('product.ajax.genders');
|
||||||
Route::get('/product/{slug}',[ProductController::class, 'detail'])->name('product.detail');
|
Route::get('/product/{slug}',[ProductController::class, 'detail'])->name('product.detail');
|
||||||
|
|
||||||
// Search routes
|
// Search routes
|
||||||
Route::get('/search', [SearchController::class, 'search'])->name('search.ajax');
|
Route::get('/search', [SearchController::class, 'search'])->name('search.ajax');
|
||||||
|
|
||||||
|
// Component loading routes
|
||||||
|
Route::get('/components/{component}', [ComponentController::class, 'load'])->name('component.load');
|
||||||
Loading…
Reference in New Issue