38 lines
2.7 KiB
TypeScript
38 lines
2.7 KiB
TypeScript
|
|
'use client';
|
|||
|
|
import {useEffect,useState} from 'react';
|
|||
|
|
import {Download,X} from 'lucide-react';
|
|||
|
|
type InstallEvent=Event & {prompt:()=>Promise<void>;userChoice:Promise<{outcome:'accepted'|'dismissed'}>};
|
|||
|
|
export function ClockInstallPrompt() {
|
|||
|
|
const [visible,setVisible]=useState(false);
|
|||
|
|
const [ios,setIos]=useState(false);
|
|||
|
|
const [install,setInstall]=useState<InstallEvent|null>(null);
|
|||
|
|
const [busy,setBusy]=useState(false);
|
|||
|
|
useEffect(()=>{
|
|||
|
|
const standalone=window.matchMedia('(display-mode: standalone)').matches || (navigator as Navigator & {standalone?:boolean}).standalone===true;
|
|||
|
|
if(standalone)return;
|
|||
|
|
try{if(sessionStorage.getItem('plant-clock-install-dismissed'))return;}catch{/* Storage may be disabled. */}
|
|||
|
|
setIos(/iphone|ipad|ipod/i.test(navigator.userAgent)||(navigator.platform==='MacIntel'&&navigator.maxTouchPoints>1));
|
|||
|
|
setVisible(true);
|
|||
|
|
const prompt=(event:Event)=>{event.preventDefault();setInstall(event as InstallEvent);};
|
|||
|
|
const installed=()=>setVisible(false);
|
|||
|
|
window.addEventListener('beforeinstallprompt',prompt);window.addEventListener('appinstalled',installed);
|
|||
|
|
return()=>{window.removeEventListener('beforeinstallprompt',prompt);window.removeEventListener('appinstalled',installed);};
|
|||
|
|
},[]);
|
|||
|
|
if(!visible)return null;
|
|||
|
|
async function installApp() {
|
|||
|
|
if(!install||busy)return;setBusy(true);
|
|||
|
|
try{await install.prompt();const result=await install.userChoice;if(result.outcome==='accepted')setVisible(false);setInstall(null);}
|
|||
|
|
catch{setInstall(null);}finally{setBusy(false);}
|
|||
|
|
}
|
|||
|
|
return <aside aria-label="Install Plant Clock" className="mx-auto max-w-6xl px-4 pt-4 sm:px-6 lg:px-8">
|
|||
|
|
<div className="plant-clock-panel flex items-start gap-3 p-3 text-text">
|
|||
|
|
<Download size={21} className="mt-3 shrink-0 text-accent-ink" aria-hidden/>
|
|||
|
|
<div className="min-w-0 flex-1 py-2"><p className="font-semibold text-sm">Install Plant Clock</p>
|
|||
|
|
<p className="text-xs text-text-muted leading-relaxed mt-1">{ios?'In Safari, tap Share → Add to Home Screen, then open Plant Clock from its icon.':install?'Add a separate Plant Clock app to this phone’s home screen.':'Open the browser menu and choose Install app or Add to Home Screen.'}</p>
|
|||
|
|
{install&&!ios&&<button disabled={busy} className="plant-clock-button plant-clock-primary mt-3" onClick={()=>void installApp()}>{busy?'Installing…':'Install Plant Clock'}</button>}
|
|||
|
|
</div>
|
|||
|
|
<button type="button" aria-label="Dismiss install help" className="plant-clock-button plant-clock-secondary p-2 shrink-0" onClick={()=>{setVisible(false);try{sessionStorage.setItem('plant-clock-install-dismissed','1');}catch{/* Optional. */}}}><X size={18}/></button>
|
|||
|
|
</div>
|
|||
|
|
</aside>;
|
|||
|
|
}
|