120 lines
3.2 KiB
Vue
120 lines
3.2 KiB
Vue
<script setup lang="ts">
|
|
import MainHeader from "@/Components/FlightsGoneBy/MainHeader.vue";
|
|
import MainFooter from "@/Components/FlightsGoneBy/MainFooter.vue";
|
|
import Radar from "@/Components/FlightsGoneBy/Radar.vue";
|
|
import StatusNotifications from "@/Components/FlightsGoneBy/StatusNotifications.vue";
|
|
import ToastNotifications from "@/Components/FlightsGoneBy/ToastNotifications.vue";
|
|
import {router, usePage} from "@inertiajs/vue3";
|
|
import { ref } from "vue";
|
|
import NotificationListener from "@/Components/FlightsGoneBy/NotificationListener.vue";
|
|
import {SharedProps} from "@/Types/types";
|
|
import PushNotificationPrompt from "@/Components/PushNotificationPrompt.vue";
|
|
import CopyPageButton from "@/Components/FlightsGoneBy/CopyPageButton.vue";
|
|
const transitionKey = ref(0);
|
|
|
|
const page = usePage<SharedProps>().props
|
|
|
|
router.on('success', () => {
|
|
transitionKey.value++;
|
|
});
|
|
|
|
const isIOS27PlusPWA = (() => {
|
|
const ua = navigator.userAgent;
|
|
|
|
const isStandalone =
|
|
window.matchMedia('(display-mode: standalone)').matches ||
|
|
(navigator as Navigator & { standalone?: boolean }).standalone;
|
|
|
|
if (!isStandalone) return false;
|
|
|
|
// iPhone / iPad detection
|
|
const isIOS =
|
|
/iPhone|iPad|iPod/.test(ua) ||
|
|
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
|
|
|
if (!isIOS) return false;
|
|
|
|
// iOS 27+ detection (Safari version token)
|
|
const version = ua.match(/Version\/(\d+)/);
|
|
|
|
return version && parseInt(version[1]) >= 27;
|
|
})();
|
|
</script>
|
|
|
|
<template>
|
|
<Radar>
|
|
<div class="layoutContainer">
|
|
<div v-if="isIOS27PlusPWA" class="ios-top-bar"></div>
|
|
<MainHeader :key="`header-${transitionKey}`" />
|
|
<Transition name="fade" mode="out-in">
|
|
<main id="pageContainer" :key="`main-${transitionKey}`">
|
|
<slot />
|
|
</main>
|
|
</Transition>
|
|
<span class="footer-share">
|
|
<CopyPageButton label="Share Link" />
|
|
</span>
|
|
<MainFooter :key="`footer-${transitionKey}`" />
|
|
</div>
|
|
<NotificationListener v-if="page.auth.user?.id" :user-id="page.auth.user?.id" />
|
|
<StatusNotifications />
|
|
<ToastNotifications />
|
|
<PushNotificationPrompt v-if="page.auth.user?.id" />
|
|
</Radar>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.layoutContainer {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100dvh;
|
|
color: var(--text);
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.ios-top-bar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 6px;
|
|
padding-bottom: 16px;
|
|
z-index: 9999;
|
|
background: var(--surface);
|
|
}
|
|
|
|
header,
|
|
footer {
|
|
flex: 0 0 5dvh;
|
|
min-height: 3rem;
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
footer {
|
|
flex: 0 1 auto;
|
|
min-height: 3.25rem;
|
|
padding-block: 0.35rem;
|
|
}
|
|
}
|
|
|
|
main {
|
|
flex: 1 1 auto;
|
|
background: transparent;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.footer-share {
|
|
padding:1em;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.fade-enter-from,
|
|
.fade-leave-to { opacity: 0; }
|
|
.fade-enter-active,
|
|
.fade-leave-active { transition: opacity 0.2s ease; }
|
|
</style>
|