Files
auto-trade/app/layout.tsx
2026-02-11 14:06:06 +09:00

78 lines
2.2 KiB
TypeScript

/**
* @file app/layout.tsx
* @description 애플리케이션의 최상위 루트 레이아웃 (RootLayout)
* @remarks
* - [레이어] Infrastructure/Layout
* - [역할] 전역 스타일(Font/CSS), 테마(Provider), 세션 관리(Manager) 초기화
* - [데이터 흐름] Providers -> Children
* - [연관 파일] globals.css, theme-provider.tsx
*/
import type { Metadata } from "next";
import { Geist, Geist_Mono, Outfit } from "next/font/google";
import { QueryProvider } from "@/providers/query-provider";
import { ThemeProvider } from "@/components/theme-provider";
import { SessionManager } from "@/features/auth/components/session-manager";
import { Toaster } from "sonner";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
const outfit = Outfit({
variable: "--font-heading",
subsets: ["latin"],
display: "swap",
});
export const metadata: Metadata = {
title: "Jurini - 감이 아닌 전략으로 시작하는 자동매매",
description:
"주린이를 위한 자동매매 파트너 Jurini. 손실 방어 규칙, 데이터 신호 분석, 실시간 자동 실행으로 초보의 첫 수익 루틴을 만듭니다.",
};
/**
* RootLayout 컴포넌트
* @param children 렌더링할 자식 컴포넌트
* @returns HTML 구조 및 전역 Provider 래퍼
* @see theme-provider.tsx - 다크모드 지원
* @see session-manager.tsx - 세션 타임아웃 감지
*/
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" className="scroll-smooth" suppressHydrationWarning>
<body
className={`${geistSans.variable} ${geistMono.variable} ${outfit.variable} antialiased`}
>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<SessionManager />
<QueryProvider>{children}</QueryProvider>
<Toaster
richColors
position="top-right"
toastOptions={{
duration: 4000,
}}
/>
</ThemeProvider>
</body>
</html>
);
}