diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
index 706d687..f4d228a 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js
@@ -9823,13 +9823,55 @@ function shouldIgnoreGlobalShortcut(target) {
return !!target.closest("[contenteditable='true']");
}
+// ── Shortcut help overlay ─────────────────────────────────────────────────────
+function toggleShortcutOverlay() {
+ const el = document.getElementById("shortcut-overlay");
+ if (!el) return;
+ el.classList.toggle("is-hidden");
+}
+function hideShortcutOverlay() {
+ const el = document.getElementById("shortcut-overlay");
+ if (el) el.classList.add("is-hidden");
+}
+function isShortcutOverlayVisible() {
+ const el = document.getElementById("shortcut-overlay");
+ return el && !el.classList.contains("is-hidden");
+}
+document.addEventListener("DOMContentLoaded", () => {
+ const overlay = document.getElementById("shortcut-overlay");
+ if (overlay) overlay.addEventListener("click", (e) => {
+ if (e.target === overlay) hideShortcutOverlay();
+ });
+});
+
window.addEventListener("keydown", (event) => {
if (event.defaultPrevented || event.repeat || event.isComposing) return;
+
+ const key = (event.key || "").toLowerCase();
+
+ // F1 — toggle shortcut help
+ if (event.key === "F1") {
+ event.preventDefault();
+ toggleShortcutOverlay();
+ return;
+ }
+
+ // Escape — close shortcut overlay if open
+ if (event.key === "Escape" && isShortcutOverlayVisible()) {
+ event.preventDefault();
+ hideShortcutOverlay();
+ return;
+ }
+
if (event.ctrlKey || event.metaKey || event.altKey) return;
if (shouldIgnoreGlobalShortcut(event.target)) return;
- if ((event.key || "").toLowerCase() !== "s") return;
- event.preventDefault();
- void captureSpectrumScreenshot();
+
+ // S — spectrum screenshot
+ if (key === "s") {
+ event.preventDefault();
+ void captureSpectrumScreenshot();
+ return;
+ }
}, { capture: true });
// ── Zoom helpers ──────────────────────────────────────────────────────────────
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
index 8f6f489..9a3dc37 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html
@@ -1046,6 +1046,19 @@
+
Loading decode history…
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
index 87a3ee9..c86a219 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
@@ -1320,6 +1320,83 @@ small { color: var(--text-muted); }
.sub-tab { flex-shrink: 0; background: transparent; border: none; border-bottom: 2px solid transparent; border-radius: 0; padding: 0.35rem 0.75rem; color: var(--text-muted); cursor: pointer; font-size: 0.85rem; height: auto; }
.sub-tab.active { border-bottom-color: var(--accent-green); color: var(--accent-green); font-weight: 600; }
.sub-tab:hover:not(.active) { color: var(--text); }
+/* ── Shortcut help overlay (F1) ─────────────────────────────────────── */
+.shortcut-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 9600;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1.2rem;
+ background: color-mix(in srgb, var(--bg) 36%, transparent);
+ backdrop-filter: blur(6px);
+ -webkit-backdrop-filter: blur(6px);
+ opacity: 1;
+ visibility: visible;
+ transition: opacity 140ms ease, visibility 140ms ease;
+}
+.shortcut-overlay.is-hidden {
+ opacity: 0;
+ visibility: hidden;
+ pointer-events: none;
+}
+.shortcut-overlay-card {
+ min-width: min(22rem, calc(100vw - 2.4rem));
+ max-width: min(28rem, calc(100vw - 2.4rem));
+ padding: 1.2rem 1.4rem;
+ border-radius: 0.9rem;
+ border: 1px solid color-mix(in srgb, var(--border-light) 72%, transparent);
+ background: color-mix(in srgb, var(--card-bg) 92%, transparent);
+ box-shadow: 0 18px 40px rgba(0, 0, 0, 0.22);
+}
+.shortcut-overlay-title {
+ font-size: 1.05rem;
+ font-weight: 800;
+ color: var(--text-heading);
+ margin-bottom: 0.8rem;
+ text-align: center;
+}
+.shortcut-table {
+ width: 100%;
+ border-collapse: collapse;
+}
+.shortcut-table td {
+ padding: 0.32rem 0.4rem;
+ font-size: 0.88rem;
+ color: var(--text);
+ border-bottom: 1px solid color-mix(in srgb, var(--border-light) 40%, transparent);
+}
+.shortcut-table tr:last-child td {
+ border-bottom: none;
+}
+.shortcut-key {
+ width: 5rem;
+ text-align: right;
+ padding-right: 0.9rem !important;
+}
+.shortcut-key kbd,
+.shortcut-overlay-hint kbd {
+ display: inline-block;
+ min-width: 1.6em;
+ padding: 0.12em 0.45em;
+ border: 1px solid var(--border);
+ border-radius: 0.3rem;
+ background: var(--bg);
+ font-family: inherit;
+ font-size: 0.82rem;
+ font-weight: 600;
+ text-align: center;
+ color: var(--text);
+ box-shadow: 0 1px 0 color-mix(in srgb, var(--border) 60%, transparent);
+}
+.shortcut-overlay-hint {
+ margin-top: 0.7rem;
+ text-align: center;
+ font-size: 0.76rem;
+ color: var(--text-muted);
+}
+
.decode-history-overlay {
position: fixed;
inset: 0;