Name each install, fix the notification badge, switch to Archivo
- Settings > General: an App name (super admin) for the installed app. The manifest's name/short_name, the iOS head tags and the loading page's title use it, so two installs on one phone can be told apart. - Notifications get a real badge (white stone silhouette): Android masks the badge by alpha, so the opaque app icon showed as a square. - The loading and offline pages load the app's font. - The font is now Archivo (variable, one request for every weight), matching the marketing site. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
type Params = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Text made safe to drop into HTML, in an element or a quoted attribute.
|
||||
*/
|
||||
export default function escapeHtml({ text }: Params) {
|
||||
return text
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
|
||||
type Params = {
|
||||
install_name?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* What the installed app is called: the install's own name, else
|
||||
* `SiteName`.
|
||||
*/
|
||||
export default function installDisplayName({ install_name }: Params) {
|
||||
return install_name?.trim() || SiteData["SiteName"];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
import namePwaManifest from "./name-pwa-manifest";
|
||||
|
||||
const manifest = {
|
||||
name: SiteData["SiteName"],
|
||||
short_name: SiteData["SiteName"],
|
||||
start_url: "/admin/bots",
|
||||
};
|
||||
|
||||
describe("namePwaManifest", () => {
|
||||
test("leaves an unnamed install's manifest alone", () => {
|
||||
expect(namePwaManifest({ manifest, install_name: "" })).toEqual(manifest);
|
||||
expect(namePwaManifest({ manifest, install_name: " " })).toEqual(manifest);
|
||||
expect(namePwaManifest({ manifest })).toEqual(manifest);
|
||||
});
|
||||
|
||||
test("labels the icon with the name and adds the site name to the full name", () => {
|
||||
expect(namePwaManifest({ manifest, install_name: " Acme " })).toEqual({
|
||||
...manifest,
|
||||
name: `Acme - ${SiteData["SiteName"]}`,
|
||||
short_name: "Acme",
|
||||
});
|
||||
});
|
||||
|
||||
test("doesn't repeat the site name when the name already has it", () => {
|
||||
const install_name = `Acme ${SiteData["SiteName"].toUpperCase()}`;
|
||||
|
||||
expect(namePwaManifest({ manifest, install_name })).toMatchObject({
|
||||
name: install_name,
|
||||
short_name: install_name,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { SiteData } from "@/src/data/site-data";
|
||||
|
||||
type Params = {
|
||||
manifest: Record<string, unknown>;
|
||||
install_name?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* The generated manifest with the install's own name, so the launcher
|
||||
* tells two installs apart. `short_name` (the label under the icon) is the
|
||||
* name alone; `name` adds `SiteName` unless the name already says it.
|
||||
* Unnamed, the manifest is unchanged.
|
||||
*/
|
||||
export default function namePwaManifest({ manifest, install_name }: Params) {
|
||||
const name = install_name?.trim();
|
||||
|
||||
if (!name) return manifest;
|
||||
|
||||
const site_name = SiteData["SiteName"];
|
||||
const says_site_name = name.toLowerCase().includes(site_name.toLowerCase());
|
||||
|
||||
return {
|
||||
...manifest,
|
||||
name: says_site_name ? name : `${name} - ${site_name}`,
|
||||
short_name: name,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user