style(space): 리추얼 진입 UX와 포커스 전환 흐름을 고급화
맥락: - /space 진입 경험이 설정 패널처럼 보여 몰입형 라운지 톤이 약했습니다. - 목표 입력 후 시작 전환 동선을 더 빠르고 일관되게 만들 필요가 있었습니다. 변경사항: - 도크 아이콘을 이모지에서 단일 라인 SVG 세트로 통일해 시각 언어 일관성을 맞췄습니다. - Setup Drawer 밀도를 낮추고(타이포/테두리/칩 크기) 3-step 리추얼 흐름을 더 간결하게 정리했습니다. - 목표 입력 필드 자동 포커스를 추가해 진입 즉시 타이핑이 가능하도록 했습니다. - 시작 버튼을 form submit으로 연결해 Enter 입력과 버튼 클릭이 동일하게 동작하도록 변경했습니다. - SpaceSideSheet에 300ms 닫힘 전환(오버레이/시트 opacity+translate) 애니메이션을 적용했습니다. - Focus 진입 토스트 카피를 목표 중심 문구로 바꾸고 Setup 선택지를 최소 개수로 제한했습니다. - 배경에 미세 stage-pan/light-drift 키프레임을 추가해 정적인 평면감을 줄였습니다. 검증: - npx tsc --noEmit - npm run build 세션-상태: /space에서 목표 입력 후 10초 내 Focus 전환 가능한 리추얼 흐름이 정리되었습니다. 세션-다음: 실제 브라우저에서 애니메이션 강도와 드로어 밀도 체감 QA를 진행합니다. 세션-리스크: 저사양 환경에서 배경 미세 모션이 과하게 느껴질 수 있어 추후 reduce-motion 강화를 검토할 수 있습니다.
This commit is contained in:
@@ -69,6 +69,10 @@ export const SpaceWorkspaceWidget = () => {
|
||||
const selectedRoom = useMemo(() => {
|
||||
return getRoomById(selectedRoomId) ?? ROOM_THEMES[0];
|
||||
}, [selectedRoomId]);
|
||||
const setupRooms = useMemo(() => {
|
||||
const restRooms = ROOM_THEMES.filter((room) => room.id !== selectedRoom.id);
|
||||
return [selectedRoom, ...restRooms].slice(0, 4);
|
||||
}, [selectedRoom]);
|
||||
|
||||
const canStart = goalInput.trim().length > 0;
|
||||
const isFocusMode = workspaceMode === 'focus';
|
||||
@@ -95,8 +99,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
setSetupDrawerOpen(false);
|
||||
|
||||
pushToast({
|
||||
title: '집중을 시작했어요 (더미)',
|
||||
description: `${selectedRoom.name} · ${goalInput.trim()}`,
|
||||
title: `목표: ${goalInput.trim()} 시작해요.`,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -106,18 +109,26 @@ export const SpaceWorkspaceWidget = () => {
|
||||
|
||||
return (
|
||||
<div className="relative min-h-screen overflow-hidden text-white">
|
||||
<div aria-hidden className="absolute inset-0" style={getRoomBackgroundStyle(selectedRoom)} />
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(180deg, rgba(15,23,42,0.16) 0%, rgba(15,23,42,0.32) 100%)',
|
||||
}}
|
||||
className="absolute inset-0 bg-cover bg-center will-change-transform animate-[space-stage-pan_42s_ease-in-out_infinite_alternate] motion-reduce:animate-none"
|
||||
style={getRoomBackgroundStyle(selectedRoom)}
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 opacity-[0.08]"
|
||||
className="absolute inset-0 opacity-[0.2] bg-[radial-gradient(68%_54%_at_18%_12%,rgba(191,219,254,0.58)_0%,rgba(191,219,254,0)_72%)] animate-[space-light-drift_24s_ease-in-out_infinite_alternate] motion-reduce:animate-none"
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 opacity-[0.14] bg-[radial-gradient(62%_48%_at_82%_14%,rgba(125,211,252,0.5)_0%,rgba(125,211,252,0)_72%)] animate-[space-light-drift_30s_ease-in-out_infinite_alternate] motion-reduce:animate-none"
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 bg-[linear-gradient(180deg,rgba(15,23,42,0.08)_0%,rgba(15,23,42,0.24)_100%)]"
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 opacity-[0.06]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(0deg, rgba(255,255,255,0.016) 0 1px, transparent 1px 2px)',
|
||||
@@ -151,7 +162,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
<SpaceSetupDrawerWidget
|
||||
open={isSetupDrawerOpen}
|
||||
dismissible={isFocusMode}
|
||||
rooms={ROOM_THEMES}
|
||||
rooms={setupRooms}
|
||||
selectedRoomId={selectedRoom.id}
|
||||
goalInput={goalInput}
|
||||
selectedGoalId={selectedGoalId}
|
||||
|
||||
Reference in New Issue
Block a user