Make the app an installable PWA with phone layout and Web Push
Add a generated manifest, icon set, offline page and service worker that never caches authenticated HTML, plus install and update UI. Turn the rail into a drawer below md with container-query internals, dvh and safe-area handling, and reconnect the socket after visibility/network changes. Add Web Push subscriptions, presence-aware delivery, notification settings and tests.
This commit is contained in:
@@ -1,14 +1,21 @@
|
||||
import { useContext } from "react";
|
||||
"use client";
|
||||
|
||||
import { useContext, useState } from "react";
|
||||
import Paper from "@moduletrace/twui/elements/Paper";
|
||||
import Divider from "@moduletrace/twui/layout/Divider";
|
||||
import { Download } from "lucide-react";
|
||||
import { RailUserMenuItems } from "../(dict)/rail-user-menu-dict";
|
||||
import RailUserMenuEntry from "./rail-user-menu-entry";
|
||||
import RailUserMenuAction from "./rail-user-menu-action";
|
||||
import InstallAppModal from "./install-app-modal";
|
||||
import { AppContext } from "@/src/pages/__root";
|
||||
import isPassThroughUser from "@/src/utils/rbac/is-pass-through-user";
|
||||
import useInstallPrompt from "@/src/hooks/use-install-prompt";
|
||||
|
||||
/**
|
||||
* 220px popover: the only element in the shell with elevation. Super
|
||||
* admin items show to super admins only.
|
||||
* admin items show to super admins only. Install app shows while the
|
||||
* browser can install it; Safari gets the Share menu steps instead.
|
||||
*/
|
||||
export default function RailUserMenu() {
|
||||
const { pageProps } = useContext(AppContext);
|
||||
@@ -17,6 +24,12 @@ export default function RailUserMenu() {
|
||||
const items = shown.filter((item) => !item.destructive);
|
||||
const destructive = shown.filter((item) => item.destructive);
|
||||
|
||||
const { can_install, needs_ios_steps, installing, install } =
|
||||
useInstallPrompt();
|
||||
const [ios_modal_open, setIosModalOpen] = useState(false);
|
||||
|
||||
const show_install = can_install || needs_ios_steps;
|
||||
|
||||
return (
|
||||
<Paper
|
||||
role="menu"
|
||||
@@ -25,10 +38,30 @@ export default function RailUserMenu() {
|
||||
{items.map((item) => (
|
||||
<RailUserMenuEntry key={item.title} {...item} />
|
||||
))}
|
||||
{show_install ? (
|
||||
<RailUserMenuAction
|
||||
title={needs_ios_steps ? "How to install" : "Install app"}
|
||||
Icon={Download}
|
||||
disabled={installing}
|
||||
onClick={() => {
|
||||
if (needs_ios_steps) {
|
||||
setIosModalOpen(true);
|
||||
return;
|
||||
}
|
||||
install();
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<Divider className="my-1 mx-3 w-auto border-hairline dark:border-hairline" />
|
||||
{destructive.map((item) => (
|
||||
<RailUserMenuEntry key={item.title} {...item} />
|
||||
))}
|
||||
{needs_ios_steps ? (
|
||||
<InstallAppModal
|
||||
open={ios_modal_open}
|
||||
setOpen={setIosModalOpen}
|
||||
/>
|
||||
) : null}
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user