feat(live-atc): put ACTIVE left of STANDBY, lighten the HUD action cluster

Real avionics (Garmin GTN and friends) place the active frequency window to
the left of standby; the panel now matches, so muscle memory transfers.

In the HUD, "Report issue" is the tool pilots reach for most often during a
session, so it gets a filled amber pill with icon + label while Settings drops
to an icon-only gear. The divider moves down to sit directly above Logout,
grouping the three session tools (report / settings / help) together.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
itsrubberduck
2026-07-10 16:20:57 +02:00
parent ab9b52ad4c
commit 4a143de4a8
2 changed files with 85 additions and 59 deletions

View File

@@ -84,61 +84,8 @@ const channelLabel = (entry: DisplayAirportFrequencyEntry) => FREQ_ROLE_LABEL[en
</HoldSelect>
</header>
<!-- ACTIVE sits left of STANDBY, matching real avionics (Garmin GTN et al.). -->
<div class="radio-panel__windows">
<HoldSelect
:options="presetOptions"
placement="down"
title="Select standby frequency"
menu-class="freq-hold-menu"
@select="emit('select-standby', $event)"
>
<template #default="{ open }">
<button type="button" class="freq-window freq-window--sby" :class="{ 'is-open': open }">
<span class="freq-window__tag">STANDBY</span>
<span class="freq-window__value">{{ standby || '---.---' }}</span>
<span class="freq-window__station">{{ standbyStation || '—' }}</span>
</button>
</template>
<template #option="{ option }">
<v-tooltip :text="`Source: ${option.sourceLabel}`" location="end" open-delay="200">
<template #activator="{ props: tip }">
<div v-bind="tip" class="freq-option">
<div class="freq-option-main">
<span class="freq-option-label">{{ option.label }}</span>
<span class="freq-option-sub">{{ option.sublabel }}</span>
</div>
<span class="freq-option-source" :aria-label="`Source ${option.sourceLabel}`">
{{ option.sourceLabel }}
</span>
</div>
</template>
</v-tooltip>
</template>
<template #header="{ close }">
<form class="freq-manual" @submit.prevent="emit('apply-manual', 'standby', close)">
<input
v-model="manualFreqStandby"
class="freq-manual-input"
type="text"
inputmode="decimal"
placeholder="Manuell, z.B. 121.500"
maxlength="7"
aria-label="Manual standby frequency"
>
<button type="submit" class="freq-manual-btn" :disabled="!normalizeManualFreq(manualFreqStandby)">SET</button>
</form>
</template>
</HoldSelect>
<button
type="button"
class="freq-swap-btn"
aria-label="Swap active and standby frequencies"
@click="emit('swap')"
>
<v-icon :class="{ 'swap-animation': swapAnimation }">mdi-swap-horizontal</v-icon>
</button>
<HoldSelect
:options="presetOptions"
placement="down"
@@ -183,6 +130,60 @@ const channelLabel = (entry: DisplayAirportFrequencyEntry) => FREQ_ROLE_LABEL[en
</form>
</template>
</HoldSelect>
<button
type="button"
class="freq-swap-btn"
aria-label="Swap active and standby frequencies"
@click="emit('swap')"
>
<v-icon :class="{ 'swap-animation': swapAnimation }">mdi-swap-horizontal</v-icon>
</button>
<HoldSelect
:options="presetOptions"
placement="down"
title="Select standby frequency"
menu-class="freq-hold-menu"
@select="emit('select-standby', $event)"
>
<template #default="{ open }">
<button type="button" class="freq-window freq-window--sby" :class="{ 'is-open': open }">
<span class="freq-window__tag">STANDBY</span>
<span class="freq-window__value">{{ standby || '---.---' }}</span>
<span class="freq-window__station">{{ standbyStation || '—' }}</span>
</button>
</template>
<template #option="{ option }">
<v-tooltip :text="`Source: ${option.sourceLabel}`" location="end" open-delay="200">
<template #activator="{ props: tip }">
<div v-bind="tip" class="freq-option">
<div class="freq-option-main">
<span class="freq-option-label">{{ option.label }}</span>
<span class="freq-option-sub">{{ option.sublabel }}</span>
</div>
<span class="freq-option-source" :aria-label="`Source ${option.sourceLabel}`">
{{ option.sourceLabel }}
</span>
</div>
</template>
</v-tooltip>
</template>
<template #header="{ close }">
<form class="freq-manual" @submit.prevent="emit('apply-manual', 'standby', close)">
<input
v-model="manualFreqStandby"
class="freq-manual-input"
type="text"
inputmode="decimal"
placeholder="Manuell, z.B. 121.500"
maxlength="7"
aria-label="Manual standby frequency"
>
<button type="submit" class="freq-manual-btn" :disabled="!normalizeManualFreq(manualFreqStandby)">SET</button>
</form>
</template>
</HoldSelect>
</div>
<!-- Published channels for this airport; tapping one stages it in standby. -->

View File

@@ -191,26 +191,26 @@
</NuxtLink>
</template>
</v-tooltip>
<!-- Report issue carries a filled treatment: it is the most-reached-for
secondary tool, so it outranks the neighbouring ghost icons. -->
<button
type="button"
class="btn ghost"
class="btn hud-report-btn"
title="Fehler melden"
:disabled="bugReportCapturing"
@click="openBugReport"
>
<v-icon size="18">{{ bugReportCapturing ? 'mdi-loading mdi-spin' : 'mdi-bug-outline' }}</v-icon>
<span class="btn-label">{{ bugReportCapturing ? '…' : 'Bug' }}</span>
<span class="btn-label">{{ bugReportCapturing ? '…' : 'Report issue' }}</span>
</button>
<button
type="button"
class="btn ghost"
class="btn ghost hud-icon-btn"
title="Settings"
@click="showSettingsSheet = true"
>
<v-icon size="18">mdi-cog</v-icon>
<span class="btn-label">Settings</span>
</button>
<div class="hud-divider" aria-hidden="true"></div>
<button
type="button"
class="btn ghost hud-icon-btn"
@@ -219,6 +219,7 @@
>
<v-icon size="18">mdi-help-circle-outline</v-icon>
</button>
<div class="hud-divider" aria-hidden="true"></div>
<NuxtLink class="btn ghost hud-icon-btn" to="/logout" title="Logout">
<v-icon size="18">mdi-logout</v-icon>
</NuxtLink>
@@ -1844,6 +1845,30 @@ onUnmounted(() => {
min-width: 40px;
justify-content: center;
}
.hud-report-btn {
border: 1px solid rgba(245, 158, 11, 0.5);
background: rgba(245, 158, 11, 0.18);
color: #fcd34d;
font-weight: 600;
font-size: 0.82rem;
transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.hud-report-btn:hover:not(:disabled),
.hud-report-btn:focus-visible:not(:disabled) {
background: rgba(245, 158, 11, 0.28);
border-color: rgba(245, 158, 11, 0.7);
color: #fde68a;
outline: none;
}
.hud-report-btn:disabled {
opacity: 0.6;
cursor: progress;
}
.pm-page[data-theme="light"] .hud-report-btn {
background: rgba(180, 83, 9, 0.12);
border-color: rgba(180, 83, 9, 0.4);
color: #92400e;
}
.bridge-badge {
display: inline-flex;
align-items: center;