feat(sidebar): RelatedStocks defaults collapsed + readOpen garbage-value fallback

readOpen() (reviewer f9027f5 non-blocking note):
- Previously returned v === '1' which collapsed '0' AND any garbage
  value (legacy markers, manual edits) into the same false branch,
  contradicting the 'fallback to default' comment. Split into three
  explicit cases: '1' → true, '0' → false, anything else →
  defaultOpen. Behavior unchanged for the writeOpen-only path; only
  garbage input is corrected.

RelatedStocks defaultOpen=false:
- Of the three collapsible sidebar panels (AlertsPanel,
  InvestmentNote, RelatedStocks), RelatedStocks has the lowest
  information density per row and the weakest direct tie to 'this
  symbol' (it's other symbols in the same market). Starting collapsed
  cuts initial mobile scroll height for first-time visitors; once the
  user toggles, localStorage pins their preference.
This commit is contained in:
claude-owner
2026-06-01 10:31:48 +09:00
parent f9027f5365
commit d53ff7a745
2 changed files with 13 additions and 4 deletions

View File

@@ -33,7 +33,15 @@ export function RelatedStocks({ code }: { code: string }) {
const subtitle = data?.market ? `${data.market} · 거래량 기준` : undefined; const subtitle = data?.market ? `${data.market} · 거래량 기준` : undefined;
return ( return (
<Collapsible title="관련 종목" subtitle={subtitle} storageKey="related"> // defaultOpen=false — 사이드바의 세 collapsible 중 정보 밀도가 가장 낮고 "이 종목 자체"
// 와의 직접 연관도 약함(같은 시장의 다른 종목 리스트). 진입 즉시 접혀 있다가 사용자가
// 필요할 때 펴는 게 자연스러움. 첫 토글 이후엔 localStorage 가 사용자 선호로 굳음.
<Collapsible
title="관련 종목"
subtitle={subtitle}
storageKey="related"
defaultOpen={false}
>
{err && ( {err && (
<div className="text-xs text-zinc-500"> : {err}</div> <div className="text-xs text-zinc-500"> : {err}</div>
)} )}

View File

@@ -3,7 +3,7 @@
// 접어 둔다" 같은 panel 단위 습관이 있지 종목별로 다르게 설정하지 않음. 모든 종목 페이지에서 // 접어 둔다" 같은 panel 단위 습관이 있지 종목별로 다르게 설정하지 않음. 모든 종목 페이지에서
// 같은 상태로 보이는 것이 직관적. // 같은 상태로 보이는 것이 직관적.
// //
// 값 형식: '1' = open, '0' = closed. 다른 값은 default 로 폴백. // 값 형식: '1' = open, '0' = closed. 다른 값(수동 편집·legacy 등) 은 default 로 폴백.
// 쿼타/잠금 환경에선 silently fail — 그 세션 동안 default 상태 유지. // 쿼타/잠금 환경에선 silently fail — 그 세션 동안 default 상태 유지.
const STORAGE_PREFIX = "panel-open:"; const STORAGE_PREFIX = "panel-open:";
@@ -12,8 +12,9 @@ export function readOpen(key: string, defaultOpen: boolean): boolean {
if (typeof window === "undefined") return defaultOpen; if (typeof window === "undefined") return defaultOpen;
try { try {
const v = window.localStorage.getItem(STORAGE_PREFIX + key); const v = window.localStorage.getItem(STORAGE_PREFIX + key);
if (v === null) return defaultOpen; if (v === "1") return true;
return v === "1"; if (v === "0") return false;
return defaultOpen;
} catch { } catch {
return defaultOpen; return defaultOpen;
} }