feat(control-policy): 컨트롤 자동 숨김 표시 정책 옵션 추가
맥락: - Focus-First 구조에서 패널을 열어둔 채 방치되면 몰입 흐름이 깨질 수 있어, 모드 토글이 아닌 표시 정책 기반 정리가 필요했습니다. 변경사항: - Quick Controls 패널 하단에 컨트롤 자동 숨김 옵션을 추가했습니다. - 옵션은 Focus 화면 상시 UI가 아닌 패널 내부에서만 노출되도록 제한했습니다. - 옵션 ON 상태에서 Control Center가 열려 있고 입력이 없으면 8초 후 패널이 자동으로 닫히도록 UI 상태 로직을 추가했습니다. - 모드 전환 토스트는 추가하지 않고 상태 변화만 반영했습니다. 검증: - npx tsc --noEmit 세션-상태: 컨트롤 자동 숨김 정책으로 설정 후 자연스럽게 몰입 화면으로 복귀됩니다. 세션-다음: Scene 추천 매핑 품질과 override UX 체감 검증을 진행합니다. 세션-리스크: 자동 닫힘 8초 타이밍은 실사용 피드백에 따라 추가 조정이 필요할 수 있습니다.
This commit is contained in:
@@ -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 = ({
|
||||
추천으로 되돌리기
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<section className="space-y-2 rounded-2xl border border-white/12 bg-black/18 px-3 py-2.5 backdrop-blur-md">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<p className="text-[11px] text-white/72">컨트롤 자동 숨김</p>
|
||||
<p className="mt-0.5 text-[10px] text-white/52">입력이 없으면 잠시 후 패널을 닫아요.</p>
|
||||
</div>
|
||||
<Toggle
|
||||
checked={autoHideControls}
|
||||
onChange={onAutoHideControlsChange}
|
||||
ariaLabel="컨트롤 자동 숨김"
|
||||
className="shrink-0"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -76,6 +76,7 @@ export const SpaceToolsDockWidget = ({
|
||||
const { pushToast } = useToast();
|
||||
const [openPopover, setOpenPopover] = useState<SpaceAnchorPopoverId | null>(null);
|
||||
const [utilityPanel, setUtilityPanel] = useState<SpaceUtilityPanelId | null>(null);
|
||||
const [autoHideControls, setAutoHideControls] = useState(true);
|
||||
const [noteDraft, setNoteDraft] = useState('');
|
||||
const [volumeFeedback, setVolumeFeedback] = useState<string | null>(null);
|
||||
const [plan, setPlan] = useState<PlanTier>('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);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user