From 21edf27de69c58dc9667361275e2a86939ae500c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A1=9C=EB=A1=9C?= Date: Sun, 22 Feb 2026 11:04:36 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=EB=8C=80=EB=B3=B8=20=EC=9D=BD?= =?UTF-8?q?=EA=B8=B0=20=EC=86=8D=EB=8F=84=20=EC=84=A4=EC=A0=95,=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EC=B6=94=EA=B0=80=20(#311)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/icon-setting.svg | 7 + .../slide/script/ScriptBoxContent.tsx | 51 +++++-- .../slide/script/ScriptBulkEditModal.tsx | 17 +++ .../slide/script/ScriptReadingSpeedModal.tsx | 134 ++++++++++++++++++ src/hooks/index.ts | 1 + src/hooks/useScriptReadingSpeed.ts | 36 +++++ src/stores/scriptReadingSpeedStore.ts | 35 +++++ src/utils/scriptDuration.test.ts | 84 +++++++++++ src/utils/scriptDuration.ts | 109 ++++++++++++++ 9 files changed, 464 insertions(+), 10 deletions(-) create mode 100644 src/assets/icons/icon-setting.svg create mode 100644 src/components/slide/script/ScriptReadingSpeedModal.tsx create mode 100644 src/hooks/useScriptReadingSpeed.ts create mode 100644 src/stores/scriptReadingSpeedStore.ts create mode 100644 src/utils/scriptDuration.test.ts create mode 100644 src/utils/scriptDuration.ts diff --git a/src/assets/icons/icon-setting.svg b/src/assets/icons/icon-setting.svg new file mode 100644 index 00000000..7899ee02 --- /dev/null +++ b/src/assets/icons/icon-setting.svg @@ -0,0 +1,7 @@ + + + + diff --git a/src/components/slide/script/ScriptBoxContent.tsx b/src/components/slide/script/ScriptBoxContent.tsx index cbd9bb64..961ef4d3 100644 --- a/src/components/slide/script/ScriptBoxContent.tsx +++ b/src/components/slide/script/ScriptBoxContent.tsx @@ -6,12 +6,25 @@ * Zustand store를 통해 대본을 읽고 업데이트하며, * debounce로 자동저장됩니다. */ -import { useAutoSaveScript, useSlideActions, useSlideScript } from '@/hooks'; +import { useMemo, useState } from 'react'; + +import IconSetting from '@/assets/icons/icon-setting.svg?react'; +import { useAutoSaveScript, useScriptReadingSpeed, useSlideActions, useSlideScript } from '@/hooks'; +import { estimateScriptDurationSeconds, formatScriptDuration } from '@/utils/scriptDuration'; + +import ScriptReadingSpeedModal from './ScriptReadingSpeedModal'; export default function ScriptBoxContent() { + const [isSpeedModalOpen, setIsSpeedModalOpen] = useState(false); const script = useSlideScript(); const { updateScript } = useSlideActions(); const { autoSave, flushSave } = useAutoSaveScript(); + const { selectedSpeed } = useScriptReadingSpeed(); + + const estimatedDuration = useMemo(() => { + const durationSeconds = estimateScriptDurationSeconds(script, selectedSpeed); + return formatScriptDuration(durationSeconds); + }, [script, selectedSpeed]); const handleChange = (value: string) => { updateScript(value); @@ -19,15 +32,33 @@ export default function ScriptBoxContent() { }; return ( -
-