Skip to content

Commit 4fa52a9

Browse files
committed
fix(viz): collapsible TurnBanner + vertical scroll on cohort grid track
1 parent 54e17a3 commit 4fa52a9

3 files changed

Lines changed: 50 additions & 4 deletions

File tree

src/dashboard/src/components/viz/CohortSwarmGrid.module.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
position: relative;
88
width: 100%;
99
overflow-x: auto;
10-
overflow-y: hidden;
10+
// Vertical scroll on the track so a 640px+ column body never gets
11+
// clipped invisible when the viewport leaves less than that under
12+
// the TurnBanner + sub-tabs + chart strip. Was `hidden`, which hid
13+
// the entire body when squeezed and left only column headers visible.
14+
overflow-y: auto;
1115
background: var(--bg-deep);
1216
border-radius: 8px;
1317
border: 1px solid var(--border);

src/dashboard/src/components/viz/TurnBanner.module.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@
1919
flex-wrap: wrap;
2020
}
2121

22+
.collapseBtn {
23+
margin-left: auto;
24+
padding: 2px 8px;
25+
font-family: var(--mono);
26+
font-size: var(--font-2xs);
27+
font-weight: 700;
28+
letter-spacing: 0.06em;
29+
background: transparent;
30+
color: var(--text-3);
31+
border: 1px solid var(--border);
32+
border-radius: 3px;
33+
cursor: pointer;
34+
white-space: nowrap;
35+
36+
&:hover {
37+
color: var(--text-1);
38+
border-color: var(--border-hl);
39+
}
40+
}
41+
2242
.turnLabel { color: var(--text-3); }
2343

2444
.title {

src/dashboard/src/components/viz/TurnBanner.tsx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useMemo } from 'react';
1+
import { useMemo, useState } from 'react';
22
import type { GameState, ActorSideState } from '../../hooks/useGameState.js';
33
import { humanizeOutcome } from './humanize-outcome.js';
44
import styles from './TurnBanner.module.scss';
@@ -69,6 +69,15 @@ const MAX_INLINE_OUTCOMES = 6;
6969
* so the banner stays under a screen on large cohort runs.
7070
*/
7171
export function TurnBanner({ state, currentTurn }: TurnBannerProps) {
72+
// Cohort runs (3+ actors) render all per-actor outcome lines which
73+
// can eat 6+ rows of vertical space on the viz tab, squeezing the
74+
// cohort grid below to just its column headers with the bodies
75+
// clipped. Default the per-actor block to collapsed for cohort runs
76+
// so the headline stays visible without crowding the grid; pair runs
77+
// keep the expanded default since two lines never crowd the layout.
78+
const isCohortDefault = state.actorIds.length > 2;
79+
const [collapsed, setCollapsed] = useState(isCohortDefault);
80+
7281
const summaries = useMemo(() => {
7382
const out: Array<{ actorId: string; summary: LeaderTurnSummary | null }> = [];
7483
for (const actorId of state.actorIds) {
@@ -87,15 +96,28 @@ export function TurnBanner({ state, currentTurn }: TurnBannerProps) {
8796

8897
const visible = populated.slice(0, MAX_INLINE_OUTCOMES);
8998
const hidden = populated.length - visible.length;
99+
const showLines = !collapsed;
100+
const canCollapse = populated.length > 0;
90101

91102
return (
92103
<div role="status" aria-label="Current turn narrative" className={styles.banner}>
93104
<div className={styles.headline}>
94105
<span className={styles.turnLabel}>T{currentTurn + 1}{time ? ` \u00b7 ${time}` : ''}</span>
95106
<span className={styles.title}>{headline}</span>
96107
{category && <span className={styles.categoryPill}>{category}</span>}
108+
{canCollapse && (
109+
<button
110+
type="button"
111+
onClick={() => setCollapsed(c => !c)}
112+
aria-expanded={!collapsed}
113+
aria-label={collapsed ? 'Expand per-actor outcomes' : 'Collapse per-actor outcomes'}
114+
className={styles.collapseBtn}
115+
>
116+
{collapsed ? `\u25be ${populated.length} actors` : '\u25b4 hide'}
117+
</button>
118+
)}
97119
</div>
98-
{visible.map((entry, idx) => (
120+
{showLines && visible.map((entry, idx) => (
99121
<div
100122
key={entry.actorId}
101123
// For 2-actor pair runs, keep the legacy `.lineA` / `.lineB`
@@ -110,7 +132,7 @@ export function TurnBanner({ state, currentTurn }: TurnBannerProps) {
110132
<span className={styles.lineBody}>: {humanizeOutcome(entry.summary)}</span>
111133
</div>
112134
))}
113-
{hidden > 0 && (
135+
{showLines && hidden > 0 && (
114136
<div className={styles.lineMore}>
115137
+{hidden} more \u00b7 see cohort grid below for the rest
116138
</div>

0 commit comments

Comments
 (0)