feat: implement blog homepage widgets including hero carousel, category highlights, and sidebar components

This commit is contained in:
Ümit Tunç
2026-05-24 10:37:32 +03:00
parent 2d6af94c88
commit b36ccf298b
4 changed files with 375 additions and 428 deletions
+185 -42
View File
@@ -2,33 +2,112 @@
@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>
<section class="wrapper bg-[rgba(246,247,249,1)] ">
<div class="container pt-10 pb-[4.5rem] xl:pb-24 lg:pb-24 md:pb-24">
<!-- Carousel Section -->
@if(isset($carouselPosts) && $carouselPosts->count() > 0)
<div class="swiper-container blog grid-view !mb-24 relative z-10" data-margin="30" data-dots="true" data-items-lg="2" data-items-md="1" data-items-xs="1">
<div class="swiper">
<div class="swiper-wrapper">
@foreach($carouselPosts as $cPost)
@php
$cTitle = method_exists($cPost, 'translate') ? $cPost->translate('title') : $cPost->title;
$cExcerpt = method_exists($cPost, 'translate') ? $cPost->translate('excerpt') : ($cPost->excerpt ?? '');
$cCategoryName = $cPost->category ? $cPost->category->name : '';
$cCategorySlug = $cPost->category ? $cPost->category->slug : '';
$cDate = $cPost->published_at ? $cPost->published_at->format('d M Y') : $cPost->created_at->format('d M Y');
$cImage = $cPost->featured_image ? asset('storage/' . $cPost->featured_image) : asset('assets/img/photos/tb1.jpg');
$cUrl = route('blog.show', $cPost->slug);
@endphp
<div class="swiper-slide">
<figure class="overlay caption caption-overlay rounded !mb-0">
<a href="{{ $cUrl }}">
<img src="{{ $cImage }}" alt="{{ $cTitle }}" style="height: 380px; object-fit: cover; width: 100%;" loading="lazy">
</a>
<figcaption class="group-hover:opacity-100 absolute w-full h-full opacity-0 text-center px-4 py-3 inset-0 z-[5] pointer-events-none p-2">
@if($cCategoryName)
<span class="badge badge-lg bg-[rgba(255,255,255)] opacity-100 uppercase !mb-3">{{ $cCategoryName }}</span>
@endif
<h2 class="post-title h3 !mt-1 !mb-3">
<a class="!text-white" href="{{ $cUrl }}">{{ \Illuminate\Support\Str::limit($cTitle, 60) }}</a>
</h2>
<ul class="!text-[0.75rem] !text-[#aab0bc] m-0 p-0 list-none !text-white !mb-0">
<li class="post-date inline-block">
<i class="uil uil-calendar-alt pr-[0.2rem] align-[-.05rem] before:content-['\e9ba']"></i>
<span>{{ $cDate }}</span>
</li>
@if($cPost->author)
<li class="post-author inline-block before:content-[''] before:inline-block before:w-[0.2rem] before:h-[0.2rem] before:opacity-50 before:m-[0_.6rem_0] before:rounded-[100%] before:align-[.15rem] before:bg-[#aab0bc]">
<span class="!text-[#aab0bc]">
<i class="uil uil-user pr-[0.2rem] align-[-.05rem] before:content-['\ed6f']"></i>
<span>{{ $cPost->author->name }}</span>
</span>
</li>
@endif
</ul>
</figcaption>
</figure>
</div>
@endforeach
</div>
</div>
<!-- /column -->
</div>
<!-- /.row -->
</div>
<!-- /.container -->
</section>
<!-- /section -->
@endif
<div class="wrapper !bg-[#ffffff]">
<div class="container !pb-[4.5rem] xl:!pb-24 lg:!pb-24 md:!pb-24">
<!-- Welcome Banner Section -->
<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">
<div class="lg:w-full xl:w-10/12 xxl:w-8/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !mx-auto !text-center">
<h2 class="xl:!text-[1.7rem] !text-[calc(1.295rem_+_0.54vw)] !leading-[1.25] font-semibold !text-center !mt-4 !mb-10">
Merhaba! Biz Trunçgil. Blogumuza hoş geldiniz. Burada web tasarım, yazılım geliştirme ve teknolojik yeniliklere dair ipuçlarını ve deneyimlerimizi paylaşıyoruz.
</h2>
</div>
</div>
<!-- 3-Column Highlights Section -->
@if(isset($highlightCategories) && $highlightCategories->count() > 0)
<div class="flex flex-wrap mx-[-15px] grid-view md:mx-[-20px] lg:mx-[-20px] xl:mx-[-25px] !mt-[-40px] xl:!mt-0 lg:!mt-0 !text-center !mb-16">
@foreach($highlightCategories as $index => $hCat)
@php
$images = ['assets/img/photos/f1.jpg', 'assets/img/photos/f2.jpg', 'assets/img/photos/f3.jpg'];
$hImg = asset($images[$index % 3]);
$hUrl = route('blog.index', ['category' => $hCat->slug]);
@endphp
<div class="md:w-6/12 lg:w-4/12 xl:w-4/12 w-full flex-[0_0_auto] !px-[15px] max-w-full !mx-auto md:!px-[20px] lg:!px-[20px] xl:!px-[25px] !mt-[40px] xl:!mt-0 lg:!mt-0">
<div class="card !shadow-[0_0.25rem_1.75rem_rgba(30,34,40,0.07)]">
<figure class="card-img-top overlay overlay-1 group">
<a href="{{ $hUrl }}">
<img class="max-w-full h-auto" src="{{ $hImg }}" alt="{{ $hCat->name }}" style="height: 240px; object-fit: cover; width: 100%;" loading="lazy">
</a>
<figcaption class="group-hover:opacity-100 absolute w-full h-full opacity-0 text-center px-4 py-3 inset-0 z-[5] pointer-events-none p-2">
<h5 class="from-top !mb-0 !absolute w-full translate-y-[-80%] px-4 py-3 left-0 top-2/4 !text-white">Keşfet</h5>
</figcaption>
</figure>
<div class="card-body p-5">
<h4 class="!mb-0">
<a class="!text-[#343f52] hover:!text-[#e31e24]" href="{{ $hUrl }}">{{ $hCat->name }}</a>
</h4>
</div>
</div>
</div>
@endforeach
</div>
@endif
<!-- Main Content & Sidebar Layout -->
<div class="flex flex-wrap mx-[-15px] xl:mx-[-35px] lg:mx-[-20px] !mt-[4rem]">
<!-- Left Column: Posts Feed (8/12) -->
<div class="xl:w-8/12 lg:w-8/12 w-full flex-[0_0_auto] !px-[15px] max-w-full lg:!px-[20px] xl:!px-[35px] xl:!mt-0 lg:!mt-0">
<!-- 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ü']) }}
<div class="flex flex-wrap justify-start !mb-10 gap-2 blog-filter-menu">
<a href="#" class="category-filter-btn active !text-[0.75rem] !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="">
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 }}">
<a href="#" class="category-filter-btn !text-[0.75rem] !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
@@ -39,12 +118,94 @@
@include('blog.partials.posts')
</div>
</div>
<!-- /column -->
<!-- Right Column: Sidebar (4/12) -->
<aside class="xl:w-4/12 lg:w-4/12 flex-[0_0_auto] !px-[15px] max-w-full sidebar !mt-8 lg:!px-[20px] xl:!px-[35px] xl:!mt-0 lg:!mt-0">
<!-- Widget: About Me -->
<div class="widget">
<h4 class="widget-title !mb-3">Hakkımızda</h4>
<figure class="!rounded-[.4rem] !mb-4">
<img class="max-w-full h-auto !rounded-[.4rem]" src="{{ asset('assets/img/photos/f1.jpg') }}" alt="Trunçgil Teknoloji" style="height: 220px; object-fit: cover; width: 100%;">
</figure>
<p>Trunçgil Teknoloji, Gaziantep Teknopark bünyesinde web tasarım, özel yazılım geliştirme, yapay zeka çözümleri ve dijital dönüşüm süreçlerinde kurumlara premium ve yenilikçi çözümler sunan bir teknoloji ajansıdır.</p>
<nav class="nav social !mt-4">
<a class="m-[0_.7rem_0_0] text-[1rem] transition-all duration-[0.2s] ease-in-out translate-y-0 hover:translate-y-[-0.15rem]" href="https://twitter.com/truncgil" target="_blank"><i class="uil uil-twitter before:content-['\ed59'] text-[1rem] !text-[#5daed5]"></i></a>
<a class="m-[0_.7rem_0_0] text-[1rem] transition-all duration-[0.2s] ease-in-out translate-y-0 hover:translate-y-[-0.15rem]" href="https://facebook.com/truncgil" target="_blank"><i class="uil uil-facebook-f before:content-['\eae2'] text-[1rem] !text-[#4470cf]"></i></a>
<a class="m-[0_.7rem_0_0] text-[1rem] transition-all duration-[0.2s] ease-in-out translate-y-0 hover:translate-y-[-0.15rem]" href="https://instagram.com/truncgil" target="_blank"><i class="uil uil-instagram before:content-['\eb9c'] text-[1rem] !text-[#d53581]"></i></a>
<a class="m-[0_.7rem_0_0] text-[1rem] transition-all duration-[0.2s] ease-in-out translate-y-0 hover:translate-y-[-0.15rem]" href="https://youtube.com/truncgil" target="_blank"><i class="uil uil-youtube before:content-['\edb5'] text-[1rem] !text-[#c8312b]"></i></a>
</nav>
</div>
<!-- Widget: Popular Posts -->
@if(isset($popularPosts) && $popularPosts->count() > 0)
<div class="widget !mt-[40px]">
<h4 class="widget-title !mb-3">Popüler Yazılar</h4>
<ul class="m-0 p-0 after:content-[''] after:block after:h-0 after:clear-both after:invisible">
@foreach($popularPosts as $pPost)
@php
$pTitle = method_exists($pPost, 'translate') ? $pPost->translate('title') : $pPost->title;
$pDate = $pPost->published_at ? $pPost->published_at->format('d M Y') : $pPost->created_at->format('d M Y');
$pImage = $pPost->featured_image ? asset('storage/' . $pPost->featured_image) : asset('assets/img/photos/a4.jpg');
$pUrl = route('blog.show', $pPost->slug);
@endphp
<li class="clear-both block overflow-hidden !mt-4 first:!mt-0">
<figure class="!rounded-[.4rem] float-left w-14 !h-[4.5rem]">
<a href="{{ $pUrl }}">
<img class="!rounded-[.4rem]" src="{{ $pImage }}" alt="{{ $pTitle }}" style="height: 100%; object-fit: cover; width: 100%;" loading="lazy">
</a>
</figure>
<div class="!relative !ml-[4.25rem] !mb-0">
<h6 class="!mb-1">
<a class="!text-[#343f52] hover:!text-[#e31e24]" href="{{ $pUrl }}">{{ \Illuminate\Support\Str::limit($pTitle, 45) }}</a>
</h6>
<ul class="!text-[.75rem] !text-[#aab0bc] m-0 p-0 list-none">
<li class="post-date inline-block"><i class="uil uil-calendar-alt pr-[0.2rem] align-[-.05rem] before:content-['\e9ba']"></i><span>{{ $pDate }}</span></li>
</ul>
</div>
</li>
@endforeach
</ul>
</div>
@endif
<!-- Widget: Categories -->
@if(isset($sidebarCategories) && $sidebarCategories->count() > 0)
<div class="widget !mt-[40px]">
<h4 class="widget-title !mb-3">Kategoriler</h4>
<ul class="pl-0 list-none bullet-primary !text-inherit">
@foreach($sidebarCategories as $sCat)
<li class="relative !pl-[1rem] before:absolute before:top-[-0.15rem] before:text-[1rem] before:content-['\2022'] before:left-0 before:!text-[#e31e24] before:font-SansSerif !mt-[.35rem] first:!mt-0">
<a class="!text-[#60697b] hover:!text-[#e31e24]" href="{{ route('blog.index', ['category' => $sCat->slug]) }}">
{{ $sCat->name }} ({{ $sCat->blogs_count }})
</a>
</li>
@endforeach
</ul>
</div>
@endif
<!-- Widget: Tags -->
@if(isset($tags) && $tags->count() > 0)
<div class="widget !mt-[40px]">
<h4 class="widget-title !mb-3">Etiketler</h4>
<ul class="pl-0 list-none tag-list">
@foreach($tags as $tag)
<li class="!mt-0 !mb-[0.45rem] !mr-[0.2rem] inline-block">
<a href="{{ route('blog.index', ['tag' => $tag]) }}" class="btn btn-soft-ash btn-sm !rounded-[50rem] flex items-center hover:translate-y-[-0.15rem] hover:shadow-[0_0.25rem_0.75rem_rgba(30,34,40,.05)] before:not-italic before:content-['#'] before:font-normal before:!pr-[0.2rem]">
{{ $tag }}
</a>
</li>
@endforeach
</ul>
</div>
@endif
</aside>
</div>
<!-- /.row -->
</div>
<!-- /.container -->
</div>
</section>
@push('styles')
<style>
@@ -95,12 +256,11 @@ document.addEventListener('DOMContentLoaded', function() {
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',
@@ -109,20 +269,12 @@ document.addEventListener('DOMContentLoaded', function() {
})
.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(() => {
@@ -151,7 +303,6 @@ document.addEventListener('DOMContentLoaded', function() {
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]');
@@ -160,29 +311,24 @@ document.addEventListener('DOMContentLoaded', function() {
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') || '';
@@ -195,15 +341,12 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
} 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) {