06/05 Optimize app: report upgrades

This commit is contained in:
2026-06-05 14:22:19 -04:00
parent 2f62417c9f
commit 04acefd9f8
6 changed files with 486 additions and 25 deletions
+102 -1
View File
@@ -169,7 +169,10 @@
.table-wrap, .pcard.p-0 { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Remove h-100 height constraint on table wrappers so overflow-x works */
.pcard.p-0.h-100 { height: auto !important; }
.pfm-table { min-width: 560px; }
/* Default min-width — hides .d-mob-none columns first, then scroll */
.pfm-table { min-width: 420px; }
/* Wider tables (investments, etc.) can opt in to more space */
.pfm-table.wide { min-width: 700px; }
/* Hide low-priority columns */
.d-mob-none { display: none !important; }
/* Topbar title: truncate so action buttons always fit */
@@ -187,6 +190,10 @@
.tb-right .btn { padding-left: 8px; padding-right: 8px; }
.stat-card .stat-value { font-size: 16px; }
}
/* Keyboard shortcut cheatsheet modal */
#kbd-modal .kbd-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
#kbd-modal .kbd-row:last-child { border: none; }
#kbd-modal kbd { background: #f1f5f9; border: 1px solid #cbd5e1; border-radius: 4px; padding: 2px 7px; font-size: 12px; font-family: 'DM Mono', monospace; }
.sb-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 1039; }
.sb-overlay.on { display: block; }
@@ -311,6 +318,12 @@
<span class="tb-title">{% block page_title %}{% endblock %}</span>
<div class="tb-right">
{% block topbar_actions %}{% endblock %}
<button type="button" data-bs-toggle="modal" data-bs-target="#kbd-modal"
title="Keyboard shortcuts (?)"
style="background:none;border:none;color:var(--muted);font-size:13px;padding:3px 6px;border-radius:6px;cursor:pointer;line-height:1;"
class="d-none d-md-inline-flex align-items-center">
<i class="bi bi-keyboard"></i>
</button>
<span class="d-none d-sm-inline small text-muted mono"
>{{ current_user.display_name or current_user.username }}</span
>
@@ -339,6 +352,27 @@
<!-- MAIN -->
<main id="main">{% block content %}{% endblock %}</main>
<!-- Keyboard shortcuts cheatsheet modal -->
<div class="modal fade" id="kbd-modal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header py-2 px-3">
<h6 class="modal-title mb-0"><i class="bi bi-keyboard me-2"></i>Keyboard Shortcuts</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body px-3 py-2">
<div class="kbd-row"><span>New expense</span><kbd>n</kbd></div>
<div class="kbd-row"><span>New income</span><kbd>i</kbd></div>
<div class="kbd-row"><span>Focus search</span><kbd>/</kbd></div>
<div class="kbd-row"><span>Go to dashboard</span><kbd>g</kbd> then <kbd>h</kbd></div>
<div class="kbd-row"><span>Go to transactions</span><kbd>g</kbd> then <kbd>t</kbd></div>
<div class="kbd-row"><span>Go to accounts</span><kbd>g</kbd> then <kbd>a</kbd></div>
<div class="kbd-row"><span>Show this help</span><kbd>?</kbd></div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
(function () {
@@ -372,6 +406,73 @@
}, 4500);
});
})();
// ── Keyboard shortcuts ────────────────────────────────────────────────
(function () {
var gPending = false, gTimer = null;
function inInput() {
var t = document.activeElement;
return t && (t.tagName === 'INPUT' || t.tagName === 'TEXTAREA' ||
t.tagName === 'SELECT' || t.isContentEditable);
}
document.addEventListener('keydown', function (e) {
if (inInput()) return;
if (e.ctrlKey || e.metaKey || e.altKey) return;
var key = e.key;
// ? → show shortcut modal
if (key === '?') {
e.preventDefault();
bootstrap.Modal.getOrCreateInstance(
document.getElementById('kbd-modal')
).show();
return;
}
// g-chord for navigation
if (gPending) {
clearTimeout(gTimer);
gPending = false;
if (key === 'h') { window.location.href = '/'; return; }
if (key === 't') { window.location.href = '{{ url_for("transactions.index") }}'; return; }
if (key === 'a') { window.location.href = '{{ url_for("accounts.index") }}'; return; }
return;
}
if (key === 'g') {
gPending = true;
gTimer = setTimeout(function () { gPending = false; }, 1000);
return;
}
// n → new expense
if (key === 'n') {
e.preventDefault();
window.location.href = '{{ url_for("transactions.new", type="expense") }}';
return;
}
// i → new income
if (key === 'i') {
e.preventDefault();
window.location.href = '{{ url_for("transactions.new", type="income") }}';
return;
}
// / → focus search input
if (key === '/') {
var s = document.querySelector('input[name="q"], input[type="search"], .search-input');
if (s) {
e.preventDefault();
s.focus();
s.select();
}
}
});
})();
</script>
{% block extra_js %}{% endblock %}
</body>