대상: 웹 프론트엔드 처음 하는 분
목표: 다크모드 토글, 브랜드 컬러·폰트 적용, 탭 제목/파비콘 교체까지 한 번에.
0) 사전 상태 점검
- 프로젝트: Next.js(App Router) + Tailwind v4 + shadcn/ui
 - 포트: 7401
 - 전편에서 만든 파일들이 있다는 가정
 
1) 탭 제목(브랜드) 바꾸기
App Router의
metadata로 설정하는 것이 정석입니다.
src/app/layout.tsx
export const metadata = {
  title: "naver.how",
  description: "naver.how admin",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>{children}</body>
    </html>
  );
}
2) 폰트 적용(한글 + 라틴) — next/font
로컬 호스팅 + 자동 최적화. 구글폰트 직접 링크 불필요.
설치 없음. Next 내장 기능이라 바로 사용합니다.
src/app/layout.tsx
import { Noto_Sans_KR, Inter } from "next/font/google";
const noto = Noto_Sans_KR({ subsets: ["latin"], weight: ["400","500","700"], variable: "--font-noto" });
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });
export const metadata = {
  title: "naver.how",
  description: "naver.how admin",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body className={`${noto.variable} ${inter.variable} font-sans`}>{children}</body>
    </html>
  );
}
src/app/globals.css (Tailwind v4)
@import "tailwindcss";
@plugin "@tailwindcss/typography";
/* 기본 폰트 스택: Noto Sans KR 우선, 보조로 Inter */
@layer base {
  :root { color-scheme: light dark; }
  html, body { height: 100%; }
  body { font-family: var(--font-noto), var(--font-inter), system-ui, -apple-system, Segoe UI, Roboto, sans-serif; }
}
3) 브랜드 컬러/그라데이션 토큰 만들기
v4에서는 CSS 변수를 정의해 두고 Tailwind의 **임의 값(Arbitrary values)**로 바로 씁니다.
src/app/globals.css 에 아래 블록 추가:
@layer base {
  :root {
    /* 밝은 테마 */
    --brand: #6d28d9;               /* main (indigo-700 느낌) */
    --brand-2: #f43f5e;             /* accent (rose-500) */
    --surface: #ffffff;
    --text: #0b0b0c;
  }
  .dark {
    /* 다크 테마 */
    --brand: #8b5cf6;               /* main (violet-500) */
    --brand-2: #fb7185;             /* accent (rose-400) */
    --surface: #0b0b0c;
    --text: #e5e7eb;
  }
  /* 배경/전경 컬러를 전역으로 */
  body {
    background: var(--surface);
    color: var(--text);
  }
}
/* 유틸리티(필요한 만큼만) */
@layer utilities {
  .bg-brand { background-color: var(--brand); }
  .text-brand { color: var(--brand); }
  .bg-brand-2 { background-color: var(--brand-2); }
}
사용법 예시 (컴포넌트 어디서든):
<div className="h-7 w-7 rounded-xl bg-[var(--brand)]" />
<button className="bg-[var(--brand)] text-white hover:opacity-90 px-3 py-2 rounded-xl">
  Primary
</button>
우리 데모 상단 로고 뱃지의 그라데이션도 바꿔 보세요:
<div className="h-7 w-7 rounded-xl bg-[var(--brand)] [background:linear-gradient(135deg,var(--brand),var(--brand-2))]" />
4) 다크모드 토글(전역) — 로컬 저장 + OS 연동
버튼 한번 누르면
.dark클래스를 html에 달아 전체 색 체계를 전환합니다.
(A) 전역 Provider 작성
src/components/theme/ThemeProvider.tsx
"use client";
import { createContext, useContext, useEffect, useMemo, useState } from "react";
type Theme = "light" | "dark" | "system";
type Ctx = { theme: Theme; setTheme: (t: Theme) => void; isDark: boolean };
const ThemeCtx = createContext<Ctx | null>(null);
export default function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<Theme>(() => (typeof window === "undefined" ? "system" : (localStorage.getItem("theme") as Theme) || "system"));
  const isDark = useMemo(() => {
    if (theme === "system") {
      if (typeof window === "undefined") return false;
      return window.matchMedia("(prefers-color-scheme: dark)").matches;
    }
    return theme === "dark";
  }, [theme]);
  useEffect(() => {
    const root = document.documentElement;
    root.classList.toggle("dark", isDark);
    localStorage.setItem("theme", theme);
  }, [theme, isDark]);
  // 시스템 테마 변경 감지
  useEffect(() => {
    if (typeof window === "undefined") return;
    const mq = window.matchMedia("(prefers-color-scheme: dark)");
    const handler = () => { if ((localStorage.getItem("theme") || "system") === "system") {
      document.documentElement.classList.toggle("dark", mq.matches);
    }};
    mq.addEventListener("change", handler);
    return () => mq.removeEventListener("change", handler);
  }, []);
  return <ThemeCtx.Provider value={{ theme, setTheme, isDark }}>{children}</ThemeCtx.Provider>;
}
export const useTheme = () => {
  const ctx = useContext(ThemeCtx);
  if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
  return ctx;
};
src/app/layout.tsx 에 Provider 감싸기
import ThemeProvider from "@/components/theme/ThemeProvider";
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>
        <ThemeProvider>{children}</ThemeProvider>
      </body>
    </html>
  );
}
(B) 어디서든 토글 버튼 만들기
"use client";
import { useTheme } from "@/components/theme/ThemeProvider";
import { Moon, Sun, Laptop } from "lucide-react";
export function ThemeToggle(){
  const { theme, setTheme, isDark } = useTheme();
  return (
    <div className="inline-flex items-center gap-2">
      <button onClick={()=>setTheme("light")} className={`px-2 py-1 rounded ${theme==="light"?"bg-gray-200 dark:bg-neutral-800":""}`}>Light</button>
      <button onClick={()=>setTheme("dark")} className={`px-2 py-1 rounded ${theme==="dark"?"bg-gray-200 dark:bg-neutral-800":""}`}>Dark</button>
      <button onClick={()=>setTheme("system")} className={`px-2 py-1 rounded ${theme==="system"?"bg-gray-200 dark:bg-neutral-800":""}`}>System</button>
      <span className="ml-2 text-sm opacity-70 inline-flex items-center gap-1">
        {isDark ? <Moon className="h-4 w-4"/> : <Sun className="h-4 w-4"/>} 현재: {theme}
      </span>
    </div>
  );
}
우리 데모의 상단바(헤더)에 이 토글을 넣어두면 전역으로 먹습니다.
5) shadcn/ui와 컬러 변수 연결(간단 버전)
shadcn 컴포넌트는
bg-primary,text-primary-foreground같은 클래스를 자주 씁니다.
Tailwind v4에선 아래처럼 CSS 변수 기반 유틸리티를 만들어주면 바로 적용됩니다.
src/app/globals.css 에 유틸 추가:
@layer utilities {
  .bg-primary { background-color: var(--brand); }
  .text-primary-foreground { color: #ffffff; }
  .hover\:bg-primary:hover { background-color: var(--brand); filter: brightness(0.95); }
  .border-border { border-color: rgba(0,0,0,0.12); }
}
이제 shadcn의 <Button>이 variant="default"일 때 bg-primary를 쓴다면, 우리가 정의한 –brand 색이 적용됩니다.
(컴포넌트 소스에서 클래스 확인 후 필요 유틸만 추가하세요.)
6) 파비콘/로고 교체
- App Router 규약: 
src/app/icon.png(또는 .ico, .svg)을 두면 자동 파비콘으로 사용됩니다. - 로고 이미지는 
public/아래에 두고<Image src="/neverhow_logo.png" ... />식으로 사용. 
# 예시
# 프로젝트 루트에서
cp ~/Downloads/naverhow_favicon.png src/app/icon.png
cp ~/Downloads/naverhow_logo.png public/naverhow_logo.png
상단 로고 교체:
<img src="/naverhow_logo.png" alt="naver.how" className="h-7 w-auto" />
7) 실행 & 확인(포트 7401)
pnpm approve-builds         # 처음 한 번
pnpm dev -- -H 0.0.0.0 -p 7401
브라우저 체크:
- 탭 제목: naverhow
 - 다크/라이트 전환 OK
 - 로고/파비콘 적용 OK
 - 버튼 등 주요 색상에 브랜드 색 반영 OK
 
마무리
이제 **브랜딩 체계(컬러/폰트/타이틀/파비콘/다크모드)**가 갖춰졌어요.
다음 편에서는 사이드바 그룹 구조(IA) 반영, 라우트 키 설계, 페이지 템플릿(테이블/로그/차트/시트)을 빠르게 찍어내는 법을 다룹니다.