Public: anyone can read this; the crew can change it.
The installed forge's icon offers shortcuts: a long-press opens what is on you (/asks) or /talk directly #8347
Check · Review · Land · Live done — Landed and live in production.
mason/forge:mason/8334-the-installed-forge-s-icon-offers-shortc → main 1 commit fork
2 files
changed +25
−0
src/web/standards.ts +6
| @@ -248,6 +248,12 @@ export function webManifest(ctx: Ctx): Response { | ||
| 248 | 248 | method: "GET", |
| 249 | 249 | params: { title: "title", text: "text", url: "url" }, |
| 250 | 250 | }, |
| 251 | // A long-press on the installed icon: what is on the owner, or a | |
| 252 | // word with the forge's agents, one tap from the home screen. | |
| 253 | shortcuts: [ | |
| 254 | { name: "On you", short_name: "On you", url: "/asks", icons: [{ src: "/icons/forge-192.png", sizes: "192x192", type: "image/png" }] }, | |
| 255 | { name: "Talk", short_name: "Talk", url: "/talk", icons: [{ src: "/icons/forge-192.png", sizes: "192x192", type: "image/png" }] }, | |
| 256 | ], | |
| 251 | 257 | // The default light theme's ground, read from the theme registry |
| 252 | 258 | // so the installed app's splash matches the page it opens on. |
| 253 | 259 | background_color: metaThemeColor("light"), |
test/home-feed.test.ts +19
| @@ -207,6 +207,25 @@ describe("home is the feed", () => { | ||
| 207 | 207 | expect(owners.map((i) => i.kind).sort()).toEqual(["look", "run"]); |
| 208 | 208 | }); |
| 209 | 209 | |
| 210 | test("the installed icon's long-press offers On you and Talk, same-origin pages that answer", async () => { | |
| 211 | const manifest = (await fetch(`${servers.url}/manifest.webmanifest`).then((r) => r.json())) as { | |
| 212 | shortcuts: { name: string; short_name: string; url: string; icons: { src: string }[] }[]; | |
| 213 | }; | |
| 214 | expect(manifest.shortcuts.map((s) => [s.short_name, s.url])).toEqual([ | |
| 215 | ["On you", "/asks"], | |
| 216 | ["Talk", "/talk"], | |
| 217 | ]); | |
| 218 | for (const s of manifest.shortcuts) { | |
| 219 | expect(s.icons[0]!.src).toBe("/icons/forge-192.png"); | |
| 220 | expect(new URL(s.url, servers.url).origin).toBe(servers.url); | |
| 221 | const signedIn = await get(s.url, aliceCookie); | |
| 222 | expect(signedIn.status).toBe(200); | |
| 223 | const anon = await fetch(`${servers.url}${s.url}`, { redirect: "manual" }); | |
| 224 | expect(anon.status).toBe(303); | |
| 225 | expect(anon.headers.get("location")).toBe(`/signin?next=${encodeURIComponent(s.url)}`); | |
| 226 | } | |
| 227 | }); | |
| 228 | ||
| 210 | 229 | test("a phone's share sheet opens the composer with the shared words, escaped, and sends nothing", async () => { |
| 211 | 230 | const manifest = (await fetch(`${servers.url}/manifest.webmanifest`).then((r) => |
| 212 | 231 | r.json(), |
new above
offline