feat: WP'den header + kart stilleri + blog sidebar widget

Header (components/header.tsx + header-scroll.tsx):
- WP'deki 'floating pill' efekti — scroll'da küçülen + yuvarlanan + gölgeli
- 3 sütun grid: Logo | Nav | CTA
- Hizmetler mega menu dropdown — 2 sütunlu (Web&Yazılım + Dijital Pazarlama)
  - Hover'da açılır, services tablosundan dinamik
  - Alt linkle 'Tüm hizmetleri gör'
- Mobil için scroll-down'da gizlenir
- Sağda 'Ücretsiz Teklif' CTA butonu + telefon link

Kart stilleri (WP'ye eşlendi):
- ServicesGrid:
  - Gradient icon (sky → purple) ile WP'deki '🎨 🚀 📱' emoji yerine ikon
  - Hover: -translate-y-2 + colored shadow + scale icon
  - ArrowUpRight ikonu absolute, hover'da görünür
- ProjectsGrid:
  - Kategori bazlı renkli badge (Kurumsal navy, Klinik cyan, Portfolio violet, …)
  - Hover: image scale-105 + gradient overlay
  - 5/3 aspect ratio (daha WP-like)

Public sidebar (components/content-sidebar.tsx):
- CTA card (gradient navy→sky): Telefon + WhatsApp
- Son yazılar (4 adet, kapak + başlık + tarih)
- Etiketler (en sık kullanılan 10)
- Hizmetler menü (6 adet)
- Site analizi lead magnet

Blog detay sayfası (/blog/[slug]):
- Tek sütun → 2 sütun grid (content + sidebar)
- sticky sidebar, max-w-7xl
- Aynı pattern hizmet/proje detay sayfalarına da uygulanabilir

37 route, build temiz.
This commit is contained in:
Ege Can Komur
2026-05-20 18:45:02 +03:00
parent deff889f0c
commit e45c44721f
6 changed files with 577 additions and 169 deletions
+86
View File
@@ -0,0 +1,86 @@
"use client";
import { useEffect } from "react";
/**
* WordPress sitesindeki "floating pill" header efekti.
* Scroll'da header küçülür, kenar yuvarlanır, gölge alır.
* Mobilde scroll-down'da gizlenir, scroll-up'ta görünür.
*/
export function HeaderScrollEffect() {
useEffect(() => {
const wrap = document.getElementById("floating-header-wrap");
const pillWrap = document.getElementById("header-pill-wrap");
const header = document.getElementById("site-header");
const navBar = document.getElementById("header-nav-bar");
if (!wrap || !pillWrap || !header || !navBar) return;
let lastY = 0;
let ticking = false;
wrap.style.transition = "transform 0.3s ease, opacity 0.3s ease";
function applyScroll() {
const y = window.scrollY;
const mobile = window.innerWidth < 1024;
const scrolled = y > 10;
const goingDown = y > lastY;
if (!mobile && pillWrap && header && navBar && wrap) {
wrap.style.transform = "";
wrap.style.opacity = "";
if (scrolled) {
pillWrap.style.padding = "12px 16px 0";
header.style.maxWidth = "1100px";
header.style.borderRadius = "1rem";
header.style.border = "1px solid #e5e7eb";
header.style.boxShadow = "0 8px 24px rgba(0,0,0,0.08)";
navBar.style.height = "52px";
navBar.style.padding = "0 1.25rem";
} else {
pillWrap.style.padding = "";
header.style.maxWidth = "";
header.style.borderRadius = "";
header.style.border = "";
header.style.boxShadow = "";
navBar.style.height = "";
navBar.style.padding = "";
}
}
if (mobile && wrap && y > 80) {
if (goingDown) {
wrap.style.transform = "translateY(-110%)";
wrap.style.opacity = "0";
} else {
wrap.style.transform = "";
wrap.style.opacity = "";
}
} else if (mobile && wrap) {
wrap.style.transform = "";
wrap.style.opacity = "";
}
lastY = y;
ticking = false;
}
function onScroll() {
if (!ticking) {
requestAnimationFrame(applyScroll);
ticking = true;
}
}
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", applyScroll);
applyScroll();
return () => {
window.removeEventListener("scroll", onScroll);
window.removeEventListener("resize", applyScroll);
};
}, []);
return null;
}