Added Notifications
This commit is contained in:
@@ -239,7 +239,7 @@ body {
|
||||
color: #df8fdf;
|
||||
}
|
||||
|
||||
.difficulty-near-impossible-global {
|
||||
.difficulty-near_impossible-global {
|
||||
background: rgba(160, 20, 20, 0.25);
|
||||
border: 1px solid rgba(220, 60, 60, 0.3);
|
||||
color: #e87070;
|
||||
|
||||
@@ -42,18 +42,6 @@ const unlocked = computed(() => {
|
||||
return true
|
||||
})
|
||||
|
||||
const difficultyVariant = computed(() => {
|
||||
switch (props.achievement.difficulty?.internal_name) {
|
||||
case 'easy': return 'easy'
|
||||
case 'moderate': return 'moderate'
|
||||
case 'hard': return 'hard'
|
||||
case 'expensive': return 'expensive'
|
||||
case 'near_impossible': return 'near-impossible'
|
||||
case 'impossible': return 'impossible'
|
||||
default: return 'economy'
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -79,7 +67,7 @@ const difficultyVariant = computed(() => {
|
||||
<GlassTooltip>
|
||||
<template #activator="{ props: tooltipProps }">
|
||||
<span v-bind="tooltipProps" style="display:inline-flex">
|
||||
<InlineBadge type="difficulty" :variant="difficultyVariant">
|
||||
<InlineBadge type="difficulty" :variant="props.achievement.difficulty.internal_name">
|
||||
{{ achievement.difficulty?.name }}
|
||||
<v-icon icon="mdi-help-circle-outline" size="12" />
|
||||
</InlineBadge>
|
||||
@@ -87,7 +75,7 @@ const difficultyVariant = computed(() => {
|
||||
</template>
|
||||
|
||||
<div class="difficulty-tooltip">
|
||||
<InlineBadge type="difficulty" :variant="difficultyVariant">
|
||||
<InlineBadge type="difficulty" :variant="props.achievement.difficulty.internal_name">
|
||||
{{ achievement.difficulty?.name }}
|
||||
</InlineBadge>
|
||||
<p class="difficulty-description">{{ achievement.difficulty?.description }}</p>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { Aircraft } from "@/Types/types";
|
||||
import {Aircraft, Airline, Flight} from "@/Types/types";
|
||||
import GlassTooltip from "@/Components/FlightsGoneBy/GlassTooltip.vue";
|
||||
import InlineBadge from "@/Components/FlightsGoneBy/InlineBadge.vue";
|
||||
import WakeTurbulence from "@/Components/FlightsGoneBy/WakeTurbulence.vue";
|
||||
import LiveryImage from "@/Components/FlightsGoneBy/LiveryImage.vue";
|
||||
|
||||
defineProps<{
|
||||
aircraft: Aircraft
|
||||
flight?: Flight
|
||||
showTooltips?: boolean
|
||||
}>()
|
||||
|
||||
@@ -46,6 +48,11 @@ function formatEngineType(type: string): string {
|
||||
<span class="tooltip-value">{{ aircraft.engine_count }}x {{ formatEngineType(aircraft.engine_type) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tooltip-divider" v-if="flight?.livery_url" />
|
||||
<div class="tooltip-rows" v-if="flight?.livery_url">
|
||||
<LiveryImage :flight="flight" />
|
||||
</div>
|
||||
</GlassTooltip>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import {Flight, User} from "@/Types/types";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPass.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPass.vue";
|
||||
import { FlightStats } from "@/Composables/useFlightStats";
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
+12
-122
@@ -1,11 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import {Flight, SharedProps, User} from "@/Types/types";
|
||||
import AirlineLogo from "@/Components/FlightsGoneBy/AirlineLogo.vue";
|
||||
import AirportToolTip from "@/Components/FlightsGoneBy/AirportToolTip.vue";
|
||||
import AircraftToolTip from "@/Components/FlightsGoneBy/AircraftToolTip.vue";
|
||||
import Distance from "@/Components/Distance.vue";
|
||||
import UserFlightContextMenu from "@/Components/FlightsGoneBy/UserFlightContextMenu.vue";
|
||||
import {usePage} from "@inertiajs/vue3";
|
||||
import Mono from "@/Components/FlightsGoneBy/Mono.vue";
|
||||
import BoardingPassEndpoint from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPassEndpoint.vue";
|
||||
import BoardingPassStat from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPassStat.vue";
|
||||
|
||||
defineProps<{
|
||||
flight: Flight
|
||||
@@ -21,64 +22,38 @@ const page = usePage<SharedProps>().props
|
||||
<template>
|
||||
<div class="boarding-pass">
|
||||
<div class="pass-header" :class="`class-${flight.flight_class?.internal_name}-global`">
|
||||
<span v-if="flight.flight_class?.name !== 'Unspecified'" class="pass-header-class">
|
||||
<Mono v-if="flight.flight_class?.name !== 'Unspecified'" class="pass-header-class" uppercase smallest largeSpacing>
|
||||
{{ flight.flight_class?.name }}
|
||||
</span>
|
||||
</Mono>
|
||||
<span v-else></span>
|
||||
<UserFlightContextMenu v-if="user" :profile-user="user" :flight="flight" :can-edit="canEdit ?? false" referrer="boarding-passes"/>
|
||||
</div>
|
||||
|
||||
<div class="pass-body">
|
||||
<div class="pass-route">
|
||||
<div class="pass-endpoint">
|
||||
<AirportToolTip :airport="flight.departure_airport">
|
||||
<div class="pass-iata">{{ flight.departure_airport.display_code}}</div>
|
||||
</AirportToolTip>
|
||||
<div class="pass-endpoint-city">{{ flight.departure_airport.municipality }}</div>
|
||||
<div class="pass-endpoint-date">{{ flight.departure_date_display }}</div>
|
||||
<div class="pass-endpoint-time">{{ flight.departure_time_display }}</div>
|
||||
</div>
|
||||
<BoardingPassEndpoint :airport="flight.departure_airport" :date="flight.departure_date_display" :time="flight.departure_time_display" />
|
||||
|
||||
<div class="pass-centre">
|
||||
<AirlineLogo :airline="flight.airline" size="44" class="pass-logo" />
|
||||
<div class="pass-flight-number">{{ flight.flight_number }}</div>
|
||||
<Mono class="pass-flight-number">{{ flight.flight_number }}</Mono>
|
||||
<div class="pass-airline-name">{{ flight.airline?.name }}</div>
|
||||
<AircraftToolTip v-if="flight.aircraft?.designator" :aircraft="flight.aircraft">
|
||||
<div v-if="flight.aircraft?.designator" class="pass-aircraft">{{ flight.aircraft.manufacturer_code}} {{flight.aircraft.model_full_name}}</div>
|
||||
</AircraftToolTip>
|
||||
</div>
|
||||
|
||||
<div class="pass-endpoint pass-endpoint--right">
|
||||
<AirportToolTip :airport="flight.arrival_airport">
|
||||
<div class="pass-iata">{{ flight.arrival_airport.display_code}}</div>
|
||||
</AirportToolTip>
|
||||
<div class="pass-endpoint-city">{{ flight.arrival_airport.municipality }}</div>
|
||||
<div class="pass-endpoint-date">{{ flight.arrival_date_display ?? flight.departure_date_display }}</div>
|
||||
<div class="pass-endpoint-time">
|
||||
{{ flight.arrival_time_display }}
|
||||
<span v-if="flight.arrival_day_difference" class="pass-daydiff">+{{ flight.arrival_day_difference }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<BoardingPassEndpoint :dayDifference="flight.arrival_day_difference" right :airport="flight.arrival_airport" :date="flight.arrival_date_display" :time="flight.arrival_time_display" />
|
||||
</div>
|
||||
|
||||
<div v-if="flight.duration_display || flight.distance || flight.seat_number" class="pass-tear">
|
||||
<div class="pass-tear-notch pass-tear-notch--left" />
|
||||
<div class="pass-tear-notch pass-tear-notch--right" />
|
||||
<div v-if="flight.duration_display || flight.distance " class="pass-stats-row">
|
||||
<span v-if="flight.seat_number" class="pass-stat">
|
||||
<span class="pass-stat-label">SEAT</span>
|
||||
<span class="pass-stat-value">{{ flight.seat_number }}</span>
|
||||
</span>
|
||||
<BoardingPassStat v-if="flight.seat_number" label="Seat" :value="flight.seat_number" />
|
||||
<span class="pass-stat-divider" v-if="flight.duration_display && flight.distance">·</span>
|
||||
<span v-if="flight.duration_display" class="pass-stat">
|
||||
<span class="pass-stat-label">DURATION</span>
|
||||
<span class="pass-stat-value">{{ flight.duration_display }}</span>
|
||||
</span>
|
||||
<BoardingPassStat label="Duration" :value="flight.duration_display" />
|
||||
<span class="pass-stat-divider" v-if="flight.duration_display && flight.distance">·</span>
|
||||
<span v-if="flight.distance" class="pass-stat">
|
||||
<span class="pass-stat-label">DISTANCE</span>
|
||||
<span class="pass-stat-value"><Distance :unit="page.auth?.user?.distance_unit" :value="Math.round(flight.distance)" /></span>
|
||||
</span>
|
||||
<BoardingPassStat label="Distance" :value="flight.distance" isDistance />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -126,28 +101,6 @@ const page = usePage<SharedProps>().props
|
||||
.pass-tear-notch--left { left: -1.6rem; } /* bleeds into the padding */
|
||||
.pass-tear-notch--right { right: -1.6rem; }
|
||||
|
||||
.pass-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
|
||||
.pass-stat-label {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.55rem;
|
||||
letter-spacing: 0.18em;
|
||||
color: #445566;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.pass-stat-value {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.82rem;
|
||||
color: #9aa;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.pass-stat-divider {
|
||||
color: #334;
|
||||
font-size: 1rem;
|
||||
@@ -172,12 +125,7 @@ const page = usePage<SharedProps>().props
|
||||
border-bottom: 1px solid rgba(255,255,255,0.06);
|
||||
}
|
||||
|
||||
.pass-header-class {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.62rem;
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
|
||||
.pass-body {
|
||||
padding: 1.25rem 1.25rem 1rem;
|
||||
@@ -190,47 +138,6 @@ const page = usePage<SharedProps>().props
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.pass-endpoint {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.pass-endpoint--right {
|
||||
text-align: right;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.pass-iata {
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: #f0f2f5;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pass-endpoint-city {
|
||||
font-family: 'Barlow', sans-serif;
|
||||
font-size: 0.8rem;
|
||||
color: #778899;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pass-endpoint-date {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: #445566;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.pass-endpoint-time {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 1rem;
|
||||
color: #c8cdd8;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.pass-centre {
|
||||
display: flex;
|
||||
@@ -240,20 +147,10 @@ const page = usePage<SharedProps>().props
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.pass-plane-icon {
|
||||
font-size: 0.9rem;
|
||||
color: #445566;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.pass-logo { opacity: 0.9; }
|
||||
|
||||
.pass-flight-number {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
color: #e8eaf0;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.pass-airline-name {
|
||||
@@ -269,11 +166,4 @@ const page = usePage<SharedProps>().props
|
||||
letter-spacing: 0.06em;
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
.pass-daydiff {
|
||||
font-size: 0.65rem;
|
||||
color: #ffc107;
|
||||
margin-left: 0.15rem;
|
||||
vertical-align: super;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import AirportToolTip from "@/Components/FlightsGoneBy/AirportToolTip.vue";
|
||||
import Mono from "@/Components/FlightsGoneBy/Mono.vue";
|
||||
import {Airport, Flight} from "@/Types/types";
|
||||
import DayDifference from "@/Components/FlightsGoneBy/DayDifference.vue";
|
||||
|
||||
defineProps<{
|
||||
airport: Airport
|
||||
right?: boolean
|
||||
dayDifference?: number
|
||||
date: string
|
||||
time: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pass-endpoint" :class="{'pass-endpoint--right': right}">
|
||||
<AirportToolTip :airport="airport">
|
||||
<div class="pass-iata">{{ airport.display_code}}</div>
|
||||
</AirportToolTip>
|
||||
<div class="pass-endpoint-city">{{ airport.municipality }}</div>
|
||||
<Mono dark smaller>{{ date }}</Mono>
|
||||
<Mono>{{ time }}<DayDifference v-if="right" :value="dayDifference ?? 0" /></Mono>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pass-endpoint {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.pass-endpoint--right {
|
||||
text-align: right;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.pass-iata {
|
||||
font-family: 'Barlow Condensed', sans-serif;
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: #f0f2f5;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pass-endpoint-city {
|
||||
font-family: 'Barlow', sans-serif;
|
||||
font-size: 0.8rem;
|
||||
color: #778899;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import Mono from "@/Components/FlightsGoneBy/Mono.vue";
|
||||
import Distance from "@/Components/Distance.vue";
|
||||
|
||||
defineProps<{
|
||||
label: string,
|
||||
value: any
|
||||
isDistance?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="pass-stat">
|
||||
<Mono smallest dark uppercase largeSpacing>{{label}}</Mono>
|
||||
<Mono smaller muted v-if="!isDistance">{{ value?.toString() }}</Mono>
|
||||
<Mono smaller muted v-if="isDistance">
|
||||
<Distance :value="parseInt(value)" />
|
||||
</Mono>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pass-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import {computed} from "vue";
|
||||
import Mono from "@/Components/FlightsGoneBy/Mono.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
value: number
|
||||
}>()
|
||||
|
||||
const signedValue = computed(() => {
|
||||
return props.value >= 0 ? `+${props.value}` : `${props.value}`
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<sup v-if="value != 0" class="day-diff">
|
||||
<Mono>{{signedValue}}</Mono>
|
||||
</sup>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.day-diff {
|
||||
font-size: 0.65rem;
|
||||
color: #ffc107;
|
||||
margin-left: 0.15rem;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import FlightClassBadge from "@/Components/FlightsGoneBy/FlightClassBadge.vue";
|
||||
import AirlineLogo from "@/Components/FlightsGoneBy/AirlineLogo.vue";
|
||||
import {Flight, SharedProps, User} from "@/Types/types";
|
||||
import {Flight, User} from "@/Types/types";
|
||||
import { computed, ref, watch, nextTick } from "vue";
|
||||
import type { DataTableSortItem } from 'vuetify';
|
||||
import InlineBadge from "@/Components/FlightsGoneBy/InlineBadge.vue";
|
||||
import AirportToolTip from "@/Components/FlightsGoneBy/AirportToolTip.vue";
|
||||
import AircraftToolTip from "@/Components/FlightsGoneBy/AircraftToolTip.vue";
|
||||
import {FlightStats} from "@/Composables/useFlightStats";
|
||||
import CrewTooltip from "@/Components/FlightsGoneBy/CrewTooltip.vue";
|
||||
import Distance from "@/Components/Distance.vue";
|
||||
import UserFlightContextMenu from "@/Components/FlightsGoneBy/UserFlightContextMenu.vue";
|
||||
import {usePage} from "@inertiajs/vue3";
|
||||
import DepartureBoardTableRow from "@/Components/FlightsGoneBy/DepartureBoardTableRow.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
flightStats: FlightStats
|
||||
@@ -21,7 +12,6 @@ const props = defineProps<{
|
||||
flightId?: number | null
|
||||
}>()
|
||||
|
||||
|
||||
const ITEMS_PER_PAGE = 25
|
||||
|
||||
const headers = [
|
||||
@@ -65,14 +55,9 @@ const customKeySort = {
|
||||
},
|
||||
}
|
||||
|
||||
const page = usePage<SharedProps>()
|
||||
|
||||
const sortBy = ref<DataTableSortItem[]>([])
|
||||
const currentPage = ref(1)
|
||||
|
||||
const today = new Date()
|
||||
today.setHours(0, 0, 0, 0)
|
||||
|
||||
const isSorting = computed(() => sortBy.value.length > 0)
|
||||
|
||||
const upcomingFlights = computed(() =>
|
||||
@@ -117,7 +102,6 @@ watch(
|
||||
async ([id]) => {
|
||||
if (!id) return
|
||||
|
||||
// Count the flight's position among data rows (skipping group headers)
|
||||
const items = tableItems.value
|
||||
let dataIndex = 0
|
||||
let found = false
|
||||
@@ -175,92 +159,14 @@ watch(
|
||||
</template>
|
||||
|
||||
<template v-else-if="!(item as any)._groupHeader">
|
||||
<tr
|
||||
class="v-data-table__tr"
|
||||
:class="[
|
||||
(item as any)._group && !isSorting ? `group-row--${(item as any)._group}` : '',
|
||||
(item as any).id === flightId ? 'flight-row--highlighted' : '',
|
||||
]"
|
||||
:data-flight-id="(item as any).id"
|
||||
>
|
||||
<td class="v-data-table__td airline-logo-cell">
|
||||
<AirlineLogo size="32" :airline="(item as any).airline" class="airline-logo-img" />
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td flight-number-cell">
|
||||
<div class="flight-cell">
|
||||
<span class="flight-number">{{ (item as any).flight_number }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<AirportToolTip :airport="(item as Flight).departure_airport">
|
||||
<span class="iata">{{ (item as Flight).departure_airport.display_code }}</span><br/>
|
||||
</AirportToolTip>
|
||||
<span class="city-name">{{ (item as Flight).departure_airport.municipality }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<AirportToolTip :airport="(item as Flight).arrival_airport">
|
||||
<span class="iata">{{ (item as Flight).arrival_airport.display_code }}</span><br/>
|
||||
</AirportToolTip>
|
||||
<span class="city-name">{{ (item as Flight).arrival_airport.municipality }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="date-cell">{{ (item as Flight).departure_date_display }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="time-cell">{{ (item as Flight).departure_time_display }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="time-cell">{{ (item as Flight).arrival_time_display }}</span>
|
||||
<sup v-if="(item as Flight).arrival_day_difference" class="day-diff">
|
||||
+{{ (item as Flight).arrival_day_difference }}
|
||||
</sup>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="mono-tag">{{ (item as Flight).duration_display ?? '—' }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="mono-tag distance-cell">
|
||||
<Distance :unit="page.props.auth.user?.distance_unit" :value="Math.round((item as Flight).distance)" />
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<AircraftToolTip v-if="(item as any).aircraft" :aircraft="(item as any).aircraft">
|
||||
<span class="mono-tag">{{ (item as any).aircraft?.designator }}</span>
|
||||
</AircraftToolTip>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td ">
|
||||
<span class="mono-tag">
|
||||
{{(item as Flight).aircraft_registration}}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td ">
|
||||
<span class="class-cell">
|
||||
<CrewTooltip v-if="(item as Flight).flight_reason?.name == 'Crew'" :crew-type="(item as Flight).crew_type!">
|
||||
<FlightClassBadge v-if="(item as Flight).flight_class?.internal_name === 'crew'" :flight="(item as Flight)" />
|
||||
<InlineBadge v-else variant="crew">Crew</InlineBadge>
|
||||
</CrewTooltip>
|
||||
<FlightClassBadge v-if="(item as Flight).flight_reason?.name !== 'Crew' || (item as Flight).flight_class?.internal_name !== 'crew'" :flight="(item as Flight)" />
|
||||
<InlineBadge v-if="(item as Flight).seat_number" variant="economy">{{ (item as Flight).seat_number }}</InlineBadge>
|
||||
<InlineBadge v-if="(item as Flight).seat_type?.name && (item as Flight).seat_type?.name !== 'Unassigned'" variant="economy">{{ (item as Flight).seat_type?.name }}</InlineBadge>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td actions-cell">
|
||||
<UserFlightContextMenu :profile-user="user" :can-edit="canEdit" :flight="(item as Flight)" />
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<DepartureBoardTableRow
|
||||
:flight="(item as Flight)"
|
||||
:user="user"
|
||||
:can-edit="canEdit"
|
||||
:highlighted="(item as any).id === flightId"
|
||||
:group="(item as any)._group"
|
||||
:is-sorting="isSorting"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -408,95 +314,6 @@ watch(
|
||||
padding-left: 0.5rem !important;
|
||||
}
|
||||
|
||||
.airline-logo-cell {
|
||||
width: 50px !important;
|
||||
min-width: 50px !important;
|
||||
max-width: 50px !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.flight-number-cell {
|
||||
padding-left: 0.5rem !important;
|
||||
}
|
||||
|
||||
.flight-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.airline-logo-img {
|
||||
opacity: 0.85;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.flight-number {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.9rem;
|
||||
color: #e8eaf0;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.iata {
|
||||
display: inline-block;
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #e8eaf0;
|
||||
letter-spacing: 0.08em;
|
||||
margin-right: 0.35rem;
|
||||
}
|
||||
|
||||
.city-name {
|
||||
font-size: 0.75rem;
|
||||
color: #556;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.date-cell {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.82rem;
|
||||
color: #9aa;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.time-cell {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.82rem;
|
||||
color: #c8cdd8;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.day-diff {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.65rem;
|
||||
color: #ffc107;
|
||||
letter-spacing: 0.04em;
|
||||
margin-left: 0.15rem;
|
||||
}
|
||||
|
||||
.mono-tag {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.8rem;
|
||||
color: #778899;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.seat-cell {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
font-size: 0.85rem;
|
||||
color: #c8cdd8;
|
||||
}
|
||||
|
||||
.class-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
padding: 3rem;
|
||||
text-align: center;
|
||||
@@ -506,26 +323,10 @@ watch(
|
||||
color: #445;
|
||||
}
|
||||
|
||||
.actions-cell {
|
||||
width: 40px;
|
||||
padding: 0 0.5rem !important;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.v-list-item-title) {
|
||||
font-family: 'Share Tech Mono', monospace !important;
|
||||
font-size: 0.8rem !important;
|
||||
letter-spacing: 0.08em !important;
|
||||
color: #c8cdd8 !important;
|
||||
}
|
||||
|
||||
/* ── Highlighted flight row ── */
|
||||
.flight-row--highlighted {
|
||||
box-shadow: inset 3px 0 0 #ffc107;
|
||||
|
||||
}
|
||||
.flight-row--highlighted td {
|
||||
background: rgba(255, 193, 7, 0.08) !important;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
<script setup lang="ts">
|
||||
import FlightClassBadge from "@/Components/FlightsGoneBy/FlightClassBadge.vue";
|
||||
import AirlineLogo from "@/Components/FlightsGoneBy/AirlineLogo.vue";
|
||||
import { Flight, SharedProps } from "@/Types/types";
|
||||
import InlineBadge from "@/Components/FlightsGoneBy/InlineBadge.vue";
|
||||
import AirportToolTip from "@/Components/FlightsGoneBy/AirportToolTip.vue";
|
||||
import AircraftToolTip from "@/Components/FlightsGoneBy/AircraftToolTip.vue";
|
||||
import CrewTooltip from "@/Components/FlightsGoneBy/CrewTooltip.vue";
|
||||
import Distance from "@/Components/Distance.vue";
|
||||
import UserFlightContextMenu from "@/Components/FlightsGoneBy/UserFlightContextMenu.vue";
|
||||
import { usePage } from "@inertiajs/vue3";
|
||||
import { User } from "@/Types/types";
|
||||
import Mono from "@/Components/FlightsGoneBy/Mono.vue";
|
||||
import DayDifference from "@/Components/FlightsGoneBy/DayDifference.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
flight: Flight
|
||||
user: User
|
||||
canEdit: boolean
|
||||
highlighted?: boolean
|
||||
group?: 'upcoming' | 'departed'
|
||||
isSorting?: boolean
|
||||
}>()
|
||||
|
||||
const page = usePage<SharedProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<tr
|
||||
class="v-data-table__tr"
|
||||
:class="[
|
||||
group && !isSorting ? `group-row--${group}` : '',
|
||||
highlighted ? 'flight-row--highlighted' : '',
|
||||
]"
|
||||
:data-flight-id="flight.id"
|
||||
>
|
||||
<td class="v-data-table__td airline-logo-cell">
|
||||
<AirlineLogo size="32" :airline="flight.airline" class="airline-logo-img" />
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td flight-number-cell">
|
||||
<div class="flight-cell">
|
||||
<Mono class="flight-number">
|
||||
{{ flight.flight_number }}
|
||||
</Mono>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<AirportToolTip :airport="flight.departure_airport">
|
||||
<Mono class="iata">{{ flight.departure_airport.display_code }}</Mono><br/>
|
||||
</AirportToolTip>
|
||||
<span class="city-name">{{ flight.departure_airport.municipality }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<AirportToolTip :airport="flight.arrival_airport">
|
||||
<span class="iata"><Mono>{{ flight.arrival_airport.display_code }}</Mono></span><br/>
|
||||
</AirportToolTip>
|
||||
<span class="city-name" >{{ flight.arrival_airport.municipality }}</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="date-cell"><Mono muted smaller>{{ flight.departure_date_display }}</Mono></span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td">
|
||||
<span class="time-cell">
|
||||
<Mono small>{{ flight.departure_time_display }}</Mono>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td arrival-time-cell">
|
||||
<Mono small>{{ flight.arrival_time_display }}</Mono>
|
||||
<DayDifference :value="flight.arrival_day_difference" />
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td duration-cell">
|
||||
<Mono muted small>{{ flight.duration_display ?? '—' }}</Mono>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td distance-cell">
|
||||
<Mono muted small>
|
||||
<Distance :unit="page.props.auth.user?.distance_unit" :value="Math.round(flight.distance)" />
|
||||
</Mono>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td aircraft-cell">
|
||||
<AircraftToolTip v-if="flight.aircraft" :aircraft="flight.aircraft" :flight="flight">
|
||||
<Mono muted small>{{ flight.aircraft?.designator }}</Mono>
|
||||
</AircraftToolTip>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td registration-cell">
|
||||
<Mono muted smaller v-if="flight.aircraft_registration">{{ flight.aircraft_registration }}</Mono>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td class-badges-cell">
|
||||
<span class="class-cell">
|
||||
<CrewTooltip v-if="flight.flight_reason?.name == 'Crew'" :crew-type="flight.crew_type!">
|
||||
<FlightClassBadge v-if="flight.flight_class?.internal_name === 'crew'" :flight="flight" />
|
||||
<InlineBadge v-else variant="crew">Crew</InlineBadge>
|
||||
</CrewTooltip>
|
||||
<FlightClassBadge v-if="flight.flight_reason?.name !== 'Crew' || flight.flight_class?.internal_name !== 'crew'" :flight="flight" />
|
||||
<InlineBadge v-if="flight.seat_number" variant="economy">{{ flight.seat_number }}</InlineBadge>
|
||||
<InlineBadge v-if="flight.seat_type?.name && flight.seat_type?.name !== 'Unassigned'" variant="economy">{{ flight.seat_type?.name }}</InlineBadge>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="v-data-table__td actions-cell">
|
||||
<UserFlightContextMenu :profile-user="user" :can-edit="canEdit" :flight="flight" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.airline-logo-cell {
|
||||
width: 50px !important;
|
||||
min-width: 50px !important;
|
||||
max-width: 50px !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
.city-name{
|
||||
color: #556;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .05em;
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
.flight-number-cell {
|
||||
padding-left: 0.5rem !important;
|
||||
}
|
||||
|
||||
.flight-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.arrival-time-cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.class-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
gap: 0.5rem;
|
||||
overflow-x: auto;
|
||||
max-width: 160px;
|
||||
/* Hide scrollbar but keep functionality */
|
||||
scrollbar-width: none;
|
||||
&::-webkit-scrollbar { display: none; }
|
||||
}
|
||||
|
||||
.iata {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.class-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.actions-cell {
|
||||
width: 40px;
|
||||
padding: 0 0.5rem !important;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.flight-row--highlighted td {
|
||||
background: rgba(255, 193, 7, 0.08) !important;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
:deep(.v-data-table__td) {
|
||||
padding: 0 4px !important;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.arrival-time-cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flight-number-cell,
|
||||
.duration-cell,
|
||||
.distance-cell,
|
||||
.aircraft-cell,
|
||||
.registration-cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.class-badges-cell {
|
||||
max-width: 140px;
|
||||
overflow: hidden;
|
||||
display:none;
|
||||
}
|
||||
|
||||
.class-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
&::-webkit-scrollbar { display: none; }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {Flight} from "@/Types/types";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPass.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPass.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
flight: Flight
|
||||
|
||||
@@ -4,7 +4,7 @@ import AirportToolTip from "@/Components/FlightsGoneBy/AirportToolTip.vue";
|
||||
import AirlineLogo from "@/Components/FlightsGoneBy/AirlineLogo.vue";
|
||||
import FlightClassBadge from "@/Components/FlightsGoneBy/FlightClassBadge.vue";
|
||||
import AircraftToolTip from "@/Components/FlightsGoneBy/AircraftToolTip.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPass.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPass.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
data: UserActionFlightCancelledData
|
||||
|
||||
@@ -4,7 +4,7 @@ import AirportToolTip from "@/Components/FlightsGoneBy/AirportToolTip.vue";
|
||||
import AirlineLogo from "@/Components/FlightsGoneBy/AirlineLogo.vue";
|
||||
import FlightClassBadge from "@/Components/FlightsGoneBy/FlightClassBadge.vue";
|
||||
import AircraftToolTip from "@/Components/FlightsGoneBy/AircraftToolTip.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPass.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPass.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
flight: Flight
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {Flight} from "@/Types/types";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPass.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPass.vue";
|
||||
import FlightBadge from "@/Components/FlightsGoneBy/FlightBadge.vue";
|
||||
import {computed} from "vue";
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import {Flight} from "@/Types/types";
|
||||
|
||||
defineProps<{
|
||||
flight: Flight
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="livery" v-if="flight.livery_url" :style="{ backgroundImage: `url('${flight.livery_url}')` }">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.livery{
|
||||
width: 100%;
|
||||
aspect-ratio: 16/9;
|
||||
background-size: cover;
|
||||
min-width: 300px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
withDefaults(defineProps<{
|
||||
muted?: boolean
|
||||
dark?: boolean
|
||||
small?: boolean
|
||||
smaller?: boolean,
|
||||
smallest?: boolean,
|
||||
uppercase?: boolean
|
||||
smallSpacing?: boolean
|
||||
largeSpacing?: boolean
|
||||
}>(), {
|
||||
size: 'medium',
|
||||
muted: false,
|
||||
uppercase: false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="mono-tag" :class="{ 'muted': muted, 'dark' : dark ,'text-sm': small, 'text-smaller': smaller, 'text-smallest': smallest, 'uppercase': uppercase, 'small-spacing': smallSpacing, 'large-spacing': largeSpacing}">
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.mono-tag {
|
||||
font-family: 'Share Tech Mono', monospace;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.dark{
|
||||
color: rgb(85, 85, 102);
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.text-sm{
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.text-smaller{
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.text-smallest{
|
||||
font-size: 0.62rem;
|
||||
}
|
||||
|
||||
.muted{
|
||||
color: rgb(119, 136, 153);;
|
||||
}
|
||||
|
||||
.uppercase{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.small-spacing{
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.large-spacing{
|
||||
letter-spacing: 0.18em;
|
||||
}
|
||||
</style>
|
||||
@@ -5,6 +5,7 @@ import DetailRow from "@/Components/FlightsGoneBy/Panels/DetailRow.vue";
|
||||
import type {Flight} from "@/Types/types";
|
||||
import PanelHeader from "@/Components/FlightsGoneBy/Panels/PanelHeader.vue";
|
||||
import PanelSubHeader from "@/Components/FlightsGoneBy/Panels/PanelSubHeader.vue";
|
||||
import LiveryImage from "@/Components/FlightsGoneBy/LiveryImage.vue";
|
||||
|
||||
defineProps<{
|
||||
flight: Flight
|
||||
@@ -13,8 +14,7 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<Panel label="Aircraft">
|
||||
<div class="livery" v-if="flight.livery_url" :style="{ backgroundImage: `url('${flight.livery_url}')` }">
|
||||
</div>
|
||||
<LiveryImage :flight="flight" />
|
||||
<PanelHeader>{{ flight.aircraft?.display_name_short }}</PanelHeader>
|
||||
<PanelSubHeader v-if="flight.aircraft?.manufacturer_code">{{ flight.aircraft.manufacturer_code }}</PanelSubHeader>
|
||||
<PanelSubHeader v-if="!flight.aircraft && !flight.aircraft_registration">No Aircraft Information Found</PanelSubHeader>
|
||||
@@ -29,9 +29,5 @@ defineProps<{
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.livery{
|
||||
width: 100%;
|
||||
aspect-ratio: 16/9;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@ import MainLayout from "@/Layouts/MainLayout.vue";
|
||||
import {Head, Link} from "@inertiajs/vue3";
|
||||
import ProfileLayout from "@/Components/FlightsGoneBy/ProfileLayout.vue";
|
||||
import {Achievement, Flight, User, UserAchievement} from "@/Types/types";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPass.vue";
|
||||
import BoardingPass from "@/Components/FlightsGoneBy/BoardingPasses/BoardingPass.vue";
|
||||
import Panel from "@/Components/FlightsGoneBy/Panels/Panel.vue";
|
||||
import AirportPanel from "@/Components/FlightsGoneBy/Panels/AirportPanel.vue";
|
||||
import AirlinePanel from "@/Components/FlightsGoneBy/Panels/AirlinePanel.vue";
|
||||
|
||||
Vendored
+3
-3
@@ -10,7 +10,7 @@ declare module '@vue/runtime-core' {
|
||||
|
||||
export type ProfileView = 'map' | 'board' | 'passes' | 'achievements' ;
|
||||
export type ChartType = "line" | "area" | "bar" | "pie" | "donut" | "radialBar" | "scatter" | "bubble" | "heatmap" | "candlestick" | "boxPlot" | "radar" | "polarArea" | "rangeBar" | "rangeArea" | "treemap" | undefined
|
||||
export type BadgeVariant = 'first' | 'business' | 'premium' | 'economy' | 'private' | 'unspecified' | 'generic' | 'general_aviation' | 'crew' | "easy" | "moderate" | "hard" | "expensive" | "near-impossible" | "impossible"
|
||||
export type BadgeVariant = 'first' | 'business' | 'premium' | 'economy' | 'private' | 'unspecified' | 'generic' | 'general_aviation' | 'crew' | "easy" | "moderate" | "hard" | "expensive" | "near_impossible" | "impossible"
|
||||
|
||||
export interface User {
|
||||
id: number
|
||||
@@ -69,7 +69,7 @@ export type SharedProps = import('@inertiajs/core').PageProps & {
|
||||
}
|
||||
export interface AchievementDifficulty {
|
||||
id: number
|
||||
internal_name: string
|
||||
internal_name: "easy" | "moderate" | "hard" | "expensive" | "near_impossible" | "impossible"
|
||||
name: string
|
||||
description: string
|
||||
created_at: string | null
|
||||
@@ -98,7 +98,7 @@ export interface Achievement {
|
||||
achievement_category_id: number
|
||||
achievement_difficulty_id: number
|
||||
category?: AchievementCategory
|
||||
difficulty?: AchievementDifficulty
|
||||
difficulty: AchievementDifficulty
|
||||
has_page: boolean
|
||||
sort_order: number
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user