From 7ccd8fbc6a2264c7cfac3cea3ad8d68875be5097 Mon Sep 17 00:00:00 2001 From: dohyeons Date: Tue, 14 Oct 2025 10:23:20 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8B=9C=EA=B3=84=20=EC=9C=84=EC=A0=AF=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=EC=9D=84=20=ED=8C=9D=EC=98=A4=EB=B2=84?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/dashboard/CanvasElement.tsx | 15 +- .../admin/dashboard/ElementConfigModal.tsx | 9 +- .../admin/dashboard/widgets/ClockSettings.tsx | 213 ++++++++++++++++++ .../admin/dashboard/widgets/ClockWidget.tsx | 102 ++++++--- 4 files changed, 296 insertions(+), 43 deletions(-) create mode 100644 frontend/components/admin/dashboard/widgets/ClockSettings.tsx diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx index 77165820..d830263d 100644 --- a/frontend/components/admin/dashboard/CanvasElement.tsx +++ b/frontend/components/admin/dashboard/CanvasElement.tsx @@ -310,8 +310,8 @@ export function CanvasElement({
{element.title}
- {/* 설정 버튼 */} - {onConfigure && ( + {/* 설정 버튼 (시계 위젯은 자체 설정 UI 사용) */} + {onConfigure && !(element.type === "widget" && element.subtype === "clock") && (
) : element.type === "widget" && element.subtype === "weather" ? ( // 날씨 위젯 렌더링 -
+
) : element.type === "widget" && element.subtype === "exchange" ? ( // 환율 위젯 렌더링 -
+
- + { + onUpdate(element.id, { clockConfig: newConfig }); + }} + />
) : ( // 기타 위젯 렌더링 diff --git a/frontend/components/admin/dashboard/ElementConfigModal.tsx b/frontend/components/admin/dashboard/ElementConfigModal.tsx index 5dc82900..dc9d3f32 100644 --- a/frontend/components/admin/dashboard/ElementConfigModal.tsx +++ b/frontend/components/admin/dashboard/ElementConfigModal.tsx @@ -72,8 +72,13 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element // 모달이 열려있지 않으면 렌더링하지 않음 if (!isOpen) return null; - // 시계 위젯인 경우 시계 설정 모달 표시 + // 시계 위젯은 자체 설정 UI를 가지고 있으므로 모달 표시하지 않음 if (element.type === "widget" && element.subtype === "clock") { + return null; + } + + // 이전 코드 호환성 유지 (아래 주석 처리된 코드는 제거 예정) + if (false && element.type === "widget" && element.subtype === "clock") { return ( +
{/* 모달 헤더 */}
diff --git a/frontend/components/admin/dashboard/widgets/ClockSettings.tsx b/frontend/components/admin/dashboard/widgets/ClockSettings.tsx new file mode 100644 index 00000000..dd28c3af --- /dev/null +++ b/frontend/components/admin/dashboard/widgets/ClockSettings.tsx @@ -0,0 +1,213 @@ +"use client"; + +import { useState } from "react"; +import { ClockConfig } from "../types"; +import { Button } from "@/components/ui/button"; +import { Label } from "@/components/ui/label"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { Input } from "@/components/ui/input"; +import { Card } from "@/components/ui/card"; +import { Separator } from "@/components/ui/separator"; + +interface ClockSettingsProps { + config: ClockConfig; + onSave: (config: ClockConfig) => void; + onClose: () => void; +} + +/** + * 시계 위젯 설정 UI (Popover 내부용) + * - 모달 없이 순수 설정 폼만 제공 + */ +export function ClockSettings({ config, onSave, onClose }: ClockSettingsProps) { + const [localConfig, setLocalConfig] = useState(config); + + const handleSave = () => { + onSave(localConfig); + }; + + return ( +
+ {/* 헤더 */} +
+

+ + 시계 설정 +

+
+ + {/* 내용 - 스크롤 가능 */} +
+ {/* 스타일 선택 */} +
+ +
+ {[ + { value: "digital", label: "디지털", icon: "🔢" }, + { value: "analog", label: "아날로그", icon: "🕐" }, + { value: "both", label: "둘 다", icon: "⏰" }, + ].map((style) => ( + + ))} +
+
+ + + + {/* 타임존 선택 */} +
+ + +
+ + + + {/* 테마 선택 */} +
+ +
+ {[ + { + value: "light", + label: "Light", + gradient: "bg-gradient-to-br from-white to-gray-100", + text: "text-gray-900", + }, + { + value: "dark", + label: "Dark", + gradient: "bg-gradient-to-br from-gray-800 to-gray-900", + text: "text-white", + }, + { + value: "custom", + label: "사용자", + gradient: "bg-gradient-to-br from-blue-400 to-purple-600", + text: "text-white", + }, + ].map((theme) => ( + + ))} +
+ + {/* 사용자 지정 색상 */} + {localConfig.theme === "custom" && ( + + +
+ setLocalConfig({ ...localConfig, customColor: e.target.value })} + className="h-10 w-16 cursor-pointer" + /> + setLocalConfig({ ...localConfig, customColor: e.target.value })} + placeholder="#3b82f6" + className="flex-1 font-mono text-xs" + /> +
+
+ )} +
+ + + + {/* 옵션 토글 */} +
+ +
+ {/* 날짜 표시 */} +
+
+ 📅 + +
+ setLocalConfig({ ...localConfig, showDate: checked })} + /> +
+ + {/* 초 표시 */} +
+
+ ⏱️ + +
+ setLocalConfig({ ...localConfig, showSeconds: checked })} + /> +
+ + {/* 24시간 형식 */} +
+
+ 🕐 + +
+ setLocalConfig({ ...localConfig, format24h: checked })} + /> +
+
+
+
+ + {/* 푸터 */} +
+ + +
+
+ ); +} diff --git a/frontend/components/admin/dashboard/widgets/ClockWidget.tsx b/frontend/components/admin/dashboard/widgets/ClockWidget.tsx index cd0661db..e85623f8 100644 --- a/frontend/components/admin/dashboard/widgets/ClockWidget.tsx +++ b/frontend/components/admin/dashboard/widgets/ClockWidget.tsx @@ -1,12 +1,17 @@ "use client"; import { useState, useEffect } from "react"; -import { DashboardElement } from "../types"; +import { DashboardElement, ClockConfig } from "../types"; import { AnalogClock } from "./AnalogClock"; import { DigitalClock } from "./DigitalClock"; +import { ClockSettings } from "./ClockSettings"; +import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; +import { Button } from "@/components/ui/button"; +import { Settings } from "lucide-react"; interface ClockWidgetProps { element: DashboardElement; + onConfigUpdate?: (config: ClockConfig) => void; } /** @@ -14,9 +19,11 @@ interface ClockWidgetProps { * - 실시간으로 1초마다 업데이트 * - 아날로그/디지털/둘다 스타일 지원 * - 타임존 지원 + * - 내장 설정 UI */ -export function ClockWidget({ element }: ClockWidgetProps) { +export function ClockWidget({ element, onConfigUpdate }: ClockWidgetProps) { const [currentTime, setCurrentTime] = useState(new Date()); + const [settingsOpen, setSettingsOpen] = useState(false); // 기본 설정값 const config = element.clockConfig || { @@ -26,6 +33,13 @@ export function ClockWidget({ element }: ClockWidgetProps) { showSeconds: true, format24h: true, theme: "light", + customColor: "#3b82f6", + }; + + // 설정 저장 핸들러 + const handleSaveSettings = (newConfig: ClockConfig) => { + onConfigUpdate?.(newConfig); + setSettingsOpen(false); }; // 1초마다 시간 업데이트 @@ -38,23 +52,21 @@ export function ClockWidget({ element }: ClockWidgetProps) { return () => clearInterval(timer); }, []); - // 스타일별 렌더링 - if (config.style === "analog") { - return ( -
+ // 시계 콘텐츠 렌더링 + const renderClockContent = () => { + if (config.style === "analog") { + return ( -
- ); - } + ); + } - if (config.style === "digital") { - return ( -
+ if (config.style === "digital") { + return ( + ); + } + + // 'both' - 아날로그 + 디지털 + return ( +
+
+ +
+
+ +
); - } + }; - // 'both' - 아날로그 + 디지털 (작은 크기에 최적화) return ( -
- {/* 아날로그 시계 (상단 55%) */} -
- -
+
+ {/* 시계 콘텐츠 */} + {renderClockContent()} - {/* 디지털 시계 (하단 45%) - 컴팩트 버전 */} -
- + {/* 설정 버튼 - 우측 상단 */} +
+ + + + + + setSettingsOpen(false)} /> + +
);