feat(orderbook): wrap OrderbookPanel in Collapsible (sticky-aware)

사이드바 6 패널 중 마지막 남은 비-collapsible 패널이던 OrderbookPanel 을
공용 Collapsible 로 통일. 이제 SymbolSidebar/PriceTargets 제외 모든 사이드
패널이 같은 토글/영속 패턴.

sticky 충돌 해소:
- 기존 sticky 스타일은 OrderbookPanel 자체 outer div 에 직접 박혀 있었음.
  Collapsible 로 감싸면 outer 가 바뀌므로 Collapsible 의 className prop 으로
  sticky 톤(bg-zinc-900/80 backdrop-blur)을 sticky=true 일 때만 주입.
- 접혔을 때: 헤더 한 줄(호가 + ts) 만 sticky top-4 로 상단에 떠 있음 →
  차트/지표 영역 길게 스크롤 중에도 호가 헤더 접근 가능, 한 번 클릭이면
  본문 펴짐. 펼쳤을 때: 본문 포함 전체 sticky.
- 내부 p-3 패딩은 제거 — Collapsible 의 px-4/pb-4/pt-3 본문 패딩이
  카드 안쪽 여백을 대체.

defaultOpen=true:
- 호가는 사이드바에서 정보 밀도/시의성 모두 가장 높은 패널 →
  진입 즉시 펴진 상태가 자연스러움. RelatedStocks(밀도 낮음) 만 false.

storageKey="orderbook": panel-open:orderbook 으로 영속.

검증:
- npx tsc --noEmit clean
- npx next lint "✔ No ESLint warnings or errors"
This commit is contained in:
claude-owner
2026-06-01 10:37:23 +09:00
parent d53ff7a745
commit 70d56b14ec

View File

@@ -13,6 +13,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { api, type OrderbookLevel, type OrderbookResponse } from "../lib/api"; import { api, type OrderbookLevel, type OrderbookResponse } from "../lib/api";
import { Collapsible } from "./Collapsible";
type Props = { type Props = {
code: string; code: string;
@@ -20,6 +21,10 @@ type Props = {
// 시야에 남도록. 일봉 이상에선 호가의 실시간 가치가 낮아 일반 흐름으로 두는 게 사이드바 // 시야에 남도록. 일봉 이상에선 호가의 실시간 가치가 낮아 일반 흐름으로 두는 게 사이드바
// 다른 패널(PriceTargets/AlertsPanel/InvestmentNote/RelatedStocks) 의 위치 안정성을 해치지 // 다른 패널(PriceTargets/AlertsPanel/InvestmentNote/RelatedStocks) 의 위치 안정성을 해치지
// 않음. // 않음.
//
// sticky + collapsible 조합: Collapsible 의 outer 래퍼 자체에 sticky 를 걸어두면 접혔을
// 때는 헤더 한 줄(호가 + ts) 만 상단에 떠 있고, 펼치면 본문 포함 전체가 시야에 남는다.
// — 사용자가 차트/지표 영역을 길게 스크롤하다 호가 보고 싶을 때 늘 접근 가능.
sticky?: boolean; sticky?: boolean;
}; };
@@ -55,21 +60,19 @@ export function OrderbookPanel({ code, sticky = false }: Props) {
}; };
}, [code]); }, [code]);
// 호가는 사이드바에서 정보 밀도/시의성 모두 가장 높음 → 기본 펼침 유지.
// 사용자가 접고 싶다면 헤더 클릭 한 번 + localStorage 영속.
return ( return (
<div <Collapsible
title="호가"
subtitle={data?.ts ? `${data.ts} · 10초 갱신` : "10초 갱신"}
storageKey="orderbook"
className={ className={
sticky sticky
? "sticky top-4 rounded-md border border-zinc-800 bg-zinc-900/80 p-3 backdrop-blur" ? "sticky top-4 rounded-md border border-zinc-800 bg-zinc-900/80 backdrop-blur"
: "rounded-md border border-zinc-800 bg-zinc-900/40 p-3" : "rounded-md border border-zinc-800 bg-zinc-900/40"
} }
> >
<div className="mb-2 flex items-center justify-between gap-2">
<span className="text-xs font-medium text-zinc-300"></span>
<span className="text-[10px] text-zinc-500">
{data?.ts ? `${data.ts} · 10초 갱신` : "10초 갱신"}
</span>
</div>
{loading && !data && ( {loading && !data && (
<div className="py-6 text-center text-[11px] text-zinc-500"> </div> <div className="py-6 text-center text-[11px] text-zinc-500"> </div>
)} )}
@@ -87,7 +90,7 @@ export function OrderbookPanel({ code, sticky = false }: Props) {
)} )}
{data && data.status === "ok" && <OrderbookTable data={data} />} {data && data.status === "ok" && <OrderbookTable data={data} />}
</div> </Collapsible>
); );
} }