From 245746a99602ddb4bd99d775f89386f53df057f5 Mon Sep 17 00:00:00 2001 From: corpi Date: Thu, 5 Mar 2026 15:19:02 +0900 Subject: [PATCH] =?UTF-8?q?feat(control-policy):=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=20=EC=9E=90=EB=8F=99=20=EC=88=A8=EA=B9=80=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=A0=95=EC=B1=85=20=EC=98=B5=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 맥락: - Focus-First 구조에서 패널을 열어둔 채 방치되면 몰입 흐름이 깨질 수 있어, 모드 토글이 아닌 표시 정책 기반 정리가 필요했습니다. 변경사항: - Quick Controls 패널 하단에 컨트롤 자동 숨김 옵션을 추가했습니다. - 옵션은 Focus 화면 상시 UI가 아닌 패널 내부에서만 노출되도록 제한했습니다. - 옵션 ON 상태에서 Control Center가 열려 있고 입력이 없으면 8초 후 패널이 자동으로 닫히도록 UI 상태 로직을 추가했습니다. - 모드 전환 토스트는 추가하지 않고 상태 변화만 반영했습니다. 검증: - npx tsc --noEmit 세션-상태: 컨트롤 자동 숨김 정책으로 설정 후 자연스럽게 몰입 화면으로 복귀됩니다. 세션-다음: Scene 추천 매핑 품질과 override UX 체감 검증을 진행합니다. 세션-리스크: 자동 닫힘 8초 타이밍은 실사용 피드백에 따라 추가 조정이 필요할 수 있습니다. --- .../ui/ControlCenterSheetWidget.tsx | 20 ++++++++++ .../ui/SpaceToolsDockWidget.tsx | 40 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/widgets/control-center-sheet/ui/ControlCenterSheetWidget.tsx b/src/widgets/control-center-sheet/ui/ControlCenterSheetWidget.tsx index 4e5c958..814f13c 100644 --- a/src/widgets/control-center-sheet/ui/ControlCenterSheetWidget.tsx +++ b/src/widgets/control-center-sheet/ui/ControlCenterSheetWidget.tsx @@ -10,6 +10,7 @@ import { getRoomCardBackgroundStyle, type RoomTheme } from '@/entities/room'; import type { TimerPreset } from '@/entities/session'; import { cn } from '@/shared/lib/cn'; import { useReducedMotion } from '@/shared/lib/useReducedMotion'; +import { Toggle } from '@/shared/ui'; interface ControlCenterSheetWidgetProps { plan: PlanTier; @@ -19,6 +20,8 @@ interface ControlCenterSheetWidgetProps { sceneRecommendedSoundLabel: string; sceneRecommendedTimerLabel: string; timerPresets: TimerPreset[]; + autoHideControls: boolean; + onAutoHideControlsChange: (next: boolean) => void; onSelectRoom: (roomId: string) => void; onSelectTimer: (timerLabel: string) => void; onLockedClick: (source: string) => void; @@ -50,6 +53,8 @@ export const ControlCenterSheetWidget = ({ sceneRecommendedSoundLabel, sceneRecommendedTimerLabel, timerPresets, + autoHideControls, + onAutoHideControlsChange, onSelectRoom, onSelectTimer, onLockedClick, @@ -163,6 +168,21 @@ export const ControlCenterSheetWidget = ({ 추천으로 되돌리기 + +
+
+
+

컨트롤 자동 숨김

+

입력이 없으면 잠시 후 패널을 닫아요.

+
+ +
+
); }; diff --git a/src/widgets/space-tools-dock/ui/SpaceToolsDockWidget.tsx b/src/widgets/space-tools-dock/ui/SpaceToolsDockWidget.tsx index f69e191..f835f52 100644 --- a/src/widgets/space-tools-dock/ui/SpaceToolsDockWidget.tsx +++ b/src/widgets/space-tools-dock/ui/SpaceToolsDockWidget.tsx @@ -76,6 +76,7 @@ export const SpaceToolsDockWidget = ({ const { pushToast } = useToast(); const [openPopover, setOpenPopover] = useState(null); const [utilityPanel, setUtilityPanel] = useState(null); + const [autoHideControls, setAutoHideControls] = useState(true); const [noteDraft, setNoteDraft] = useState(''); const [volumeFeedback, setVolumeFeedback] = useState(null); const [plan, setPlan] = useState('normal'); @@ -158,6 +159,43 @@ export const SpaceToolsDockWidget = ({ }; }, [isFocusMode, openPopover, utilityPanel]); + useEffect(() => { + if (utilityPanel !== 'control-center' || !autoHideControls) { + return; + } + + let timerId: number | null = null; + const closeDelayMs = 8000; + + const armCloseTimer = () => { + if (timerId) { + window.clearTimeout(timerId); + } + + timerId = window.setTimeout(() => { + setUtilityPanel((current) => (current === 'control-center' ? null : current)); + }, closeDelayMs); + }; + + const resetTimer = () => { + armCloseTimer(); + }; + + armCloseTimer(); + window.addEventListener('pointermove', resetTimer); + window.addEventListener('pointerdown', resetTimer); + window.addEventListener('keydown', resetTimer); + + return () => { + if (timerId) { + window.clearTimeout(timerId); + } + window.removeEventListener('pointermove', resetTimer); + window.removeEventListener('pointerdown', resetTimer); + window.removeEventListener('keydown', resetTimer); + }; + }, [autoHideControls, utilityPanel]); + const openUtilityPanel = (panel: SpaceUtilityPanelId) => { setOpenPopover(null); setUtilityPanel(panel); @@ -414,6 +452,8 @@ export const SpaceToolsDockWidget = ({ sceneRecommendedSoundLabel={sceneRecommendedSoundLabel} sceneRecommendedTimerLabel={sceneRecommendedTimerLabel} timerPresets={timerPresets} + autoHideControls={autoHideControls} + onAutoHideControlsChange={setAutoHideControls} onSelectRoom={(roomId) => { onRoomSelect(roomId); }}