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:
52
web/lib/recent.ts
Normal file
52
web/lib/recent.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
// 최근 본 종목 — localStorage 기반. 종목 페이지 진입 시 자동으로 push.
|
||||
// 단순 string[] 직렬화. 최신이 앞쪽, 최대 MAX 개로 캡.
|
||||
|
||||
const KEY = "stockchart.recent";
|
||||
const MAX = 10;
|
||||
|
||||
function read(): string[] {
|
||||
if (typeof window === "undefined") return [];
|
||||
try {
|
||||
const raw = window.localStorage.getItem(KEY);
|
||||
if (!raw) return [];
|
||||
const v = JSON.parse(raw);
|
||||
return Array.isArray(v) ? v.filter((s) => typeof s === "string") : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function write(codes: string[]) {
|
||||
if (typeof window === "undefined") return;
|
||||
window.localStorage.setItem(KEY, JSON.stringify(codes));
|
||||
// 같은 탭은 storage 이벤트가 안 떠서 수동 dispatch.
|
||||
window.dispatchEvent(new CustomEvent("recent:change"));
|
||||
}
|
||||
|
||||
export const recent = {
|
||||
get(): string[] {
|
||||
return read();
|
||||
},
|
||||
push(code: string): void {
|
||||
if (!code) return;
|
||||
const cur = read().filter((c) => c !== code);
|
||||
cur.unshift(code);
|
||||
write(cur.slice(0, MAX));
|
||||
},
|
||||
clear(): void {
|
||||
write([]);
|
||||
},
|
||||
subscribe(cb: () => void): () => void {
|
||||
if (typeof window === "undefined") return () => {};
|
||||
const onStorage = (e: StorageEvent) => {
|
||||
if (e.key === KEY) cb();
|
||||
};
|
||||
const onCustom = () => cb();
|
||||
window.addEventListener("storage", onStorage);
|
||||
window.addEventListener("recent:change", onCustom as EventListener);
|
||||
return () => {
|
||||
window.removeEventListener("storage", onStorage);
|
||||
window.removeEventListener("recent:change", onCustom as EventListener);
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user