-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScriptBoxContent.tsx
More file actions
66 lines (59 loc) · 2.68 KB
/
ScriptBoxContent.tsx
File metadata and controls
66 lines (59 loc) · 2.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
* @file ScriptBoxContent.tsx
* @description ScriptBox 본문 영역
*
* 슬라이드 대본을 입력하는 텍스트 영역입니다.
* Zustand store를 통해 대본을 읽고 업데이트하며,
* debounce로 자동저장됩니다.
*/
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);
autoSave(value);
};
return (
<>
<div className="relative h-full bg-white px-4 pt-3 pb-6">
<textarea
value={script}
onChange={(e) => handleChange(e.target.value)}
onBlur={flushSave}
placeholder="슬라이드 대본을 입력하세요..."
aria-label="슬라이드 대본"
className="h-full w-full resize-none overflow-y-auto border-none bg-transparent pb-8 text-base leading-relaxed text-gray-800 outline-none placeholder:text-gray-600"
/>
<div className="pointer-events-none absolute bottom-3 right-4 z-10">
<button
type="button"
onClick={() => setIsSpeedModalOpen(true)}
aria-label={`읽기 속도 설정 열기 (현재 예상 시간 ${estimatedDuration})`}
className="pointer-events-auto inline-flex min-h-9 items-center gap-2 rounded-full border border-gray-200 bg-white/95 px-3 py-1.5 text-gray-700 shadow-xs backdrop-blur-sm transition-colors hover:bg-gray-100 active:bg-gray-200 focus-visible:outline-2 focus-visible:outline-main"
>
<span aria-live="polite" aria-atomic="true" className="text-sm font-semibold leading-4">
{estimatedDuration}
</span>
<IconSetting className="size-4 shrink-0 text-gray-700" aria-hidden="true" />
</button>
</div>
</div>
<ScriptReadingSpeedModal
isOpen={isSpeedModalOpen}
onClose={() => setIsSpeedModalOpen(false)}
/>
</>
);
}