wing-ops/frontend/src/pages/design/ComponentsOverview.tsx

215 lines
6.7 KiB
TypeScript

// ComponentsOverview.tsx — Components 탭 Overview 카드 그리드
import type { DesignTheme } from './designTheme';
// ---------- 타입 ----------
interface OverviewCard {
id: string;
label: string;
thumbnail: (isDark: boolean) => React.ReactNode;
}
// ---------- 썸네일 구현 ----------
const ButtonsThumbnail = ({ isDark }: { isDark: boolean }) => {
const accent = isDark ? '#4cd7f6' : '#06b6d4';
const secondaryBg = isDark ? 'rgba(255,255,255,0.07)' : '#e2e8f0';
const secondaryText = isDark ? 'rgba(223,226,243,0.85)' : '#475569';
const outlineBorder = isDark ? 'rgba(76,215,246,0.40)' : 'rgba(6,182,212,0.50)';
const buttons = [
{ label: 'Primary', bg: accent, border: accent, color: isDark ? '#0a0e1a' : '#ffffff' },
{ label: 'Secondary', bg: secondaryBg, border: 'transparent', color: secondaryText },
{ label: 'Outline', bg: 'transparent', border: outlineBorder, color: accent },
];
return (
<div className="w-full h-full flex flex-col items-center justify-center gap-3 px-8">
{buttons.map(({ label, bg, border, color }) => (
<div
key={label}
className="w-full rounded flex items-center justify-center"
style={{
height: '32px',
backgroundColor: bg,
border: `1.5px solid ${border}`,
color,
fontSize: '12px',
fontWeight: 600,
}}
>
{label}
</div>
))}
</div>
);
};
const TextInputsThumbnail = ({ isDark }: { isDark: boolean }) => {
const labelColor = isDark ? 'rgba(194,198,214,0.80)' : '#64748b';
const inputBg = isDark ? 'rgba(255,255,255,0.04)' : '#ffffff';
const inputBorder = isDark ? 'rgba(255,255,255,0.12)' : '#cbd5e1';
const placeholderColor = isDark ? 'rgba(140,144,159,0.60)' : '#94a3b8';
const accentBorder = isDark ? '#4cd7f6' : '#06b6d4';
return (
<div className="w-full h-full flex flex-col items-center justify-center gap-3 px-8">
{/* 라벨 + 기본 입력 */}
<div className="w-full flex flex-col gap-1.5">
<div
className="rounded"
style={{ height: '9px', width: '48px', backgroundColor: labelColor, opacity: 0.6 }}
/>
<div
className="w-full rounded flex items-center px-3"
style={{
height: '30px',
backgroundColor: inputBg,
border: `1.5px solid ${inputBorder}`,
}}
>
<div
className="rounded"
style={{
height: '8px',
width: '70px',
backgroundColor: placeholderColor,
opacity: 0.5,
}}
/>
</div>
</div>
{/* 포커스 상태 입력 */}
<div className="w-full flex flex-col gap-1.5">
<div
className="rounded"
style={{ height: '9px', width: '56px', backgroundColor: labelColor, opacity: 0.6 }}
/>
<div
className="w-full rounded flex items-center px-3"
style={{
height: '30px',
backgroundColor: inputBg,
border: `1.5px solid ${accentBorder}`,
boxShadow: isDark
? `0 0 0 2px rgba(76,215,246,0.15)`
: `0 0 0 2px rgba(6,182,212,0.12)`,
}}
>
<div
className="rounded"
style={{
height: '8px',
width: '90px',
backgroundColor: isDark ? 'rgba(223,226,243,0.50)' : '#475569',
opacity: 0.7,
}}
/>
</div>
</div>
</div>
);
};
// ---------- 카드 정의 ----------
const OVERVIEW_CARDS: OverviewCard[] = [
{
id: 'buttons',
label: 'Buttons',
thumbnail: (isDark) => <ButtonsThumbnail isDark={isDark} />,
},
{
id: 'text-field',
label: 'Text Field',
thumbnail: (isDark) => <TextInputsThumbnail isDark={isDark} />,
},
];
// ---------- Props ----------
interface ComponentsOverviewProps {
theme: DesignTheme;
onNavigate: (id: string) => void;
}
// ---------- 컴포넌트 ----------
const ComponentsOverview = ({ theme, onNavigate }: ComponentsOverviewProps) => {
const t = theme;
const isDark = t.mode === 'dark';
const cardBg = isDark ? 'rgba(255,255,255,0.03)' : '#f5f5f5';
const cardBorder = isDark ? 'rgba(255,255,255,0.06)' : '#e5e5e5';
const thumbnailBorderBottom = isDark ? 'rgba(255,255,255,0.06)' : '#e0e0e0';
return (
<div className="pt-24 px-12 pb-16 max-w-5xl flex flex-col gap-12">
{/* ── 헤더 영역 ── */}
<div className="flex flex-col gap-3">
<span
className="font-mono text-xs font-semibold uppercase"
style={{ letterSpacing: '1.4px', color: t.textAccent }}
>
Components
</span>
<h1 className="font-sans text-4xl font-bold leading-tight" style={{ color: t.textPrimary }}>
Overview
</h1>
<p className="font-korean text-sm leading-6" style={{ color: t.textSecondary }}>
UI .
</p>
</div>
{/* ── 3열 카드 그리드 ── */}
<div className="grid gap-5" style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}>
{OVERVIEW_CARDS.map((card) => (
<div
key={card.id}
className="rounded-lg border border-solid flex flex-col cursor-pointer transition-all duration-200"
style={{
backgroundColor: cardBg,
borderColor: cardBorder,
}}
onClick={() => onNavigate(card.id)}
onMouseEnter={(e) => {
const el = e.currentTarget;
el.style.transform = 'scale(1.025)';
el.style.boxShadow = isDark
? '0 8px 24px rgba(0,0,0,0.35)'
: '0 6px 18px rgba(0,0,0,0.10)';
el.style.borderColor = isDark ? 'rgba(76,215,246,0.22)' : 'rgba(6,182,212,0.28)';
}}
onMouseLeave={(e) => {
const el = e.currentTarget;
el.style.transform = 'scale(1)';
el.style.boxShadow = 'none';
el.style.borderColor = cardBorder;
}}
>
{/* 썸네일 영역 */}
<div
className="h-48 rounded-t-lg overflow-hidden"
style={{
borderBottom: `1px solid ${thumbnailBorderBottom}`,
}}
>
{card.thumbnail(isDark)}
</div>
{/* 카드 라벨 */}
<div className="px-5 py-4">
<span className="font-sans text-sm font-semibold" style={{ color: t.textPrimary }}>
{card.label}
</span>
</div>
</div>
))}
</div>
</div>
);
};
export default ComponentsOverview;