feat(web): iPhone PWA fixes (M1) + warm RTO redesign (M2) #3
@@ -247,5 +247,6 @@
|
|||||||
}
|
}
|
||||||
load();
|
load();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -80,5 +80,6 @@
|
|||||||
}
|
}
|
||||||
load();
|
load();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -100,5 +100,6 @@
|
|||||||
}
|
}
|
||||||
load();
|
load();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -80,11 +80,6 @@
|
|||||||
<button id="newSessionBtn">➕ New</button>
|
<button id="newSessionBtn">➕ New</button>
|
||||||
<button id="renameSessionBtn">✏️ Rename</button>
|
<button id="renameSessionBtn">✏️ Rename</button>
|
||||||
<button id="thinkingStreamBtn" title="Show live activity log">📜 Live Log</button>
|
<button id="thinkingStreamBtn" title="Show live activity log">📜 Live Log</button>
|
||||||
<a id="fullLogBtn" href="/logs" target="_blank" rel="noopener" title="Open the full-page log" role="button">⛶ Full Log</a>
|
|
||||||
<a id="sessionBtn" href="/session" target="_blank" rel="noopener" title="Live session HUD" role="button">🎬 Session</a>
|
|
||||||
<a id="historyBtn" href="/history" target="_blank" rel="noopener" title="Past sessions" role="button">📚 Sessions</a>
|
|
||||||
<a id="mindBtn" href="/self" target="_blank" rel="noopener" title="Read her mind — Lyra's current self-state" role="button">🧠 Mind</a>
|
|
||||||
<a id="handsBtn" href="/hands" target="_blank" rel="noopener" title="Recorded poker hands" role="button">🃏 Hands</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status -->
|
<!-- Status -->
|
||||||
@@ -990,6 +985,9 @@
|
|||||||
loadSessionList(); // Refresh session list when opening settings
|
loadSessionList(); // Refresh session list when opening settings
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Sidebar "Settings" from another page navigates here with ?settings=1.
|
||||||
|
if (new URLSearchParams(location.search).get("settings")) settingsBtn.click();
|
||||||
|
|
||||||
// Hide modal functions
|
// Hide modal functions
|
||||||
const hideModal = () => {
|
const hideModal = () => {
|
||||||
settingsModal.classList.remove("show");
|
settingsModal.classList.remove("show");
|
||||||
@@ -1187,5 +1185,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -157,5 +157,6 @@
|
|||||||
setInterval(load, 20000);
|
setInterval(load, 20000);
|
||||||
document.addEventListener('visibilitychange', () => { if (!document.hidden) load(); });
|
document.addEventListener('visibilitychange', () => { if (!document.hidden) load(); });
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -235,5 +235,6 @@
|
|||||||
}
|
}
|
||||||
connect();
|
connect();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* Shared app navigation — one source of truth across all pages (no build step).
|
||||||
|
Injects a left sidebar on desktop (>=769px) with active-page highlighting; stays
|
||||||
|
out of the way on mobile, where each page keeps its bottom bar / back-links. */
|
||||||
|
(function () {
|
||||||
|
const ITEMS = [
|
||||||
|
{ href: "/", icon: "💬", label: "Chat" },
|
||||||
|
{ href: "/session", icon: "♠", label: "Session" },
|
||||||
|
{ href: "/history", icon: "📚", label: "History" },
|
||||||
|
{ href: "/hands", icon: "🃏", label: "Hands" },
|
||||||
|
{ href: "/self", icon: "🧠", label: "Mind" },
|
||||||
|
{ href: "/journal", icon: "📔", label: "Journal" },
|
||||||
|
{ href: "/logs", icon: "📜", label: "Logs" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const path = location.pathname;
|
||||||
|
function isActive(href) {
|
||||||
|
if (href === "/") return path === "/" || path === "";
|
||||||
|
if (href === "/hands") return path === "/hands" || path.indexOf("/hand") === 0;
|
||||||
|
if (href === "/history") return path.indexOf("/history") === 0 || path.indexOf("/recap") === 0;
|
||||||
|
return path === href || path.indexOf(href + "/") === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const css = `
|
||||||
|
#app-nav { display: none; }
|
||||||
|
@media screen and (min-width: 769px) {
|
||||||
|
body { padding-left: 212px; }
|
||||||
|
#app-nav {
|
||||||
|
position: fixed; left: 0; top: 0; bottom: 0; width: 212px; z-index: 1000;
|
||||||
|
display: flex; flex-direction: column; gap: 2px; box-sizing: border-box;
|
||||||
|
padding: 14px 10px; background: #0b0b0b; border-right: 1px solid #2a1d12;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
#app-nav .brand {
|
||||||
|
display: flex; align-items: center; gap: 8px; text-decoration: none;
|
||||||
|
color: #ff7a00; font-weight: 700; font-size: 1.15rem; letter-spacing: .5px;
|
||||||
|
padding: 6px 11px 14px;
|
||||||
|
}
|
||||||
|
#app-nav .brand .dot { width: 8px; height: 8px; border-radius: 50%;
|
||||||
|
background: #8fd694; box-shadow: 0 0 8px rgba(143,214,148,.6); }
|
||||||
|
#app-nav .navitem {
|
||||||
|
display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
|
||||||
|
padding: 9px 11px; border-radius: 9px; border: none; background: none;
|
||||||
|
color: #cfcfcf; text-decoration: none; font-size: .95rem; cursor: pointer;
|
||||||
|
font-family: inherit; -webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
#app-nav .navitem .i { font-size: 1.05rem; width: 20px; text-align: center; filter: grayscale(.3); }
|
||||||
|
#app-nav .navitem:hover { background: rgba(255,122,0,.08); color: #fff; }
|
||||||
|
#app-nav .navitem.active { background: rgba(255,122,0,.14); color: #ff7a00; }
|
||||||
|
#app-nav .navitem.active .i { filter: none; }
|
||||||
|
#app-nav .spacer { flex: 1; }
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.textContent = css;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
const nav = document.createElement("nav");
|
||||||
|
nav.id = "app-nav";
|
||||||
|
nav.setAttribute("aria-label", "App navigation");
|
||||||
|
nav.innerHTML =
|
||||||
|
'<a class="brand" href="/"><span class="dot"></span> Lyra</a>' +
|
||||||
|
ITEMS.map(function (it) {
|
||||||
|
return '<a class="navitem' + (isActive(it.href) ? " active" : "") + '" href="' + it.href + '">' +
|
||||||
|
'<span class="i">' + it.icon + '</span><span class="l">' + it.label + "</span></a>";
|
||||||
|
}).join("") +
|
||||||
|
'<div class="spacer"></div>' +
|
||||||
|
'<button class="navitem" id="navSettings" type="button"><span class="i">⚙</span><span class="l">Settings</span></button>';
|
||||||
|
document.body.insertBefore(nav, document.body.firstChild);
|
||||||
|
|
||||||
|
// Settings opens the chat-page modal; from other pages, jump to chat and open it.
|
||||||
|
nav.querySelector("#navSettings").addEventListener("click", function () {
|
||||||
|
const btn = document.getElementById("settingsBtn");
|
||||||
|
if (btn) btn.click();
|
||||||
|
else location.href = "/?settings=1";
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -74,5 +74,6 @@
|
|||||||
}
|
}
|
||||||
load();
|
load();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -195,5 +195,6 @@
|
|||||||
setInterval(refresh, 12000);
|
setInterval(refresh, 12000);
|
||||||
document.addEventListener('visibilitychange', () => { if (!document.hidden) refresh(); });
|
document.addEventListener('visibilitychange', () => { if (!document.hidden) refresh(); });
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -355,5 +355,6 @@
|
|||||||
if (!SID) setInterval(refresh, 5000); // live HUD polls; a past session is static
|
if (!SID) setInterval(refresh, 5000); // live HUD polls; a past session is static
|
||||||
document.addEventListener('visibilitychange', () => { if (!document.hidden) refresh(); });
|
document.addEventListener('visibilitychange', () => { if (!document.hidden) refresh(); });
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/nav.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user