diff --git a/src/components/AnalysisReportPage.tsx b/src/components/AnalysisReportPage.tsx index c81e44fa..e2295e0d 100644 --- a/src/components/AnalysisReportPage.tsx +++ b/src/components/AnalysisReportPage.tsx @@ -10,6 +10,7 @@ import { LayoutDashboard, LogOut, Maximize2, + Menu, Play, Target, User, @@ -46,6 +47,7 @@ import type { HeatmapPoint, } from "../types/reportpageType"; import { Footer } from "./ui/footer"; +import { useMediaQuery } from "./ui/use-mobile"; import { fetchReport } from "../api/reportpageApi"; import { updateMatchScore, @@ -303,7 +305,9 @@ function PlayerToggle({ // grid-cols-2: 두 칸이 항상 같은 폭. flex로 두면 글자 길이만큼 // 칸 넓이가 달라져 한쪽이 넓어 보인다.
{PLAYERS.map(({ key, label, full }) => { const isActive = active === key; @@ -375,7 +379,7 @@ function CollapsibleCard({ // 내용이 적은 카드는 본문이 늘어나고, 하단 요약은 mt-auto로 바닥에 붙는다. className="flex h-full flex-col rounded-2xl border border-slate-200/70 bg-white overflow-hidden scroll-mt-20" > -
+
-
{children}
+
{children}
); @@ -1156,14 +1160,18 @@ function BadmintonHeatmapCourt({ } return ( -
+ // 좁은 화면에서는 코트에 조금 더 폭을 주고 사이 간격을 줄인다. 32%로 두면 + // 폰에서 코트가 100px 남짓으로 쪼그라들어 타점이 서로 겹쳐 읽히지 않는다. +
{courtSvg}
-
{infoPanel}
+
{infoPanel}
); } @@ -1461,12 +1469,21 @@ function StrokeDonut({ return ( // w-full이 없으면 범례의 flex-1이 늘어날 폭을 못 잡아 묶음이 가운데 뭉치고 // 카드 좌우에 빈 공간이 남는다. -
- {/* 값은 옆 범례가 글자로 전부 전달하므로 그림은 보조 표현이다 */} +
+ {/* 값은 옆 범례가 글자로 전부 전달하므로 그림은 보조 표현이다. + 폰에서는 도넛을 줄인다 — 원래 폭을 그대로 두면 옆 범례가 한 줄에 + "12회 40%"를 못 담아 숫자가 잘린다. viewBox 라 폭만 줄이면 된다. */} -
    +
      {rows.map((row, i) => { const pct = total > 0 ? Math.round((row.count / total) * 100) : 0; const zero = row.count === 0; @@ -1595,7 +1614,7 @@ function StrokeDonut({ {row.name} (null); - // 사이드바 + // 사이드바 — lg 미만에서는 화면을 덮는 서랍으로 바뀐다. const [sidebarOpen, setSidebarOpen] = useState(true); + const [mobileNavOpen, setMobileNavOpen] = useState(false); + const isDesktopNav = useMediaQuery("(min-width: 1024px)"); + /** + * '접기'는 데스크톱에서만 의미가 있다. 서랍으로 열릴 때 아이콘만 남은 + * 모양이 될 이유가 없으므로 항상 펼친 상태로 그린다. + */ + const navExpanded = isDesktopNav ? sidebarOpen : true; + + // 서랍은 ESC로 닫히고, 데스크톱 폭으로 넓어지면 상태를 비운다. + useEffect(() => { + if (isDesktopNav) { + setMobileNavOpen(false); + return; + } + if (!mobileNavOpen) return; + + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") setMobileNavOpen(false); + }; + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, [isDesktopNav, mobileNavOpen]); // 섹션 refs (스크롤용) const mainScrollRef = useRef(null); @@ -2175,8 +2216,8 @@ ${coaching?.feedbackText ?? "(없음)"} />
      - {/* 사이드바 스켈레톤 */} -