import React from 'react'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ConfigProvider, type ThemeConfig, message } from 'antd'; import koKR from 'antd/locale/ko_KR'; import 'dayjs/locale/ko'; import { COLOR_PRIMARY, COLOR_PRIMARY_LIGHT, COLOR_SUCCESS, COLOR_WARNING, COLOR_ERROR, COLOR_INFO, GRAY, FONT_FAMILY, FONT_SIZE, RADIUS, SPACING, LAYOUT, } from './theme/tokens'; import App from './App'; import './index.css'; // 토스트 메시지 전역 설정 (top-right, 최대 5개, 3초) message.config({ top: 16, maxCount: 5, duration: 3 }); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: 1, staleTime: 30_000 } }, }); const theme: ThemeConfig = { token: { // ── 브랜드 — 토스 블루 ── colorPrimary: COLOR_PRIMARY, colorPrimaryBg: COLOR_PRIMARY_LIGHT, colorSuccess: COLOR_SUCCESS, colorWarning: COLOR_WARNING, colorError: COLOR_ERROR, colorInfo: COLOR_INFO, // ── 배경 ── colorBgContainer: '#ffffff', colorBgLayout: GRAY[50], colorBgElevated: '#ffffff', colorBgSpotlight: GRAY[100], // ── 텍스트 — 토스 단계 ── colorText: GRAY[800], colorTextSecondary: GRAY[600], colorTextTertiary: GRAY[500], colorTextDisabled: GRAY[400], // ── 테두리 — 거의 보이지 않게 ── colorBorder: GRAY[200], colorBorderSecondary: GRAY[100], // ── 폰트 ── fontFamily: FONT_FAMILY, fontSize: FONT_SIZE.base, // 15px fontSizeHeading1: FONT_SIZE['2xl'], // 32px fontSizeHeading2: FONT_SIZE.xl, // 24px fontSizeHeading3: FONT_SIZE.lg, // 20px fontSizeHeading4: FONT_SIZE.md, // 16px fontSizeHeading5: FONT_SIZE.base, // 15px // ── Border Radius — 토스 비율 ── borderRadius: RADIUS.md, // 12 (버튼, 입력) borderRadiusLG: RADIUS.lg, // 16 (카드) borderRadiusSM: RADIUS.sm, // 8 borderRadiusXS: 4, // ── 공간 ── padding: SPACING[4], paddingLG: SPACING[6], paddingSM: SPACING[2], paddingXS: SPACING[1], margin: SPACING[4], marginLG: SPACING[6], marginSM: SPACING[2], // ── 컨트롤 높이 — 토스는 큼직하게 ── controlHeight: 40, // 기본 입력/버튼 controlHeightSM: 32, controlHeightLG: 48, // large 입력/버튼 // ── 그림자 — 옅은 합성 ── boxShadow: '0 1px 3px rgba(0,0,0,0.04), 0 4px 16px rgba(0,0,0,0.04)', boxShadowSecondary: '0 2px 8px rgba(0,0,0,0.06), 0 8px 24px rgba(0,0,0,0.06)', }, components: { // ── 메뉴 ── Menu: { itemHeight: 44, itemMarginInline: 8, itemBorderRadius: RADIUS.sm, subMenuItemBg: 'transparent', itemSelectedBg: COLOR_PRIMARY_LIGHT, itemSelectedColor: COLOR_PRIMARY, itemHoverBg: GRAY[50], itemHoverColor: GRAY[800], itemColor: GRAY[600], }, // ── 테이블 ── Table: { headerBg: GRAY[50], rowHoverBg: GRAY[50], cellPaddingBlock: 14, cellPaddingInline: 16, headerSplitColor: GRAY[200], }, // ── 버튼 — 토스 CTA 스타일 ── Button: { paddingInline: 20, fontWeight: 600, borderRadius: RADIUS.md, primaryShadow: 'none', defaultShadow: 'none', dangerShadow: 'none', }, // ── 입력 — 토스 filled 느낌 ── Input: { paddingInline: 12, paddingBlock: 12, borderRadius: RADIUS.md, hoverBorderColor: COLOR_PRIMARY, }, // ── 카드 ── Card: { bodyPadding: SPACING[6], // 24px headerBg: '#ffffff', borderRadius: RADIUS.lg, // 16px }, // ── 레이아웃 ── Layout: { headerHeight: LAYOUT.headerHeight, headerBg: '#ffffff', siderBg: '#ffffff', bodyBg: GRAY[50], }, // ── 폼 ── Form: { itemMarginBottom: 20, labelFontSize: 13, labelColor: GRAY[600], }, // ── 배지 ── Badge: { textFontSize: 11, }, // ── 태그/칩 ── Tag: { borderRadius: RADIUS.full, }, // ── Select ── Select: { borderRadius: RADIUS.md, }, // ── DatePicker ── DatePicker: { borderRadius: RADIUS.md, }, // ── 모달 ── Modal: { borderRadius: RADIUS.xl, // 20px }, }, }; ReactDOM.createRoot(document.getElementById('root')!).render( , );