fix(ui): keep the OPERATIONS tab bar intact when tall tabs overflow the pane (#36)
CI / build + unit + e2e (pull_request) Successful in 2m30s
CI / build + unit + e2e (pull_request) Successful in 2m30s
This commit is contained in:
@@ -383,26 +383,28 @@ export function MissionControl() {
|
||||
</PanelHeader>
|
||||
|
||||
<PanelContent style={{ padding: 0, flex: 1, minHeight: 0, overflowY: 'auto' }}>
|
||||
{/* Flex column at full height so a tab can fill the pane (#36); other tabs stay
|
||||
content-sized and overflow into this same scroll area as before. */}
|
||||
{/* Flex column at least pane-tall so a tab can fill it (#36). min-height, not height:
|
||||
tall tabs grow the box to their content, which keeps the sticky tab bar's containing
|
||||
block spanning the whole scroll range (a capped height releases the pin on deep
|
||||
scrolls) and means items never overflow the box, so nothing gets shrink-squashed. */}
|
||||
<Tabs
|
||||
value={activeTab ?? 'world-map'}
|
||||
onValueChange={(v) => {
|
||||
setActiveTab(v)
|
||||
window.localStorage.setItem(ACTIVE_TAB_KEY, v) // #27 — keep the tab across refreshes
|
||||
}}
|
||||
style={{ display: 'flex', flexDirection: 'column', height: '100%' }}
|
||||
style={{ display: 'flex', flexDirection: 'column', minHeight: '100%' }}
|
||||
>
|
||||
<TabsList
|
||||
style={{
|
||||
padding: '0 1rem',
|
||||
background: 'var(--surface-raised)', // opaque — content scrolls under it (#31)
|
||||
overflowX: 'auto',
|
||||
position: 'sticky', // #31 — pinned in both modes: to the top of the OPERATIONS
|
||||
top: 0, // scroll area (wide) and to the viewport when the body scrolls (narrow)
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<TabsList
|
||||
style={{
|
||||
padding: '0 1rem',
|
||||
background: 'var(--surface-raised)', // opaque — content scrolls under it (#31)
|
||||
overflowX: 'auto',
|
||||
position: 'sticky', // #31 — pinned in both modes: to the top of the OPERATIONS
|
||||
top: 0, // scroll area (wide) and to the viewport when the body scrolls (narrow)
|
||||
zIndex: 1,
|
||||
}}
|
||||
>
|
||||
<TabsTrigger value="world-map">WORLD MAP</TabsTrigger>
|
||||
<TabsTrigger value="local-system">LOCAL SYSTEM</TabsTrigger>
|
||||
<TabsTrigger value="crew">CREW</TabsTrigger>
|
||||
@@ -412,8 +414,13 @@ export function MissionControl() {
|
||||
<TabsTrigger value="event-log">EVENT LOG</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
{/* WORLD MAP TAB — live data from /api/world; fills the whole pane (#36) */}
|
||||
<TabsContent value="world-map" style={{ margin: 0, padding: '1rem', flex: 1, minHeight: 0 }}>
|
||||
{/* WORLD MAP TAB — live data from /api/world; fills the whole pane (#36). Wide mode:
|
||||
flex column so the panel can fill it with pure flex sizing (a min-height-only
|
||||
container breaks percentage resolution, so no height:'100%' anywhere in this chain). */}
|
||||
<TabsContent
|
||||
value="world-map"
|
||||
style={{ margin: 0, padding: '1rem', ...(!narrow ? { display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 } : {}) }}
|
||||
>
|
||||
<WorldMapPanel height={380} narrow={narrow} onJumped={refreshSystem} />
|
||||
</TabsContent>
|
||||
|
||||
|
||||
@@ -265,8 +265,9 @@ export function WorldMapPanel({ height = 380, narrow = false, onJumped }: WorldM
|
||||
)
|
||||
}
|
||||
|
||||
// flex (not height:'100%'): the pane chain is sized by min-height, where percentages don't resolve
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', ...(filling ? { height: '100%' } : {}) }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', ...(filling ? { flex: 1, minHeight: 0 } : {}) }}>
|
||||
{/* Wrapper + title bar; in wide mode the box flexes to fill the whole pane (#36). d3 owns everything inside it. */}
|
||||
<div
|
||||
style={{
|
||||
|
||||
Reference in New Issue
Block a user