Compare commits

..
4 Commits
Author SHA1 Message Date
dredgy c7327cac1a Fixed PWA on iOS 27 2026-11-05 21:43:12 +10:00
dredgy 1411cadcc9 Fixed PWA on iOS 27 2026-11-03 20:22:00 +10:00
dredgy f2c789f900 Fixed PWA on iOS 27 2026-11-03 20:11:49 +10:00
dredgy d09fa60f47 Fixed PWA on iOS 27 2026-11-03 19:44:45 +10:00
2 changed files with 38 additions and 41 deletions

No files matched your search

+37 -40
View File
@@ -4,47 +4,32 @@ import MainFooter from "@/Components/FlightsGoneBy/MainFooter.vue";
import Radar from "@/Components/FlightsGoneBy/Radar.vue"; import Radar from "@/Components/FlightsGoneBy/Radar.vue";
import StatusNotifications from "@/Components/FlightsGoneBy/StatusNotifications.vue"; import StatusNotifications from "@/Components/FlightsGoneBy/StatusNotifications.vue";
import ToastNotifications from "@/Components/FlightsGoneBy/ToastNotifications.vue"; import ToastNotifications from "@/Components/FlightsGoneBy/ToastNotifications.vue";
import {router, usePage} from "@inertiajs/vue3"; import { router, usePage } from "@inertiajs/vue3";
import { ref } from "vue"; import { ref } from "vue";
import NotificationListener from "@/Components/FlightsGoneBy/NotificationListener.vue"; import NotificationListener from "@/Components/FlightsGoneBy/NotificationListener.vue";
import {SharedProps} from "@/Types/types"; import { SharedProps } from "@/Types/types";
import PushNotificationPrompt from "@/Components/PushNotificationPrompt.vue"; import PushNotificationPrompt from "@/Components/PushNotificationPrompt.vue";
import CopyPageButton from "@/Components/FlightsGoneBy/CopyPageButton.vue"; import CopyPageButton from "@/Components/FlightsGoneBy/CopyPageButton.vue";
const transitionKey = ref(0); const transitionKey = ref(0);
const page = usePage<SharedProps>().props const page = usePage<SharedProps>().props;
router.on('success', () => { router.on("success", () => {
transitionKey.value++; 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> </script>
<template> <template>
<Radar> <Radar>
<!--
A real fixed element at the top edge: Safari tints the status bar
with its colour instead of drawing the translucent blur.
(Pseudo-elements don't trigger this.)
-->
<div class="status-bar-backing" aria-hidden="true"></div>
<div class="layoutContainer"> <div class="layoutContainer">
<div v-if="isIOS27PlusPWA" class="ios-top-bar"></div>
<MainHeader :key="`header-${transitionKey}`" /> <MainHeader :key="`header-${transitionKey}`" />
<Transition name="fade" mode="out-in"> <Transition name="fade" mode="out-in">
<main id="pageContainer" :key="`main-${transitionKey}`"> <main id="pageContainer" :key="`main-${transitionKey}`">
@@ -56,6 +41,7 @@ const isIOS27PlusPWA = (() => {
</span> </span>
<MainFooter :key="`footer-${transitionKey}`" /> <MainFooter :key="`footer-${transitionKey}`" />
</div> </div>
<NotificationListener v-if="page.auth.user?.id" :user-id="page.auth.user?.id" /> <NotificationListener v-if="page.auth.user?.id" :user-id="page.auth.user?.id" />
<StatusNotifications /> <StatusNotifications />
<ToastNotifications /> <ToastNotifications />
@@ -64,22 +50,28 @@ const isIOS27PlusPWA = (() => {
</template> </template>
<style scoped> <style scoped>
.status-bar-backing {
position: fixed;
top: 0;
left: 0;
right: 0;
height: max(10px, env(safe-area-inset-top, 0px));
background: var(--surface);
z-index: 9999;
pointer-events: none;
}
.layoutContainer { .layoutContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 100dvh; min-height: 100dvh;
color: var(--text); color: var(--text);
overflow-y: auto; overflow-y: auto;
} box-sizing: border-box;
/* Push the header below the status bar. If Safari's solid area is taller
.ios-top-bar { than the reported inset, add a few px here, e.g. calc(env(...) + 12px). */
position: fixed; padding-top: calc(env(safe-area-inset-top, 0px) + 16px);
top: 0; padding-bottom: env(safe-area-inset-bottom, 0px);
left: 0;
right: 0;
height: 6px;
z-index: 9999;
background: var(--surface);
} }
header, header,
@@ -106,13 +98,18 @@ main {
} }
.footer-share { .footer-share {
padding:1em; padding: 1em;
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.fade-enter-from, .fade-enter-from,
.fade-leave-to { opacity: 0; } .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-enter-active,
.fade-leave-active { transition: opacity 0.2s ease; } .fade-leave-active {
transition: opacity 0.2s ease;
}
</style> </style>
+1 -1
View File
@@ -2,7 +2,7 @@
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="app-name" content="{{ config('app.name') }}"> <meta name="app-name" content="{{ config('app.name') }}">
<title inertia>{{ config('app.name', 'Laravel') }}</title> <title inertia>{{ config('app.name', 'Laravel') }}</title>