tinyrelaycommit

Commit 143080a91f7f

browse files at this commit | history

1diff --git a/internal/webui/bridge.js b/internal/webui/bridge.js
2index eaecd9b..225c3b5 100644
3--- a/internal/webui/bridge.js
4+++ b/internal/webui/bridge.js
5@@ -74,6 +74,21 @@
6 };
7 paintChrome();
8 matchMedia("(prefers-color-scheme: dark)").addEventListener("change", paintChrome);
9+ // Browsers that can install the app announce it; the footer then offers
10+ // a quiet link and nothing else changes until it is pressed.
11+ let installPrompt = null;
12+ const installButton = () => document.getElementById("install");
13+ window.addEventListener("beforeinstallprompt", event => {
14+ event.preventDefault();
15+ installPrompt = event;
16+ const button = installButton();
17+ if (button) button.hidden = false;
18+ });
19+ window.addEventListener("appinstalled", () => {
20+ installPrompt = null;
21+ const button = installButton();
22+ if (button) button.hidden = true;
23+ });
24 const setMenu = open => {
25 const menu = document.getElementById("nav-menu");
26 if (menu) menu.open = open;
27@@ -86,6 +101,18 @@
28 shellBindings.add(rail);
29 rail.addEventListener("click", event => { if (event.target.closest("a")) setMenu(false); });
30 }
31+ const install = installButton();
32+ if (install && !shellBindings.has(install)) {
33+ shellBindings.add(install);
34+ install.hidden = !installPrompt;
35+ install.addEventListener("click", async () => {
36+ if (!installPrompt) return;
37+ const prompt = installPrompt;
38+ installPrompt = null;
39+ install.hidden = true;
40+ try { await prompt.prompt(); } catch {}
41+ });
42+ }
43 if (themeButton && !shellBindings.has(themeButton)) {
44 shellBindings.add(themeButton);
45 const label = () => { themeButton.textContent = currentTheme() === "dark" ? "light" : "dark"; };
46diff --git a/internal/webui/page.html b/internal/webui/page.html
47index aa4e6c6..4788e82 100644
48--- a/internal/webui/page.html
49+++ b/internal/webui/page.html
50@@ -61,7 +61,7 @@
51 {{end}}</div></td>
52 <td id="aside"><div id="panel">{{template "panel" .}}</div></td>
53 </tr></tbody></table>
54-<footer id="footer"><table><tr><td><span id="prompt"><b>{{.Slug}}</b> &raquo; {{prompt .Path .Query}}</span></td><td><span id="who">{{if .Private}}private relay{{else if .Actor}}signed in as {{template "nostrKey" .Actor}} (<button id="session-logout" type="button">sign out</button>){{else}}browsing as guest (<a href="/signin">Sign in</a>){{end}}</span> <span id="session-status" role="status"></span><span id="navigation-status" role="status" aria-live="polite"></span></td></tr></table></footer>
55+<footer id="footer"><table><tr><td><span id="prompt"><b>{{.Slug}}</b> &raquo; {{prompt .Path .Query}}</span></td><td><span id="who">{{if .Private}}private relay{{else if .Actor}}signed in as {{template "nostrKey" .Actor}} (<button id="session-logout" type="button">sign out</button>){{else}}browsing as guest (<a href="/signin">Sign in</a>){{end}}</span> <span id="session-status" role="status"></span><span id="navigation-status" role="status" aria-live="polite"></span></td></tr></table><button id="install" type="button" hidden>install app</button></footer>
56 <script src="{{scriptURL "tiny.js"}}"></script>
57 <script src="{{scriptURL "bridge.js"}}"></script>
58 {{if or (eq .Tab "files") (eq .Tab "file")}}<script src="{{scriptURL "blossom-encryption.js"}}"></script>
59diff --git a/internal/webui/style.css b/internal/webui/style.css
60index c28602d..45a481b 100644
61--- a/internal/webui/style.css
62+++ b/internal/webui/style.css
63@@ -38,6 +38,8 @@ img{max-width:100%}
64 #who button{border:0;background:none;padding:0;color:var(--accent);font:inherit}#who button:hover{text-decoration:underline}
65 #railbox{box-sizing:border-box;padding-bottom:44px}
66 #rail-tools{position:absolute;right:0;bottom:0;margin:0;padding:10px 2ch 10px 2.5ch}
67+/* The install hint sits on the footer's centre line so it never moves the prompt or the session. */
68+#install{position:absolute;left:50%;top:0;transform:translateX(-50%);border:0;background:none;padding:0;color:var(--muted);font:12px var(--mono);line-height:27px;cursor:pointer}#install:hover{color:var(--ink);text-decoration:underline}#install[hidden]{display:none}
69 share-link{display:inline-block}share-link:empty{display:none}
70 #theme{border:0;background:none;padding:0;color:var(--muted);font:12px var(--mono)}#theme:hover{color:var(--ink);text-decoration:underline}
71
72@@ -210,6 +212,7 @@ html,body{overflow:auto}
73 #content>section{padding:14px 2.5ch 20px}
74 #prompt{display:none}#footer td:last-child{text-align:left;white-space:nowrap}
75 #footer{padding:0 12px}#who{font-size:11px}
76+#install{left:auto;right:12px;transform:none}
77 #navigation-status:not(:empty),#session-status:not(:empty){position:absolute;bottom:100%;left:0;right:0;padding:6px 12px;background:var(--rail);border-top:1px solid var(--line);white-space:normal}
78 #split,#split>tbody,#split>tbody>tr,#split>tbody>tr>td{display:block;width:auto}
79 #tree{border-right:0;border-bottom:1px solid var(--line)}
80diff --git a/scripts/signer.test.mjs b/scripts/signer.test.mjs
81index 08b2771..b895b90 100644
82--- a/scripts/signer.test.mjs
83+++ b/scripts/signer.test.mjs
84@@ -24,6 +24,7 @@ async function page({signedIn = false, bunkerResult = null} = {}) {
85 navigator: {clipboard: {writeText: async () => {} }},
86 getComputedStyle: () => ({getPropertyValue: () => ""}),
87 matchMedia: () => ({matches: false, addEventListener() {}}),
88+ addEventListener() {},
89 localStorage: {getItem: () => null, setItem() {}, removeItem() {}},
90 sessionStorage: {getItem: key => saved.get(key), setItem: (key, value) => saved.set(key, value), removeItem: key => saved.delete(key)},
91 NostrSigner: {

About

ownerc01503e8035f
visibilitypublic
head143080a91f7f

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs