diff --git a/src/app/router.tsx b/src/app/router.tsx
index dfe0538..9f09a3e 100644
--- a/src/app/router.tsx
+++ b/src/app/router.tsx
@@ -1,9 +1,24 @@
+import React, { Suspense } from 'react'
import { Routes, Route } from 'react-router-dom'
+const DesignSystemPage = import.meta.env.DEV
+ ? React.lazy(() => import('@/features/design-system/DesignSystemPage'))
+ : () => null
+
export function AppRouter() {
return (
} />
+ {import.meta.env.DEV && (
+ Loading…}>
+
+
+ }
+ />
+ )}
)
}
diff --git a/src/features/design-system/DesignSystemPage.tsx b/src/features/design-system/DesignSystemPage.tsx
new file mode 100644
index 0000000..27edc6f
--- /dev/null
+++ b/src/features/design-system/DesignSystemPage.tsx
@@ -0,0 +1,248 @@
+import React, { useState } from 'react'
+import { useTheme } from '@/shared/hooks/useTheme'
+import { Button } from '@/shared/components/ui/button'
+import { Badge } from '@/shared/components/ui/badge'
+import { Input } from '@/shared/components/ui/input'
+import { Label } from '@/shared/components/ui/label'
+import { Separator } from '@/shared/components/ui/separator'
+import { Progress } from '@/shared/components/ui/progress'
+import {
+ Avatar,
+ AvatarFallback,
+ AvatarImage,
+ AvatarGroup,
+ AvatarGroupCount,
+} from '@/shared/components/ui/avatar'
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from '@/shared/components/ui/dialog'
+
+// ─── palette data ────────────────────────────────────────────────────────────
+
+const PALETTE: { token: string; var: string; light: string; dark: string }[] = [
+ { token: 'canvas', var: '--color-canvas', light: '#EEF2F8', dark: '#0D1220' },
+ { token: 'canvas-2', var: '--color-canvas-2', light: '#E6EBF4', dark: '#121A2D' },
+ { token: 'surface', var: '--color-surface', light: '#FFFFFF', dark: '#182238' },
+ { token: 'surface-hover',var: '--color-surface-hover',light: '#F8FAFD', dark: '#1E2A42' },
+ { token: 'line', var: '--color-line', light: '#DDE3ED', dark: '#27324B' },
+ { token: 'line-strong', var: '--color-line-strong', light: '#C7D0E0', dark: '#364363' },
+ { token: 'ink-1', var: '--color-ink-1', light: '#0F172A', dark: '#F1F4FA' },
+ { token: 'ink-2', var: '--color-ink-2', light: '#1E293B', dark: '#DDE3EF' },
+ { token: 'ink-3', var: '--color-ink-3', light: '#475569', dark: '#A8B2C7' },
+ { token: 'ink-4', var: '--color-ink-4', light: '#64748B', dark: '#7A8499' },
+ { token: 'ink-5', var: '--color-ink-5', light: '#94A3B8', dark: '#525C73' },
+ { token: 'expria', var: '--color-expria', light: '#1B4FD8', dark: '#5B7FFF' },
+ { token: 'expria-hover', var: '--color-expria-hover', light: '#1741B8', dark: '#6F8EFF' },
+ { token: 'expria-50', var: '--color-expria-50', light: '#EEF3FF', dark: 'rgba(91,127,255,.12)' },
+ { token: 'expria-100', var: '--color-expria-100', light: '#DCE6FF', dark: '—' },
+ { token: 'expria-200', var: '--color-expria-200', light: '#B8CDFF', dark: '—' },
+ { token: 'deep', var: '--color-deep', light: '#0B1F5C', dark: '#060B1A' },
+ { token: 'success', var: '--color-success', light: '#0E9F6E', dark: '#3DD68C' },
+ { token: 'success-bg', var: '--color-success-bg', light: '#E6F6F0', dark: 'rgba(61,214,140,.12)' },
+ { token: 'warning', var: '--color-warning', light: '#C77A00', dark: '#F5B849' },
+ { token: 'warning-bg', var: '--color-warning-bg', light: '#FEF3E2', dark: 'rgba(245,184,73,.12)' },
+ { token: 'danger', var: '--color-danger', light: '#C53030', dark: '#F06B6B' },
+ { token: 'danger-bg', var: '--color-danger-bg', light: '#FDECEC', dark: 'rgba(240,107,107,.12)' },
+]
+
+// ─── section wrapper ─────────────────────────────────────────────────────────
+
+function Section({ title, children }: { title: string; children: React.ReactNode }) {
+ return (
+
+ {title}
+
+ {children}
+
+ )
+}
+
+// ─── main page ───────────────────────────────────────────────────────────────
+
+export default function DesignSystemPage() {
+ const { theme, setTheme } = useTheme()
+ const [dialogOpen, setDialogOpen] = useState(false)
+
+ return (
+
+
+ {/* ── header ── */}
+
+
+ {/* ── palette ── */}
+
+
+ {PALETTE.map(({ token, var: cssVar, light, dark }) => (
+
+
+
+
{token}
+
+ ☀ {light}
+
+
+ ☾ {dark}
+
+
+
+ ))}
+
+
+
+ {/* ── typography ── */}
+
+
+
Display / 36px Bold
+
Heading 1 / 24px Semibold
+
Heading 2 / 20px Semibold
+
Heading 3 / 18px Medium
+
Body / 16px Regular — Plus Jakarta Sans
+
Small / 14px Regular — secondary copy
+
Caption / 12px Regular — labels, metadata
+
Mono / 12px — token names, code
+
+
+
+ {/* ── buttons ── */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* ── badges ── */}
+
+
+ Default
+ Secondary
+ Outline
+ Destructive
+
+
+
+ {/* ── inputs / forms ── */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Content below separator
+
+
+
+ {/* ── avatar ── */}
+
+
+
+
+
+
+
+ {['AB', 'CD', 'EF'].map(initials => (
+
+ {initials}
+
+ ))}
+ +5
+
+
group
+
+
+
+
+ {/* ── dialog ── */}
+
+
+
+
+
+
+
+ )
+}