feat: 테마 전환용 아이콘 컴포넌트 추가
Co-Authored-By: Claude Opus 5
@1333063d3063e16e7552a00aefa467c64f4a9397
+++ components/ui/icons/monitor-icon.tsx
... | ... | @@ -0,0 +1,29 @@ |
| 1 | +interface MonitorIconProps { | |
| 2 | + /** 표시 제어용 클래스 패스스루(예: 테마 CSS 변형자 `hidden theme-system:contents`). | |
| 3 | + * 디자인 값(색상·치수 등) 주입은 금지 — 색은 상위 요소의 currentColor를 상속한다. */ | |
| 4 | + className?: string; | |
| 5 | +} | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 시스템(OS) 테마를 상징하는 모니터 아이콘(화면 사각형 + 받침). 직접 작도한 인라인 SVG. | |
| 9 | + * `stroke="currentColor"`라 버튼 등 상위 요소의 text 색 토큰을 그대로 상속하며, | |
| 10 | + * 장식용이므로 `aria-hidden`을 부여한다 — 접근성 이름은 소비처(IconButton)가 책임진다. | |
| 11 | + */ | |
| 12 | +export function MonitorIcon({ className }: MonitorIconProps) { | |
| 13 | + return ( | |
| 14 | + <svg | |
| 15 | + viewBox="0 0 24 24" | |
| 16 | + fill="none" | |
| 17 | + stroke="currentColor" | |
| 18 | + strokeWidth="2" | |
| 19 | + strokeLinecap="round" | |
| 20 | + strokeLinejoin="round" | |
| 21 | + aria-hidden="true" | |
| 22 | + className={`size-5 ${className ?? ""}`} | |
| 23 | + > | |
| 24 | + <rect x="3" y="4" width="18" height="13" rx="1.5" /> | |
| 25 | + <path d="M8 21h8" /> | |
| 26 | + <path d="M12 17v4" /> | |
| 27 | + </svg> | |
| 28 | + ); | |
| 29 | +} |
+++ components/ui/icons/moon-icon.tsx
... | ... | @@ -0,0 +1,29 @@ |
| 1 | +interface MoonIconProps { | |
| 2 | + /** 표시 제어용 클래스 패스스루(예: 테마 CSS 변형자 `hidden theme-dark:contents`). | |
| 3 | + * 디자인 값(색상·치수 등) 주입은 금지 — 색은 상위 요소의 currentColor를 상속한다. */ | |
| 4 | + className?: string; | |
| 5 | +} | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 다크 테마를 상징하는 초승달 아이콘(단일 path). 직접 작도한 인라인 SVG — 큰 원호(외곽)와 | |
| 9 | + * 작은 원호(안쪽 오려내기)를 이어 붙인 표준 초승달 구성법을 사용했다(외부 아이콘 | |
| 10 | + * 저작물 복제 없음). | |
| 11 | + * `stroke="currentColor"`라 버튼 등 상위 요소의 text 색 토큰을 그대로 상속하며, | |
| 12 | + * 장식용이므로 `aria-hidden`을 부여한다 — 접근성 이름은 소비처(IconButton)가 책임진다. | |
| 13 | + */ | |
| 14 | +export function MoonIcon({ className }: MoonIconProps) { | |
| 15 | + return ( | |
| 16 | + <svg | |
| 17 | + viewBox="0 0 24 24" | |
| 18 | + fill="none" | |
| 19 | + stroke="currentColor" | |
| 20 | + strokeWidth="2" | |
| 21 | + strokeLinecap="round" | |
| 22 | + strokeLinejoin="round" | |
| 23 | + aria-hidden="true" | |
| 24 | + className={`size-5 ${className ?? ""}`} | |
| 25 | + > | |
| 26 | + <path d="M20 14.5A8.5 8.5 0 1 1 9.5 4A6.5 6.5 0 0 0 20 14.5Z" /> | |
| 27 | + </svg> | |
| 28 | + ); | |
| 29 | +} |
+++ components/ui/icons/sun-icon.tsx
... | ... | @@ -0,0 +1,35 @@ |
| 1 | +interface SunIconProps { | |
| 2 | + /** 표시 제어용 클래스 패스스루(예: 테마 CSS 변형자 `hidden theme-light:contents`). | |
| 3 | + * 디자인 값(색상·치수 등) 주입은 금지 — 색은 상위 요소의 currentColor를 상속한다. */ | |
| 4 | + className?: string; | |
| 5 | +} | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 라이트 테마를 상징하는 해 아이콘(중심 원 + 8방향 광선). 직접 작도한 인라인 SVG. | |
| 9 | + * `stroke="currentColor"`라 버튼 등 상위 요소의 text 색 토큰을 그대로 상속하며, | |
| 10 | + * 장식용이므로 `aria-hidden`을 부여한다 — 접근성 이름은 소비처(IconButton)가 책임진다. | |
| 11 | + */ | |
| 12 | +export function SunIcon({ className }: SunIconProps) { | |
| 13 | + return ( | |
| 14 | + <svg | |
| 15 | + viewBox="0 0 24 24" | |
| 16 | + fill="none" | |
| 17 | + stroke="currentColor" | |
| 18 | + strokeWidth="2" | |
| 19 | + strokeLinecap="round" | |
| 20 | + strokeLinejoin="round" | |
| 21 | + aria-hidden="true" | |
| 22 | + className={`size-5 ${className ?? ""}`} | |
| 23 | + > | |
| 24 | + <circle cx="12" cy="12" r="4" /> | |
| 25 | + <path d="M12 2v2.5" /> | |
| 26 | + <path d="M12 19.5V22" /> | |
| 27 | + <path d="M2 12h2.5" /> | |
| 28 | + <path d="M19.5 12H22" /> | |
| 29 | + <path d="M4.93 4.93l1.77 1.77" /> | |
| 30 | + <path d="M17.3 17.3l1.77 1.77" /> | |
| 31 | + <path d="M4.93 19.07l1.77-1.77" /> | |
| 32 | + <path d="M17.3 6.7l1.77-1.77" /> | |
| 33 | + </svg> | |
| 34 | + ); | |
| 35 | +} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?