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.
31 lines
1.2 KiB
TypeScript
31 lines
1.2 KiB
TypeScript
// 사이드바 collapsible 패널의 펼침/접힘 상태 영속 저장.
|
|
// 키 형식: `panel-open:<name>` — 종목별이 아닌 panel-name 단위. 사용자는 "관련 종목은 늘
|
|
// 접어 둔다" 같은 panel 단위 습관이 있지 종목별로 다르게 설정하지 않음. 모든 종목 페이지에서
|
|
// 같은 상태로 보이는 것이 직관적.
|
|
//
|
|
// 값 형식: '1' = open, '0' = closed. 다른 값(수동 편집·legacy 등) 은 default 로 폴백.
|
|
// 쿼타/잠금 환경에선 silently fail — 그 세션 동안 default 상태 유지.
|
|
|
|
const STORAGE_PREFIX = "panel-open:";
|
|
|
|
export function readOpen(key: string, defaultOpen: boolean): boolean {
|
|
if (typeof window === "undefined") return defaultOpen;
|
|
try {
|
|
const v = window.localStorage.getItem(STORAGE_PREFIX + key);
|
|
if (v === "1") return true;
|
|
if (v === "0") return false;
|
|
return defaultOpen;
|
|
} catch {
|
|
return defaultOpen;
|
|
}
|
|
}
|
|
|
|
export function writeOpen(key: string, open: boolean): void {
|
|
if (typeof window === "undefined") return;
|
|
try {
|
|
window.localStorage.setItem(STORAGE_PREFIX + key, open ? "1" : "0");
|
|
} catch {
|
|
// quota / private mode — 다음 페이지 진입엔 default 로 되돌아감.
|
|
}
|
|
}
|