first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 22:14:08 +03:00
commit b2825e1698
41 changed files with 14258 additions and 0 deletions

181
components/header.tsx Normal file
View File

@@ -0,0 +1,181 @@
"use client";
import React, { useEffect, useState } from "react";
import Link from "next/link";
import { useSession, signOut } from "next-auth/react";
import clsx from "clsx";
import { Search, ShoppingCart, ChevronDown, LogOut, User } from "lucide-react";
import { Button } from "@/components/ui/button";
import { ThemeToggle } from "@/components/theme-toggle";
import {
getCookieSession,
logoutViaCookie,
clearTokens,
AUTH_CHANGE_EVENT,
notifyAuthChange,
} from "@/lib/auth-api";
const navItems = [
{ label: "Home", href: "/", hasDropdown: true },
{ label: "About Us", href: "/about", hasDropdown: false },
{ label: "Pages", href: "/pages", hasDropdown: true },
{ label: "Blog", href: "/blog", hasDropdown: true, active: true },
{ label: "Contact", href: "/contact", hasDropdown: false },
];
function TechwixLogo() {
return (
<Link href="/" className="flex items-center gap-2">
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="shrink-0"
>
<defs>
<linearGradient id="logoGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="#3b82f6" />
<stop offset="100%" stopColor="#8b5cf6" />
</linearGradient>
</defs>
{/* Single gradient shape - diamond/arrowhead */}
<path
d="M16 5L27 16L16 27L5 16L16 5Z"
fill="url(#logoGrad)"
/>
<path
d="M16 9L23 16L16 23L9 16L16 9Z"
fill="white"
fillOpacity="0.2"
/>
</svg>
<span className="text-xl font-semibold text-neutral-800 dark:text-neutral-100">
Techwix
</span>
</Link>
);
}
export default function Header() {
const [scrolled, setScrolled] = useState(false);
const { data: session, status } = useSession();
const [cookieLoggedIn, setCookieLoggedIn] = useState(false);
const isLoggedIn = Boolean(session?.user) || cookieLoggedIn;
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 8);
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
return () => window.removeEventListener("scroll", onScroll);
}, []);
const refreshCookieSession = () => {
getCookieSession().then((s) => setCookieLoggedIn(s.loggedIn));
};
useEffect(() => {
refreshCookieSession();
const handler = () => refreshCookieSession();
window.addEventListener(AUTH_CHANGE_EVENT, handler);
return () => window.removeEventListener(AUTH_CHANGE_EVENT, handler);
}, []);
const handleLogout = async () => {
clearTokens(); // eski localStorage token varsa temizle
await logoutViaCookie();
signOut({ callbackUrl: "/" });
setCookieLoggedIn(false);
notifyAuthChange();
};
return (
<header
className={clsx(
"sticky top-0 z-40 w-full border-b border-neutral-200/80 transition-colors duration-200 backdrop-blur dark:border-neutral-800",
scrolled
? "bg-white/95 shadow-sm dark:bg-neutral-950/95"
: "bg-white dark:bg-neutral-950/90"
)}
>
<div className="container mx-auto flex h-16 items-center justify-between gap-6 px-4 lg:px-6">
<TechwixLogo />
<nav className="hidden items-center gap-1 md:flex">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={clsx(
"flex items-center gap-0.5 rounded-md px-3 py-2 text-sm font-medium transition-colors",
item.active
? "text-blue-500 dark:text-blue-400"
: "text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white"
)}
>
{item.label}
{item.hasDropdown && (
<ChevronDown className="size-3.5 text-current opacity-70" />
)}
</Link>
))}
</nav>
<div className="flex items-center gap-2">
<ThemeToggle />
<button
type="button"
className="relative rounded-md p-2 text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-white"
aria-label="Cart"
>
<ShoppingCart className="size-5" />
<span className="absolute -right-0.5 -top-0.5 flex size-4 items-center justify-center rounded-full bg-blue-500 text-[10px] font-medium text-white">
0
</span>
</button>
<button
type="button"
className="rounded-md p-2 text-neutral-600 hover:bg-neutral-100 hover:text-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-white"
aria-label="Search"
>
<Search className="size-5" />
</button>
{status === "loading" ? null : isLoggedIn ? (
<>
<Link
href="/profile"
className="flex items-center gap-1.5 rounded-md px-3 py-2 text-sm font-medium text-neutral-700 hover:bg-neutral-100 hover:text-neutral-900 dark:text-neutral-300 dark:hover:bg-neutral-800 dark:hover:text-white"
>
<User className="size-4" />
<span className="hidden sm:inline">Profil</span>
</Link>
<button
type="button"
onClick={handleLogout}
className="flex items-center gap-1.5 rounded-md px-3 py-2 text-sm font-medium text-neutral-700 hover:bg-neutral-100 hover:text-neutral-900 dark:text-neutral-300 dark:hover:bg-neutral-800 dark:hover:text-white"
>
<LogOut className="size-4" />
<span className="hidden sm:inline">Çıkış</span>
</button>
</>
) : (
<>
<Button variant="ghost" size="sm" asChild>
<Link href="/auth/login">Giriş</Link>
</Button>
<Button
asChild
size="sm"
className="rounded-md bg-gradient-to-r from-blue-500 to-blue-400 text-white shadow-sm hover:from-blue-600 hover:to-blue-500 dark:from-blue-600 dark:to-blue-500 dark:hover:from-blue-700 dark:hover:to-blue-600"
>
<Link href="/auth/register">Kayıt</Link>
</Button>
</>
)}
</div>
</div>
</header>
);
}