56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useI18n } from "@/lib/i18n";
|
|
|
|
/** Soft install hint — shows once when browser fires beforeinstallprompt. */
|
|
export default function PwaInstallHint() {
|
|
const { t } = useI18n();
|
|
const [deferred, setDeferred] = useState<{ prompt: () => Promise<void> } | null>(null);
|
|
const [hidden, setHidden] = useState(true);
|
|
|
|
useEffect(() => {
|
|
if (window.matchMedia("(display-mode: standalone)").matches) return;
|
|
if (localStorage.getItem("nomadro-pwa-hint") === "1") return;
|
|
|
|
const onBip = (e: Event) => {
|
|
e.preventDefault();
|
|
const ev = e as Event & { prompt: () => Promise<void> };
|
|
setDeferred({ prompt: () => ev.prompt() });
|
|
setHidden(false);
|
|
};
|
|
window.addEventListener("beforeinstallprompt", onBip);
|
|
return () => window.removeEventListener("beforeinstallprompt", onBip);
|
|
}, []);
|
|
|
|
if (hidden || !deferred) return null;
|
|
|
|
const dismiss = () => {
|
|
localStorage.setItem("nomadro-pwa-hint", "1");
|
|
setHidden(true);
|
|
};
|
|
|
|
const install = async () => {
|
|
try {
|
|
await deferred.prompt();
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
dismiss();
|
|
};
|
|
|
|
return (
|
|
<div className="pwa-install-hint" role="status">
|
|
<p>{t.pwa.installHint}</p>
|
|
<div className="pwa-install-actions">
|
|
<button type="button" className="btn btn-primary btn-sm" onClick={() => void install()}>
|
|
安装
|
|
</button>
|
|
<button type="button" className="btn btn-ghost btn-sm" onClick={dismiss}>
|
|
稍后再说
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|