89 lines
3.3 KiB
TypeScript
89 lines
3.3 KiB
TypeScript
import type { Metadata, Viewport } from "next";
|
|
import "./globals.css";
|
|
import BottomNav from "@/components/BottomNav";
|
|
|
|
export const viewport: Viewport = {
|
|
width: "device-width",
|
|
initialScale: 1,
|
|
viewportFit: "cover",
|
|
userScalable: false,
|
|
themeColor: "#111827",
|
|
};
|
|
|
|
export const metadata: Metadata = {
|
|
title: { default: "Puzzle Trainer", template: "%s — Puzzle Trainer" },
|
|
description: "5 puzzles logiques chaque jour. Queens, Tango, Zip, Sudoku, Patches.",
|
|
applicationName: "Puzzle Trainer",
|
|
appleWebApp: {
|
|
capable: true,
|
|
title: "Puzzle Trainer",
|
|
statusBarStyle: "black-translucent",
|
|
},
|
|
openGraph: {
|
|
title: "Puzzle Trainer",
|
|
description: "5 puzzles logiques chaque jour.",
|
|
url: "https://puzzles.reverdin.eu",
|
|
siteName: "Puzzle Trainer",
|
|
locale: "fr_FR",
|
|
type: "website",
|
|
},
|
|
twitter: {
|
|
card: "summary_large_image",
|
|
title: "Puzzle Trainer",
|
|
description: "5 puzzles logiques chaque jour.",
|
|
},
|
|
metadataBase: new URL("https://puzzles.reverdin.eu"),
|
|
manifest: "/manifest.json",
|
|
formatDetection: { telephone: false },
|
|
};
|
|
|
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<html lang="fr" className="h-full">
|
|
<head>
|
|
{/* iOS standalone — critical meta tags */}
|
|
<meta name="mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
<meta name="apple-mobile-web-app-title" content="Puzzles" />
|
|
|
|
{/* iOS splash screens — key iPhone sizes */}
|
|
<link rel="apple-touch-startup-image"
|
|
href="/splash/splash-1290x2796.png"
|
|
media="(device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3)" />
|
|
<link rel="apple-touch-startup-image"
|
|
href="/splash/splash-1179x2556.png"
|
|
media="(device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3)" />
|
|
<link rel="apple-touch-startup-image"
|
|
href="/splash/splash-1170x2532.png"
|
|
media="(device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3)" />
|
|
<link rel="apple-touch-startup-image"
|
|
href="/splash/splash-1080x2340.png"
|
|
media="(device-width: 360px) and (device-height: 780px) and (-webkit-device-pixel-ratio: 3)" />
|
|
<link rel="apple-touch-startup-image"
|
|
href="/splash/splash-750x1334.png"
|
|
media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" />
|
|
|
|
{/* Service worker registration */}
|
|
<script dangerouslySetInnerHTML={{ __html: `
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', function() {
|
|
navigator.serviceWorker.register('/sw.js');
|
|
});
|
|
}
|
|
`}} />
|
|
</head>
|
|
<body className="h-full bg-[#f8fafc]">
|
|
{/* Main content — padded for top safe area and bottom nav */}
|
|
<main className="flex-1 overflow-y-auto" style={{ paddingTop: "env(safe-area-inset-top)" }}>
|
|
<div className="pt-4 pb-[calc(72px+env(safe-area-inset-bottom))]">
|
|
{children}
|
|
</div>
|
|
</main>
|
|
|
|
{/* Bottom tab bar */}
|
|
<BottomNav />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|