From 9bcf6b733bcff7d1db25299107d0b8dfad779781 Mon Sep 17 00:00:00 2001 From: wonellyho Date: Tue, 30 Dec 2025 23:57:17 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20PD=5FSLD=20=EB=8C=80=EB=B3=B8?= =?UTF-8?q?=EB=B0=95=EC=8A=A4=20=EA=B5=AC=ED=98=84=20(#7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/refreshIcon.svg | 4 + src/assets/icons/replyIcon.svg | 4 + src/assets/icons/smallArrowIcon.svg | 3 + src/assets/icons/treshcanIcon.svg | 5 + src/components/ScriptBox.tsx | 457 ++++++++++++++++++++++++++++ src/hooks/useToggle.ts | 16 + 6 files changed, 489 insertions(+) create mode 100644 src/assets/icons/refreshIcon.svg create mode 100644 src/assets/icons/replyIcon.svg create mode 100644 src/assets/icons/smallArrowIcon.svg create mode 100644 src/assets/icons/treshcanIcon.svg create mode 100644 src/components/ScriptBox.tsx create mode 100644 src/hooks/useToggle.ts diff --git a/src/assets/icons/refreshIcon.svg b/src/assets/icons/refreshIcon.svg new file mode 100644 index 00000000..a5f8d31a --- /dev/null +++ b/src/assets/icons/refreshIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/replyIcon.svg b/src/assets/icons/replyIcon.svg new file mode 100644 index 00000000..7f5ec49c --- /dev/null +++ b/src/assets/icons/replyIcon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/smallArrowIcon.svg b/src/assets/icons/smallArrowIcon.svg new file mode 100644 index 00000000..e8e4bf8e --- /dev/null +++ b/src/assets/icons/smallArrowIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/treshcanIcon.svg b/src/assets/icons/treshcanIcon.svg new file mode 100644 index 00000000..e38ed0ac --- /dev/null +++ b/src/assets/icons/treshcanIcon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/ScriptBox.tsx b/src/components/ScriptBox.tsx new file mode 100644 index 00000000..dc944a08 --- /dev/null +++ b/src/components/ScriptBox.tsx @@ -0,0 +1,457 @@ +import { useState } from 'react'; + +import refreshIcon from '../assets/icons/refreshIcon.svg'; +import replyIcon from '../assets/icons/replyIcon.svg'; +import smallArrowIcon from '../assets/icons/smallArrowIcon.svg'; +import treshcanIcon from '../assets/icons/treshcanIcon.svg'; +import { useToggle } from '../hooks/useToggle'; + +const ScriptBox = () => { + // 0. 슬라이드 이름(이름 변경) 버튼 + const slideNameChange = useToggle(false); + // 0-1. 현재 슬라이드 이름 + const [slideTitle, setSlideTitle] = useState('슬라이드 1'); + // 0-2. 타이틀 저장 버튼(서버 요청) + // const handleSaveSlideTitle = () => { + // + // }; + + // 1. 이모지버튼 + const [isEmogiClick, SetEmogiClick] = useState(false); + + const handleEmogiClick = () => { + SetEmogiClick((prev) => !prev); + }; + + // 2. 변경기록 버튼 + const scriptHistroy = useToggle(false); + // 3. 의견 버튼 + const opinion = useToggle(false); + // 3-1. 답변 (나중에 피드백id랑 매칭해야됨) + // 어떤 댓글에 답글 입력창이 열려있는지 + const [activeReplyIdx, setActiveReplyIdx] = useState(null); + + // 답글 입력값(일단 1개만) + const [replyText, setReplyText] = useState(''); + + // 4. 대본섹션 닫기 토글 + const scriptBoxDock = useToggle(false); + return ( + <> +
+ {/* 변경: 상단바 내부 레이아웃(좌/우 정렬) */} + +
+
+ + + {/* 슬라이드 이름변경 popover */} + {slideNameChange.value && ( + <> + {/* 바깥 클릭 시 닫기 */} +
+ +
+ {/* 슬라이드 제목 변경 입력창 */} + setSlideTitle(e.target.value)} + className=" + flex-1 h-9 px-3 + rounded-md + border border-zinc-200 + text-sm text-zinc-700 + outline-none + focus:border-indigo-500 + " + /> + + {/* 저장 버튼: 핸들러만 연결(현재는 아무 동작 X) */} + +
+ + )} +
+ + {/* 우측 컨트롤 영역 */} +
+ {/* 이모지 카운트 영역 */} +
+
+
👍
+
99+
+
+
+
😡
+
12
+
+
+ + {/* 변경: 이모지 버튼을 오른쪽 컨트롤 쪽에 자연스럽게 배치 + popover 기준점 유지 */} +
+ + + {isEmogiClick && ( // 받은 이모티콘 서버에서 뿌려줌 +
+
+
+
😏
+
15
+
+
+
❤️
+
28
+
+
+
😎️
+
5
+
+
+
👀
+
182
+
+
+
🤪
+
3
+
+
+
+
+
💡
+
11
+
+
+
🙈️
+
488
+
+
+
💕
+
2
+
+
+
😂
+
46
+
+
+
🤓
+
36
+
+
+
+ )} +
+ + {/* 변경: 변경기록/의견 버튼 그룹 */} +
+
+ + + {scriptHistroy.value && ( + <> +
+ +
+
+
+ 대본 변경 기록 +
+
+ +
+
+
+
+ 현재 +
+
+ (현재 대본 내용이 들어올 자리) +
+
+
+ + {[0, 1, 2, 3].map((idx) => ( +
+
+
+ (시간 표시 자리) +
+ + +
+ +
+ (이전 대본 내용 자리 #{idx + 1}) +
+
+ ))} +
+
+ + )} +
+ +
+ + + {/* 의견 pop over */} + {opinion.value && ( + <> +
+ + {/* popover 위치 = 버튼 right edge에 붙이고 왼쪽으로 펼쳐지게 */} +
+
+
의견
+
+ +
+ {[0, 1, 2, 3].map((idx) => { + const isMine = idx < 2; + const hasReply = idx === 2; + + return ( +
+
+
+
+ +
+
+
+
+
+ {isMine ? '익명 사용자' : '김철수'} +
+
+ {idx === 0 ? '방금 전' : '1시간 전'} +
+
+ + {isMine && ( + + )} +
+ +
+ 이 부분 설명이 명확해요! +
+
+ +
+ + + {/* 답글 버튼 밑에 inputBox렌더링 */} + {activeReplyIdx === idx && ( +
+ setReplyText(e.target.value)} + placeholder="답글을 입력하세요" + className="flex-1 h-10 px-3 rounded-lg border border-zinc-200 text-sm outline-none focus:border-indigo-500" + /> + +
+ )} +
+
+
+ ); + })} +
+
+ + )} +
+
+ + +
+
+ + {/* "대본 입력 영역" textarea */} +
+