mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 07:42:23 +00:00
Restyle the cockpit side panels
The cockpit's Display and Radio panels get the compact dark styling of the rest of the shell, a header with the edge switch and collapse, and a rail. Co-authored-by: Sameh Khamis <[email protected]>
This commit is contained in:
1 parent
cd785b1cec
commit
733b227c01
5 files changed
+699
-10
No files matched your search
@@ -1275,7 +1275,7 @@ test('cockpit briefing cycle control keeps its state as the accessible name', ()
|
||||
assert.match(match[0], />CYCLE OFF<\/button>/);
|
||||
assert.match(
|
||||
match[0],
|
||||
/title="Cycle briefing pages automatically every 9 seconds \(Signals → News → Local\)\./,
|
||||
/title="Cycle briefing pages automatically every 9 seconds \(Signals → Local\)\./,
|
||||
);
|
||||
|
||||
// The presented label is the state; the help is only the tooltip.
|
||||
|
||||
@@ -31,12 +31,6 @@ export const COCKPIT_BRIEF_PAGES = [
|
||||
subtitleKey: msg('OBSERVED / MAPPED PINGS'),
|
||||
sourceKey: msg('SOURCE-BACKED EVENTS · NO SYNTHETIC NEWS'),
|
||||
},
|
||||
{
|
||||
id: 'news',
|
||||
kickerKey: msg('REGIONAL NEWS'),
|
||||
subtitleKey: msg('LATEST LOCATION-MATCHED REPORTING'),
|
||||
// The news footer comes from the news state (`news.footer`), not here.
|
||||
},
|
||||
{
|
||||
id: 'local',
|
||||
kickerKey: msg('LOCAL INFO'),
|
||||
@@ -52,7 +46,7 @@ export const CYCLE_HELP_KEYS = Object.freeze({
|
||||
'Stop automatic page cycling. Previous, Next, and the SIG/NEWS/LOCAL tabs stay available.',
|
||||
),
|
||||
off: msg(
|
||||
'Cycle briefing pages automatically every 9 seconds (Signals → News → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.',
|
||||
'Cycle briefing pages automatically every 9 seconds (Signals → Local). Pauses while you hover or focus the panel. Live signal data refreshes continuously either way.',
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,668 @@
|
||||
/* ── Cockpit side windows in the app's panel look ───────────────────────
|
||||
Contact (left), the briefing carousel (right) and the Display / Radio
|
||||
controls get the same smoked glass, 16px corners and card rows as the
|
||||
main panels. They keep cockpit.css's slight 3D slant toward the centre,
|
||||
and stand the same height. The text glow goes; the state colours on the
|
||||
top edge (uncertain, lost) stay. */
|
||||
|
||||
.cockpit-context-window,
|
||||
.cockpit-signal-window {
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-top-color: rgba(255, 255, 255, 0.14);
|
||||
border-radius: 16px;
|
||||
background: rgba(12, 12, 20, 0.72);
|
||||
box-shadow:
|
||||
0 8px 32px rgba(0, 0, 0, 0.42),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||
backdrop-filter: blur(24px) saturate(1.4);
|
||||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||||
text-shadow: none;
|
||||
scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
|
||||
}
|
||||
|
||||
/* Open, both windows share one compact size; their lists scroll. */
|
||||
.cockpit-context-window:not([data-collapsed='true']),
|
||||
.cockpit-signal-window:not([data-collapsed='true']) {
|
||||
width: min(280px, 23vw);
|
||||
height: min(34vh, 330px);
|
||||
}
|
||||
|
||||
/* Their foot sits just above the bottom HUD readouts (MGRS / GSD), which
|
||||
stand at clamp(84px, 11vh, 118px) and are about 38px tall. */
|
||||
.cockpit-context-window,
|
||||
.cockpit-signal-window {
|
||||
bottom: calc(clamp(84px, 11vh, 118px) + 54px);
|
||||
}
|
||||
|
||||
.cockpit-context-window[data-state='uncertain'] {
|
||||
border-top-color: rgba(116, 219, 255, 0.72);
|
||||
}
|
||||
|
||||
.cockpit-context-window[data-state='lost'] {
|
||||
border-top-color: rgba(213, 168, 99, 0.72);
|
||||
}
|
||||
|
||||
.cockpit-context-window[data-collapsed='true'],
|
||||
.cockpit-signal-window[data-collapsed='true'] {
|
||||
border-radius: 12px;
|
||||
background: rgba(12, 12, 20, 0.66);
|
||||
}
|
||||
|
||||
/* Headers: a quiet hairline like the panel headers. */
|
||||
.cockpit-card-header {
|
||||
border-bottom-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.cockpit-card-actions button {
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: rgba(224, 236, 242, 0.82);
|
||||
}
|
||||
|
||||
.cockpit-card-actions button:hover,
|
||||
.cockpit-card-actions button:focus-visible {
|
||||
border-color: rgba(0, 212, 255, 0.45);
|
||||
background: rgba(0, 212, 255, 0.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Rows and tiles inside: the card style used in Context and Visual. */
|
||||
.cockpit-context-cohorts > div,
|
||||
.cockpit-signal-list li,
|
||||
.cockpit-news-list li,
|
||||
.cockpit-local-grid > div {
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 10px;
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
}
|
||||
|
||||
.cockpit-route-card {
|
||||
border-bottom-color: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
/* Display / Radio: the closed launchers and the open panels match too. */
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded {
|
||||
border-color: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 16px;
|
||||
background: rgba(12, 12, 20, 0.72);
|
||||
box-shadow:
|
||||
0 8px 32px rgba(0, 0, 0, 0.42),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
/* ── Cockpit uses the main page's rails ───────────────────────────────
|
||||
The left rail shows (Data Layers, Utilities; Authoring has no place in
|
||||
first person, and the cockpit has its own Display control on the right in
|
||||
place of Visual), one panel opens beside it, and the collapsed header
|
||||
strips the cockpit used instead are hidden. */
|
||||
body.cockpit-mode #left-panel-stack > .gev-panel-rail--left {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body.cockpit-mode #left-panel-stack > .gev-panel-rail--left :is([data-rail-item='scene-panel'], [data-rail-item='pp-toggles']) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode #left-panel-stack > [data-panel-id].collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Display and Radio as the main page's right rail: a column of labels and a
|
||||
column of icon buttons, each reading as one glass strip. */
|
||||
body.cockpit-mode .cockpit-utility-controls {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: stretch;
|
||||
gap: 6px;
|
||||
width: auto;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher > span:first-child,
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-block-width: 0;
|
||||
background: rgba(12, 12, 20, 0.72);
|
||||
backdrop-filter: blur(24px) saturate(1.4);
|
||||
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher > span:first-child {
|
||||
width: 120px;
|
||||
padding: 0 14px;
|
||||
color: rgba(224, 236, 242, 0.72);
|
||||
font: 9px/1 var(--font-mono);
|
||||
letter-spacing: 0.16em;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-divider {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph {
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
color: rgba(224, 236, 242, 0.82);
|
||||
font-size: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-glyph::before {
|
||||
font-family: 'Material Symbols Outlined';
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
letter-spacing: normal;
|
||||
-webkit-font-feature-settings: 'liga';
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded .cockpit-utility-glyph {
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
body.cockpit-mode #cockpit-display-toggle-btn::before {
|
||||
content: 'tune';
|
||||
}
|
||||
|
||||
body.cockpit-mode #cockpit-radio-toggle-btn::before {
|
||||
content: 'radio';
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph:hover {
|
||||
color: #fff;
|
||||
background: rgba(0, 212, 255, 0.12);
|
||||
}
|
||||
|
||||
/* Round the ends of each strip and draw its top / bottom edge. */
|
||||
body.cockpit-mode .cockpit-utility-control:first-child:not(.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph) {
|
||||
padding-top: 4px;
|
||||
border-top-width: 1px;
|
||||
border-radius: 12px 12px 0 0;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:last-child:not(.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph) {
|
||||
padding-bottom: 4px;
|
||||
border-bottom-width: 1px;
|
||||
border-radius: 0 0 12px 12px;
|
||||
}
|
||||
|
||||
/* A strip left alone beside an open panel is rounded all round. */
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded + .cockpit-utility-control:not(.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph),
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded):has(+ .cockpit-utility-control.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph) {
|
||||
padding-block: 4px;
|
||||
border-block-width: 1px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded + .cockpit-utility-control:not(.is-expanded) {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
/* Map credits: one quiet centred line at the very bottom, under Reset /
|
||||
Exit Cockpit, clear of the HUD readouts in the corners. */
|
||||
body.cockpit-mode #cesium-credits {
|
||||
top: auto !important;
|
||||
right: auto !important;
|
||||
bottom: 8px !important;
|
||||
left: 50% !important;
|
||||
max-width: calc(100vw - 2rem) !important;
|
||||
padding: 0.2rem 0.75rem !important;
|
||||
border-radius: 999px !important;
|
||||
transform: translateX(-50%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
body.cockpit-mode #cesium-credits :is(.cesium-widget-credits, .cesium-credit-textContainer) {
|
||||
display: inline-flex !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
body.cockpit-mode #cesium-credits img {
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
/* Both rails start at one height, just under the top HUD text, so their top
|
||||
edges line up. */
|
||||
body.cockpit-mode #left-panel-stack,
|
||||
body.cockpit-mode #cockpit-utility-controls {
|
||||
top: max(206px, 22vh) !important;
|
||||
}
|
||||
|
||||
/* Bottom HUD readouts: scale from their foot, and drop the three-line right
|
||||
block (GSD / ALT / AIS) by one scaled line so both start level, as on the
|
||||
main page. */
|
||||
body.cockpit-mode #intel-hud .hud-bottom-left {
|
||||
transform-origin: left bottom;
|
||||
}
|
||||
|
||||
body.cockpit-mode #intel-hud .hud-bottom-right {
|
||||
bottom: calc(clamp(84px, 11vh, 118px) - 20px);
|
||||
transform-origin: right bottom;
|
||||
}
|
||||
|
||||
/* ── Live signals rows ──────────────────────────────────────────────────
|
||||
Callsign on the left, time small at the top right, the detail under it.
|
||||
The status colour is a slim inset bar (cyan for the aircraft you ride,
|
||||
white for nearby, amber for military / warnings), not a bent border. */
|
||||
.cockpit-signal-list {
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.cockpit-signal-list li {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 8px 12px 8px 14px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
box-shadow: inset 2px 0 0 rgba(244, 251, 255, 0.22);
|
||||
}
|
||||
|
||||
.cockpit-signal-list li:is(.track, .current) {
|
||||
border-color: rgba(0, 212, 255, 0.22);
|
||||
background: rgba(0, 212, 255, 0.06);
|
||||
box-shadow: inset 2px 0 0 var(--cockpit-accent, #00d4ff);
|
||||
}
|
||||
|
||||
.cockpit-signal-list li:is(.nearby) {
|
||||
border-color: rgba(255, 255, 255, 0.06);
|
||||
box-shadow: inset 2px 0 0 rgba(244, 251, 255, 0.55);
|
||||
}
|
||||
|
||||
.cockpit-signal-list li:is(.military, .warning) {
|
||||
border-color: rgba(255, 255, 255, 0.06);
|
||||
box-shadow: inset 2px 0 0 #d5a863;
|
||||
}
|
||||
|
||||
.cockpit-signal-list li.actionable:is(:hover, :focus-within) {
|
||||
border-color: rgba(0, 212, 255, 0.3);
|
||||
background: rgba(0, 212, 255, 0.08);
|
||||
}
|
||||
|
||||
.cockpit-signal-list time {
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
right: 30px;
|
||||
color: rgba(224, 236, 242, 0.4);
|
||||
font: 7px/1 var(--font-mono);
|
||||
letter-spacing: 0.06em;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.cockpit-signal-list li > div {
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.cockpit-signal-target {
|
||||
grid-template-columns: minmax(0, 1fr) 14px;
|
||||
gap: 8px;
|
||||
font-size: 10.5px;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.cockpit-signal-target-rule {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cockpit-signal-target-chevron {
|
||||
justify-self: end;
|
||||
color: rgba(224, 236, 242, 0.5) !important;
|
||||
}
|
||||
|
||||
.cockpit-signal-list li.actionable:is(:hover, :focus-within) .cockpit-signal-target-chevron {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.cockpit-signal-list span:not([class]) {
|
||||
color: rgba(224, 236, 242, 0.62);
|
||||
font-size: 8px;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
/* Keep a long callsign clear of the time at the top right. */
|
||||
.cockpit-signal-list .cockpit-signal-target-label {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
/* ── Briefing content fits the narrower window ────────────────────────── */
|
||||
.cockpit-signal-window {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.cockpit-signal-window > *,
|
||||
.cockpit-brief-stage,
|
||||
.cockpit-brief-stage > section,
|
||||
.cockpit-signal-list,
|
||||
.cockpit-signal-list li {
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Route: a quiet heading, endpoints that truncate. */
|
||||
.cockpit-route-card {
|
||||
padding-inline: 4px;
|
||||
}
|
||||
|
||||
.cockpit-route-heading {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#cockpit-route-status {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cockpit-route-airport strong {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Header: the title on one line, the controls on the row under it. */
|
||||
.cockpit-signal-window:not([data-collapsed='true']) .cockpit-signal-header {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 6px;
|
||||
padding-inline: 4px;
|
||||
}
|
||||
|
||||
.cockpit-signal-window:not([data-collapsed='true']) .cockpit-brief-heading {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 2px 8px;
|
||||
}
|
||||
|
||||
.cockpit-signal-window:not([data-collapsed='true']) .cockpit-signal-kicker {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.cockpit-signal-window:not([data-collapsed='true']) .cockpit-brief-actions {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.cockpit-signal-window:not([data-collapsed='true']) #cockpit-signal-toggle {
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
|
||||
/* The Display / Radio strips carry the left rail's exact frame: border,
|
||||
glass, corners and drop shadow. */
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher > span:first-child,
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph {
|
||||
border-color: rgba(255, 255, 255, 0.14);
|
||||
background: rgba(16, 20, 28, 0.82);
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:first-child:not(.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph) {
|
||||
border-radius: 14px 14px 0 0;
|
||||
box-shadow:
|
||||
0 6px 20px rgba(0, 0, 0, 0.45),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:last-child:not(.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph) {
|
||||
border-radius: 0 0 14px 14px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded + .cockpit-utility-control:not(.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph),
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded):has(+ .cockpit-utility-control.is-expanded) :is(.cockpit-utility-launcher > span:first-child, .cockpit-utility-glyph) {
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
/* ── Open Display / Radio panels: the main panels' header and size ───── */
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded {
|
||||
min-width: 295px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded .cockpit-utility-launcher {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 4px 10px 8px;
|
||||
color: rgba(224, 236, 242, 0.78);
|
||||
font: 9px/1 var(--font-mono);
|
||||
letter-spacing: 0.22em;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded .cockpit-utility-divider {
|
||||
flex: 0 1 22px;
|
||||
height: 1px;
|
||||
margin-right: auto;
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* The launcher's own toggle steps aside; "−" collapses instead. */
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded .cockpit-utility-glyph {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-collapse {
|
||||
display: grid;
|
||||
flex: none;
|
||||
place-items: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: rgba(206, 232, 239, 0.75);
|
||||
font: 13px/1 var(--font-mono);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-collapse:hover,
|
||||
body.cockpit-mode .cockpit-utility-collapse:focus-visible {
|
||||
border-color: rgba(0, 212, 255, 0.45);
|
||||
color: #fff;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Align-to-edge keeps the rail's inset (mirroring the left rail); docked, the
|
||||
open panel takes the rail's place and the icons go above it (below). */
|
||||
|
||||
/* Same measurements as the left rail: a 170px label strip, 4px gap, 42px
|
||||
icon strip, 38px rows. */
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher > span:first-child {
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher > span:first-child,
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph {
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
/* Hover as on the left rail: a 32px rounded square lights behind the icon
|
||||
and the icon and its label brighten; the strip itself stays put. */
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph::before {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--btn-radius, 8px);
|
||||
box-sizing: border-box;
|
||||
transition:
|
||||
color var(--transition-fast, 120ms),
|
||||
background var(--transition-fast, 120ms);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph:hover {
|
||||
background: rgba(16, 20, 28, 0.82);
|
||||
color: var(--text-primary, #fff);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-glyph:hover::before {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) .cockpit-utility-launcher:has(.cockpit-utility-glyph:hover) > span:first-child {
|
||||
color: var(--text-primary, #fff);
|
||||
}
|
||||
|
||||
/* ── Right rail as on the left: an icon column that stays, labels beside it
|
||||
while nothing is open, and the open panel to its left. The launchers'
|
||||
own strips give way to it. ─────────────────────────────────────────── */
|
||||
body.cockpit-mode .cockpit-utility-controls {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto;
|
||||
align-items: start;
|
||||
justify-content: end;
|
||||
column-gap: 6px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control:not(.is-expanded) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-control.is-expanded {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.cockpit-utility-rail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: stretch;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
body.cockpit-mode :is(.cockpit-utility-rail__labels, .cockpit-utility-rail__icons) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 4px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
border-radius: 14px;
|
||||
background: rgba(16, 20, 28, 0.82);
|
||||
box-shadow:
|
||||
0 6px 20px rgba(0, 0, 0, 0.45),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail__labels {
|
||||
box-sizing: border-box;
|
||||
width: 170px;
|
||||
padding-inline: 14px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail__labels > span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 32px;
|
||||
color: rgba(225, 236, 242, 0.82);
|
||||
font: 500 9.28px/1 Inter, -apple-system, system-ui, sans-serif;
|
||||
letter-spacing: 2.08px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail.is-open .cockpit-utility-rail__labels {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail__item {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
background: transparent;
|
||||
color: var(--text-secondary, rgba(206, 232, 239, 0.75));
|
||||
cursor: pointer;
|
||||
transition:
|
||||
color var(--transition-fast, 120ms),
|
||||
background var(--transition-fast, 120ms),
|
||||
border-color var(--transition-fast, 120ms);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail__item .material-symbols-outlined {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail__item:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: var(--text-primary, #fff);
|
||||
}
|
||||
|
||||
body.cockpit-mode .cockpit-utility-rail__item.is-on,
|
||||
body.cockpit-mode .cockpit-utility-rail__item.is-on:hover {
|
||||
border-color: rgba(0, 212, 255, 0.15);
|
||||
background: rgba(0, 212, 255, 0.15);
|
||||
color: #00d4ff;
|
||||
}
|
||||
|
||||
/* Hovering an icon lights its label too, as on the left. */
|
||||
body.cockpit-mode .cockpit-utility-rail:has(.cockpit-utility-rail__item:nth-child(1):hover) .cockpit-utility-rail__labels > span:nth-child(1),
|
||||
body.cockpit-mode .cockpit-utility-rail:has(.cockpit-utility-rail__item:nth-child(2):hover) .cockpit-utility-rail__labels > span:nth-child(2) {
|
||||
color: var(--text-primary, #fff);
|
||||
}
|
||||
|
||||
/* Docked (align-to-edge) with a panel open: as on the main page, the panel
|
||||
takes the edge and the rail's icons sit in a row above it. */
|
||||
body.cockpit-mode.panels-edge-right .cockpit-utility-controls:has(.cockpit-utility-control.is-expanded) {
|
||||
grid-template-columns: auto;
|
||||
justify-items: end;
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
body.cockpit-mode.panels-edge-right .cockpit-utility-controls:has(.cockpit-utility-control.is-expanded) .cockpit-utility-rail {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
body.cockpit-mode.panels-edge-right .cockpit-utility-controls:has(.cockpit-utility-control.is-expanded) .cockpit-utility-control.is-expanded {
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
body.cockpit-mode.panels-edge-right .cockpit-utility-controls:has(.cockpit-utility-control.is-expanded) .cockpit-utility-rail__icons {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
/* Mirror the left rail's 52px inset, clear of the HUD's vertical readouts. */
|
||||
body.cockpit-mode .cockpit-utility-controls {
|
||||
right: 52px;
|
||||
}
|
||||
@@ -84,8 +84,7 @@ function leaveSignals() {
|
||||
<span id="cockpit-brief-source">{{ b.source }}</span>
|
||||
<nav class="cockpit-brief-tabs" :aria-label="t('Cockpit briefing pages')">
|
||||
<button type="button" data-cockpit-brief-index="0" :aria-label="t('Show Live Signals')" :aria-current="String(b.pageIndex === 0)">{{ t('SIG') }}</button>
|
||||
<button type="button" data-cockpit-brief-index="1" :aria-label="t('Show Regional News')" :aria-current="brief ? String(b.pageIndex === 1) : undefined">{{ t('NEWS') }}</button>
|
||||
<button type="button" data-cockpit-brief-index="2" :aria-label="t('Show Local Info')" :aria-current="brief ? String(b.pageIndex === 2) : undefined">{{ t('LOCAL') }}</button>
|
||||
<button type="button" data-cockpit-brief-index="1" :aria-label="t('Show Local Info')" :aria-current="brief ? String(b.pageIndex === 1) : undefined">{{ t('LOCAL') }}</button>
|
||||
</nav>
|
||||
</footer>
|
||||
</aside>
|
||||
|
||||
@@ -8,6 +8,20 @@ import { useRadioStore } from '../../stores/radio.js';
|
||||
import { useCockpitStore } from '../../stores/cockpit.js';
|
||||
import { useDisplayStore } from '../../stores/display.js';
|
||||
import UiButton from '../../kit/UiButton.vue';
|
||||
import UiPanelEdge from '../../kit/UiPanelEdge.vue';
|
||||
|
||||
// The open panel's header carries the same edge switch and collapse button as
|
||||
// the main panels; collapsing goes through each launcher's own toggle.
|
||||
function collapse(which) {
|
||||
if (which === 'radio') act('toggleCockpitRadio');
|
||||
else document.getElementById('cockpit-display-toggle-btn')?.click();
|
||||
}
|
||||
// The rail opens one panel at a time, as the main page's rails do.
|
||||
function railToggle(which) {
|
||||
const other = which === 'radio' ? 'display' : 'radio';
|
||||
if (open.value[other]) collapse(other);
|
||||
collapse(which);
|
||||
}
|
||||
|
||||
// The Cockpit's Display and Radio launchers and their popovers. RadioControls
|
||||
// presents which popover is open and the compact Radio controls; until it
|
||||
@@ -52,6 +66,8 @@ const radioLabel = computed(() =>
|
||||
<div class="cockpit-utility-launcher" data-cockpit-launcher="display">
|
||||
<span>{{ t('DISPLAY') }}</span>
|
||||
<span class="cockpit-utility-divider" aria-hidden="true"></span>
|
||||
<UiPanelEdge v-if="open.display" />
|
||||
<button v-if="open.display" type="button" class="cockpit-utility-collapse" :aria-label="t('Collapse panel')" :title="t('Collapse panel')" @click="collapse('display')">−</button>
|
||||
<button id="cockpit-display-toggle-btn" class="cockpit-utility-glyph" type="button" :aria-expanded="String(open.display)" aria-controls="cockpit-display-panel" :aria-label="displayLabel" :title="displayLabel">{{ open.display ? '▶' : '◀' }}</button>
|
||||
</div>
|
||||
<div id="cockpit-display-panel" class="cockpit-utility-popover ui-scroll" v-class-toggle="{ 'uses-shared-display-controls': !!cockpitPortal }" role="group" :aria-label="t('Cockpit display options')" :hidden="!open.display">
|
||||
@@ -65,6 +81,8 @@ const radioLabel = computed(() =>
|
||||
<div class="cockpit-utility-launcher" data-cockpit-launcher="radio">
|
||||
<span>{{ t('RADIO') }}</span>
|
||||
<span class="cockpit-utility-divider" aria-hidden="true"></span>
|
||||
<UiPanelEdge v-if="open.radio" />
|
||||
<button v-if="open.radio" type="button" class="cockpit-utility-collapse" :aria-label="t('Collapse panel')" :title="t('Collapse panel')" @click="collapse('radio')">−</button>
|
||||
<button id="cockpit-radio-toggle-btn" @click="act('toggleCockpitRadio')" class="cockpit-utility-glyph" type="button" :aria-expanded="String(open.radio)" aria-controls="cockpit-radio-panel" :aria-label="radioLabel" :title="radioLabel">{{ open.radio ? '▶' : '◀' }}</button>
|
||||
</div>
|
||||
<div id="cockpit-radio-panel" class="cockpit-utility-popover cockpit-radio-compact" role="group" :aria-label="t('Cockpit compact Radio controls')" :hidden="!open.radio">
|
||||
@@ -82,5 +100,15 @@ const radioLabel = computed(() =>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="cockpit-utility-rail" :class="{ 'is-open': open.display || open.radio }" :aria-label="t('Cockpit display and Radio controls')">
|
||||
<span class="cockpit-utility-rail__labels" aria-hidden="true">
|
||||
<span>{{ t('DISPLAY') }}</span>
|
||||
<span>{{ t('RADIO') }}</span>
|
||||
</span>
|
||||
<span class="cockpit-utility-rail__icons">
|
||||
<button type="button" class="cockpit-utility-rail__item" :class="{ 'is-on': open.display }" :aria-pressed="String(open.display)" :aria-label="displayLabel" :title="displayLabel" @click="railToggle('display')"><span class="material-symbols-outlined" aria-hidden="true">tune</span></button>
|
||||
<button type="button" class="cockpit-utility-rail__item" :class="{ 'is-on': open.radio }" :aria-pressed="String(open.radio)" :aria-label="radioLabel" :title="radioLabel" @click="railToggle('radio')"><span class="material-symbols-outlined" aria-hidden="true">radio</span></button>
|
||||
</span>
|
||||
</nav>
|
||||
</aside>
|
||||
</template>
|
||||
Reference in new issue
Block a user