06/05 Optimize app: report upgrades
This commit is contained in:
+102
-1
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user