/** * Hwatu card drawn in SVG (our own simple artwork, no commercial hwatu images — docs/games/seotda.md §12). * Large month number + kind badge so the card is readable without knowing the pictures. */ import type { CSSProperties, ReactNode } from 'react'; export interface HwatuInfo { id: number; month: number; // 0 for bonus kind: 'gwang' | 'yeol' | 'tti' | 'pi' | 'ssangpi' | 'bonus'; tti?: 'hong' | 'cheong' | 'cho' | 'plain'; name: string; piValue?: number; } const MONTH_COLOR = ['#6b7280', '#15803d', '#be185d', '#db2777', '#1f2937', '#7c3aed', '#dc2626', '#b91c1c', '#111827', '#ca8a04', '#c2410c', '#7c2d12', '#1e40af']; const MONTH_NAME = ['보너스', '송학', '매조', '벚꽃', '흑싸리', '난초', '모란', '홍싸리', '공산', '국화', '단풍', '오동', '비']; const KIND_BADGE: Record = { gwang: '光', yeol: '열', tti: '띠', pi: '피', ssangpi: '쌍피', bonus: '+' }; const TTI_COLOR = { hong: '#dc2626', cheong: '#2563eb', cho: '#15803d', plain: '#dc2626' }; const TTI_TEXT = { hong: '홍단', cheong: '청단', cho: '', plain: '' }; /** A small motif per month (flowers/plants), drawn with basic shapes. */ function Motif({ month, color }: { month: number; color: string }): ReactNode { const c = color; switch (month) { case 1: // 송학: pine return ; case 2: // 매조: plum blossoms case 3: // 벚꽃 return ( {[[34, 70], [62, 62], [50, 92], [70, 100], [30, 108]].map(([x, y], i) => ( ))} ); case 4: // 흑싸리 case 7: // 홍싸리 return ( {[30, 45, 60, 75].map((x, i) => ( ))} ); case 5: // 난초: iris leaves return ( ); case 6: // 모란: peony return ( ); case 8: // 공산: hill return ; case 9: // 국화 return ( {Array.from({ length: 10 }, (_, i) => { const a = (i / 10) * Math.PI * 2; return ; })} ); case 10: // 단풍: maple return ; case 11: // 오동 return ( ); case 12: // 비: rain lines + umbrella return ( {[20, 35, 50, 65, 80].map((x) => ( ))} ); default: return ★; } } export type HwatuSize = 'sm' | 'md' | 'lg'; const WIDTH: Record = { sm: 40, md: 60, lg: 84 }; export function HwatuCard({ card, size = 'md', selected, dimmed, highlight, onClick, style, }: { card: HwatuInfo | null; size?: HwatuSize; selected?: boolean; dimmed?: boolean; highlight?: boolean; onClick?: () => void; style?: CSSProperties; }) { const w = WIDTH[size]; const h = Math.round(w * 1.6); const Tag = onClick ? 'button' : 'span'; const s: CSSProperties = { width: w, height: h, flex: 'none', display: 'inline-block', padding: 0, border: 0, background: 'none', cursor: onClick ? 'pointer' : 'default', opacity: dimmed ? 0.45 : 1, transform: selected ? `translateY(${-Math.round(w * 0.2)}px)` : undefined, transition: 'transform 0.12s ease', filter: highlight ? 'drop-shadow(0 0 6px #f59e0b)' : 'drop-shadow(0 1px 2px rgba(0,0,0,0.3))', ...style, }; if (!card) { return ( ); } const color = MONTH_COLOR[card.month] ?? '#374151'; return ( {card.kind === 'bonus' ? ( {card.piValue ?? 2}피 ) : ( )} {card.kind === 'tti' && ( {TTI_TEXT[card.tti ?? 'plain'] && ( {TTI_TEXT[card.tti ?? 'plain']} )} )} {(card.kind === 'gwang' || card.kind === 'yeol') && ( {card.kind === 'gwang' ? '光' : '열'} )} {/* Month number: large and always readable */} {card.month || '+'} {MONTH_NAME[card.month]} · {card.kind === 'bonus' ? `${card.piValue ?? 2}피` : card.kind === 'tti' ? (TTI_TEXT[card.tti ?? 'plain'] || '띠') : KIND_BADGE[card.kind] === '光' ? '광' : KIND_BADGE[card.kind] === '열' ? '열끗' : KIND_BADGE[card.kind]} ); }