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

1547 lines
58 KiB
TypeScript
Raw Blame 히스토리

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// TextFieldContent.tsx — WING-OPS Text Field 컴포넌트 상세 페이지 (다크/라이트 테마 지원)
import type { DesignTheme } from './designTheme';
// ---------- 타입 ----------
interface InputFieldStyle {
bg: string;
border: string;
textColor: string;
placeholderColor: string;
borderWidth?: string;
opacity?: string;
}
interface StateRow {
state: string;
badge: string;
placeholder: string;
hasCursor: boolean;
style: InputFieldStyle;
showClear?: boolean;
showSparkle?: boolean;
}
// ---------- 헬퍼 데이터 ----------
const getDarkStateRows = (): StateRow[] => [
{
state: 'Enabled',
badge: 'Enabled',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: '#1e293b', border: '#334155', textColor: '#e2e8f0', placeholderColor: '#64748b' },
},
{
state: 'Focused',
badge: 'Focused',
placeholder: '플레이스홀더',
hasCursor: true,
style: { bg: '#1e293b', border: '#e2e8f0', textColor: '#e2e8f0', placeholderColor: '#64748b', borderWidth: '2px' },
},
{
state: 'Error',
badge: 'Error',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: '#1e293b', border: '#ef4444', textColor: '#e2e8f0', placeholderColor: '#64748b' },
},
{
state: 'Error Focused',
badge: 'Error Focused',
placeholder: '플레이스홀더',
hasCursor: true,
style: { bg: '#1e293b', border: '#ef4444', textColor: '#e2e8f0', placeholderColor: '#64748b', borderWidth: '2px' },
},
{
state: 'Disabled',
badge: 'Disabled',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: 'rgba(255,255,255,0.02)', border: '#1e293b', textColor: '#e2e8f0', placeholderColor: '#64748b', opacity: '0.4' },
},
{
state: 'Read Only',
badge: 'Read Only',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: 'rgba(255,255,255,0.02)', border: '#334155', textColor: '#e2e8f0', placeholderColor: '#64748b' },
},
{
state: 'AI Loading',
badge: 'AI Loading',
placeholder: '단서를 모아서 추리 중...',
hasCursor: false,
showSparkle: true,
style: { bg: 'rgba(255,255,255,0.02)', border: '#334155', textColor: '#e2e8f0', placeholderColor: '#64748b' },
},
];
const getLightStateRows = (): StateRow[] => [
{
state: 'Enabled',
badge: 'Enabled',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: '#fff', border: '#d1d5db', textColor: '#1f2937', placeholderColor: '#9ca3af' },
},
{
state: 'Focused',
badge: 'Focused',
placeholder: '플레이스홀더',
hasCursor: true,
style: { bg: '#fff', border: '#1f2937', textColor: '#1f2937', placeholderColor: '#9ca3af', borderWidth: '2px' },
},
{
state: 'Error',
badge: 'Error',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: '#fff', border: '#ef4444', textColor: '#1f2937', placeholderColor: '#9ca3af' },
},
{
state: 'Error Focused',
badge: 'Error Focused',
placeholder: '플레이스홀더',
hasCursor: true,
style: { bg: '#fff', border: '#ef4444', textColor: '#1f2937', placeholderColor: '#9ca3af', borderWidth: '2px' },
},
{
state: 'Disabled',
badge: 'Disabled',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: '#f9fafb', border: '#e5e7eb', textColor: '#1f2937', placeholderColor: '#9ca3af', opacity: '0.4' },
},
{
state: 'Read Only',
badge: 'Read Only',
placeholder: '플레이스홀더',
hasCursor: false,
style: { bg: '#f9fafb', border: '#d1d5db', textColor: '#1f2937', placeholderColor: '#9ca3af' },
},
{
state: 'AI Loading',
badge: 'AI Loading',
placeholder: '단서를 모아서 추리 중...',
hasCursor: false,
showSparkle: true,
style: { bg: '#f9fafb', border: '#d1d5db', textColor: '#1f2937', placeholderColor: '#9ca3af' },
},
];
// ---------- Props ----------
interface TextFieldContentProps {
theme: DesignTheme;
}
// ---------- 컴포넌트 ----------
export const TextFieldContent = ({ theme }: TextFieldContentProps) => {
const t = theme;
const isDark = t.mode === 'dark';
const sectionCardBg = isDark ? 'rgba(255,255,255,0.03)' : '#f5f5f5';
const dividerColor = isDark ? 'rgba(255,255,255,0.08)' : '#e5e7eb';
const annotationColor = '#8b5cf6';
// 입력 필드 공통 스타일 (Anatomy, Guideline용)
const fieldBg = isDark ? '#1e293b' : '#fff';
const fieldBorder = isDark ? '#334155' : '#d1d5db';
const fieldText = isDark ? '#e2e8f0' : '#1f2937';
const fieldPlaceholder = isDark ? '#64748b' : '#9ca3af';
const stateRows = isDark ? getDarkStateRows() : getLightStateRows();
return (
<div className="p-12" style={{ color: t.textPrimary }}>
<div style={{ maxWidth: '64rem' }}>
{/* ── 섹션 1: 헤더 ── */}
<div
className="pb-10 mb-12 border-b border-solid"
style={{ borderColor: dividerColor }}
>
<p
className="font-mono text-sm uppercase tracking-widest mb-3"
style={{ color: t.textAccent }}
>
Components
</p>
<h1
className="text-4xl font-bold mb-4"
style={{ color: t.textPrimary }}
>
Text Field
</h1>
<p
className="text-lg"
style={{ color: t.textSecondary }}
>
.
</p>
</div>
{/* ── Input Field 소제목 ── */}
<div
className="pb-6 mb-10 border-b border-solid"
style={{ borderColor: dividerColor }}
>
<h2 className="text-2xl font-bold mb-2" style={{ color: t.textPrimary }}>
Input Field
</h2>
<p className="text-sm" style={{ color: t.textSecondary }}>
.
</p>
</div>
{/* ── 섹션 2: Anatomy ── */}
<div className="mb-16">
<h2
className="text-2xl font-bold mb-8"
style={{ color: t.textPrimary }}
>
Anatomy
</h2>
{/* Anatomy 카드 */}
<div
className="rounded-xl p-10 mb-8"
style={{ backgroundColor: sectionCardBg }}
>
<div className="flex flex-col items-center gap-12">
{/* 입력 필드 구조 분해도 */}
<div className="relative flex flex-col items-center" style={{ width: '480px' }}>
{/* 상단 주석 라벨: Prefix, Input, Suffix */}
<div className="flex items-end justify-between w-full mb-1 px-2">
{/* Prefix label */}
<div className="flex flex-col items-center gap-0.5" style={{ width: '70px' }}>
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Prefix
</span>
<span
className="font-mono"
style={{ fontSize: '9px', color: annotationColor }}
>
(Optional)
</span>
{/* 아래 화살표 선 */}
<div style={{ width: '1px', height: '10px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderTop: `5px solid ${annotationColor}`,
}}
/>
</div>
{/* Input label */}
<div className="flex flex-col items-center gap-0.5">
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Input
</span>
{/* 아래 화살표 선 */}
<div style={{ width: '1px', height: '18px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderTop: `5px solid ${annotationColor}`,
}}
/>
</div>
{/* Suffix label */}
<div className="flex flex-col items-center gap-0.5" style={{ width: '70px' }}>
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Suffix
</span>
<span
className="font-mono"
style={{ fontSize: '9px', color: annotationColor }}
>
(Optional)
</span>
{/* 아래 화살표 선 */}
<div style={{ width: '1px', height: '10px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderTop: `5px solid ${annotationColor}`,
}}
/>
</div>
</div>
{/* 실제 입력 필드 */}
<div
className="relative w-full flex items-center rounded-md px-3"
style={{
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
}}
>
{/* Prefix 아이콘 영역 */}
<div
className="flex items-center justify-center mr-2 shrink-0"
style={{
width: '20px',
height: '20px',
borderRadius: '4px',
border: `1px dashed ${annotationColor}`,
}}
>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
<circle cx="5" cy="5" r="3.5" stroke={fieldPlaceholder} strokeWidth="1.5" />
<line x1="7.5" y1="7.5" x2="10.5" y2="10.5" stroke={fieldPlaceholder} strokeWidth="1.5" strokeLinecap="round" />
</svg>
</div>
{/* 입력 텍스트 영역 */}
<div className="flex-1" style={{ fontSize: '14px', color: fieldText }}>
</div>
{/* Clear 버튼 */}
<div
className="flex items-center justify-center shrink-0 ml-2"
style={{
width: '18px',
height: '18px',
borderRadius: '50%',
backgroundColor: fieldPlaceholder,
fontSize: '11px',
color: fieldBg,
fontWeight: 700,
lineHeight: 1,
cursor: 'default',
}}
>
×
</div>
{/* Suffix 텍스트 */}
<span
className="shrink-0 ml-2 font-mono text-sm"
style={{ color: fieldPlaceholder }}
>
</span>
{/* Container 점선 테두리 */}
<span
className="absolute inset-0 rounded-md pointer-events-none"
style={{
border: `1.5px dashed ${annotationColor}`,
}}
/>
</div>
{/* Container 왼쪽 주석 */}
<div
className="absolute flex items-center gap-1"
style={{
left: '-120px',
top: '50%',
transform: 'translateY(-50%)',
}}
>
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Container
</span>
{/* 화살표 선 */}
<div style={{ width: '30px', height: '1px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderTop: '4px solid transparent',
borderBottom: '4px solid transparent',
borderLeft: `5px solid ${annotationColor}`,
}}
/>
</div>
{/* 하단 주석 라벨: Clear Button */}
<div className="flex justify-end w-full mt-1 pr-16">
<div className="flex flex-col items-center gap-0.5">
{/* 위 화살표 선 */}
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderBottom: `5px solid ${annotationColor}`,
}}
/>
<div style={{ width: '1px', height: '10px', backgroundColor: annotationColor }} />
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Clear Button
</span>
<span
className="font-mono"
style={{ fontSize: '9px', color: annotationColor }}
>
(Optional)
</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* ── 섹션 3: Guideline ── */}
<div className="mb-16">
<h2
className="text-2xl font-bold mb-10"
style={{ color: t.textPrimary }}
>
Guideline
</h2>
{/* 3-1. Container */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span
className="font-mono text-lg font-bold"
style={{ color: annotationColor }}
>
1
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Container
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. , , .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex items-center gap-8">
{/* 컨테이너 박스 + 치수선 */}
<div className="relative" style={{ marginLeft: '20px', marginTop: '20px', marginBottom: '24px' }}>
{/* 높이 치수선 (오른쪽) */}
<div
className="absolute flex flex-col items-center"
style={{ right: '-32px', top: 0, bottom: 0, justifyContent: 'center' }}
>
<div style={{ width: '1px', flex: 1, backgroundColor: '#ef4444' }} />
<span className="font-mono" style={{ fontSize: '9px', color: '#ef4444', writingMode: 'vertical-rl', padding: '2px 0' }}>
44px
</span>
<div style={{ width: '1px', flex: 1, backgroundColor: '#ef4444' }} />
</div>
{/* padding 치수선 (상단 왼쪽) */}
<span
className="absolute font-mono"
style={{ fontSize: '9px', color: '#ef4444', top: '-16px', left: '0' }}
>
px: 12px
</span>
{/* 빈 컨테이너 박스 */}
<div
className="rounded-md"
style={{
width: '280px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
}}
/>
</div>
<div>
<p className="font-mono text-xs" style={{ color: t.textSecondary }}>
height: 44px (Medium)
</p>
<p className="font-mono text-xs mt-1" style={{ color: t.textSecondary }}>
padding: 12px ()
</p>
<p className="font-mono text-xs mt-1" style={{ color: t.textSecondary }}>
border-radius: 6px
</p>
</div>
</div>
</div>
</div>
{/* 3-2. Placeholder */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
2
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Placeholder
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-6">
{/* 플레이스홀더 있는 필드 */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
</span>
<div
className="flex items-center rounded-md px-3"
style={{
width: '240px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
}}
>
</div>
</div>
{/* 빈 필드 (플레이스홀더 없음) */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
</span>
<div
className="flex items-center rounded-md px-3"
style={{
width: '240px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
}}
/>
</div>
</div>
</div>
</div>
{/* 3-3. Label */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
3
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Label
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. * .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-8">
{/* 일반 라벨 */}
<div className="flex flex-col gap-1">
<span
className="text-sm font-semibold mb-1.5"
style={{ color: t.textPrimary }}
>
</span>
<div
className="flex items-center rounded-md px-3"
style={{
width: '200px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
}}
>
</div>
</div>
{/* 필수 라벨 */}
<div className="flex flex-col gap-1">
<span className="text-sm font-semibold mb-1.5" style={{ color: t.textPrimary }}>
{' '}
<span style={{ color: '#ef4444' }}>*</span>
</span>
<div
className="flex items-center rounded-md px-3"
style={{
width: '200px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
}}
>
</div>
</div>
</div>
</div>
</div>
{/* 3-4. Input Text */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
4
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Input Text
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex flex-col gap-4">
<div
className="flex items-center rounded-md px-3"
style={{
width: '280px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldText,
}}
>
</div>
<div className="flex gap-6 text-xs font-mono" style={{ color: t.textSecondary }}>
<span>font-size: 14px</span>
<span>color: textPrimary</span>
<span>font-weight: 400</span>
</div>
</div>
</div>
</div>
{/* 3-5. Clear Icon */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
5
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Clear Icon
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-6">
{/* 텍스트 입력 + Clear 아이콘 표시 */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
(Clear )
</span>
<div
className="flex items-center rounded-md px-3 gap-2"
style={{
width: '240px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldText,
}}
>
<span className="flex-1"></span>
{/* Clear 버튼 */}
<div
className="flex items-center justify-center shrink-0"
style={{
width: '18px',
height: '18px',
borderRadius: '50%',
backgroundColor: fieldPlaceholder,
fontSize: '11px',
color: fieldBg,
fontWeight: 700,
lineHeight: 1,
cursor: 'default',
}}
>
×
</div>
</div>
</div>
{/* 빈 상태 (Clear 미표시) */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
(Clear )
</span>
<div
className="flex items-center rounded-md px-3"
style={{
width: '240px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
}}
>
</div>
</div>
</div>
</div>
</div>
{/* 3-6. Helper Text */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
6
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Helper Text
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-8">
{/* 기본 도움말 */}
<div className="flex flex-col gap-1.5">
<div
className="flex items-center rounded-md px-3"
style={{
width: '240px',
height: '44px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
}}
>
</div>
<span className="text-xs" style={{ color: t.textMuted }}>
, 8
</span>
</div>
{/* 에러 메시지 */}
<div className="flex flex-col gap-1.5">
<div
className="flex items-center rounded-md px-3"
style={{
width: '240px',
height: '44px',
backgroundColor: fieldBg,
border: '1px solid #ef4444',
fontSize: '14px',
color: fieldPlaceholder,
}}
>
</div>
<span className="text-xs" style={{ color: '#ef4444' }}>
.
</span>
</div>
</div>
</div>
</div>
</div>
{/* ── 섹션 4: State (Input Field) ── */}
<div
className="pt-12 border-t border-solid"
style={{ borderColor: dividerColor }}
>
<h2
className="text-2xl font-bold mb-8"
style={{ color: t.textPrimary }}
>
State
</h2>
<div
className="rounded-xl p-8"
style={{ backgroundColor: sectionCardBg }}
>
<div className="flex flex-col gap-5">
{stateRows.map((row) => (
<div
key={row.state}
className="flex items-center gap-8"
>
{/* 왼쪽: State 라벨 + 뱃지 */}
<div className="flex items-center gap-2 shrink-0" style={{ width: '200px' }}>
<span
className="font-mono text-xs"
style={{ color: t.textSecondary }}
>
State
</span>
<span
className="rounded-md px-2 font-semibold"
style={{
fontSize: '11px',
paddingTop: '2px',
paddingBottom: '2px',
backgroundColor: '#3b82f6',
color: '#fff',
}}
>
{row.badge}
</span>
</div>
{/* 오른쪽: 입력 필드 */}
<div
className="flex items-center rounded-md px-3 gap-2"
style={{
width: '320px',
height: '44px',
backgroundColor: row.style.bg,
border: `${row.style.borderWidth ?? '1px'} solid ${row.style.border}`,
opacity: row.style.opacity ?? '1',
fontSize: '14px',
}}
>
{row.showSparkle && (
<span style={{ fontSize: '16px' }}></span>
)}
<span
className="flex-1"
style={{ color: row.style.placeholderColor }}
>
{row.placeholder}
{row.hasCursor && (
<span
style={{
color: row.style.textColor,
fontWeight: 400,
marginLeft: '1px',
}}
>
|
</span>
)}
</span>
</div>
</div>
))}
</div>
</div>
</div>
{/* ════════════════════════════════════════════════════
Text Area 단락
════════════════════════════════════════════════════ */}
{/* ── Text Area 소제목 ── */}
<div
className="pt-12 pb-6 mt-16 mb-10 border-t border-b border-solid"
style={{ borderColor: dividerColor }}
>
<h2 className="text-2xl font-bold mb-2" style={{ color: t.textPrimary }}>
Text Area
</h2>
<p className="text-sm" style={{ color: t.textSecondary }}>
.
</p>
</div>
{/* ── Text Area Anatomy ── */}
<div className="mb-16">
<h2
className="text-2xl font-bold mb-8"
style={{ color: t.textPrimary }}
>
Anatomy
</h2>
<div
className="rounded-xl p-10 mb-8"
style={{ backgroundColor: sectionCardBg }}
>
<div className="flex flex-col items-center gap-12">
{/* TextArea 구조 분해도 */}
<div className="relative flex flex-col items-center" style={{ width: '480px' }}>
{/* 상단 주석 라벨: Input Area, Character Counter */}
<div className="flex items-end justify-between w-full mb-1 px-2">
{/* Input Area label */}
<div className="flex flex-col items-center gap-0.5" style={{ width: '80px' }}>
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Input Area
</span>
<div style={{ width: '1px', height: '18px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderTop: `5px solid ${annotationColor}`,
}}
/>
</div>
{/* Placeholder label */}
<div className="flex flex-col items-center gap-0.5">
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Placeholder
</span>
<div style={{ width: '1px', height: '18px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderTop: `5px solid ${annotationColor}`,
}}
/>
</div>
{/* Character Counter label */}
<div className="flex flex-col items-center gap-0.5" style={{ width: '110px' }}>
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Character Counter
</span>
<span
className="font-mono"
style={{ fontSize: '9px', color: annotationColor }}
>
(Optional)
</span>
<div style={{ width: '1px', height: '10px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderTop: `5px solid ${annotationColor}`,
}}
/>
</div>
</div>
{/* 실제 TextArea */}
<div
className="relative w-full rounded-md p-3"
style={{
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
}}
>
{/* 플레이스홀더 텍스트 */}
<div
style={{
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
{/* 우하단: 문자 수 카운터 + resize 핸들 */}
<div
className="absolute bottom-2 right-2 flex items-center gap-2"
>
<span
className="font-mono"
style={{ fontSize: '11px', color: fieldPlaceholder }}
>
0/500
</span>
{/* Resize 핸들 (대각선 줄무늬) */}
<div
style={{
width: '12px',
height: '12px',
backgroundImage: `repeating-linear-gradient(
135deg,
${fieldPlaceholder} 0px,
${fieldPlaceholder} 1px,
transparent 1px,
transparent 4px
)`,
cursor: 'nwse-resize',
}}
/>
</div>
{/* Container 점선 테두리 */}
<span
className="absolute inset-0 rounded-md pointer-events-none"
style={{
border: `1.5px dashed ${annotationColor}`,
}}
/>
</div>
{/* Container 왼쪽 주석 */}
<div
className="absolute flex items-center gap-1"
style={{
left: '-120px',
top: '50%',
transform: 'translateY(calc(-50% + 20px))',
}}
>
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Container
</span>
<div style={{ width: '30px', height: '1px', backgroundColor: annotationColor }} />
<div
style={{
width: 0,
height: 0,
borderTop: '4px solid transparent',
borderBottom: '4px solid transparent',
borderLeft: `5px solid ${annotationColor}`,
}}
/>
</div>
{/* 하단 주석 라벨: Resize Handle */}
<div className="flex justify-end w-full mt-1 pr-1">
<div className="flex flex-col items-center gap-0.5">
<div
style={{
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderBottom: `5px solid ${annotationColor}`,
}}
/>
<div style={{ width: '1px', height: '10px', backgroundColor: annotationColor }} />
<span
className="font-mono text-xs font-semibold"
style={{ color: annotationColor }}
>
Resize Handle
</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* ── Text Area Guideline ── */}
<div className="mb-16">
<h2
className="text-2xl font-bold mb-10"
style={{ color: t.textPrimary }}
>
Guideline
</h2>
{/* TA-1. Container */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
1
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Container
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. 112px이며 .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex items-start gap-8">
<div className="relative" style={{ marginLeft: '20px', marginTop: '20px', marginBottom: '24px' }}>
{/* 높이 치수선 (오른쪽) */}
<div
className="absolute flex flex-col items-center"
style={{ right: '-36px', top: 0, bottom: 0, justifyContent: 'center' }}
>
<div style={{ width: '1px', flex: 1, backgroundColor: '#ef4444' }} />
<span className="font-mono" style={{ fontSize: '9px', color: '#ef4444', writingMode: 'vertical-rl', padding: '2px 0' }}>
112px
</span>
<div style={{ width: '1px', flex: 1, backgroundColor: '#ef4444' }} />
</div>
{/* padding 치수선 (상단 왼쪽) */}
<span
className="absolute font-mono"
style={{ fontSize: '9px', color: '#ef4444', top: '-16px', left: '0' }}
>
p: 12px
</span>
{/* 빈 컨테이너 박스 */}
<div
className="rounded-md"
style={{
width: '280px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
}}
/>
</div>
<div className="pt-2">
<p className="font-mono text-xs" style={{ color: t.textSecondary }}>
height: 112px (default)
</p>
<p className="font-mono text-xs mt-1" style={{ color: t.textSecondary }}>
padding: 12px
</p>
<p className="font-mono text-xs mt-1" style={{ color: t.textSecondary }}>
border-radius: 6px
</p>
<p className="font-mono text-xs mt-1" style={{ color: t.textSecondary }}>
resize: vertical
</p>
</div>
</div>
</div>
</div>
{/* TA-2. Placeholder */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
2
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Placeholder
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
.
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-6">
{/* 플레이스홀더 있는 TextArea */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
</span>
<div
className="rounded-md p-3"
style={{
width: '240px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
</div>
{/* 빈 TextArea */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
</span>
<div
className="rounded-md p-3"
style={{
width: '240px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
}}
/>
</div>
</div>
</div>
</div>
{/* TA-3. Label */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
3
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Label
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
.
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-8">
{/* 기본 라벨 */}
<div className="flex flex-col gap-1">
<span
className="text-sm font-semibold mb-1.5"
style={{ color: t.textPrimary }}
>
</span>
<div
className="rounded-md p-3"
style={{
width: '200px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
</div>
{/* 필수(*) 라벨 */}
<div className="flex flex-col gap-1">
<span className="text-sm font-semibold mb-1.5" style={{ color: t.textPrimary }}>
{' '}
<span style={{ color: '#ef4444' }}>*</span>
</span>
<div
className="rounded-md p-3"
style={{
width: '200px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
</div>
</div>
</div>
</div>
{/* TA-4. Input Text */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
4
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Input Text
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
.
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex flex-col gap-4">
<div
className="rounded-md p-3"
style={{
width: '320px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldText,
lineHeight: '1.6',
whiteSpace: 'pre-line',
}}
>
{'오늘 점검 내용을 기록합니다.\n상세 내용은 아래와 같습니다.'}
</div>
<div className="flex gap-6 text-xs font-mono" style={{ color: t.textSecondary }}>
<span>font-size: 14px</span>
<span>color: textPrimary</span>
<span>line-height: 1.6</span>
</div>
</div>
</div>
</div>
{/* TA-5. Clear Icon */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
5
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Clear Icon
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
. .
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-6">
{/* 텍스트 있는 상태 (Clear 표시) */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
(Clear )
</span>
<div
className="relative rounded-md p-3"
style={{
width: '240px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldText,
lineHeight: '1.5',
}}
>
.
{/* Clear 버튼 우상단 */}
<div
className="absolute top-2 right-2 flex items-center justify-center"
style={{
width: '18px',
height: '18px',
borderRadius: '50%',
backgroundColor: fieldPlaceholder,
fontSize: '11px',
color: fieldBg,
fontWeight: 700,
lineHeight: 1,
cursor: 'default',
}}
>
×
</div>
</div>
</div>
{/* 빈 상태 (Clear 미표시) */}
<div className="flex flex-col gap-2">
<span className="text-xs font-mono" style={{ color: t.textSecondary }}>
(Clear )
</span>
<div
className="rounded-md p-3"
style={{
width: '240px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
</div>
</div>
</div>
</div>
{/* TA-6. Helper Text */}
<div className="mb-12">
<div className="flex items-baseline gap-3 mb-2">
<span className="font-mono text-lg font-bold" style={{ color: annotationColor }}>
6
</span>
<h3 className="text-xl font-bold" style={{ color: t.textPrimary }}>
Helper Text
</h3>
</div>
<p className="mb-5 text-sm" style={{ color: t.textSecondary }}>
.
</p>
<div className="rounded-xl p-8" style={{ backgroundColor: sectionCardBg }}>
<div className="flex gap-8">
{/* 기본 도움말 + 문자 수 카운터 */}
<div className="flex flex-col gap-1.5">
<div
className="rounded-md p-3"
style={{
width: '240px',
height: '112px',
backgroundColor: fieldBg,
border: `1px solid ${fieldBorder}`,
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
<div className="flex items-center justify-between" style={{ width: '240px' }}>
<span className="text-xs" style={{ color: t.textMuted }}>
</span>
<span className="text-xs font-mono" style={{ color: t.textMuted }}>
0/500
</span>
</div>
</div>
{/* 에러 메시지 */}
<div className="flex flex-col gap-1.5">
<div
className="rounded-md p-3"
style={{
width: '240px',
height: '112px',
backgroundColor: fieldBg,
border: '1px solid #ef4444',
fontSize: '14px',
color: fieldPlaceholder,
lineHeight: '1.5',
}}
>
</div>
<span className="text-xs" style={{ color: '#ef4444' }}>
.
</span>
</div>
</div>
</div>
</div>
</div>
{/* ── Text Area State ── */}
<div
className="pt-12 border-t border-solid"
style={{ borderColor: dividerColor }}
>
<h2
className="text-2xl font-bold mb-8"
style={{ color: t.textPrimary }}
>
State
</h2>
<div
className="rounded-xl p-8"
style={{ backgroundColor: sectionCardBg }}
>
<div className="flex flex-col gap-5">
{stateRows.map((row) => (
<div
key={`ta-${row.state}`}
className="flex items-start gap-8"
>
{/* 왼쪽: State 라벨 + 뱃지 */}
<div className="flex items-center gap-2 shrink-0 pt-3" style={{ width: '200px' }}>
<span
className="font-mono text-xs"
style={{ color: t.textSecondary }}
>
State
</span>
<span
className="rounded-md px-2 font-semibold"
style={{
fontSize: '11px',
paddingTop: '2px',
paddingBottom: '2px',
backgroundColor: '#3b82f6',
color: '#fff',
}}
>
{row.badge}
</span>
</div>
{/* 오른쪽: TextArea */}
<div
className="relative rounded-md p-3"
style={{
width: '320px',
height: '112px',
backgroundColor: row.style.bg,
border: `${row.style.borderWidth ?? '1px'} solid ${row.style.border}`,
opacity: row.style.opacity ?? '1',
fontSize: '14px',
lineHeight: '1.5',
}}
>
<div className="flex items-start gap-2">
{row.showSparkle && (
<span style={{ fontSize: '16px' }}></span>
)}
<span style={{ color: row.style.placeholderColor }}>
{row.placeholder}
{row.hasCursor && (
<span
style={{
color: row.style.textColor,
fontWeight: 400,
marginLeft: '1px',
}}
>
|
</span>
)}
</span>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
</div>
);
};
export default TextFieldContent;