From f3f99c74288d97ac7173ce4d4333dadbc5e323d1 Mon Sep 17 00:00:00 2001 From: caadiq Date: Fri, 6 Feb 2026 18:30:34 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=93=9C=EB=A1=AD=EB=8B=A4=EC=9A=B4=20z?= =?UTF-8?q?-index=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20YouTubeBotDialog=20?= =?UTF-8?q?=EC=BB=A4=EC=8A=A4=ED=85=80=20=EB=93=9C=EB=A1=AD=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WordItem, ScheduleDict 드롭다운 z-index를 z-20에서 z-40으로 변경 (테이블 헤더의 z-30보다 높게 설정하여 가려지는 문제 해결) - YouTubeBotDialog에 커스텀 Dropdown 컴포넌트 추가 - 네이티브 select 요소를 커스텀 드롭다운으로 교체 - 시간 선택을 위한 TIME_OPTIONS (00:00~23:00) 추가 Co-Authored-By: Claude Opus 4.5 --- .../pc/admin/bot/YouTubeBotDialog.jsx | 130 +++++++++++++----- .../components/pc/admin/schedule/WordItem.jsx | 2 +- .../pages/pc/admin/schedules/ScheduleDict.jsx | 4 +- 3 files changed, 97 insertions(+), 39 deletions(-) diff --git a/frontend/src/components/pc/admin/bot/YouTubeBotDialog.jsx b/frontend/src/components/pc/admin/bot/YouTubeBotDialog.jsx index b64cb34..07acf22 100644 --- a/frontend/src/components/pc/admin/bot/YouTubeBotDialog.jsx +++ b/frontend/src/components/pc/admin/bot/YouTubeBotDialog.jsx @@ -1,10 +1,10 @@ /** * YouTube 봇 추가/수정 다이얼로그 */ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import { motion, AnimatePresence } from 'framer-motion'; -import { Youtube, Search, X, ChevronDown, ChevronUp } from 'lucide-react'; +import { Youtube, Search, X, ChevronDown, ChevronUp, Clock } from 'lucide-react'; // 동기화 간격 옵션 const INTERVAL_OPTIONS = [ @@ -27,6 +27,79 @@ const DAY_OPTIONS = [ { value: 6, label: '토요일' }, ]; +// 시간 옵션 (00:00 ~ 23:00) +const TIME_OPTIONS = Array.from({ length: 24 }, (_, i) => ({ + value: `${String(i).padStart(2, '0')}:00`, + label: `${String(i).padStart(2, '0')}:00`, +})); + +/** + * 커스텀 드롭다운 컴포넌트 + */ +function Dropdown({ value, options, onChange, placeholder = '선택', className = '' }) { + const [isOpen, setIsOpen] = useState(false); + const dropdownRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setIsOpen(false); + } + }; + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + } + return () => document.removeEventListener('mousedown', handleClickOutside); + }, [isOpen]); + + const selectedOption = options.find((opt) => opt.value === value); + + return ( +
+ + + {isOpen && ( + + {options.map((opt) => ( + + ))} + + )} + +
+ ); +} + function YouTubeBotDialog({ isOpen, onClose, bot = null, onSubmit }) { const isEdit = !!bot; @@ -202,17 +275,12 @@ function YouTubeBotDialog({ isOpen, onClose, bot = null, onSubmit }) { - + options={INTERVAL_OPTIONS} + onChange={setInterval} + placeholder="간격 선택" + /> {/* 예정 일정 자동 생성 */} @@ -244,25 +312,20 @@ function YouTubeBotDialog({ isOpen, onClose, bot = null, onSubmit }) {
- + options={DAY_OPTIONS} + onChange={setScheduleDayOfWeek} + placeholder="요일 선택" + />
- setScheduleTime(e.target.value)} - className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 focus:border-red-500" + options={TIME_OPTIONS} + onChange={setScheduleTime} + placeholder="시간 선택" />
@@ -285,17 +348,12 @@ function YouTubeBotDialog({ isOpen, onClose, bot = null, onSubmit }) { {/* 마감 요일 */}
- + options={DAY_OPTIONS} + onChange={setDeadlineDayOfWeek} + placeholder="요일 선택" + />

이 요일까지 영상이 없으면 예정 일정을 삭제합니다

diff --git a/frontend/src/components/pc/admin/schedule/WordItem.jsx b/frontend/src/components/pc/admin/schedule/WordItem.jsx index 8c7e4f2..35a6f82 100644 --- a/frontend/src/components/pc/admin/schedule/WordItem.jsx +++ b/frontend/src/components/pc/admin/schedule/WordItem.jsx @@ -126,7 +126,7 @@ function WordItem({ id, word, pos, index, onUpdate, onDelete }) { initial={{ opacity: 0, y: -5 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -5 }} - className="absolute top-full left-0 mt-1 w-64 bg-white rounded-xl shadow-lg border border-gray-200 py-1 z-20" + className="absolute top-full left-0 mt-1 w-64 bg-white rounded-xl shadow-lg border border-gray-200 py-1 z-40" > {POS_TAGS.map((tag) => (