diff --git a/index.html b/index.html index 6ed209eb8..eb4a3d0e0 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ + content="width=device-width, initial-scale=1, viewport-fit=cover, maximum-scale=1.0, user-scalable=no" /> @@ -21,108 +21,110 @@ + + + media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_15_Pro_Max__iPhone_15_Plus__iPhone_14_Pro_Max_landscape.png"> + media="screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_15_Pro__iPhone_15__iPhone_14_Pro_landscape.png"> + media="screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_landscape.png"> + media="screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_landscape.png"> + media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_landscape.png"> + media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_11_Pro_Max__iPhone_XS_Max_landscape.png"> + media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/iPhone_11__iPhone_XR_landscape.png"> + media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" + href="/splash_screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_landscape.png"> + media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_landscape.png"> + media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_landscape.png"> + media="screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/12.9__iPad_Pro_landscape.png"> + media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/11__iPad_Pro__10.5__iPad_Pro_landscape.png"> + media="screen and (device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/10.9__iPad_Air_landscape.png"> + media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/10.5__iPad_Air_landscape.png"> + media="screen and (device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/10.2__iPad_landscape.png"> + media="screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_landscape.png"> + media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" + href="/splash_screens/8.3__iPad_Mini_landscape.png"> + media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_15_Pro_Max__iPhone_15_Plus__iPhone_14_Pro_Max_portrait.png"> + media="screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_15_Pro__iPhone_15__iPhone_14_Pro_portrait.png"> + media="screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_portrait.png"> + media="screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_portrait.png"> + media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_portrait.png"> + media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_11_Pro_Max__iPhone_XS_Max_portrait.png"> + media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/iPhone_11__iPhone_XR_portrait.png"> + media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" + href="/splash_screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_portrait.png"> + media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_portrait.png"> + media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_portrait.png"> + media="screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/12.9__iPad_Pro_portrait.png"> + media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/11__iPad_Pro__10.5__iPad_Pro_portrait.png"> + media="screen and (device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/10.9__iPad_Air_portrait.png"> + media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/10.5__iPad_Air_portrait.png"> + media="screen and (device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/10.2__iPad_portrait.png"> + media="screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_portrait.png"> + media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" + href="/splash_screens/8.3__iPad_Mini_portrait.png"> @@ -144,27 +146,27 @@ + { + "@context": "https://schema.org", + "@type": "WebSite", + "url": "{{ routeDomain }}", + "potentialAction": { + "@type": "SearchAction", + "target": { + "@type": "EntryPoint", + "urlTemplate": "{{ routeDomain }}/browse/?q={search_term_string}" + }, + "query-input": "required name=search_term_string" + } + } + {{/if}} - -
- + +
+ diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index dda27f5f1..4bd627a68 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -68,6 +68,8 @@ export enum Icons { BRUSH = "brush", UPLOAD = "upload", WEB = "web", + SHRINK = "shrink", + STRETCH = "stretch", } export interface IconProps { @@ -153,6 +155,8 @@ const iconList: Record = { `, + shrink: ``, + stretch: ``, }; function ChromeCastButton() { diff --git a/src/components/buttons/IosPwaLimitations.tsx b/src/components/buttons/IosPwaLimitations.tsx new file mode 100644 index 000000000..dc0ee9e7c --- /dev/null +++ b/src/components/buttons/IosPwaLimitations.tsx @@ -0,0 +1,23 @@ +/* eslint-disable no-alert */ +import { Icon, Icons } from "../Icon"; + +function IosPwaLimitations() { + const showAlert = () => { + alert( + "Due to Apple’s limitations, Picture-in-Picture (PiP) and Fullscreen are disabled on iOS PWAs. Use the browser vertion to re-enable these features.\n" + + "Tip: To hide the iOS home indicator, use guided access within the PWA!", + ); + }; + + return ( + + ); +} + +export default IosPwaLimitations; diff --git a/src/components/layout/Navigation.tsx b/src/components/layout/Navigation.tsx index 90e91e595..0abf62da5 100644 --- a/src/components/layout/Navigation.tsx +++ b/src/components/layout/Navigation.tsx @@ -47,14 +47,14 @@ export function Navigation(props: NavigationProps) { {/* backgrounds - these are seperate because of z-index issues */}
{props.children} diff --git a/src/pages/parts/home/HeroPart.tsx b/src/pages/parts/home/HeroPart.tsx index 5c2a0c126..bbb688529 100644 --- a/src/pages/parts/home/HeroPart.tsx +++ b/src/pages/parts/home/HeroPart.tsx @@ -39,20 +39,30 @@ export function HeroPart({ setIsSticky, searchParams }: HeroPartProps) { }, [setShowBg, setIsSticky], ); + const { width: windowWidth, height: windowHeight } = useWindowSize(); - const { width: windowWidth } = useWindowSize(); + // Detect if running as a PWA on iOS + const isIOSPWA = + /iPad|iPhone|iPod/i.test(navigator.userAgent) && + window.matchMedia("(display-mode: standalone)").matches; - const topSpacing = 16; + const topSpacing = isIOSPWA ? 60 : 16; const [stickyOffset, setStickyOffset] = useState(topSpacing); + + const isLandscape = windowHeight < windowWidth && isIOSPWA; + const adjustedOffset = isLandscape + ? -40 // landscape + : 0; // portrait + useEffect(() => { - if (windowWidth > 1200) { + if (windowWidth > 1280) { // On large screens the bar goes inline with the nav elements setStickyOffset(topSpacing); } else { // On smaller screens the bar goes below the nav elements - setStickyOffset(topSpacing + 60); + setStickyOffset(topSpacing + 60 + adjustedOffset); } - }, [windowWidth]); + }, [adjustedOffset, topSpacing, windowWidth]); const time = getTimeOfDay(new Date()); const title = randomT(`home.titles.${time}`); diff --git a/src/pages/parts/player/PlayerPart.tsx b/src/pages/parts/player/PlayerPart.tsx index 2d73286ba..cd82e35ae 100644 --- a/src/pages/parts/player/PlayerPart.tsx +++ b/src/pages/parts/player/PlayerPart.tsx @@ -1,5 +1,6 @@ import { ReactNode } from "react"; +import IosPwaLimitations from "@/components/buttons/IosPwaLimitations"; import { BrandPill } from "@/components/layout/BrandPill"; import { Player } from "@/components/player"; import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls"; @@ -20,6 +21,11 @@ export function PlayerPart(props: PlayerPartProps) { const { isMobile } = useIsMobile(); const isLoading = usePlayerStore((s) => s.mediaPlaying.isLoading); + // Detect if running as a PWA on iOS + const isIOSPWA = + /iPad|iPhone|iPod/i.test(navigator.userAgent) && + window.matchMedia("(display-mode: standalone)").matches; + return ( {props.children} @@ -122,12 +128,25 @@ export function PlayerPart(props: PlayerPartProps) {
- {status === playerStatus.PLAYING ? : null} + {/* Disable PiP for iOS PWA */} + {!isIOSPWA && + (status === playerStatus.PLAYING ? : null)} {status === playerStatus.PLAYING ? : null}
- + {/* Disable for iOS PWA */} + {!isIOSPWA && ( +
+ +
+ )} + {/* Add info for iOS PWA */} + {isIOSPWA && ( +
+ +
+ )}