Files
citrus/resources/views/blog/index.blade.php

224 lines
8.4 KiB
PHP

<?php $headerTemplate = "Blog Header"; ?>
@extends('layouts.site')
@section('content')
<section class="wrapper !bg-[#edf2fc]">
<div class="container !pt-10 !pb-36 xl:!pt-[4.5rem] lg:!pt-[4.5rem] md:!pt-[4.5rem] xl:!pb-40 lg:!pb-40 md:!pb-40 !text-center">
<div class="flex flex-wrap mx-[-15px]">
<div class="md:w-7/12 lg:w-6/12 xl:w-5/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !mx-auto">
<h1 class="!text-[calc(1.365rem_+_1.38vw)] font-bold !leading-[1.2] xl:!text-[2.4rem] !mb-3">{{ __('blog.meta-index-title') }}</h1>
<p class="lead lg:!px-[1.25rem] xl:!px-[1.25rem] xxl:!px-[2rem] !leading-[1.65] text-[0.9rem] font-medium">{{ __('blog.meta-index-description') }}</p>
</div>
<!-- /column -->
</div>
<!-- /.row -->
</div>
<!-- /.container -->
</section>
<!-- /section -->
<div class="wrapper !bg-[#ffffff]">
<div class="container !pb-[4.5rem] xl:!pb-24 lg:!pb-24 md:!pb-24">
<div class="flex flex-wrap mx-[-15px]">
<div class="xl:w-10/12 lg:w-10/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !mx-auto">
<!-- Category Filter -->
@if(isset($categories) && $categories->count() > 0)
<div class="flex flex-wrap justify-center !mb-10 gap-2 blog-filter-menu">
<a href="#" class="category-filter-btn active !text-[0.8rem] !font-bold !uppercase !tracking-[0.02rem] !px-4 !py-2 !rounded-full !border !border-[#e31e24] !bg-[#e31e24] !text-white hover:!bg-[#c8191f] hover:!border-[#c8191f] transition-colors" data-category="">
{{ __('blog.all_categories', ['default' => 'Tümü']) }}
</a>
@foreach($categories as $category)
<a href="#" class="category-filter-btn !text-[0.8rem] !font-bold !uppercase !tracking-[0.02rem] !px-4 !py-2 !rounded-full !border !border-[#eef2f6] !bg-[#eef2f6] !text-[#343f52] hover:!bg-[#e31e24] hover:!text-white hover:!border-[#e31e24] transition-colors" data-category="{{ $category->slug }}">
{{ $category->name }}
</a>
@endforeach
</div>
@endif
<div id="blog-posts-container" class="relative min-h-[400px]">
@include('blog.partials.posts')
</div>
</div>
<!-- /column -->
</div>
<!-- /.row -->
</div>
<!-- /.container -->
</div>
@push('styles')
<style>
/* Loading Overlay for AJAX Requests */
.blog-loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.7);
z-index: 10;
display: flex;
justify-content: center;
align-items: flex-start;
padding-top: 5rem;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.blog-loading-overlay.active {
opacity: 1;
pointer-events: all;
}
.blog-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #e31e24;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
@endpush
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
const container = document.getElementById('blog-posts-container');
const filterBtns = document.querySelectorAll('.category-filter-btn');
// Create loading overlay
const overlay = document.createElement('div');
overlay.className = 'blog-loading-overlay';
overlay.innerHTML = '<div class="blog-spinner"></div>';
container.appendChild(overlay);
function fetchPosts(url) {
overlay.classList.add('active');
container.style.minHeight = container.offsetHeight + 'px'; // Maintain height during load
// Add AJAX header
fetch(url, {
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'text/html'
}
})
.then(response => response.text())
.then(html => {
// Update the posts container with new HTML
container.innerHTML = html;
// Re-append the overlay so it's ready for the next request
container.appendChild(overlay);
// Re-bind pagination links
bindPaginationLinks();
// Reinitialize any necessary plugins here (e.g. tooltips or image loaders if any)
// Update URL and History
window.history.pushState({html: html}, '', url);
// Smooth scroll to top of blog section
document.querySelector('.blog-filter-menu').scrollIntoView({ behavior: 'smooth', block: 'start' });
setTimeout(() => {
overlay.classList.remove('active');
container.style.minHeight = 'auto'; // Reset min-height safely
}, 300);
})
.catch(error => {
console.error('Error fetching posts:', error);
overlay.classList.remove('active');
});
}
function bindPaginationLinks() {
const paginationLinks = container.querySelectorAll('.pagination-container a, .pagination a');
paginationLinks.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
fetchPosts(this.href);
});
});
}
// Bind Filter Buttons
filterBtns.forEach(btn => {
btn.addEventListener('click', function(e) {
e.preventDefault();
// Update active state
filterBtns.forEach(b => {
b.classList.remove('!text-white', '!bg-[#e31e24]', '!border-[#e31e24]');
b.classList.add('!text-[#343f52]', '!bg-[#eef2f6]', '!border-[#eef2f6]');
});
this.classList.remove('!text-[#343f52]', '!bg-[#eef2f6]', '!border-[#eef2f6]');
this.classList.add('!text-white', '!bg-[#e31e24]', '!border-[#e31e24]');
const category = this.getAttribute('data-category');
// Construct URL
const url = new URL(window.location.href);
if (category) {
url.searchParams.set('category', category);
} else {
url.searchParams.delete('category');
}
// Reset to page 1 on category change
url.searchParams.delete('page');
fetchPosts(url.toString());
});
});
// Handle browser back/forward buttons
window.addEventListener('popstate', function(e) {
if (e.state && e.state.html) {
container.innerHTML = e.state.html;
container.appendChild(overlay);
bindPaginationLinks();
// Update active filter button based on URL
const urlParams = new URLSearchParams(window.location.search);
const currentCategory = urlParams.get('category') || '';
filterBtns.forEach(b => {
b.classList.remove('!text-white', '!bg-[#e31e24]', '!border-[#e31e24]');
b.classList.add('!text-[#343f52]', '!bg-[#eef2f6]', '!border-[#eef2f6]');
if (b.getAttribute('data-category') === currentCategory) {
b.classList.remove('!text-[#343f52]', '!bg-[#eef2f6]', '!border-[#eef2f6]');
b.classList.add('!text-white', '!bg-[#e31e24]', '!border-[#e31e24]');
}
});
} else {
// Fallback for full page reload for history items without state
window.location.reload();
}
});
// Initial binding of pagination links that are on page load
bindPaginationLinks();
// Set initial active state based on URL
const urlParams = new URLSearchParams(window.location.search);
const initialCategory = urlParams.get('category') || '';
if (initialCategory) {
const activeBtn = Array.from(filterBtns).find(btn => btn.getAttribute('data-category') === initialCategory);
if (activeBtn) {
filterBtns.forEach(b => {
b.classList.remove('!text-white', '!bg-[#e31e24]', '!border-[#e31e24]');
b.classList.add('!text-[#343f52]', '!bg-[#eef2f6]', '!border-[#eef2f6]');
});
activeBtn.classList.remove('!text-[#343f52]', '!bg-[#eef2f6]', '!border-[#eef2f6]');
activeBtn.classList.add('!text-white', '!bg-[#e31e24]', '!border-[#e31e24]');
}
}
});
</script>
@endpush
@endsection