feat(ui): 최근 본 종목 (localStorage + 홈 카드 + TopNav popover)

- web/lib/recent.ts: stockchart.recent KEY, push/get/clear/subscribe (storage + custom event)
- [code]/page.tsx: 페이지 진입 시 recent.push(code) — 자동 트래킹
- web/components/RecentTiles.tsx: 홈 카드 그리드 (최대 10개, 2~5컬럼)
- web/app/page.tsx: SearchBox 아래에 RecentTiles 배치 (빈 리스트면 자동 숨김)
- TopNav: 검색어 비면서 포커스 시 최근 본 종목 popover 표시 + "지우기" 버튼

토스 "최근 본 종목" 톤 — 검색 빈 상태에서도 popover 가 비어 있지 않게.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
claude-owner
2026-05-28 15:14:40 +09:00
parent 300f7beef0
commit aa58761176
5 changed files with 229 additions and 0 deletions

View File

@@ -17,6 +17,7 @@ import { StockChart } from "../../components/StockChart";
import { SymbolSidebar } from "../../components/SymbolSidebar";
import { TradingValuePanel } from "../../components/TradingValuePanel";
import { api, type ChartPayload, type LatestPredictionResponse } from "../../lib/api";
import { recent } from "../../lib/recent";
export default function CodePage({ params }: { params: { code: string } }) {
const { code } = params;
@@ -28,6 +29,11 @@ export default function CodePage({ params }: { params: { code: string } }) {
const spec = periodSpec(period);
const isIntraday = spec.interval === "10m";
// 종목 페이지 방문 시 최근 본 종목에 push.
useEffect(() => {
recent.push(code);
}, [code]);
useEffect(() => {
let alive = true;
setErr(null);