refine command deck header

This commit is contained in:
dirtydishes 2026-06-06 07:32:34 -04:00
parent cc5a662d1a
commit 1dee827c69
4 changed files with 582 additions and 20 deletions

View file

@ -854,6 +854,118 @@ h3 {
flex-wrap: wrap;
}
.compact-command-bar {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 8px;
padding: 10px 12px;
border-radius: 10px;
background: linear-gradient(180deg, oklch(0.17 0.013 250 / 0.95), oklch(0.13 0.011 250 / 0.95));
}
.compact-command-topline,
.compact-command-context {
min-width: 0;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.compact-command-title,
.compact-command-controls,
.compact-command-context {
min-width: 0;
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.compact-command-title span,
.compact-command-context > span {
color: var(--text-faint);
font-family: var(--font-mono), monospace;
font-size: 0.68rem;
letter-spacing: 0.12em;
text-transform: lowercase;
}
.compact-command-title strong {
color: var(--text);
font-family: var(--font-display), sans-serif;
font-size: 1.05rem;
letter-spacing: 0.02em;
text-transform: uppercase;
}
.compact-command-context strong {
color: var(--text);
font-family: var(--font-mono), monospace;
font-size: 0.8rem;
}
.command-filter-tooltip {
position: relative;
min-width: 0;
max-width: min(360px, 38vw);
min-height: 32px;
display: inline-flex;
align-items: center;
gap: 7px;
padding: 5px 8px 5px 10px;
border: 1px solid var(--border-strong);
border-radius: 999px;
background: oklch(0.78 0.12 74 / 0.09);
color: var(--text);
font-family: var(--font-mono), monospace;
font-size: 0.68rem;
text-transform: uppercase;
}
.command-filter-tooltip span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.command-filter-tooltip button {
width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: 999px;
background: oklch(0.97 0.008 250 / 0.08);
color: var(--text-dim);
cursor: pointer;
font-family: var(--font-mono), monospace;
font-size: 0.62rem;
opacity: 0;
transform: translateX(3px);
transition:
background-color 150ms ease,
color 150ms ease,
opacity 150ms ease,
transform 150ms ease;
}
.command-filter-tooltip:hover button,
.command-filter-tooltip:focus-within button {
opacity: 1;
transform: translateX(0);
}
.command-filter-tooltip button:hover,
.command-filter-tooltip button:focus-visible {
background: oklch(0.78 0.12 74 / 0.17);
color: var(--text);
outline: none;
}
.command-chip {
min-height: 32px;
display: inline-flex;
@ -2477,6 +2589,7 @@ h3 {
.interval-button,
.overlay-toggle,
.drawer-close,
.command-filter-tooltip button,
.status-inline-counter,
.missed-count,
.synthetic-control-gear {
@ -2506,6 +2619,10 @@ h3 {
grid-template-columns: minmax(220px, 0.8fr) minmax(240px, 1fr);
}
.compact-command-topline {
justify-content: flex-start;
}
.command-deck-controls {
grid-column: 1 / -1;
justify-content: flex-start;
@ -2674,6 +2791,20 @@ h3 {
justify-content: center;
}
.compact-command-bar .command-chip,
.compact-command-bar .terminal-button,
.command-filter-tooltip {
width: auto;
max-width: 100%;
justify-content: center;
}
.compact-command-topline,
.compact-command-context {
align-items: flex-start;
flex-direction: column;
}
.command-ticker-track {
grid-auto-columns: minmax(164px, 78vw);
}

View file

@ -8738,34 +8738,59 @@ const buildCommandDeckTickers = (state: TerminalState): CommandDeckTicker[] => {
const CommandDeckHeader = ({ state }: { state: TerminalState }) => {
const focus = state.activeTickers.length > 0 ? state.activeTickers.join(", ") : state.chartTicker;
const selected = state.selectedInstrumentLabel ?? "No contract lock";
const activeTickerFilter = state.filterInput.trim();
const activeContractFilter =
state.selectedInstrument?.kind === "option-contract" ? state.selectedInstrumentLabel : null;
const connectionLabel =
state.mode === "live" ? statusLabel(state.liveSession.status, false, state.mode) : "Replay";
return (
<header className="command-deck-header" aria-label="Command deck context">
<div className="command-deck-brand">
<span className="command-deck-mark" aria-hidden="true" />
<div>
<span className="command-deck-kicker">islandflow</span>
<h2>Command Deck</h2>
<header className="command-deck-header compact-command-bar" aria-label="Command deck context">
<div className="compact-command-topline">
<div className="compact-command-title">
<span>islandflow</span>
<strong>Command Deck</strong>
</div>
<div className="compact-command-controls" aria-label="Active command deck controls">
<span className={`command-chip command-chip-${state.liveSession.status}`}>
{state.mode === "live" ? "Live" : "Replay"}: {connectionLabel}
</span>
<span className="command-chip">
Last {state.lastSeen ? formatTime(state.lastSeen) : "waiting"}
</span>
<button className="terminal-button" type="button" onClick={state.toggleMode}>
{state.mode === "live" ? "Switch to Replay" : "Switch to Live"}
</button>
</div>
</div>
<div className="command-deck-brief">
<div className="compact-command-context">
<span>Evidence console</span>
<strong>{focus}</strong>
<span>{selected}</span>
</div>
<div className="command-deck-controls" aria-label="Active command deck controls">
<span className={`command-chip command-chip-${state.liveSession.status}`}>
{state.mode === "live" ? "Live" : "Replay"}: {connectionLabel}
</span>
<span className="command-chip">
Last {state.lastSeen ? formatTime(state.lastSeen) : "waiting"}
</span>
<button className="terminal-button" type="button" onClick={state.toggleMode}>
{state.mode === "live" ? "Switch to Replay" : "Switch to Live"}
</button>
{activeContractFilter ? (
<span className="command-filter-tooltip">
<span>{activeContractFilter}</span>
<button
aria-label="Clear contract filter"
type="button"
onClick={() => state.setSelectedInstrument(null)}
>
X
</button>
</span>
) : activeTickerFilter.length > 0 ? (
<span className="command-filter-tooltip">
<span>Ticker: {activeTickerFilter}</span>
<button
aria-label="Clear ticker filter"
type="button"
onClick={() => state.setFilterInput("")}
>
X
</button>
</span>
) : (
<span>No active filter</span>
)}
</div>
</header>
);