From 0521d28759e8da6ea429c572e525aa78be307350 Mon Sep 17 00:00:00 2001 From: Remi <73385395+itsrubberduck@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:17:44 +0200 Subject: [PATCH] Refactor learn page modules and scenario flow --- app/pages/learn.vue | 2324 ++++++++++++++++++++++++++++++++----------- 1 file changed, 1718 insertions(+), 606 deletions(-) diff --git a/app/pages/learn.vue b/app/pages/learn.vue index 23d5a05..899b4fe 100644 --- a/app/pages/learn.vue +++ b/app/pages/learn.vue @@ -159,7 +159,7 @@ v-for="l in current.lessons" :key="l.id" class="lesson" - :class="{ active: activeLesson?.id===l.id, ok: bestScore(current.id,l.id)>=80 }" + :class="{ active: activeLesson && activeLesson.id===l.id, ok: bestScore(current.id,l.id)>=80 }" @click="selectLesson(l)" >
@@ -179,181 +179,123 @@
+
+
+ Callsign +
{{ scenario.callsign }}
+
{{ scenario.radioCall }}
+
+
+ Flugplatz +
{{ scenario.airport.icao }}
+
{{ scenario.airport.name }}
+
+
+ Frequenzen +
+ +
+
+ {{ scenario.frequencyWords[activeFrequency.type] }} +
+
+
+
-
Zielphrase
+
Briefing
- {{ activeLesson.target }} -
- -
-
+
mdi-lightbulb-on-outline - {{ h }} + {{ hint }} +
+
+ mdi-information-outline + {{ info }}
- -
+
Deine Readback
- - -
- -
- - - - - -
-
-
- - {{ - tts.isRecording.value ? 'mdi-record-rec' : tts.isLoading.value ? 'mdi-loading mdi-spin' : 'mdi-microphone' - }} - -
-
- {{ - tts.isRecording.value ? 'Aufnahme läuft...' : - tts.isLoading.value ? 'Verarbeitung...' : - 'Bereit für Aufnahme' - }} -
-
- - - - - -
-
Ihr Readback:
-
{{ lastTranscription }}
+
+
+
- - -
- - - - -
- -
{{ result.score }}%
- - Keywords: {{ result.hits }}/{{ activeLesson.keywords.length }} · Ähnlichkeit: {{ - Math.round(result.sim * 100) - }}% - - - Genauigkeit: {{ Math.round(result.evaluation.accuracy * 100) }}% · - Keywords: {{ result.evaluation.keywordMatch * 100 }}% - -
- - -
- -
- Verbesserungen: -
    -
  • {{ mistake }}
  • -
-
-
- mdi-repeat - Funkspruch wird wiederholt... -
+ Felder korrekt: {{ result.hits }}/{{ activeLesson.fields.length }} · Ähnlichkeit: {{ Math.round(result.sim * 100) }}%
- - -
- mdi-alert - {{ tts.error.value }} -
-
-
-
Deine Readback
- -
- - -
- -
-
{{ result.score }}%
-
- Keywords: {{ result.hits }}/{{ activeLesson.keywords.length }} · Ähnlichkeit: - {{ Math.round(result.sim * 100) }}% +
+
+
{{ field.label }}
+
{{ field.answer || '—' }}
+
Soll: {{ field.expected }}
@@ -403,7 +345,7 @@
Probe-TTS
- @@ -431,130 +373,1413 @@ @@ -1319,157 +2361,227 @@ onMounted(() => { } -/* PTT-spezifische Styles */ -.ptt-toggle { - margin-bottom: 12px; -} - -.ptt-toggle .btn.active { - background: color-mix(in srgb, var(--accent) 20%, transparent); - border-color: var(--accent); -} - -.ptt-interface { +/* Scenario bar & cloze */ +.scenario-bar { + grid-column: 1 / -1; + display: flex; + flex-wrap: wrap; + gap: 12px; + padding: 12px; border: 1px solid var(--border); background: color-mix(in srgb, var(--text) 6%, transparent); - padding: 16px; - border-radius: 8px; + border-radius: 12px; margin-bottom: 12px; } -.ptt-status { - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 16px; -} - -.status-indicator { - width: 40px; - height: 40px; - border: 2px solid var(--border); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.3s ease; -} - -.status-indicator.recording { - border-color: #f44336; - background: color-mix(in srgb, #f44336 20%, transparent); - animation: pulse 1s infinite; -} - -.status-indicator.processing { - border-color: var(--accent); - background: color-mix(in srgb, var(--accent) 20%, transparent); -} - -@keyframes pulse { - 0%, 100% { transform: scale(1); } - 50% { transform: scale(1.1); } -} - -.status-text { - font-size: 14px; - color: var(--t2); -} - -.btn-ptt { - width: 100%; - padding: 20px; - border: 2px solid var(--border); - background: color-mix(in srgb, var(--text) 8%, transparent); - color: var(--text); - border-radius: 12px; +.scenario-item { + min-width: 180px; + border: 1px solid var(--border); + background: color-mix(in srgb, var(--text) 4%, transparent); + padding: 10px 12px; + border-radius: 10px; display: flex; flex-direction: column; - align-items: center; - gap: 8px; - cursor: pointer; - transition: all 0.2s ease; - user-select: none; + gap: 4px; } -.btn-ptt:hover:not(.disabled) { - background: color-mix(in srgb, var(--text) 12%, transparent); - transform: translateY(-2px); +.scenario-item.wide { + flex: 1 1 260px; } -.btn-ptt.recording { - border-color: #f44336; - background: color-mix(in srgb, #f44336 15%, transparent); - animation: pulse 1s infinite; -} - -.btn-ptt.disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.transcription { - margin-top: 16px; - padding: 12px; - background: color-mix(in srgb, var(--accent) 5%, transparent); - border: 1px dashed color-mix(in srgb, var(--accent) 30%, transparent); - border-radius: 6px; -} - -.transcription-label { - font-size: 12px; +.scenario-label { + font-size: 11px; + letter-spacing: .08em; color: var(--t3); + text-transform: uppercase; +} + +.scenario-value { + font-size: 18px; + font-weight: 600; +} + +.scenario-sub { + color: var(--t3); + font-size: 13px; +} + +.freq-chips { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 6px; +} + +.freq-chip { + border: 1px solid var(--border); + background: color-mix(in srgb, var(--text) 4%, transparent); + padding: 6px 10px; + font-size: 12px; + letter-spacing: .02em; +} + +.freq-chip.active { + border-color: color-mix(in srgb, var(--accent) 40%, transparent); + background: color-mix(in srgb, var(--accent) 12%, transparent); + color: var(--accent); +} + +.freq-hint { + margin-top: 4px; +} + +.target-main { + display: flex; + flex-direction: column; + gap: 8px; +} + +.target-text { + font-size: 18px; + font-weight: 600; + line-height: 1.4; +} + +.row.wrap { + flex-wrap: wrap; +} + +.controls { + margin-top: 12px; +} + +.readback-panel { + padding: 16px; +} + +.cloze { + display: flex; + flex-wrap: wrap; + gap: 6px; + line-height: 1.6; +} + +.blank { + position: relative; + display: inline-flex; + flex-direction: column; + background: color-mix(in srgb, var(--text) 4%, transparent); + border: 1px solid var(--border); + border-radius: 8px; + padding: 6px 10px; + min-width: 100px; + vertical-align: middle; + transition: border-color .2s ease, background .2s ease; +} + +.blank input { + background: transparent; + border: 0; + color: var(--text); + min-width: 60px; + font-size: 14px; + outline: none; +} + +.blank.size-xs { min-width: 70px; } +.blank.size-sm { min-width: 100px; } +.blank.size-md { min-width: 140px; } +.blank.size-lg { min-width: 190px; } +.blank.size-xl { min-width: 240px; } + +.blank.ok { + border-color: color-mix(in srgb, var(--accent) 50%, transparent); + background: color-mix(in srgb, var(--accent) 10%, transparent); +} + +.blank.warn { + border-color: color-mix(in srgb, #f97316 40%, transparent); +} + +.blank-status { + position: absolute; + top: 6px; + right: 6px; +} + +.blank-status.ok { + color: var(--accent); +} + +.blank-status.warn { + color: #f97316; +} + +.blank-feedback { + margin-top: 4px; + font-size: 11px; + color: var(--t3); +} + +.field-checks { + margin-top: 12px; + display: grid; + gap: 8px; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); +} + +.field-check { + border: 1px dashed color-mix(in srgb, var(--text) 20%, transparent); + padding: 10px; + border-radius: 8px; + background: color-mix(in srgb, var(--text) 3%, transparent); +} + +.field-check.ok { + border-color: color-mix(in srgb, var(--accent) 40%, transparent); +} + +.field-name { + font-size: 12px; + letter-spacing: .08em; + color: var(--t3); + text-transform: uppercase; margin-bottom: 4px; } -.transcription-text { - font-weight: 500; +.field-answer { + font-weight: 600; } -.ptt-feedback { - margin-top: 12px; - padding: 12px; - background: color-mix(in srgb, var(--text) 4%, transparent); - border-radius: 6px; +.field-expected { + font-size: 12px; + color: var(--t3); } -.feedback-text { - margin-bottom: 8px; - font-style: italic; +.hint.secondary { + opacity: 0.8; } -.mistakes { - margin-top: 8px; +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; } -.mistakes ul { - margin: 4px 0 0 16px; +@media (max-width: 720px) { + .scenario-bar { + flex-direction: column; + } + + .scenario-item { + width: 100%; + } + + .target-text { + font-size: 16px; + } } -.mistakes li { - margin: 2px 0; - font-size: 13px; -} - -.replay-notice { - display: flex; - align-items: center; - gap: 6px; - margin-top: 8px; - color: var(--accent); - font-size: 13px; -} - -.error-message { - margin-top: 8px; - padding: 8px 12px; - background: color-mix(in srgb, #f44336 10%, transparent); - border: 1px solid color-mix(in srgb, #f44336 30%, transparent); - border-radius: 6px; - color: #ff6b6b; - display: flex; - align-items: center; - gap: 8px; - font-size: 13px; -}