deniz bektaş

This commit is contained in:
2026-04-03 16:20:51 +03:00
parent d0cd1c7ee3
commit fb6933edd0
53 changed files with 4742 additions and 98 deletions

285
components/Navigation.tsx Normal file
View File

@@ -0,0 +1,285 @@
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useState } from 'react';
import { useTheme } from './ThemeProvider';
const navGroups = [
{
label: 'Ana',
items: [
{ href: '/', label: 'Anasayfa', icon: '~' },
{ href: '/merhaba', label: 'Merhaba', icon: '>' },
{ href: '/hakkimda', label: 'Hakkımda', icon: '@' },
{ href: '/su-anda', label: 'Şu Anda', icon: '◉' },
{ href: '/misyon', label: 'Misyon', icon: '⚑' },
],
},
{
label: 'İçerik',
items: [
{ href: '/blog', label: 'Personal Blog', icon: '✍' },
{ href: '/notebook', label: 'Notebook', icon: '◎' },
{ href: '/infosec', label: 'Infosec Posts', icon: '⚔' },
{ href: '/seyir-defteri', label: 'Seyir Defteri', icon: '⚓' },
{ href: '/projeler', label: 'Projeler', icon: '◈' },
{ href: '/podcast', label: 'Podcast', icon: '◉' },
],
},
{
label: 'Koleksiyon',
items: [
{ href: '/faydali-linkler', label: 'Faydalı Linkler', icon: '⊞' },
{ href: '/roadmap', label: 'Roadmap', icon: '◆' },
{ href: '/takim-cantam', label: 'Takım Çantam', icon: '⊡' },
{ href: '/hobilerim', label: 'Hobilerim', icon: '♦' },
{ href: '/fikirlerim', label: 'Fikirlerim', icon: '◇' },
],
},
{
label: 'Bilgi',
items: [
{ href: '/iletisim', label: 'İletişim', icon: '✉' },
{ href: '/ozgecmis', label: 'Özgeçmiş', icon: '▤' },
{ href: '/aktivite', label: 'Aktivite', icon: '▶' },
{ href: '/rss-beslemeleri', label: 'RSS Beslemeleri', icon: '◈' },
{ href: '/statboard', label: 'Statboard', icon: '▦' },
{ href: '/altyapi', label: 'Altyapı', icon: '⊟' },
{ href: '/tesekkurler', label: 'Teşekkürler', icon: '♡' },
],
},
{
label: 'Meta',
items: [
{ href: '/gizlilik', label: 'Gizlilik', icon: '⊘' },
{ href: '/kullanim-kosullari', label: 'Kullanım Koşulları', icon: '⊘' },
{ href: '/humans.txt', label: 'humans.txt', icon: '▸', external: true },
{ href: '/security.txt', label: 'security.txt', icon: '▸', external: true },
{ href: '/public.pgp', label: 'public.pgp', icon: '▸', external: true },
],
},
{
label: 'Harici',
items: [
{ href: '/mastodon', label: 'Mastodon', icon: '⊕', external: true },
{ href: 'mailto:info@denizbektas.com.tr', label: 'E-Mail', icon: '✉', external: true },
],
},
];
export default function Navigation() {
const pathname = usePathname();
const { theme, toggle } = useTheme();
const [mobileOpen, setMobileOpen] = useState(false);
const isActive = (href: string) => {
if (href === '/') return pathname === '/';
return pathname.startsWith(href);
};
const sidebarContent = (
<nav style={{ display: 'flex', flexDirection: 'column', gap: '1.25rem' }}>
{navGroups.map((group) => (
<div key={group.label}>
<div className="section-header">{group.label}</div>
<ul style={{ listStyle: 'none', display: 'flex', flexDirection: 'column', gap: '1px' }}>
{group.items.map((item) => (
<li key={item.href}>
{item.external && item.href.startsWith('mailto:') ? (
<a
href={item.href}
style={{
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
padding: '0.3rem 0.5rem',
borderRadius: '4px',
fontSize: '0.93rem',
color: 'var(--text-muted)',
transition: 'all 0.15s',
}}
>
<span style={{ color: 'var(--accent)', width: '1.1rem', flexShrink: 0, fontSize: '0.82rem' }}>{item.icon}</span>
{item.label}
</a>
) : item.external && !item.href.startsWith('/') ? (
<a
href={item.href}
target="_blank"
rel="noopener noreferrer"
style={{
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
padding: '0.3rem 0.5rem',
borderRadius: '4px',
fontSize: '0.93rem',
color: 'var(--text-muted)',
}}
>
<span style={{ color: 'var(--accent)', width: '1.1rem', flexShrink: 0, fontSize: '0.82rem' }}>{item.icon}</span>
{item.label}
<span style={{ marginLeft: 'auto', fontSize: '0.7rem', opacity: 0.5 }}></span>
</a>
) : (
<Link
href={item.href}
target={item.external ? '_blank' : undefined}
onClick={() => setMobileOpen(false)}
style={{
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
padding: '0.35rem 0.5rem',
borderRadius: '4px',
fontSize: '0.93rem',
color: isActive(item.href) ? 'var(--accent)' : 'var(--text-muted)',
background: isActive(item.href) ? 'var(--tag-bg)' : 'transparent',
fontWeight: isActive(item.href) ? '600' : '400',
transition: 'all 0.15s',
opacity: 1,
}}
>
<span style={{ color: 'var(--accent)', width: '1.1rem', flexShrink: 0, fontSize: '0.82rem' }}>{item.icon}</span>
{item.label}
{item.external && <span style={{ marginLeft: 'auto', fontSize: '0.7rem', opacity: 0.5 }}></span>}
</Link>
)}
</li>
))}
</ul>
</div>
))}
</nav>
);
return (
<>
{/* Desktop Sidebar */}
<aside
className="desktop-sidebar"
style={{
width: '272px',
flexShrink: 0,
background: 'var(--sidebar-bg)',
borderRight: '1px solid var(--border)',
height: '100vh',
position: 'sticky',
top: 0,
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',
}}
>
{/* Logo */}
<div style={{ padding: '1.25rem 1rem', borderBottom: '1px solid var(--border)' }}>
<Link href="/" style={{ display: 'block', color: 'var(--accent)', fontWeight: '800', fontSize: '1.1rem', letterSpacing: '-0.02em' }}>
denizbektas<span style={{ color: 'var(--text-muted)', fontWeight: 400 }}>.com.tr</span>
</Link>
<div style={{ fontSize: '0.78rem', color: 'var(--text-muted)', marginTop: '0.25rem' }}>siber güvenlik uzmanı</div>
</div>
{/* Theme Toggle */}
<div style={{ padding: '0.75rem 1rem', borderBottom: '1px solid var(--border)' }}>
<button
onClick={toggle}
style={{
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
fontSize: '0.88rem',
color: 'var(--text-muted)',
background: 'none',
border: 'none',
cursor: 'pointer',
padding: '0.35rem 0.5rem',
borderRadius: '4px',
width: '100%',
fontFamily: 'inherit',
transition: 'color 0.15s',
}}
>
<span style={{ fontSize: '0.9rem' }}>{theme === 'dark' ? '☀' : '◑'}</span>
{theme === 'dark' ? 'Light Mode' : 'Dark Mode'}
</button>
</div>
{/* Nav */}
<div style={{ padding: '1rem', flex: 1 }}>
{sidebarContent}
</div>
{/* Footer */}
<div style={{ padding: '0.75rem 1rem', borderTop: '1px solid var(--border)', fontSize: '0.6rem', color: 'var(--text-muted)' }}>
<div>© 2026 denizbektas</div>
<div style={{ marginTop: '0.2rem', color: 'var(--accent)', opacity: 0.6 }}>
<span className="blink"></span>
</div>
</div>
</aside>
{/* Mobile Header */}
<header
className="mobile-header"
style={{
display: 'none',
position: 'fixed',
top: 0,
left: 0,
right: 0,
height: '52px',
background: 'var(--header-bg)',
backdropFilter: 'blur(8px)',
borderBottom: '1px solid var(--border)',
zIndex: 100,
alignItems: 'center',
justifyContent: 'space-between',
padding: '0 1rem',
}}
>
<Link href="/" style={{ color: 'var(--accent)', fontWeight: '800', fontSize: '0.95rem' }}>
denizbektas<span style={{ color: 'var(--text-muted)', fontWeight: 400 }}>.dev</span>
</Link>
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
<button onClick={toggle} style={{ background: 'none', border: 'none', cursor: 'pointer', fontSize: '1rem', color: 'var(--text-muted)' }}>
{theme === 'dark' ? '☀' : '◑'}
</button>
<button
onClick={() => setMobileOpen(!mobileOpen)}
style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text)', fontSize: '1.2rem', fontFamily: 'inherit' }}
>
{mobileOpen ? '✕' : '☰'}
</button>
</div>
</header>
{/* Mobile Nav Overlay */}
{mobileOpen && (
<div
style={{
position: 'fixed',
top: '52px',
left: 0,
right: 0,
bottom: 0,
background: 'var(--sidebar-bg)',
zIndex: 99,
overflowY: 'auto',
padding: '1rem',
borderTop: '1px solid var(--border)',
}}
>
{sidebarContent}
</div>
)}
<style>{`
@media (max-width: 768px) {
.desktop-sidebar { display: none !important; }
.mobile-header { display: flex !important; }
}
`}</style>
</>
);
}

View File

@@ -0,0 +1,36 @@
'use client';
import { createContext, useContext, useEffect, useState } from 'react';
type Theme = 'dark' | 'light';
const ThemeContext = createContext<{
theme: Theme;
toggle: () => void;
}>({ theme: 'dark', toggle: () => {} });
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>('dark');
useEffect(() => {
const stored = localStorage.getItem('theme') as Theme | null;
const initial = stored || 'dark';
setTheme(initial);
document.documentElement.setAttribute('data-theme', initial);
}, []);
const toggle = () => {
const next = theme === 'dark' ? 'light' : 'dark';
setTheme(next);
localStorage.setItem('theme', next);
document.documentElement.setAttribute('data-theme', next);
};
return (
<ThemeContext.Provider value={{ theme, toggle }}>
{children}
</ThemeContext.Provider>
);
}
export const useTheme = () => useContext(ThemeContext);