diff --git a/app/pages/classroom.vue b/app/pages/classroom.vue index 6119d3b..269e473 100644 --- a/app/pages/classroom.vue +++ b/app/pages/classroom.vue @@ -1017,30 +1017,37 @@ -
-
- mdi-shield-check-outline - {{ activeLesson.standard }} +
+
+ mdi-card-account-details-outline + Use these values
-
- mdi-information-outline - {{ activeLesson.whyItMatters }} -
-
- mdi-lightbulb-on-outline - {{ hint }} -
-
- mdi-information-outline - {{ info }} +
+
+ {{ entry.label }} + {{ entry.value }} + {{ entry.note }} +
-
+
+ mdi-lightbulb-on-outline +
+ Response pattern + {{ primaryLessonHint }} +
+
+
-
-
- {{ entry.label }} - {{ entry.value }} +
+
+ mdi-shield-check-outline + {{ activeLesson.standard }} +
+

{{ activeLesson.whyItMatters }}

+
    +
  • {{ note }}
  • +
+
+
+ {{ entry.label }} + {{ entry.value }} +
@@ -3348,6 +3369,54 @@ const clozeGroups = computed(() => { const lessonInfo = computed(() => (activeLesson.value && scenario.value ? activeLesson.value.info(scenario.value) : [])) +type LessonValue = { + label: string + value: string + note?: string + isCallsign?: boolean +} + +function splitLessonInfo(info: string): { label: string; value: string } | null { + const separator = info.indexOf(':') + if (separator <= 0) return null + const label = info.slice(0, separator).trim() + const value = info.slice(separator + 1).trim() + if (!label || !value || value.length > 80) return null + return { label, value } +} + +const lessonHasCallsign = computed(() => Boolean(activeLesson.value?.fields.some(field => + field.label.trim().toLowerCase() === 'callsign' || field.key.toLowerCase().includes('callsign') +))) + +const lessonEssentialValues = computed(() => { + if (!activeLesson.value || !scenario.value) return [] + const entries: LessonValue[] = [] + if (lessonHasCallsign.value) { + entries.push({ + label: 'Your callsign', + value: scenario.value.radioCall, + note: `Flight ID ${scenario.value.callsign}`, + isCallsign: true, + }) + } + for (const info of lessonInfo.value) { + const parsed = splitLessonInfo(info) + if (!parsed || entries.some(entry => entry.label.toLowerCase() === parsed.label.toLowerCase())) continue + entries.push(parsed) + } + return entries +}) + +const primaryLessonHint = computed(() => activeLesson.value?.hints[0] ?? '') + +const additionalLessonNotes = computed(() => { + if (!activeLesson.value) return [] + const extraHints = activeLesson.value.hints.slice(1) + const additionalInfo = lessonInfo.value.filter(info => !splitLessonInfo(info)) + return Array.from(new Set([...extraHints, ...additionalInfo])) +}) + const lessonReference = computed(() => { if (!activeLesson.value || !scenario.value) return [] const lesson = activeLesson.value @@ -3386,6 +3455,23 @@ const lessonReference = computed(() => { } return entries }) + +const lessonReferenceDetails = computed(() => { + const visibleLabels = new Set( + lessonEssentialValues.value.map(entry => entry.label.replace(/\s*ยท.*$/, '').trim().toLowerCase()) + ) + return lessonReference.value.filter(entry => { + const label = entry.label.trim().toLowerCase() + return !visibleLabels.has(label) && !['callsign', 'radio call', 'flight identification'].includes(label) + }) +}) + +const hasLessonDetails = computed(() => Boolean( + activeLesson.value?.standard + || activeLesson.value?.whyItMatters + || additionalLessonNotes.value.length + || lessonReferenceDetails.value.length +)) const showScenarioPracticeHint = computed(() => { if (!current.value || !activeLesson.value) return false const index = modules.value.findIndex(module => module.id === current.value?.id) @@ -3558,6 +3644,7 @@ const previousActionLabel = computed(() => { const hasPreviousAction = computed(() => Boolean(prevLessonMeta.value || prevMissionMeta.value)) watch(activeLesson, lesson => { + referenceOpen.value = false if (lesson) { if (moduleStage.value === 'lessons') { rollScenario(true) @@ -6751,10 +6838,107 @@ onMounted(() => { color: color-mix(in srgb, var(--accent) 78%, var(--text)); } +.lesson-values { + margin-top: 14px; +} + +.lesson-values-title { + display: flex; + align-items: center; + gap: 7px; + margin-bottom: 7px; + color: color-mix(in srgb, var(--accent) 82%, var(--text)); + font-size: 11px; + font-weight: 750; + letter-spacing: .1em; + text-transform: uppercase; +} + +.lesson-values-grid { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.lesson-value { + flex: 0 1 auto; + min-width: 0; + padding: 7px 10px; + border: 1px solid color-mix(in srgb, var(--text) 10%, transparent); + border-radius: 10px; + background: color-mix(in srgb, var(--text) 6%, transparent); +} + +.lesson-value span, +.lesson-value strong, +.lesson-value small { + display: block; +} + +.lesson-value span { + margin-bottom: 3px; + color: var(--t3); + font-size: 10px; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; +} + +.lesson-value strong { + overflow-wrap: anywhere; + color: var(--text); + font-size: 14px; + line-height: 1.3; +} + +.lesson-value small { + margin-top: 3px; + color: var(--t3); + font-size: 10px; + line-height: 1.35; +} + +.lesson-value.is-callsign { + flex: 1 1 185px; + max-width: 260px; + border: 1px solid color-mix(in srgb, var(--accent) 24%, transparent); + background: color-mix(in srgb, var(--accent) 11%, transparent); +} + +.lesson-guidance { + display: flex; + align-items: flex-start; + gap: 9px; + margin-top: 10px; + padding: 10px 12px; + color: var(--t2); + font-size: 12px; + line-height: 1.45; +} + +.lesson-guidance .v-icon { + flex: 0 0 auto; + margin-top: 1px; + color: var(--accent); +} + +.lesson-guidance strong, +.lesson-guidance span { + display: block; +} + +.lesson-guidance strong { + margin-bottom: 2px; + color: var(--text); + font-size: 11px; + letter-spacing: .06em; + text-transform: uppercase; +} + .reference-section { - margin-top: 8px; + margin-top: 2px; border-top: 1px solid var(--b2, rgba(255, 255, 255, 0.08)); - padding-top: 6px; + padding-top: 8px; } .reference-toggle { @@ -6789,6 +6973,10 @@ onMounted(() => { line-height: 1.6; } +.reference-row { + display: contents; +} + .reference-label { color: var(--t2, rgba(255, 255, 255, 0.6)); white-space: nowrap; @@ -6799,6 +6987,44 @@ onMounted(() => { font-family: var(--font-mono, monospace); } +.lesson-details { + padding: 8px 0 4px 20px; + color: var(--t2); + font-size: 12px; + line-height: 1.55; +} + +.lesson-details p { + margin: 7px 0; +} + +.lesson-details ul { + margin: 7px 0; + padding-left: 18px; +} + +.lesson-detail-standard { + display: flex; + align-items: flex-start; + gap: 6px; + color: color-mix(in srgb, var(--accent) 78%, var(--text)); +} + +@media (max-width: 640px) { + .lesson-values-grid { + gap: 6px; + } + + .lesson-value.is-callsign { + flex-basis: 100%; + max-width: none; + } + + .lesson-details { + padding-left: 0; + } +} + .audio-blur { filter: blur(8px); pointer-events: none;