"use client";
interface AnalogClockProps {
time: Date;
theme: "light" | "dark" | "custom";
timezone?: string;
customColor?: string; // 사용자 지정 색상
}
/**
* 아날로그 시계 컴포넌트
* - SVG 기반 아날로그 시계
* - 시침, 분침, 초침 애니메이션
* - 테마별 색상 지원
* - 타임존 표시
*/
export function AnalogClock({ time, theme, timezone, customColor }: AnalogClockProps) {
const hours = time.getHours() % 12;
const minutes = time.getMinutes();
const seconds = time.getSeconds();
// 각도 계산 (12시 방향을 0도로, 시계방향으로 회전)
const secondAngle = seconds * 6 - 90; // 6도씩 회전 (360/60)
const minuteAngle = minutes * 6 + seconds * 0.1 - 90; // 6도씩 + 초당 0.1도
const hourAngle = hours * 30 + minutes * 0.5 - 90; // 30도씩 + 분당 0.5도
// 테마별 색상
const colors = getThemeColors(theme, customColor);
// 타임존 라벨
const timezoneLabel = timezone ? getTimezoneLabel(timezone) : "";
return (
{/* 타임존 표시 */}
{timezoneLabel && (
{timezoneLabel}
)}
);
}
/**
* 타임존 라벨 반환
*/
function getTimezoneLabel(timezone: string): string {
const timezoneLabels: Record = {
"Asia/Seoul": "서울 (KST)",
"Asia/Tokyo": "도쿄 (JST)",
"Asia/Shanghai": "베이징 (CST)",
"America/New_York": "뉴욕 (EST)",
"America/Los_Angeles": "LA (PST)",
"Europe/London": "런던 (GMT)",
"Europe/Paris": "파리 (CET)",
"Australia/Sydney": "시드니 (AEDT)",
};
return timezoneLabels[timezone] || timezone.split("/")[1];
}
/**
* 테마별 색상 반환
*/
function getThemeColors(theme: string, customColor?: string) {
if (theme === "custom" && customColor) {
// 사용자 지정 색상 사용 (약간 밝게/어둡게 조정)
const lighterColor = adjustColor(customColor, 40);
const darkerColor = adjustColor(customColor, -40);
return {
background: lighterColor,
border: customColor,
tick: customColor,
number: darkerColor,
hourHand: darkerColor,
minuteHand: customColor,
secondHand: "#ef4444",
center: darkerColor,
};
}
const themes = {
light: {
background: "#ffffff",
border: "#d1d5db",
tick: "#9ca3af",
number: "#374151",
hourHand: "#1f2937",
minuteHand: "#4b5563",
secondHand: "#ef4444",
center: "#1f2937",
},
dark: {
background: "#1f2937",
border: "#4b5563",
tick: "#6b7280",
number: "#f9fafb",
hourHand: "#f9fafb",
minuteHand: "#d1d5db",
secondHand: "#ef4444",
center: "#f9fafb",
},
custom: {
background: "#e0e7ff",
border: "#6366f1",
tick: "#818cf8",
number: "#4338ca",
hourHand: "#4338ca",
minuteHand: "#6366f1",
secondHand: "#ef4444",
center: "#4338ca",
},
};
return themes[theme as keyof typeof themes] || themes.light;
}
/**
* 색상 밝기 조정
*/
function adjustColor(color: string, amount: number): string {
const clamp = (num: number) => Math.min(255, Math.max(0, num));
const hex = color.replace("#", "");
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
const newR = clamp(r + amount);
const newG = clamp(g + amount);
const newB = clamp(b + amount);
return `#${newR.toString(16).padStart(2, "0")}${newG.toString(16).padStart(2, "0")}${newB.toString(16).padStart(2, "0")}`;
}