Updated adsb + ais popups to include images

This commit is contained in:
2026-07-03 13:15:19 -04:00
parent 91205d8050
commit bbcc62af7d
3 changed files with 79 additions and 12 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
const BASE_SPEED_UNITS = {
knots: { label: 'KTS', convert: (v: number) => Math.round(v) },
@@ -48,6 +48,23 @@ const climbVal = computed(() => { const v = vertical.value.convert(props.plan
const description = computed(() => props.plane.desc || [props.plane.manufacturer, props.plane.model].filter(Boolean).join(' ') || '')
const operator = computed(() => props.plane.operator || props.plane.owner || '')
// ── Aircraft photo ────────────────────────────────────────────────────────────
const photoUrl = ref<string | null>(null)
const photoLoading = ref(false)
async function fetchPhoto(icao: string) {
photoUrl.value = null
if (!icao) return
photoLoading.value = true
const res = await fetch(`https://api.planespotters.net/pub/photos/hex/${icao.toLowerCase()}`)
const data = await res.json()
const photo = data?.photos?.[0]
if (photo) photoUrl.value = photo.thumbnail_large?.src ?? photo.thumbnail?.src ?? null
photoLoading.value = false
}
watch(() => props.plane.icao || props.plane.hex, (icao) => fetchPhoto(icao), { immediate: true })
// ── Drag ──────────────────────────────────────────────────────────────────────
const pos = ref({ ...props.position })
const isDragging = ref(false)
@@ -203,7 +220,7 @@ const navball = computed(() => {
<button class="ap-close" @click.stop="emit('close')">×</button>
</div>
<!-- Body -->
<!-- Meta -->
<div class="ap-meta flex-r justify-between">
<div class="flex-c">
<span>{{ operator || 'Unknown Owner' }}</span>
@@ -214,6 +231,13 @@ const navball = computed(() => {
<span style="text-transform: capitalize">{{ plane.class || 'Unknown' }} {{ plane.type || 'Unknown' }}</span>
</div>
</div>
<!-- Photo -->
<div v-if="photoUrl" class="ap-photo-wrap">
<img class="ap-photo" :src="photoUrl" :alt="callsign" />
</div>
<!-- Body -->
<div class="ap-body">
<div class="ap-gauges">
<div class="ap-gauge-wrap">
@@ -309,6 +333,24 @@ const navball = computed(() => {
}
.ap-close:hover { background: rgba(255,255,255,0.35); }
/* ── Photo ── */
.ap-photo-wrap {
width: 100%;
height: 160px;
background: #111;
border-bottom: 1px solid rgba(200,200,220,0.15);
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.ap-photo {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.ap-body {
display: flex;
gap: 16px;