You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
// frontend/components/Topbar.tsx
|
|
"use client";
|
|
import { useEffect, useState } from "react";
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import { MAIN } from "@/lib/nav";
|
|
import { getMe } from "@/lib/auth";
|
|
import { Icon } from "./Icon";
|
|
import { ThemeToggle } from "./ThemeToggle";
|
|
|
|
// 사용자 이니셜 (원본 data.js: user.initial === "지") — 인증 꺼짐일 땐 항상 이 값.
|
|
const USER_INITIAL = "지";
|
|
const AUTH_ENABLED = process.env.NEXT_PUBLIC_AUTH_ENABLED === "true";
|
|
|
|
export function Topbar() {
|
|
const pathname = usePathname();
|
|
// 데모 무손상: 인증 꺼짐이면 "지" 고정(fetch 없음). 켜졌을 때만 GET /me 로 갱신.
|
|
const [initial, setInitial] = useState(USER_INITIAL);
|
|
useEffect(() => {
|
|
if (!AUTH_ENABLED) return;
|
|
const ac = new AbortController();
|
|
getMe(ac.signal)
|
|
.then((me) => {
|
|
if (me) setInitial(me.initial);
|
|
})
|
|
.catch(() => {});
|
|
return () => ac.abort();
|
|
}, []);
|
|
return (
|
|
<header className="topbar">
|
|
<Link href="/dashboard" className="brand" aria-label="아리 홈">
|
|
<div className="brand-mark">
|
|
<Icon name="spark" />
|
|
</div>
|
|
<div className="brand-tag">
|
|
<b>아리</b>
|
|
<span>AI LIFE OS</span>
|
|
</div>
|
|
</Link>
|
|
|
|
<nav className="mainnav" aria-label="메인 메뉴">
|
|
{MAIN.map((m) => {
|
|
// active: 정확히 일치하거나 하위 경로(예: /tasks/123)도 활성
|
|
const active = pathname === m.href || pathname.startsWith(m.href + "/");
|
|
return (
|
|
<Link
|
|
key={m.id}
|
|
href={m.href}
|
|
className={active ? "active" : ""}
|
|
aria-current={active ? "page" : undefined}
|
|
>
|
|
<Icon name={m.icon} />
|
|
{m.label}
|
|
{m.badge && <span className="badge">{m.badge}</span>}
|
|
</Link>
|
|
);
|
|
})}
|
|
</nav>
|
|
|
|
<div className="top-actions">
|
|
<button className="t-btn" aria-label="검색">
|
|
<Icon name="search" />
|
|
</button>
|
|
<button className="t-btn dot" aria-label="알림">
|
|
<Icon name="bell" />
|
|
</button>
|
|
<ThemeToggle />
|
|
<Link
|
|
href="/settings"
|
|
className={
|
|
"t-btn" +
|
|
(pathname === "/settings" || pathname.startsWith("/settings/") ? " active" : "")
|
|
}
|
|
aria-label="설정"
|
|
aria-current={pathname.startsWith("/settings") ? "page" : undefined}
|
|
>
|
|
<Icon name="gear" />
|
|
</Link>
|
|
<Link href="/settings" className="t-ava" aria-label="내 계정">
|
|
{initial}
|
|
</Link>
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|