06/05 Optimize app
This commit is contained in:
@@ -198,8 +198,88 @@
|
||||
.sb-overlay.on { display: block; }
|
||||
|
||||
@keyframes spin { to { transform: rotate(360deg); } }
|
||||
|
||||
/* ── Dark mode ─────────────────────────────────────────────────────── */
|
||||
body.dark-mode {
|
||||
--body-bg: #0f172a; --card-bg: #1e293b; --text: #e2e8f0;
|
||||
--muted: #94a3b8; --border: #334155;
|
||||
color-scheme: dark;
|
||||
}
|
||||
body.dark-mode #topbar { background: #1e293b; border-color: #334155; }
|
||||
body.dark-mode .pfm-table tbody tr:hover { background: #263548; }
|
||||
body.dark-mode .pfm-table th, body.dark-mode .pfm-table td { border-color: #334155; }
|
||||
body.dark-mode .form-control, body.dark-mode .form-select {
|
||||
background: #0f172a; border-color: #334155; color: #e2e8f0;
|
||||
}
|
||||
body.dark-mode .form-control:focus, body.dark-mode .form-select:focus {
|
||||
background: #0f172a; border-color: #3b82f6; color: #e2e8f0;
|
||||
box-shadow: 0 0 0 .2rem rgba(59,130,246,.25);
|
||||
}
|
||||
body.dark-mode .form-control::placeholder { color: #475569; }
|
||||
body.dark-mode .form-check-input { background-color: #334155; border-color: #475569; }
|
||||
body.dark-mode .form-check-input:checked { background-color: #3b82f6; border-color: #3b82f6; }
|
||||
body.dark-mode .btn-outline-secondary { color: #94a3b8; border-color: #334155; }
|
||||
body.dark-mode .btn-outline-secondary:hover,
|
||||
body.dark-mode .btn-outline-secondary:focus { background: #334155; color: #e2e8f0; border-color: #334155; }
|
||||
body.dark-mode .btn-outline-primary { color: #93c5fd; border-color: #1e40af; }
|
||||
body.dark-mode .btn-outline-primary:hover { background: #1e40af; color: #fff; }
|
||||
body.dark-mode .btn-outline-warning { color: #fcd34d; border-color: #92400e; }
|
||||
body.dark-mode .btn-outline-warning:hover { background: #92400e; color: #fff; }
|
||||
body.dark-mode .btn-outline-danger { color: #fca5a5; border-color: #991b1b; }
|
||||
body.dark-mode .btn-outline-danger:hover { background: #991b1b; color: #fff; }
|
||||
body.dark-mode .dropdown-menu { background: #1e293b; border-color: #334155; }
|
||||
body.dark-mode .dropdown-item { color: #e2e8f0; }
|
||||
body.dark-mode .dropdown-item:hover, body.dark-mode .dropdown-item:focus { background: #334155; color: #f1f5f9; }
|
||||
body.dark-mode .dropdown-divider { border-color: #334155; }
|
||||
body.dark-mode .modal-content { background: #1e293b; border-color: #334155; color: #e2e8f0; }
|
||||
body.dark-mode .modal-header, body.dark-mode .modal-footer { border-color: #334155; }
|
||||
body.dark-mode .modal-header .btn-close { filter: invert(1) grayscale(1); }
|
||||
body.dark-mode .alert-warning { background: #451a03; border-color: #92400e; color: #fcd34d; }
|
||||
body.dark-mode .alert-danger { background: #450a0a; border-color: #991b1b; color: #fca5a5; }
|
||||
body.dark-mode .alert-success { background: #052e16; border-color: #166534; color: #86efac; }
|
||||
body.dark-mode .alert-info { background: #0c1a2e; border-color: #1e40af; color: #93c5fd; }
|
||||
body.dark-mode .progress { background: #334155; }
|
||||
body.dark-mode .table { color: #e2e8f0; }
|
||||
body.dark-mode .input-group-text { background: #334155; border-color: #334155; color: #94a3b8; }
|
||||
body.dark-mode .badge-income { background: #064e3b; color: #6ee7b7; }
|
||||
body.dark-mode .badge-expense { background: #450a0a; color: #fca5a5; }
|
||||
body.dark-mode .badge-transfer { background: #1e3a5f; color: #93c5fd; }
|
||||
body.dark-mode #kbd-modal kbd { background: #334155; border-color: #475569; color: #e2e8f0; }
|
||||
body.dark-mode .report-tab { background: #1e293b; border-color: #334155; color: #94a3b8; }
|
||||
body.dark-mode .report-tab:hover { background: #334155; color: #e2e8f0; }
|
||||
body.dark-mode .report-tab.active { background: #e2e8f0; color: #0f172a; border-color: #e2e8f0; }
|
||||
/* Override common hardcoded light backgrounds in component inline styles */
|
||||
body.dark-mode [style*="background:#f8fafc"], body.dark-mode [style*="background: #f8fafc"],
|
||||
body.dark-mode [style*="background:#f1f5f9"], body.dark-mode [style*="background: #f1f5f9"]
|
||||
{ background: #263548 !important; }
|
||||
body.dark-mode [style*="background:#eff6ff"], body.dark-mode [style*="background: #eff6ff"]
|
||||
{ background: #1e3a5f !important; }
|
||||
body.dark-mode [style*="background:#fef2f2"], body.dark-mode [style*="background: #fef2f2"]
|
||||
{ background: #450a0a !important; }
|
||||
body.dark-mode [style*="background:#f0fdf4"], body.dark-mode [style*="background: #f0fdf4"]
|
||||
{ background: #052e16 !important; }
|
||||
body.dark-mode [style*="background:#fff5e6"], body.dark-mode [style*="background:#fffbeb"]
|
||||
{ background: #451a03 !important; }
|
||||
/* Text color overrides for hardcoded darks */
|
||||
body.dark-mode [style*="color:#0f172a"] { color: #e2e8f0 !important; }
|
||||
body.dark-mode [style*="color:#1e293b"] { color: #94a3b8 !important; }
|
||||
body.dark-mode [style*="color:#374151"] { color: #94a3b8 !important; }
|
||||
/* Border overrides */
|
||||
body.dark-mode [style*="border-bottom:1px solid #e2e8f0"],
|
||||
body.dark-mode [style*="border-bottom: 1px solid #e2e8f0"] { border-color: #334155 !important; }
|
||||
body.dark-mode [style*="border:1px solid #e2e8f0"],
|
||||
body.dark-mode [style*="border: 1px solid #e2e8f0"] { border-color: #334155 !important; }
|
||||
|
||||
{% block extra_css %}{% endblock %}
|
||||
</style>
|
||||
<script>
|
||||
/* Apply dark mode class to body before first paint to avoid flash */
|
||||
(function(){ if(localStorage.getItem('pfm_dark')==='1') document.documentElement.setAttribute('data-pfm-dark','1'); })();
|
||||
</script>
|
||||
<style>
|
||||
/* Instant pre-body dark (avoids FOUC) — matches body.dark-mode vars */
|
||||
html[data-pfm-dark] body { --body-bg:#0f172a; --card-bg:#1e293b; --text:#e2e8f0; --muted:#94a3b8; --border:#334155; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sb-overlay" id="sbOverlay"></div>
|
||||
@@ -318,6 +398,11 @@
|
||||
<span class="tb-title">{% block page_title %}{% endblock %}</span>
|
||||
<div class="tb-right">
|
||||
{% block topbar_actions %}{% endblock %}
|
||||
<button id="dark-toggle" type="button" title="Toggle dark mode"
|
||||
style="background:none;border:none;color:var(--muted);font-size:15px;padding:3px 6px;border-radius:6px;cursor:pointer;line-height:1;"
|
||||
class="d-inline-flex align-items-center">
|
||||
<i class="bi bi-moon-stars"></i>
|
||||
</button>
|
||||
<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;"
|
||||
@@ -473,6 +558,29 @@
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
// ── Dark mode toggle ─────────────────────────────────────────────────
|
||||
(function () {
|
||||
var DKEY = 'pfm_dark';
|
||||
var body = document.body;
|
||||
var btn = document.getElementById('dark-toggle');
|
||||
|
||||
function applyDark(on) {
|
||||
body.classList.toggle('dark-mode', on);
|
||||
document.documentElement.setAttribute('data-pfm-dark', on ? '1' : '0');
|
||||
if (btn) btn.querySelector('i').className = on ? 'bi bi-sun' : 'bi bi-moon-stars';
|
||||
}
|
||||
|
||||
// Initialise from storage
|
||||
var saved = localStorage.getItem(DKEY) === '1';
|
||||
applyDark(saved);
|
||||
|
||||
if (btn) btn.addEventListener('click', function () {
|
||||
var next = !body.classList.contains('dark-mode');
|
||||
localStorage.setItem(DKEY, next ? '1' : '0');
|
||||
applyDark(next);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user