style(app-hub): 시작/공간 카드를 라이트 카드 톤으로 전환
맥락: - /app에서 핵심 카드(지금 몰입/오늘의 공간)가 배경 이미지와 함께 어둡게 겹쳐 보이며 시인성이 떨어졌다. - 배경은 가상 공간을 유지하되 카드 표면은 stats와 유사한 흰 톤으로 분리해 정보 가독성을 높일 필요가 있었다. 변경사항: - StartRitualWidget과 RoomsGalleryWidget 컨테이너를 흰 표면 + 어두운 텍스트 라이트 카드 톤으로 조정했다. - StartRitual 입력/칩/보조 버튼 색상을 라이트 카드 팔레트에 맞춰 재정렬했다. - AppHub 배경 이미지의 blur/밝기 보정을 강화하고 다크 오버레이를 완화해 카드 외곽에서 가상 공간 배경이 부드럽게 보이도록 조정했다. - 세션 문서(90_current_state, session_brief)에 이번 작업 내역과 리스크를 반영했다. 검증: - npx tsc --noEmit 세션-상태: /app 핵심 카드 라이트 톤 전환 및 배경 블러 강화 반영 완료 세션-다음: RoomSheet/도크 패널의 인원수 기반 표현을 분위기형 정보로 전환 세션-리스크: 룸 프리뷰 카드는 이미지 기반 다크 톤이라 라이트 컨테이너와 미세한 톤 차이가 남을 수 있음
This commit is contained in:
@@ -56,6 +56,10 @@ Last Updated: 2026-02-28
|
||||
- 모달 표면/오버레이를 허브 밝은 톤과 유사한 저대비 글래스로 전환
|
||||
- `공간/사운드/타이머` 탭 콘텐츠 영역을 고정 높이로 통일해 전환 시 모달 크기 흔들림 제거
|
||||
- 탭/옵션 버튼과 입력 필드를 밝은 팔레트로 정리해 가독성 개선
|
||||
- `/app` 핵심 카드(시작/공간) 라이트 카드 전환:
|
||||
- `지금, 몰입을 시작해요` / `오늘의 공간` 컨테이너를 흰 표면 + 어두운 텍스트 톤으로 조정
|
||||
- 입력/칩/보조 버튼 색상도 라이트 카드 기준으로 재정렬
|
||||
- 허브 배경은 가상 공간 이미지를 더 강한 blur로 노출해 카드 외곽 배경으로 유지
|
||||
- 몰입 모드 ON 시 `/space` 크롬 정리:
|
||||
- 상단 `Current Room` 블록 숨김
|
||||
- 우상단 허브 버튼 소형 아이콘화
|
||||
@@ -90,6 +94,7 @@ Last Updated: 2026-02-28
|
||||
- 밝아진 배경 구간에서 일부 white 텍스트의 대비가 환경(디스플레이 밝기)에 따라 약해질 수 있음
|
||||
- 배경 필터/블러 적용으로 저사양 환경에서 스크롤 시 미세한 페인팅 비용 증가 가능성 존재
|
||||
- 모달 본문 고정 높이 적용으로 작은 화면에서 내부 스크롤 의존도가 이전보다 높아질 수 있음
|
||||
- 룸 프리뷰 카드 내부는 이미지 기반 다크 텍스트 체계라 컨테이너와 톤 차이가 남아 추가 톤 정리가 필요할 수 있음
|
||||
|
||||
## CHANGED FILES
|
||||
|
||||
@@ -149,6 +154,9 @@ Last Updated: 2026-02-28
|
||||
- `src/shared/ui/Modal.tsx`
|
||||
- `src/shared/ui/Tabs.tsx`
|
||||
- `src/features/custom-entry-modal/ui/CustomEntryModal.tsx`
|
||||
- `src/widgets/start-ritual-widget/ui/StartRitualWidget.tsx`
|
||||
- `src/widgets/rooms-gallery-widget/ui/RoomsGalleryWidget.tsx`
|
||||
- `src/widgets/app-hub/ui/AppHubWidget.tsx`
|
||||
|
||||
## QUICK VERIFY
|
||||
|
||||
@@ -159,3 +167,4 @@ Last Updated: 2026-02-28
|
||||
5. `/app`: 콘솔에 `button cannot be a descendant of button` hydration 에러가 재발하지 않음
|
||||
6. `/app`: 숲/벽난로처럼 텍스처가 많은 룸 선택 시에도 카드 내부 텍스트 시인성이 유지됨
|
||||
7. 커스텀 입장 모달 탭 전환(공간/사운드/타이머) 시 외곽 모달 크기가 유지됨
|
||||
8. `/app`: 시작 카드/공간 카드가 흰 표면 + 어두운 텍스트로 표시되고, 카드 밖 배경은 블러된 가상 공간으로 노출됨
|
||||
|
||||
@@ -48,6 +48,9 @@ Last Updated: 2026-02-28
|
||||
- 커스텀 입장 모달을 허브 톤과 맞춰 밝게 정리했다.
|
||||
- `공간/사운드/타이머` 탭 콘텐츠 영역을 고정 높이로 바꿔 전환 시 모달 크기 변화가 없게 했다.
|
||||
- 탭/옵션/입력 필드 스타일을 밝은 팔레트 기준으로 통일했다.
|
||||
- `/app`의 핵심 카드 2개를 라이트 카드 톤으로 전환했다.
|
||||
- `지금, 몰입을 시작해요`와 `오늘의 공간` 컨테이너를 흰 표면 + 어두운 텍스트로 정리했다.
|
||||
- 허브 배경 블러를 강화해 카드 외곽은 가상 공간 배경이 부드럽게 보이도록 조정했다.
|
||||
- 몰입 모드 ON 시 상단 룸 블록 숨김, 레일 미니화, HUD 저대비, 비네팅 강화가 적용된다.
|
||||
- 이후 작업은 `docs/work.md`를 기준으로 실행한다.
|
||||
|
||||
@@ -62,6 +65,7 @@ Last Updated: 2026-02-28
|
||||
- 밝은 배경 구간에서 white 텍스트 대비가 낮아질 수 있어 기기별 시인성 점검이 필요함
|
||||
- 배경 blur/filter 적용으로 저사양 환경에서 렌더링 비용이 소폭 증가할 수 있음
|
||||
- 모달 고정 높이로 인해 작은 화면에서는 탭 본문 내부 스크롤 사용 빈도가 늘 수 있음
|
||||
- 룸 프리뷰 카드의 이미지 기반 다크 톤과 라이트 컨테이너 사이 미세한 톤 차이가 남을 수 있음
|
||||
|
||||
## 상세 원문 위치
|
||||
|
||||
|
||||
@@ -93,13 +93,13 @@ export const AppHubWidget = () => {
|
||||
<div className="relative min-h-screen overflow-hidden text-white">
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 scale-[1.02] blur-[1.5px]"
|
||||
className="absolute inset-0 scale-[1.03] blur-[3px]"
|
||||
style={{
|
||||
...getRoomBackgroundStyle(selectedRoom),
|
||||
filter: 'brightness(1.08) saturate(0.88)',
|
||||
filter: 'brightness(1.12) saturate(0.82)',
|
||||
}}
|
||||
/>
|
||||
<div aria-hidden className="absolute inset-0 bg-slate-900/22" />
|
||||
<div aria-hidden className="absolute inset-0 bg-slate-900/14" />
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 bg-[radial-gradient(circle_at_14%_0%,rgba(255,255,255,0.5),transparent_45%),radial-gradient(circle_at_86%_18%,rgba(191,219,254,0.3),transparent_44%),linear-gradient(165deg,rgba(248,250,252,0.26)_0%,rgba(226,232,240,0.24)_52%,rgba(203,213,225,0.3)_100%)]"
|
||||
|
||||
@@ -14,10 +14,13 @@ export const RoomsGalleryWidget = ({
|
||||
onRoomSelect,
|
||||
}: RoomsGalleryWidgetProps) => {
|
||||
return (
|
||||
<GlassCard elevated className="space-y-5 p-5 sm:p-6">
|
||||
<GlassCard
|
||||
elevated
|
||||
className="space-y-5 border-brand-dark/12 bg-white/78 p-5 text-brand-dark backdrop-blur-md sm:p-6"
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<h2 className="text-xl font-semibold text-white">오늘의 공간</h2>
|
||||
<p className="text-sm text-white/70">감정에 맞는 분위기 하나만 고르면 충분해요.</p>
|
||||
<h2 className="text-xl font-semibold text-brand-dark">오늘의 공간</h2>
|
||||
<p className="text-sm text-brand-dark/68">감정에 맞는 분위기 하나만 고르면 충분해요.</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
|
||||
|
||||
@@ -21,10 +21,13 @@ export const StartRitualWidget = ({
|
||||
onOpenCustomEntry,
|
||||
}: StartRitualWidgetProps) => {
|
||||
return (
|
||||
<GlassCard elevated className="space-y-5 p-5 sm:p-6">
|
||||
<GlassCard
|
||||
elevated
|
||||
className="space-y-5 border-brand-dark/12 bg-white/78 p-5 text-brand-dark backdrop-blur-md sm:p-6"
|
||||
>
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold text-white">지금, 몰입을 시작해요</h1>
|
||||
<p className="mt-2 text-sm leading-relaxed text-white/72">
|
||||
<h1 className="text-2xl font-semibold text-brand-dark">지금, 몰입을 시작해요</h1>
|
||||
<p className="mt-2 text-sm leading-relaxed text-brand-dark/68">
|
||||
공간은 들어가서 바꿔도 괜찮아요. 오늘은 한 조각만.
|
||||
</p>
|
||||
</div>
|
||||
@@ -35,7 +38,7 @@ export const StartRitualWidget = ({
|
||||
value={goalInput}
|
||||
onChange={(event) => onGoalInputChange(event.target.value)}
|
||||
placeholder="이번 세션 딱 1가지만 (예: 견적서 1페이지)"
|
||||
className="w-full rounded-xl border border-white/20 bg-slate-950/55 px-3.5 py-3 text-sm text-white placeholder:text-white/45 focus:border-sky-200/60 focus:outline-none"
|
||||
className="w-full rounded-xl border border-brand-dark/16 bg-white/86 px-3.5 py-3 text-sm text-brand-dark placeholder:text-brand-dark/42 focus:border-brand-primary/42 focus:outline-none"
|
||||
/>
|
||||
|
||||
<div className="flex flex-wrap gap-2">
|
||||
@@ -44,6 +47,7 @@ export const StartRitualWidget = ({
|
||||
key={chip.id}
|
||||
active={selectedGoalId === chip.id}
|
||||
onClick={() => onGoalChipSelect(chip)}
|
||||
className="!bg-white/74 !text-brand-dark/82 !ring-brand-dark/16 hover:!bg-white"
|
||||
>
|
||||
{chip.label}
|
||||
</Chip>
|
||||
@@ -62,7 +66,7 @@ export const StartRitualWidget = ({
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full sm:w-auto sm:min-w-[152px] !bg-white/6 !text-white/84 !ring-white/24 hover:!bg-white/12"
|
||||
className="w-full sm:w-auto sm:min-w-[152px] !bg-white/72 !text-brand-dark !ring-brand-dark/16 hover:!bg-white"
|
||||
onClick={onOpenCustomEntry}
|
||||
>
|
||||
<span aria-hidden>⚙</span>
|
||||
|
||||
Reference in New Issue
Block a user