top header annoucement
This commit is contained in:
parent
3a66f08579
commit
36a763d6c0
|
|
@ -209,6 +209,41 @@ class ProductController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function announcements(Request $request)
|
||||||
|
{
|
||||||
|
// Static announcements for now - can be moved to database later
|
||||||
|
$announcements = [
|
||||||
|
[
|
||||||
|
'icon' => '🎉',
|
||||||
|
'message' => 'Free Shipping on orders over $250',
|
||||||
|
'detail' => "Don't miss a discount!"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'icon' => '💰',
|
||||||
|
'message' => 'Money back guarantee',
|
||||||
|
'detail' => 'We return money within 30 days'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'icon' => '💪',
|
||||||
|
'message' => 'Friendly 24/7 customer support',
|
||||||
|
'detail' => "We've got you covered!"
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
// Render announcement slides HTML
|
||||||
|
$announcementHtml = '';
|
||||||
|
foreach ($announcements as $announcement) {
|
||||||
|
$announcementHtml .= '<div class="swiper-slide text-truncate text-center">';
|
||||||
|
$announcementHtml .= $announcement['icon'] . ' ' . $announcement['message'] . ' <span class="d-none d-sm-inline">' . $announcement['detail'] . '</span>';
|
||||||
|
$announcementHtml .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'announcements' => $announcementHtml
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function highlights(Request $request)
|
public function highlights(Request $request)
|
||||||
{
|
{
|
||||||
$type = $request->input('type', 'new');
|
$type = $request->input('type', 'new');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\View\Components\Layout;
|
||||||
|
|
||||||
|
use Illuminate\View\Component;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class TopAnnouncementHeader extends Component
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new component instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the view/contents that represent the component.
|
||||||
|
*/
|
||||||
|
public function render(): View|string
|
||||||
|
{
|
||||||
|
return view('components.layout.top-announcement-header');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -145,47 +145,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-dismissible bg-dark text-white rounded-0 py-2 px-0 m-0 fade show" data-bs-theme="dark">
|
<x-layout.top-announcement-header />
|
||||||
<div class="container position-relative d-flex min-w-0">
|
|
||||||
<div class="d-flex flex-nowrap align-items-center g-2 w-100 min-w-0 mx-auto mt-n1"
|
|
||||||
style="max-width: 458px">
|
|
||||||
<div class="nav me-2">
|
|
||||||
<button type="button" class="nav-link fs-lg p-0" id="topbarPrev" aria-label="Prev">
|
|
||||||
<i class="ci-chevron-left"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="swiper fs-sm text-white"
|
|
||||||
data-swiper='{
|
|
||||||
"spaceBetween": 24,
|
|
||||||
"loop": true,
|
|
||||||
"autoplay": {
|
|
||||||
"delay": 5000,
|
|
||||||
"disableOnInteraction": false
|
|
||||||
},
|
|
||||||
"navigation": {
|
|
||||||
"prevEl": "#topbarPrev",
|
|
||||||
"nextEl": "#topbarNext"
|
|
||||||
}
|
|
||||||
}'>
|
|
||||||
<div class="swiper-wrapper min-w-0">
|
|
||||||
<div class="swiper-slide text-truncate text-center">🎉 Free Shipping on orders over $250. <span
|
|
||||||
class="d-none d-sm-inline">Don't miss a discount!</span></div>
|
|
||||||
<div class="swiper-slide text-truncate text-center">💰 Money back guarantee. <span
|
|
||||||
class="d-none d-sm-inline">We return money within 30 days.</span></div>
|
|
||||||
<div class="swiper-slide text-truncate text-center">💪 Friendly 24/7 customer support. <span
|
|
||||||
class="d-none d-sm-inline">We've got you covered!</span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="nav ms-2">
|
|
||||||
<button type="button" class="nav-link fs-lg p-0" id="topbarNext" aria-label="Next">
|
|
||||||
<i class="ci-chevron-right"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn-close position-static flex-shrink-0 p-1 ms-3 ms-md-n4"
|
|
||||||
data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<header class="navbar navbar-expand-lg navbar-sticky bg-body d-block z-fixed p-0"
|
<header class="navbar navbar-expand-lg navbar-sticky bg-body d-block z-fixed p-0"
|
||||||
data-sticky-navbar='{"offset": 500}'>
|
data-sticky-navbar='{"offset": 500}'>
|
||||||
<div class="container py-2 py-lg-3">
|
<div class="container py-2 py-lg-3">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
<div class="alert alert-dismissible bg-dark text-white rounded-0 py-2 px-0 m-0 d-none" id="top-announcement-bar" data-bs-theme="dark">
|
||||||
|
<div class="container position-relative d-flex min-w-0">
|
||||||
|
<div class="d-flex flex-nowrap align-items-center g-2 w-100 min-w-0 mx-auto mt-n1" style="max-width: 458px">
|
||||||
|
<div class="nav me-2">
|
||||||
|
<button type="button" class="nav-link fs-lg p-0" id="topbarPrev" aria-label="Prev">
|
||||||
|
<i class="ci-chevron-left"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="swiper fs-sm text-white"
|
||||||
|
data-swiper='{
|
||||||
|
"spaceBetween": 24,
|
||||||
|
"loop": true,
|
||||||
|
"autoplay": {
|
||||||
|
"delay": 5000,
|
||||||
|
"disableOnInteraction": false
|
||||||
|
},
|
||||||
|
"navigation": {
|
||||||
|
"prevEl": "#topbarPrev",
|
||||||
|
"nextEl": "#topbarNext"
|
||||||
|
}
|
||||||
|
}'>
|
||||||
|
<div class="swiper-wrapper min-w-0" id="announcements-wrapper">
|
||||||
|
<!-- Announcements will be loaded here via AJAX -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav ms-2">
|
||||||
|
<button type="button" class="nav-link fs-lg p-0" id="topbarNext" aria-label="Next">
|
||||||
|
<i class="ci-chevron-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close position-static flex-shrink-0 p-1 ms-3 ms-md-n4" data-bs-dismiss="alert"
|
||||||
|
aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#top-announcement-bar {
|
||||||
|
transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-announcement-bar.show-with-animation {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
loadAnnouncements();
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadAnnouncements() {
|
||||||
|
fetch(`{{ route('product.ajax.announcements') }}`, {
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success && data.announcements.trim() !== '') {
|
||||||
|
document.getElementById('announcements-wrapper').innerHTML = data.announcements;
|
||||||
|
const announcementBar = document.getElementById('top-announcement-bar');
|
||||||
|
announcementBar.classList.remove('d-none');
|
||||||
|
|
||||||
|
// Trigger animation
|
||||||
|
setTimeout(() => {
|
||||||
|
announcementBar.classList.add('show-with-animation');
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
// Reinitialize swiper if it exists
|
||||||
|
if (typeof Swiper !== 'undefined') {
|
||||||
|
const swiperElement = document.querySelector('.swiper');
|
||||||
|
if (swiperElement && swiperElement.swiper) {
|
||||||
|
swiperElement.swiper.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Hide announcement bar if no data
|
||||||
|
const announcementBar = document.getElementById('top-announcement-bar');
|
||||||
|
if (announcementBar) {
|
||||||
|
announcementBar.classList.add('d-none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading announcements:', error);
|
||||||
|
// Hide announcement bar on error
|
||||||
|
const announcementBar = document.getElementById('top-announcement-bar');
|
||||||
|
if (announcementBar) {
|
||||||
|
announcementBar.classList.add('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -31,6 +31,7 @@ Route::get('/products/ajax/highlights',[ProductController::class, 'highlights'])
|
||||||
Route::get('/products/ajax/brands',[ProductController::class, 'brands'])->name('product.ajax.brands');
|
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('/products/ajax/announcements',[ProductController::class, 'announcements'])->name('product.ajax.announcements');
|
||||||
Route::get('/product/{slug}',[ProductController::class, 'detail'])->name('product.detail');
|
Route::get('/product/{slug}',[ProductController::class, 'detail'])->name('product.detail');
|
||||||
|
|
||||||
// Search routes
|
// Search routes
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue