gabeefran.co-blog/src/components/Header.astro
2026-09-02 20:08:41 -03:00

99 lines
3.6 KiB
Text

---
import ThemeToggle from './ThemeToggle.astro';
import { getLocalizedPath, LANG_LABELS, useTranslations, type Lang } from '../lib/i18n';
interface Props {
lang: Lang;
}
const { lang } = Astro.props;
const t = useTranslations(lang);
const otherLang: Lang = lang === 'en' ? 'pt' : 'en';
const pathname = Astro.url.pathname;
const homeHref = getLocalizedPath('/', lang);
const postsHref = getLocalizedPath('/posts', lang);
const aboutHref = getLocalizedPath('/about', lang);
const langSwitchHref = getLocalizedPath(pathname, otherLang);
const navLinks = [
{ href: homeHref, label: t('nav.home') },
{ href: postsHref, label: t('nav.posts') },
{ href: aboutHref, label: t('nav.about') },
];
function isActive(href: string): boolean {
if (href === homeHref) return pathname === href;
return pathname === href || pathname.startsWith(`${href}/`);
}
---
<header class="sticky top-0 z-40 border-b border-border/80 bg-bg/85 backdrop-blur">
<div class="mx-auto flex max-w-3xl items-center justify-between gap-4 px-4 py-3 sm:px-6">
<a href={homeHref} class="flex shrink-0 items-center gap-2.5" aria-label={t('site.name')}>
<img src="/favicon.svg" alt="" width="32" height="32" class="size-8" />
<span class="font-mono text-[15px] font-semibold tracking-tight text-text">{t('site.name')}</span>
</a>
<div class="flex items-center gap-2">
<nav class="hidden items-center gap-1 sm:flex" aria-label={t('nav.menu')}>
{navLinks.map((link) => (
<a
href={link.href}
aria-current={isActive(link.href) ? 'page' : undefined}
class:list={[
'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',
isActive(link.href)
? 'bg-primary/10 text-primary'
: 'text-text-muted hover:bg-surface-alt hover:text-text',
]}
>
{link.label}
</a>
))}
</nav>
<a
href={langSwitchHref}
hreflang={otherLang}
title={t('lang.switch')}
aria-label={`${t('lang.switch')}: ${LANG_LABELS[otherLang]}`}
class="grid size-9 shrink-0 place-items-center rounded-full border border-border text-xs font-bold uppercase text-text-muted transition-colors hover:border-primary hover:text-primary"
>
{otherLang}
</a>
<ThemeToggle lang={lang} />
<details class="relative sm:hidden">
<summary
class="grid size-9 cursor-pointer list-none place-items-center rounded-full border border-border text-text-muted transition-colors hover:border-primary hover:text-primary"
aria-label={t('nav.menu')}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" class="size-[18px]">
<path d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
</summary>
<nav
class="absolute right-0 top-11 flex w-40 flex-col gap-1 rounded-xl border border-border bg-surface p-2 shadow-lg"
aria-label={t('nav.menu')}
>
{navLinks.map((link) => (
<a
href={link.href}
aria-current={isActive(link.href) ? 'page' : undefined}
class:list={[
'rounded-lg px-3 py-2 text-sm font-medium transition-colors',
isActive(link.href)
? 'bg-primary/10 text-primary'
: 'text-text-muted hover:bg-surface-alt hover:text-text',
]}
>
{link.label}
</a>
))}
</nav>
</details>
</div>
</div>
</header>