Added Notifications

This commit is contained in:
2026-06-14 16:04:01 +10:00
parent e24d3ceaec
commit a753bffaf8
49 changed files with 1118 additions and 381 deletions
@@ -0,0 +1,25 @@
<script setup lang="ts">
defineProps<{
label: string;
count: number;
weeklyGrowth: number;
icon: string;
}>();
</script>
<template>
<v-card class="pa-5 d-flex align-center justify-space-between">
<div>
<div class="text-caption text-medium-emphasis">{{ label }}</div>
<div class="text-h5 font-weight-medium">{{ count }}</div>
</div>
<div class="text-caption "><slot/></div>
<div class="text-right">
<div class="d-flex align-center justify-end ga-1">
<v-icon :icon="icon" color="success" size="20" />
<span class="text-h6 font-weight-medium text-success">+{{ weeklyGrowth }}</span>
</div>
<div class="text-caption text-disabled">new this week </div>
</div>
</v-card>
</template>
@@ -0,0 +1,57 @@
<script setup lang="ts">
import { MissingLivery } from "@/Types/types";
import {router} from "@inertiajs/vue3";
import CopyButton from "@/Components/FlightsGoneBy/CopyButton.vue";
const props = defineProps<{
livery: MissingLivery;
}>();
const ignore = () => {
router.post(route('admin.ignore-missing-livery'), { filename: props.livery.filename });
};
</script>
<template>
<v-card flat rounded="lg" class="mb-2 px-4 py-3">
<v-row align="center" no-gutters>
<v-col cols="12" sm="4">
<div class="d-flex align-center ga-1 text-medium-emphasis" style="font-size: 11px;">
Airline
</div>
<div style="font-size: 12px;" class="font-weight-medium">{{ livery.airline_name }}</div>
</v-col>
<v-col cols="12" sm="4">
<div class="d-flex align-center ga-1 text-medium-emphasis" style="font-size: 11px;">
Aircraft
<CopyButton :text="livery.clipboard_text" />
</div>
<div style="font-size: 12px;" class="font-weight-medium">{{ livery.aircraft_display_name }}</div>
</v-col>
<v-col cols="12" sm="4">
<div class="d-flex align-center ga-1 text-medium-emphasis" style="font-size: 11px;">
Filename
<CopyButton :text="livery.filename" />
</div>
<div style="font-size: 12px;" class="font-weight-medium">{{ livery.filename }}</div>
</v-col>
</v-row>
<v-row no-gutters class="mt-2" justify="end">
<v-btn
size="x-small"
variant="tonal"
color="error"
prepend-icon="mdi-eye-off"
@click="ignore"
>
Ignore
</v-btn>
</v-row>
</v-card>
</template>
@@ -4,6 +4,7 @@ import type { CodeType } from '@/Composables/useAlphabetAirlines'
import BadgeTable from '@/Components/FlightsGoneBy/GenericBadgeTable.vue'
import InlineBadge from '@/Components/FlightsGoneBy/InlineBadge.vue'
import AirlineLogo from "@/Components/FlightsGoneBy/AirlineLogo.vue";
import {computed} from "vue";
const props = defineProps<{
letters: string[]
@@ -50,8 +51,8 @@ function isHighlighted({ firstYear }: AirlineEntry): boolean {
return props.selectedYear !== null && firstYear === props.selectedYear
}
function toBBCode(): string {
return props.letters
const bbCode = computed(() =>
props.letters
.map(letter => {
const entries = airlineEntriesForLetter(letter)
if (!entries.length) return letter
@@ -65,9 +66,9 @@ function toBBCode(): string {
.join(', ')
})
.join('\n')
}
)
defineExpose({ toBBCode })
defineExpose({ bbCode })
</script>
<template>
@@ -3,6 +3,7 @@ import {Airport, Flight} from '@/Types/types'
import BadgeTable from '@/Components/FlightsGoneBy/GenericBadgeTable.vue'
import InlineBadge from '@/Components/FlightsGoneBy/InlineBadge.vue'
import AirportToolTip from '@/Components/FlightsGoneBy/AirportToolTip.vue'
import {computed} from "vue";
type CodeType = 'iata' | 'icao'
@@ -50,8 +51,8 @@ function isHighlighted({ firstYear }: AirportEntry): boolean {
return props.selectedYear !== null && firstYear === props.selectedYear
}
function toBBCode(): string {
return props.letters
const bbCode = computed(() =>
props.letters
.map(letter => {
const entries = airportEntriesForLetter(letter)
if (!entries.length) return letter
@@ -64,9 +65,9 @@ function toBBCode(): string {
.join(', ')
})
.join('\n')
}
)
defineExpose({ toBBCode })
defineExpose({ bbCode })
</script>
<template>
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { ref } from "vue";
import { copyToClipboard } from "@/Composables/useClipboard";
const props = defineProps<{
text: string;
title?: string;
size?: string;
}>();
const copied = ref(false);
const handleCopy = async () => {
await copyToClipboard(props.text);
copied.value = true;
setTimeout(() => copied.value = false, 1500);
};
</script>
<template>
<v-btn
:title="title"
:icon="copied ? 'mdi-check' : 'mdi-content-copy'"
:size="size ?? 'x-small'"
:variant="copied ? 'tonal' : 'plain'"
:color="copied ? 'success' : undefined"
density="compact"
@click="handleCopy"
/>
</template>
@@ -38,7 +38,8 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside))
<template v-else>
<Link :href="route('flights.add')" class="nav-link">Add Flight</Link>
<Link :href="route('profile.view', { user: props.auth.user.name })" class="nav-link">Profile</Link>
<Link href="/feed" class="nav-link">Feed</Link>
<Link :href="route('feed')" class="nav-link">Feed</Link>
<Link v-if="props.auth.roles.includes('admin')" :href="route('admin.dashboard')" class="nav-link">Admin</Link>
<div class="dropdown" ref="dropdownRef">
<button class="nav-link dropdown-trigger" @click.stop="dropdownOpen = !dropdownOpen">
@@ -73,7 +74,7 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside))
<span class="nav-greeting">Welcome, {{ props.auth.user.name }}</span>
<Link :href="route('flights.add')" class="nav-link" @click="menuOpen = false">Add Flight</Link>
<Link :href="route('profile.view', { user: props.auth.user.name })" class="nav-link" @click="menuOpen = false">Profile</Link>
<Link href="/feed" class="nav-link nav-link--highlight" @click="menuOpen = false">Feed</Link>
<Link :href="route('feed')" class="nav-link nav-link" @click="menuOpen = false">Feed</Link>
<Link :href="route('import.fr24')" class="nav-link" @click="menuOpen = false">Import from FR24</Link>
<div class="dropdown-divider" />
<button class="nav-link nav-link--danger" @click="logout">Log Out</button>
@@ -115,9 +116,10 @@ header {
/* Shared nav link base */
.nav-link {
display: inline-flex;
display: flex;
align-items: center;
gap: 0.3em;
height: 100%;
padding: 0.3em 0.75em;
font-size: 0.875rem;
font-weight: 500;