mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-01 06:06:05 +08:00
feat(live-atc): add TextInputPanel, LastTransmissionCard, CommLogRail
Moves the last three inline cockpit blocks out of the page into components, re-skinned onto the navy/instrument-panel language the rest of the cockpit already uses (the v-card bg-white/5 glass treatment is gone). LastTransmissionCard collapses the old four-button row (Mark as faulty / Edit issue / Reset / Delete) to two icon buttons, per the design doc. Nothing is lost: "Reset" was a duplicate of the issue dialog's own "Remove flag" action, so the amber flag icon opens that dialog and a plain × dismisses the card. resetLastTransmissionFault therefore has no caller left on the page. CommLogRail wraps the readback-check block plus CommLog for the desktop rail; the .pm-readback-* styles move with it. The mobile Log tab keeps using CommLog directly, as the design doc specifies. Verified by rendering all three on a throwaway route with fake data: the suggestion chip fills the text field through v-model, the flag button flips the card into its faulty skin, and the readback rows render matched/missing. Typecheck clean, 167/167 tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
89
app/components/live-atc/cockpit/CommLogRail.vue
Normal file
89
app/components/live-atc/cockpit/CommLogRail.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<script setup lang="ts">
|
||||
import type { ReadbackFieldDetail } from '~/composables/useRadioBackend'
|
||||
|
||||
withDefaults(defineProps<{
|
||||
log: readonly any[]
|
||||
/** Per-field STT readback breakdown for the last pilot call; empty hides the block. */
|
||||
readbackReport: readonly ReadbackFieldDetail[]
|
||||
readbackTranscript: string
|
||||
limit?: number
|
||||
dense?: boolean
|
||||
}>(), {
|
||||
limit: 30,
|
||||
dense: true,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{ (e: 'clear'): void }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rail">
|
||||
<!-- STT readback check: what was recognised vs missing in the last call. -->
|
||||
<div v-if="readbackReport.length" class="pm-readback-check">
|
||||
<div class="pm-readback-head">
|
||||
<v-icon size="15">mdi-magnify-scan</v-icon>
|
||||
<span>Readback check</span>
|
||||
</div>
|
||||
<p v-if="readbackTranscript" class="pm-readback-heard">heard: “{{ readbackTranscript }}”</p>
|
||||
<div
|
||||
v-for="r in readbackReport"
|
||||
:key="r.field"
|
||||
class="pm-readback-row"
|
||||
:class="r.matched ? 'is-ok' : 'is-missing'"
|
||||
>
|
||||
<v-icon size="13">{{ r.matched ? 'mdi-check-circle' : 'mdi-close-circle' }}</v-icon>
|
||||
<span class="pm-readback-text">
|
||||
<span class="pm-readback-field">{{ r.field }}</span>
|
||||
= <span class="pm-readback-expected">{{ r.expected || '—' }}</span>
|
||||
<template v-if="r.matched"> → “{{ r.matched_via }}”</template>
|
||||
<template v-else>
|
||||
→ not recognised<span v-if="r.accepted_forms.length" class="pm-readback-forms">
|
||||
(say: {{ r.accepted_forms.join(' / ') }})</span>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CommLog :entries="log" :limit="limit" :dense="dense" @clear="emit('clear')" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pm-readback-check {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: color-mix(in srgb, var(--text) 4%, transparent);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
.pm-readback-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: color-mix(in srgb, var(--text) 55%, transparent);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.pm-readback-heard {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
color: color-mix(in srgb, var(--text) 50%, transparent);
|
||||
margin-bottom: 6px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.pm-readback-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.pm-readback-row.is-ok { color: #6ee7a8; }
|
||||
.pm-readback-row.is-missing { color: #fca5a5; }
|
||||
.pm-readback-field { color: var(--t2); }
|
||||
.pm-readback-expected { color: var(--text); font-weight: 600; }
|
||||
.pm-readback-forms { color: var(--t4); }
|
||||
</style>
|
||||
172
app/components/live-atc/cockpit/LastTransmissionCard.vue
Normal file
172
app/components/live-atc/cockpit/LastTransmissionCard.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
/** The transcribed (or typed) text of the pilot's last transmission. */
|
||||
text: string
|
||||
faulty: boolean
|
||||
faultNote: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'flag-issue'): void
|
||||
(e: 'clear'): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="ltx" :class="{ 'is-faulty': faulty }" aria-label="Last transmission">
|
||||
<header class="ltx__head">
|
||||
<v-icon size="14" class="ltx__icon">mdi-microphone-outline</v-icon>
|
||||
<span class="ltx__title">Last transmission</span>
|
||||
<span v-if="faulty" class="ltx__badge">Faulty</span>
|
||||
|
||||
<div class="ltx__actions">
|
||||
<!-- One entry point instead of the old four-button row: the issue dialog
|
||||
itself carries "Remove flag", so a dedicated reset button was dead weight. -->
|
||||
<v-tooltip :text="faulty ? 'Edit issue' : 'Mark as faulty'" location="top">
|
||||
<template #activator="{ props: tip }">
|
||||
<button
|
||||
v-bind="tip"
|
||||
type="button"
|
||||
class="ltx__btn ltx__btn--flag"
|
||||
:aria-label="faulty ? 'Edit issue' : 'Mark as faulty'"
|
||||
@click="emit('flag-issue')"
|
||||
>
|
||||
<v-icon size="16">mdi-alert-circle-outline</v-icon>
|
||||
</button>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
<v-tooltip text="Dismiss" location="top">
|
||||
<template #activator="{ props: tip }">
|
||||
<button
|
||||
v-bind="tip"
|
||||
type="button"
|
||||
class="ltx__btn"
|
||||
aria-label="Dismiss last transmission"
|
||||
@click="emit('clear')"
|
||||
>
|
||||
<v-icon size="16">mdi-close</v-icon>
|
||||
</button>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<p class="ltx__text">{{ text }}</p>
|
||||
|
||||
<p v-if="faulty" class="ltx__note">
|
||||
{{ faultNote || 'Marked as faulty.' }}
|
||||
</p>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ltx {
|
||||
border-radius: 18px;
|
||||
border: 1px solid rgba(34, 211, 238, 0.24);
|
||||
background: rgba(34, 211, 238, 0.07);
|
||||
padding: 12px 14px 14px;
|
||||
}
|
||||
|
||||
.ltx.is-faulty {
|
||||
border-color: rgba(248, 113, 113, 0.32);
|
||||
background: rgba(248, 113, 113, 0.08);
|
||||
}
|
||||
|
||||
.ltx__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ltx__icon,
|
||||
.ltx__title {
|
||||
color: #67e8f9;
|
||||
}
|
||||
|
||||
.ltx.is-faulty .ltx__icon,
|
||||
.ltx.is-faulty .ltx__title {
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
.ltx__title {
|
||||
font-size: 9.5px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.24em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.ltx__badge {
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: #2b0606;
|
||||
background: #f87171;
|
||||
border-radius: 999px;
|
||||
padding: 2px 7px;
|
||||
}
|
||||
|
||||
.ltx__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.ltx__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 9px;
|
||||
border: 1px solid transparent;
|
||||
color: var(--t3);
|
||||
background: transparent;
|
||||
transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
|
||||
}
|
||||
|
||||
.ltx__btn:hover {
|
||||
color: var(--text);
|
||||
background: color-mix(in srgb, var(--text) 8%, transparent);
|
||||
}
|
||||
|
||||
.ltx__btn--flag {
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
.ltx__btn--flag:hover {
|
||||
color: #fcd34d;
|
||||
border-color: rgba(251, 191, 36, 0.4);
|
||||
background: rgba(251, 191, 36, 0.12);
|
||||
}
|
||||
|
||||
.ltx.is-faulty .ltx__btn--flag {
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
.ltx.is-faulty .ltx__btn--flag:hover {
|
||||
color: #fecaca;
|
||||
border-color: rgba(248, 113, 113, 0.45);
|
||||
background: rgba(248, 113, 113, 0.14);
|
||||
}
|
||||
|
||||
.ltx__text {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
white-space: pre-line;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.ltx__note {
|
||||
margin-top: 10px;
|
||||
padding: 7px 10px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(248, 113, 113, 0.28);
|
||||
background: rgba(248, 113, 113, 0.1);
|
||||
font-size: 12px;
|
||||
color: #fecaca;
|
||||
}
|
||||
</style>
|
||||
109
app/components/live-atc/cockpit/TextInputPanel.vue
Normal file
109
app/components/live-atc/cockpit/TextInputPanel.vue
Normal file
@@ -0,0 +1,109 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
activeFrequency: string
|
||||
/** The phrase the backend expects next; offered as a one-tap fill. */
|
||||
expectedPhrase: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{ (e: 'send'): void }>()
|
||||
|
||||
const pilotInput = defineModel<string>({ required: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="txt" aria-label="Text transmission">
|
||||
<header class="txt__head">
|
||||
<span class="txt__title">Text input</span>
|
||||
<span class="txt__freq">{{ activeFrequency || '---.---' }}</span>
|
||||
</header>
|
||||
|
||||
<v-text-field
|
||||
v-model="pilotInput"
|
||||
label="Pilot transmission"
|
||||
variant="outlined"
|
||||
color="cyan"
|
||||
density="comfortable"
|
||||
hide-details
|
||||
append-inner-icon="mdi-send"
|
||||
@keyup.enter="emit('send')"
|
||||
@click:append-inner="emit('send')"
|
||||
/>
|
||||
|
||||
<div v-if="expectedPhrase" class="txt__suggest">
|
||||
<span class="txt__suggest-label">Suggested phrase</span>
|
||||
<button type="button" class="txt__suggest-chip" @click="pilotInput = expectedPhrase">
|
||||
{{ expectedPhrase }}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.txt {
|
||||
border-radius: 18px;
|
||||
border: 1px solid var(--border);
|
||||
background:
|
||||
linear-gradient(165deg,
|
||||
color-mix(in srgb, var(--bg2) 90%, transparent),
|
||||
color-mix(in srgb, var(--bg) 96%, transparent));
|
||||
box-shadow:
|
||||
inset 0 1px 0 color-mix(in srgb, var(--text) 6%, transparent),
|
||||
0 20px 44px -28px rgba(0, 0, 0, 0.9);
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
.txt__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.txt__title {
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.24em;
|
||||
text-transform: uppercase;
|
||||
color: var(--t4);
|
||||
}
|
||||
|
||||
.txt__freq {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
font-size: 12px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: #67e8f9;
|
||||
}
|
||||
|
||||
.txt__suggest {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.txt__suggest-label {
|
||||
font-size: 9.5px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.24em;
|
||||
text-transform: uppercase;
|
||||
color: var(--t4);
|
||||
}
|
||||
|
||||
.txt__suggest-chip {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
font-size: 12px;
|
||||
color: #67e8f9;
|
||||
border: 1px solid rgba(34, 211, 238, 0.35);
|
||||
background: rgba(34, 211, 238, 0.08);
|
||||
border-radius: 999px;
|
||||
padding: 4px 12px;
|
||||
text-align: left;
|
||||
transition: background 130ms ease, border-color 130ms ease;
|
||||
}
|
||||
|
||||
.txt__suggest-chip:hover {
|
||||
background: rgba(34, 211, 238, 0.16);
|
||||
border-color: rgba(34, 211, 238, 0.5);
|
||||
}
|
||||
</style>
|
||||
@@ -305,39 +305,12 @@
|
||||
|
||||
<!-- Manual text input (text mode) -->
|
||||
<div v-show="activeTab === 'funk' && inputMode === 'text'" class="pm-block">
|
||||
<v-card class="bg-white/5 border border-white/10">
|
||||
<v-card-text class="space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-lg font-semibold">Text Input</h3>
|
||||
<v-chip size="small" color="cyan" variant="outlined" class="font-mono">{{ frequencies.active || '---' }}</v-chip>
|
||||
</div>
|
||||
<v-text-field
|
||||
v-model="pilotInput"
|
||||
label="Pilot Transmission (Text)"
|
||||
variant="outlined"
|
||||
color="cyan"
|
||||
hide-details
|
||||
@keyup.enter="sendPilotText"
|
||||
append-inner-icon="mdi-send"
|
||||
@click:append-inner="sendPilotText"
|
||||
/>
|
||||
|
||||
<div v-if="backendExpectedPhrase" class="space-y-1">
|
||||
<p class="text-[11px] uppercase tracking-[0.25em] text-white/40">Suggested phrase</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<v-chip
|
||||
size="small"
|
||||
color="cyan"
|
||||
variant="outlined"
|
||||
class="cursor-pointer text-xs font-mono"
|
||||
@click="pilotInput = backendExpectedPhrase"
|
||||
>
|
||||
{{ backendExpectedPhrase }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<TextInputPanel
|
||||
v-model="pilotInput"
|
||||
:active-frequency="frequencies.active"
|
||||
:expected-phrase="backendExpectedPhrase"
|
||||
@send="sendPilotText"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Last Transmission (funk) -->
|
||||
@@ -346,92 +319,13 @@
|
||||
v-if="lastTransmission"
|
||||
class="pm-block"
|
||||
>
|
||||
<v-card
|
||||
:class="[
|
||||
'border backdrop-blur',
|
||||
lastTransmissionFaulty
|
||||
? 'bg-red-500/10 border-red-400/30'
|
||||
: 'bg-cyan-500/10 border-cyan-400/20'
|
||||
]"
|
||||
>
|
||||
<v-card-text class="space-y-3">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<v-icon
|
||||
icon="mdi-microphone-outline"
|
||||
size="16"
|
||||
:class="lastTransmissionFaulty ? 'text-red-300' : 'text-cyan-300'"
|
||||
/>
|
||||
<span
|
||||
class="text-xs uppercase tracking-[0.3em]"
|
||||
:class="lastTransmissionFaulty ? 'text-red-300' : 'text-cyan-300'"
|
||||
>
|
||||
Last transmission
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-1">
|
||||
<v-chip
|
||||
v-if="lastTransmissionFaulty"
|
||||
size="x-small"
|
||||
color="red"
|
||||
variant="flat"
|
||||
>
|
||||
Faulty
|
||||
</v-chip>
|
||||
<v-btn
|
||||
variant="text"
|
||||
size="small"
|
||||
:color="lastTransmissionFaulty ? 'red' : 'amber'"
|
||||
class="text-[0.65rem] uppercase tracking-[0.3em]"
|
||||
@click="startTransmissionIssueFlow"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon size="16">mdi-alert-circle-outline</v-icon>
|
||||
</template>
|
||||
{{ lastTransmissionFaulty ? 'Edit issue' : 'Mark as faulty' }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="lastTransmissionFaulty"
|
||||
variant="text"
|
||||
size="small"
|
||||
color="cyan"
|
||||
class="text-[0.65rem] uppercase tracking-[0.3em]"
|
||||
@click="resetLastTransmissionFault"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon size="16">mdi-restore</v-icon>
|
||||
</template>
|
||||
Reset
|
||||
</v-btn>
|
||||
<v-btn
|
||||
variant="text"
|
||||
size="small"
|
||||
color="cyan"
|
||||
class="text-[0.65rem] uppercase tracking-[0.3em]"
|
||||
@click="clearLastTransmission"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon size="16">mdi-close</v-icon>
|
||||
</template>
|
||||
Delete
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-white font-mono whitespace-pre-line">{{ lastTransmission }}</p>
|
||||
<div
|
||||
v-if="lastTransmissionFaulty"
|
||||
class="space-y-2 rounded-xl border border-red-400/30 bg-red-500/10 px-3 py-2"
|
||||
>
|
||||
<p class="text-xs uppercase tracking-[0.25em] text-red-200/80">Issue description</p>
|
||||
<p v-if="lastTransmissionFaultNote" class="text-sm text-red-100">
|
||||
{{ lastTransmissionFaultNote }}
|
||||
</p>
|
||||
<p v-else class="text-xs text-red-200/70">
|
||||
Marked as faulty.
|
||||
</p>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<LastTransmissionCard
|
||||
:text="lastTransmission"
|
||||
:faulty="lastTransmissionFaulty"
|
||||
:fault-note="lastTransmissionFaultNote"
|
||||
@flag-issue="startTransmissionIssueFlow"
|
||||
@clear="clearLastTransmission"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- =============== LOG TAB (mobile only) =============== -->
|
||||
@@ -444,32 +338,12 @@
|
||||
|
||||
<!-- Desktop log rail -->
|
||||
<aside class="pm-lograil">
|
||||
<!-- STT readback check: what was recognised vs missing in the last call. -->
|
||||
<div v-if="lastReadbackReport.length" class="pm-readback-check">
|
||||
<div class="pm-readback-head">
|
||||
<v-icon size="15">mdi-magnify-scan</v-icon>
|
||||
<span>Readback check</span>
|
||||
</div>
|
||||
<p v-if="lastReadbackTranscript" class="pm-readback-heard">heard: “{{ lastReadbackTranscript }}”</p>
|
||||
<div
|
||||
v-for="r in lastReadbackReport"
|
||||
:key="r.field"
|
||||
class="pm-readback-row"
|
||||
:class="r.matched ? 'is-ok' : 'is-missing'"
|
||||
>
|
||||
<v-icon size="13">{{ r.matched ? 'mdi-check-circle' : 'mdi-close-circle' }}</v-icon>
|
||||
<span class="pm-readback-text">
|
||||
<span class="pm-readback-field">{{ r.field }}</span>
|
||||
= <span class="pm-readback-expected">{{ r.expected || '—' }}</span>
|
||||
<template v-if="r.matched"> → “{{ r.matched_via }}”</template>
|
||||
<template v-else>
|
||||
→ not recognised<span v-if="r.accepted_forms.length" class="pm-readback-forms">
|
||||
(say: {{ r.accepted_forms.join(' / ') }})</span>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<CommLog :entries="log" :limit="30" dense @clear="clearLog" />
|
||||
<CommLogRail
|
||||
:log="log"
|
||||
:readback-report="lastReadbackReport"
|
||||
:readback-transcript="lastReadbackTranscript"
|
||||
@clear="clearLog"
|
||||
/>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
@@ -608,6 +482,9 @@ import { useFrequencyPresets } from '~/composables/useFrequencyPresets'
|
||||
import RadioPanel from '~/components/live-atc/cockpit/RadioPanel.vue'
|
||||
import ExpectedCommStrip from '~/components/live-atc/cockpit/ExpectedCommStrip.vue'
|
||||
import PttPad from '~/components/live-atc/cockpit/PttPad.vue'
|
||||
import TextInputPanel from '~/components/live-atc/cockpit/TextInputPanel.vue'
|
||||
import LastTransmissionCard from '~/components/live-atc/cockpit/LastTransmissionCard.vue'
|
||||
import CommLogRail from '~/components/live-atc/cockpit/CommLogRail.vue'
|
||||
import { useAtisPlayback } from '~/composables/useAtisPlayback'
|
||||
import { usePttRecording } from '~/composables/usePttRecording'
|
||||
import { useBugReport } from '~/composables/useBugReport'
|
||||
@@ -750,7 +627,6 @@ const {
|
||||
transmissionIssueNote,
|
||||
setLastTransmission,
|
||||
clearLastTransmission,
|
||||
resetLastTransmissionFault,
|
||||
startTransmissionIssueFlow,
|
||||
confirmTransmissionIssue,
|
||||
removeTransmissionIssue,
|
||||
@@ -1564,44 +1440,6 @@ onUnmounted(() => {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pm-readback-check {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: color-mix(in srgb, var(--text) 4%, transparent);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
.pm-readback-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .12em;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: color-mix(in srgb, var(--text) 55%, transparent);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.pm-readback-heard {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
color: color-mix(in srgb, var(--text) 50%, transparent);
|
||||
margin-bottom: 6px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.pm-readback-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.pm-readback-row.is-ok { color: #6ee7a8; }
|
||||
.pm-readback-row.is-missing { color: #fca5a5; }
|
||||
.pm-readback-field { color: var(--t2); }
|
||||
.pm-readback-expected { color: var(--text); font-weight: 600; }
|
||||
.pm-readback-forms { color: var(--t4); }
|
||||
|
||||
/* Setup screens sit above the shared radar backdrop. */
|
||||
.pm-setup {
|
||||
position: relative;
|
||||
|
||||
Reference in New Issue
Block a user