From 1dc4920b32ddcbc31566127d64d5a193f65a72d5 Mon Sep 17 00:00:00 2001 From: JianMiau Date: Mon, 20 Jul 2026 13:40:38 +0800 Subject: [PATCH] =?UTF-8?q?RWD:=E7=9B=B4=E7=89=88=E6=94=B9=E7=9B=B4?= =?UTF-8?q?=E5=90=91=E5=A0=86=E7=96=8A=E8=AE=93=E8=BE=A6=E5=85=AC=E5=AE=A4?= =?UTF-8?q?=E5=8D=80=E5=9F=9F=E6=9C=80=E5=A4=A7=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 摘要: 直版/窄螢幕時辦公室改為滿寬顯示並鎖定 1200:700 比例,側邊面板移到下方; 另新增面板收合按鈕,桌面版也能全畫面看辦公室。 根本原因: 原本任何螢幕都是「辦公室 + 300px 側欄」左右排,SVG 以 meet 等比縮放, 直版視窗寬度受限時上下大量留白,辦公室被壓得很小。 影響: 直版(手機/平板)辦公室寬度從約一半提升到 100%; 窄橫版維持左右排但側欄縮為 232px;桌面版行為不變,多一顆 ⊞ 收合鈕。 修法: - styles.css:orientation: portrait 時 main-row 改 column, floorplan-wrap 用 aspect-ratio 1200/7 00 撐滿寬度,不再靠 flex 留白; ≤900px 壓縮 header(隱藏圖例/副標、按鈕縮小、允許換行) - store 新增 panelOpen/togglePanel,App 據此條件渲染 SidePanel Co-Authored-By: Claude Fable 5 --- src/App.tsx | 5 ++- src/components/HeaderBar.tsx | 8 ++++ src/store/office-store.ts | 5 +++ src/styles.css | 84 +++++++++++++++++++++++++++++++++--- 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 28f068a..b9083ca 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,6 +7,7 @@ import { useOfficeStore } from "./store/office-store"; export default function App() { const theme = useOfficeStore((s) => s.theme); + const panelOpen = useOfficeStore((s) => s.panelOpen); useEffect(() => { startRuntime(); @@ -15,9 +16,9 @@ export default function App() { return (
-
+
- + {panelOpen && }
); diff --git a/src/components/HeaderBar.tsx b/src/components/HeaderBar.tsx index 020f5c7..d99c76b 100644 --- a/src/components/HeaderBar.tsx +++ b/src/components/HeaderBar.tsx @@ -14,6 +14,7 @@ export function HeaderBar() { const setTheme = useOfficeStore((s) => s.setTheme); const mode = useOfficeStore((s) => s.mode); const agentCount = useOfficeStore((s) => s.agents.size); + const panelOpen = useOfficeStore((s) => s.panelOpen); const isLive = mode === "live"; @@ -65,6 +66,13 @@ export function HeaderBar() { +
); diff --git a/src/store/office-store.ts b/src/store/office-store.ts index 063d768..ee5075a 100644 --- a/src/store/office-store.ts +++ b/src/store/office-store.ts @@ -24,6 +24,8 @@ interface OfficeState { speed: number; /** data source: scripted simulation or live Claude Code transcripts */ mode: "sim" | "live"; + /** side panel visibility (collapse to maximise the office view) */ + panelOpen: boolean; /** simulation clock, seconds */ clock: number; @@ -32,6 +34,7 @@ interface OfficeState { setPaused: (p: boolean) => void; setSpeed: (s: number) => void; setMode: (m: "sim" | "live") => void; + togglePanel: () => void; clearWorld: () => void; addEvent: (icon: string, text: string) => void; @@ -78,6 +81,7 @@ export const useOfficeStore = create()((set, get) => ({ paused: false, speed: 1, mode: "sim", + panelOpen: true, clock: 0, selectAgent: (id) => set({ selectedAgentId: id }), @@ -85,6 +89,7 @@ export const useOfficeStore = create()((set, get) => ({ setPaused: (p) => set({ paused: p }), setSpeed: (s) => set({ speed: s }), setMode: (m) => set({ mode: m }), + togglePanel: () => set((state) => ({ panelOpen: !state.panelOpen })), clearWorld: () => set({ agents: new Map(), links: [], meetings: [], events: [], selectedAgentId: null }), diff --git a/src/styles.css b/src/styles.css index cea8791..7fe3e14 100644 --- a/src/styles.css +++ b/src/styles.css @@ -557,12 +557,86 @@ } } -/* narrow screens: hide panel */ -@media (max-width: 900px) { - .side-panel { - display: none; +/* ── RWD ── + Portrait / narrow screens: stack vertically. The office locks to its + 1200:700 aspect ratio at full width (maximum size, no letterboxing), + and the panel moves below it. */ +@media (orientation: portrait) { + .app { + height: 100dvh; } - .header-legend { + + .main-row { + flex-direction: column; + overflow-y: auto; + } + + .floorplan-wrap { + flex: none; + width: 100%; + aspect-ratio: 1200 / 700; + padding: 2px; + } + + .side-panel { + width: 100%; + flex: 1 0 auto; + border-left: none; + border-top: 1px solid var(--border); + } + + .event-feed { + max-height: 40vh; + } +} + +/* Narrow landscape: keep the row, slim the panel */ +@media (max-width: 900px) and (orientation: landscape) { + .side-panel { + width: 232px; + } +} + +/* Compact chrome on any narrow screen */ +@media (max-width: 900px) { + .header { + gap: 10px; + padding: 6px 10px; + flex-wrap: wrap; + } + + .header-legend, + .header-brand p, + .agent-count { display: none; + } + + .header-mark { + font-size: 22px; + } + + .header-brand h1 { + font-size: 17px; + } + + .header-controls { + margin-left: auto; + gap: 5px; + } + + .btn { + padding: 5px 9px; + font-size: 12px; + } +} + +/* Very tight screens: shave header further */ +@media (max-width: 480px) { + .header-brand h1 { + font-size: 15px; + } + .btn { + padding: 4px 7px; + font-size: 11px; } }