- codex UI 재구성 시 <video> element 자체와 .tarot__hero-video CSS가
누락되어 영상 재생 불가 (poster img만 정적 표시).
- <video> 복원 (autoplay, loop, muted, playsInline) + poster fallback.
- CSS z-index 0으로 poster 위, overlay(1) 아래에 stack.
- prefers-reduced-motion @media display:none 동작 복원.
- 사용자 요청에 따라 tarot__scroll-cue 제거.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Issue 1 — 우측 패널 탭이 hardcoded is-active로 클릭/state 없음:
- InterpretationPanel에 activeTab state 추가
- useEffect로 interpretation 도착 시 자동 'ai' 탭 전환, 없으면 'card'
- 두 탭 콘텐츠 분리: card=카드 의미·상징·조언, ai=위치 해석·종합·상호작용·근거
Issue 2 — useTarotReading hook의 interpretation이 새 리딩 시작에 잔존:
- hook에 reset() 함수 추가 (status/interpretation/readingId/error 초기화)
- Reading.jsx의 startShuffle/openCardSpread/restart/resetCards/changeSpread
5개 액션에서 모두 reset() 호출 — 새 리딩 시작 시 이전 해석 완전 제거
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
video와 poster img가 같은 z-index:0 + position:absolute였고 DOM 순서상
poster가 늦게 와서 video를 영원히 덮음 → 영상 재생 중이지만 안 보임.
z-index 계층 명시: poster=0 (fallback) → video=1 → overlay=2 → content=3.
video display:none 처리되면 뒤의 poster img가 자동 노출되도록 stacking 정리.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
라이더-웨이트 메이저 22 + 마이너 56 + 카드 뒷면.
slug 매핑 (the-fool, ace-of-wands 등)으로 자동 표시.
TarotCard 뒷면 참조를 SVG → PNG로 전환.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
KeywordsPanel이 전체 목록을 세로로 길게 표시하던 것을, 동일 keyword
중복 제거(최고 score 유지)·score 내림차순 후 페이지당 10개만 렌더하고
이전(←)/다음(→) 페이저로 탐색하도록 변경. 카테고리 변경 시 첫 페이지 리셋.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
요약카드(백엔드 매입가×수량)와 증권사별(매입가 단순 합) 총 매입이 서로
달라 혼란. 박재오 정의대로 총 매입 = Σ매입가(수량 미곱산)로 통일.
getBrokerSummary를 stockUtils.computeBrokerSummary로 추출(테스트 5건),
usePortfolio가 portfolioSummary.total_buy를 프론트 단순 합으로 override해
요약카드·증권사별·AI 프롬프트가 동일 값 사용. 손익은 avg_price×수량 유지.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TAB_AI 탭과 관련 컴포넌트(AiTradeTab)·훅(useAiBalance) 삭제. 헤더 카드는
aib 모의투자 요약 분기를 제거하고 항상 포트폴리오 요약을 표시.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
모바일 바텀시트(Commands/Tasks)가 55vh로 작아 내용 확인이 불편 → 헤더에
전체화면 토글 버튼 추가(100dvh 확장, 데스크톱은 숨김). music 에이전트
이미지를 agent_music_2로 교체.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend no longer emits the 'break' state (see web-backend
de8adae). Remove the matching entry from STATE_COLORS and the
.ao-card-dot.break CSS rule. Safe because AgentCard's unknown-state
fallback (DEFAULT_STATE_COLOR) handles any stray legacy value.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Old code assumed result_data was a JSON string and ran JSON.parse on it,
falling back to returning the value verbatim on parse error. When the
backend ships result_data as a dict (e.g. compose tasks return
{music_task_id, tracks}), JSON.parse threw, the catch returned the raw
object, and React threw error #31 'Objects are not valid as a React
child' the moment the user expanded the task row.
Extract formatResultData helper: object → JSON.stringify, JSON string
→ parse then pretty-print, plain string → as-is.
Regression tests cover all three input shapes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend returns {"tasks": [...]} and {"logs": [...]} but TaskTab and
LogTab stored the raw object and called .map on it, throwing
'l.map is not a function' the moment a user opened the Tasks or
Logs tab. Unwrap via Array.isArray check (also covers theoretical
bare-array responses).
Regression test for TaskTab covers all three response shapes:
wrapped object, bare array, and empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace fixed 3s reconnect with exponential backoff
(1s/2s/4s/8s/16s/30s, capped). Reduces console noise when
upstream WebSocket is blocked (e.g. DSM reverse proxy without
WS upgrade headers).
- ws.onerror swallowed (onclose still schedules reconnect) so the
browser stops printing an unhandled-error pair per attempt.
- Expose reconnectAttempt in hook; TopBar shows 'Connecting…'
pre-first-attempt and 'Disconnected · 재연결 시도 #N' after.
Root cause of WS failure is upstream (curl proves the endpoint
itself is fine — see DSM reverse proxy WebSocket headers).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ffmpeg libwebp quality=85 compression_level=6.
Total: 11.8MB → 875KB (~11MB saved). Visually indistinguishable on
the card grid at the 9:16 image aspect.
PNG removals were already staged in the previous CommandTab commit;
this commit adds the 6 .webp replacements and points constants.js
imports at .webp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously connect's onclose handler referenced connect itself before
the useCallback declaration, triggering react-hooks/immutability. Hold
the latest connect in a ref (updated in useEffect) and call through it
on reconnect. Same runtime behavior, lint-clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Was hardcoded #22c55e (green) regardless of actual state, making
error/break states look healthy. Switch to muted #94a3b8.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Approval card gated on 'waiting_approval' (was 'waiting'), matching
the state useAgentManager emits — previously the approval UI was
silently suppressed and pendingTask buttons unreachable
- QUICK_ACTIONS/PARAM_ACTIONS: drop blog (agent removed),
add insta (extract / collect_trends / render)
- Regression test covers the three approval-card branches
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
문제:
- 페이지 1~10 미리보기가 가로 overflow인데 시각 affordance 없어서 page 2~10 못 봄
- 슬레이트 목록(.ic-slates-grid)이 모바일에서 어색 + 카드 자체가 viewport 밖으로 밀림
수정:
- PagesStrip 컴포넌트 신설: 좌/우 chevron + page 인디케이터(3/10) + 양옆 fade gradient
+ 키보드 ←/→ + scroll-snap + 클릭 페이지 이동 + 활성 카드 핑크 테두리/scale
- .ic-page-img width를 clamp(140px, 42vw, 220px)로 viewport 비례
- .ic-slates-grid 모바일 2칸 강제, 640px+ 부터 auto-fill
- .ic-detail에 min-width: 0 + max-width: 100% (자식이 부모 안 밀게)
- .ic-layout grid-template-columns에 minmax(0, 1fr) — 자식 overflow 시 부모 안정
- .ic 모바일 좌우 padding 12px (768px+ 16px)
- Card image aspect-ratio 1/1 → 941/1672 (real image ratio, no crop)
- object-fit cover → contain (defensive against rounding)
- Drop card aspect-ratio so it grows from natural image+name height
- Drop grid max-width 720px so grid fills the viewport width
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>