Merge pull request 'Donker thema toevoegen via gebruikersmenu rechtsboven' (#3) from donker_thema into main

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
marijn committed 2026-10-14 16:11:54 +00:00
commit 91a5b8a7f3
10 files changed
+163 -20

No files matched your search

+103 -8
View File
@@ -37,11 +37,85 @@
--shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 4px 12px rgba(15, 23, 42, .05);
--shadow-lg: 0 10px 30px rgba(15, 23, 42, .18);
/* Overige vlakken */
--header-bg: var(--primary-color);
--row-hover: #f8fbfe;
--badge-bg: #e2e8f0; --badge-text: #334155;
--overlay: rgba(255, 255, 255, .85);
--header-height: 64px;
--page-width: 1200px;
--font: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
}
/* ---------- 1b. Donker thema (aan/uit via het gebruikersmenu rechtsboven) ---------- */
/* Alleen op scherm: afdrukken gebeurt altijd in het lichte thema */
@media screen {
html[data-theme="dark"] {
color-scheme: dark;
--primary-color: #3a8cc9;
--primary-dark: #2d73a8;
--primary-light: #17324a;
--background-color: #0f172a;
--surface: #1e293b;
--surface-muted: #172033;
--border: #334155;
--border-strong: #475569;
--text: #e2e8f0;
--text-muted: #94a3b8;
--success-bg: #14361f; --success-text: #86efac;
--warning-bg: #3a300b; --warning-text: #fde047;
--danger-bg: #3f1515; --danger-text: #fca5a5;
--info-bg: #172a4d; --info-text: #93c5fd;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
--shadow: 0 1px 3px rgba(0, 0, 0, .4), 0 4px 12px rgba(0, 0, 0, .25);
--shadow-lg: 0 10px 30px rgba(0, 0, 0, .6);
--header-bg: #13304a;
--row-hover: #243349;
--badge-bg: #334155; --badge-text: #e2e8f0;
--overlay: rgba(15, 23, 42, .85);
}
html[data-theme="dark"] .flash-message,
html[data-theme="dark"] .flash-message.success,
html[data-theme="dark"] .flash-message.error,
html[data-theme="dark"] .flash-message.danger,
html[data-theme="dark"] .flash-message.warning { border-color: var(--border); }
html[data-theme="dark"] .dash-section-title.admin::after { background: var(--danger-bg); }
html[data-theme="dark"] .tile.tile-tools .tile-icon,
html[data-theme="dark"] .tile.tile-tools .tile-links a:hover { background: #123b38; }
html[data-theme="dark"] .tile.tile-tools h3,
html[data-theme="dark"] .tile.tile-tools .tile-links a:hover { color: #5eead4; }
html[data-theme="dark"] .tile.tile-scholengroep .tile-icon,
html[data-theme="dark"] .tile.tile-scholengroep .tile-links a:hover { background: #2e1f52; }
html[data-theme="dark"] .tile.tile-scholengroep h3,
html[data-theme="dark"] .tile.tile-scholengroep .tile-links a:hover { color: #c4b5fd; }
html[data-theme="dark"] .google-btn { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
html[data-theme="dark"] .google-btn:hover { background: var(--surface-muted); }
html[data-theme="dark"] body.auth-page { background: var(--background-color); }
html[data-theme="dark"] mark { background: #854d0e; color: #fef9c3; }
/* Pagina's met eigen pastelkleuren (gemarkeerde rijen, legendes, filters) */
html[data-theme="dark"] .tellers .let,
html[data-theme="dark"] .filters button.let { background: var(--warning-bg); border-color: #854d0e; }
html[data-theme="dark"] .filters button.let[aria-pressed="true"] { background: #854d0e; color: #fef9c3; }
html[data-theme="dark"] td.leeg,
html[data-theme="dark"] tr.flagged td,
html[data-theme="dark"] table.aw .vandaag,
html[data-theme="dark"] td.inv input.gewijzigd,
html[data-theme="dark"] .panel.directie,
html[data-theme="dark"] .panel.vraag { background: #2e2710 !important; border-color: #854d0e; }
html[data-theme="dark"] tr.rij-fout td { background: #3a1a1a; }
html[data-theme="dark"] button.st:not(.aanwezig):not(.afwezig) { background: var(--surface-muted); border-color: var(--border-strong); color: var(--text-muted); }
html[data-theme="dark"] #personeelBody tr.g-account td, html[data-theme="dark"] .legende i.account { background: #14361f; border-color: #166534; }
html[data-theme="dark"] #personeelBody tr.g-alias td, html[data-theme="dark"] .legende i.alias { background: #3a2a10; border-color: #9a5b13; }
html[data-theme="dark"] #personeelBody tr.g-geen td, html[data-theme="dark"] .legende i.geen { background: #3a1a1a; border-color: #991b1b; }
}
/* ---------- 2. Basis ---------- */
*, *::before, *::after { box-sizing: border-box; }
@@ -84,7 +158,7 @@ a { color: var(--primary-color); }
align-items: center;
gap: 16px;
padding: 0 24px;
background: var(--primary-color);
background: var(--header-bg);
color: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
}
@@ -130,10 +204,29 @@ a { color: var(--primary-color); }
}
.home-btn, .header-btn { background: rgba(255, 255, 255, .16); color: #fff; }
.home-btn:hover, .header-btn:hover { background: rgba(255, 255, 255, .28); }
.logout-btn { background: #fff; color: var(--danger); }
.logout-btn { background: var(--surface); color: var(--danger); }
.logout-btn:hover { background: var(--danger-bg); }
.app-header form { margin: 0; }
/* Gebruikersmenu (klik op je naam rechtsboven) */
.user-menu { position: relative; }
.user-menu-btn { opacity: 1; font-weight: 500; }
.user-menu-btn .caret { font-size: 10px; opacity: .8; }
.user-menu-panel {
display: none;
position: absolute; right: 0; top: calc(100% + 8px);
z-index: 1100;
min-width: 260px;
padding: 6px 14px;
background: var(--surface); color: var(--text);
border: 1px solid var(--border); border-radius: var(--radius);
box-shadow: var(--shadow-lg);
}
.user-menu.open .user-menu-panel { display: block; }
.user-menu-head { padding: 8px 0 10px; border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text-muted); overflow-wrap: anywhere; }
.user-menu-head strong { display: block; color: var(--text); font-size: 14px; }
.user-menu-panel .switch-row { font-size: 14px; font-weight: 500; cursor: pointer; }
/* ---------- 4. Pagina-layout ---------- */
.app-main {
flex: 1;
@@ -187,7 +280,7 @@ select, textarea {
font: inherit;
font-size: 15px;
color: var(--text);
background: #fff;
background: var(--surface);
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
transition: border-color .15s, box-shadow .15s;
@@ -260,7 +353,7 @@ button:disabled, .btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-secondary { background: #475569; }
.btn-secondary:hover { background: #334155; }
.btn-light { background: #fff; color: var(--text); border-color: var(--border-strong); }
.btn-light { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn-light:hover { background: var(--surface-muted); }
.btn-success { background: var(--success); }
.btn-success:hover { background: #15803d; }
@@ -291,7 +384,7 @@ button:disabled, .btn:disabled { opacity: .5; cursor: not-allowed; }
border-radius: var(--radius);
margin-top: 12px;
}
table { width: 100%; border-collapse: collapse; background: #fff; text-align: left; }
table { width: 100%; border-collapse: collapse; background: var(--surface); text-align: left; }
th, td { padding: 11px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
th {
background: var(--surface-muted);
@@ -299,7 +392,7 @@ th {
color: var(--text-muted); white-space: nowrap;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: #f8fbfe; }
tbody tr:hover { background: var(--row-hover); }
td.actions, th.actions { text-align: right; white-space: nowrap; }
td.actions form { display: inline; margin: 0; }
td.actions > * + * { margin-left: 6px; }
@@ -324,7 +417,7 @@ td.center, th.center { text-align: center; }
display: inline-flex; align-items: center; gap: 4px;
padding: 3px 10px; border-radius: 999px;
font-size: 12.5px; font-weight: 600; white-space: nowrap;
background: #e2e8f0; color: #334155;
background: var(--badge-bg); color: var(--badge-text);
}
.badge-success { background: var(--success-bg); color: var(--success-text); }
.badge-warning { background: var(--warning-bg); color: var(--warning-text); }
@@ -448,7 +541,7 @@ td.center, th.center { text-align: center; }
position: fixed; inset: 0;
z-index: 9999;
flex-direction: column; justify-content: center; align-items: center; gap: 16px;
background: rgba(255, 255, 255, .85);
background: var(--overlay);
backdrop-filter: blur(2px);
}
.spinner {
@@ -563,6 +656,8 @@ body.auth-page { background: linear-gradient(160deg, #eaf2f9 0%, var(--backgroun
/* ---------- 17. Responsief ---------- */
@media (max-width: 900px) {
.brand-school, .header-user { display: none; }
.user-menu-btn { display: inline-flex; }
.user-menu-btn .user-naam { display: none; }
}
@media (max-width: 720px) {
.app-header {
+1 -1
View File
@@ -7,7 +7,7 @@
<style>
/* Bewerken-knop altijd zichtbaar: laatste kolom blijft rechts staan bij horizontaal scrollen */
.lln-tabel td.actions, .lln-tabel th.actions {
position: sticky; right: 0; background: #fff; white-space: nowrap;
position: sticky; right: 0; background: var(--surface); white-space: nowrap;
box-shadow: -6px 0 6px -6px rgba(15, 23, 42, .15);
}
.lln-tabel th.actions { background: var(--surface-muted); }
+1 -1
View File
@@ -21,7 +21,7 @@
tr.lln.open td:first-child::before { transform: rotate(90deg); }
tr.detail td { background: var(--surface-muted); padding: 10px 14px 14px 44px; }
.day-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.day-chip { display: inline-flex; gap: 6px; align-items: center; padding: 4px 10px; border-radius: 999px; background: #fff;
.day-chip { display: inline-flex; gap: 6px; align-items: center; padding: 4px 10px; border-radius: 999px; background: var(--surface);
border: 1px solid var(--border); font-size: 13px; }
.day-chip .dd { font-weight: 700; color: var(--danger-text); }
.count-badge { display: inline-block; min-width: 34px; text-align: center; padding: 3px 10px; border-radius: 999px; font-weight: 700;
+50 -2
View File
@@ -4,6 +4,10 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}PIVOT{% endblock %} – {{ school_name_short|upper or 'PIVOT' }}</title>
<script>
/* Thema meteen toepassen (vóór het tekenen) zodat de pagina niet eerst licht oplicht */
try { if (localStorage.getItem('pivot.thema') === 'donker') document.documentElement.dataset.theme = 'dark'; } catch (e) { /* geen opslag */ }
</script>
<link rel="icon" type="image/png" href="{{ url_for('static', filename='pivot_mark.png') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='global.css') }}">
{% block head %}{% endblock %}
@@ -44,7 +48,7 @@
onchange="if (this.value) location.href = this.value">
<option value="" selected>🏫 {{ school.naam }} ⇄</option>
{% for s in andere_scholen %}
<option value="{{ url_for('scholen.wissel', code=s.code) }}" style="color:#1e293b">{{ s.naam }}</option>
<option value="{{ url_for('scholen.wissel', code=s.code) }}" style="color:var(--text)">{{ s.naam }}</option>
{% endfor %}
</select>
{% else %}
@@ -52,7 +56,22 @@
{% endif %}
{% endif %}
{% if session.get('user') %}
<span class="header-user">👤 {{ session.get('user') }}</span>
<div class="user-menu" id="user-menu">
<button type="button" class="header-btn header-user user-menu-btn" id="user-menu-btn"
aria-haspopup="true" aria-expanded="false" aria-controls="user-menu-panel" title="Gebruikersmenu">
👤 <span class="user-naam">{{ session.get('user') }}</span> <span class="caret">▼</span>
</button>
<div class="user-menu-panel" id="user-menu-panel">
<div class="user-menu-head">Aangemeld als <strong>{{ session.get('user') }}</strong></div>
<label class="switch-row" for="thema-schakelaar">
<span>🌙 Donker thema</span>
<span class="switch">
<input type="checkbox" id="thema-schakelaar">
<span class="slider"></span>
</span>
</label>
</div>
</div>
{% endif %}
<form action="{{ url_for('auth.logout') }}" method="get">
<button type="submit" class="logout-btn">Uitloggen</button>
@@ -134,6 +153,35 @@
});
}, 6000);
// Gebruikersmenu rechtsboven + donker thema aan/uit (onthouden in deze browser)
(function () {
const menu = document.getElementById('user-menu');
if (!menu) return;
const knop = document.getElementById('user-menu-btn');
const schakelaar = document.getElementById('thema-schakelaar');
function zetOpen(open) {
menu.classList.toggle('open', open);
knop.setAttribute('aria-expanded', open);
}
knop.addEventListener('click', function (e) {
e.stopPropagation();
zetOpen(!menu.classList.contains('open'));
});
document.addEventListener('click', function (e) {
if (!menu.contains(e.target)) zetOpen(false);
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') zetOpen(false);
});
schakelaar.checked = document.documentElement.dataset.theme === 'dark';
schakelaar.addEventListener('change', function () {
if (schakelaar.checked) document.documentElement.dataset.theme = 'dark';
else delete document.documentElement.dataset.theme;
try { localStorage.setItem('pivot.thema', schakelaar.checked ? 'donker' : 'licht'); } catch (err) { /* negeren */ }
});
})();
// Escape sluit open modals
document.addEventListener('keydown', function (e) {
if (e.key !== 'Escape') return;
+1 -1
View File
@@ -23,7 +23,7 @@
.modus-keuze small { display: block; color: var(--text-muted); font-weight: 400; }
.tellers { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 14px; }
.teller-knop { all: unset; cursor: pointer; display: inline-flex; gap: 8px; align-items: center; padding: 8px 14px;
border-radius: var(--radius); border: 1px solid var(--border); background: #fff; font-weight: 600; font-size: 14px; }
border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface); font-weight: 600; font-size: 14px; }
.teller-knop.actief { border-color: var(--primary-color); box-shadow: 0 0 0 2px rgba(30,111,165,.18); }
.teller-knop .n { font-size: 18px; }
tr.rij-fout td { background: #fff7f7; }
+1 -1
View File
@@ -23,7 +23,7 @@
.modus-keuze small { display: block; color: var(--text-muted); font-weight: 400; }
.tellers { display: flex; flex-wrap: wrap; gap: 10px; margin: 6px 0 14px; }
.teller-knop { all: unset; cursor: pointer; display: inline-flex; gap: 8px; align-items: center; padding: 8px 14px;
border-radius: var(--radius); border: 1px solid var(--border); background: #fff; font-weight: 600; font-size: 14px; }
border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface); font-weight: 600; font-size: 14px; }
.teller-knop.actief { border-color: var(--primary-color); box-shadow: 0 0 0 2px rgba(30,111,165,.18); }
.teller-knop .n { font-size: 18px; }
tr.rij-fout td { background: #fff7f7; }
+1 -1
View File
@@ -23,7 +23,7 @@
#personeelBody tr.g-account td { background: #e8f7ee; }
#personeelBody tr.g-alias td { background: #fff1e0; }
#personeelBody tr.g-geen td { background: #fdeaea; }
#personeelBody tr[class*="g-"] input.adres, #personeelBody tr[class*="g-"] select.rol { background: #fff; }
#personeelBody tr[class*="g-"] input.adres, #personeelBody tr[class*="g-"] select.rol { background: var(--surface); }
.legende { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: center; margin: -6px 0 14px; font-size: .88em; color: var(--text-muted); }
.legende button.kleurfilter { all: unset; box-sizing: border-box; cursor: pointer; display: inline-flex; align-items: center;
gap: 6px; padding: 4px 10px; border-radius: 999px; border: 1px solid transparent; }
+1 -1
View File
@@ -11,7 +11,7 @@
.nav-bar form { display: flex; gap: 6px; margin: 0; }
.nav-bar input[type=date] { width: auto; }
.seg { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); overflow: hidden; }
.seg a { padding: 8px 14px; text-decoration: none; color: var(--text); font-weight: 600; font-size: 14px; background: #fff; }
.seg a { padding: 8px 14px; text-decoration: none; color: var(--text); font-weight: 600; font-size: 14px; background: var(--surface); }
.seg a.on { background: var(--primary-color); color: #fff; }
.day { margin-bottom: 20px; }
.day-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 10px; }
+3 -3
View File
@@ -8,18 +8,18 @@
{% block extra_css %}
<style>
.soort-switch { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.soort-switch a { padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); background: #fff; text-decoration: none; color: var(--text); font-weight: 600; font-size: 14px; }
.soort-switch a { padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); text-decoration: none; color: var(--text); font-weight: 600; font-size: 14px; }
.soort-switch a.on { background: var(--primary-color); border-color: var(--primary-color); color: #fff; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 16px; }
.grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 16px; }
@media (max-width: 640px) { .grid2, .grid3 { grid-template-columns: 1fr; } }
.dagdeel { display: flex; gap: 6px; flex-wrap: wrap; }
.dagdeel label { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: #fff; cursor: pointer; font-weight: 500; }
.dagdeel label { display: inline-flex; align-items: center; gap: 6px; padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); cursor: pointer; font-weight: 500; }
.dagdeel input:checked + span { font-weight: 700; color: var(--primary-color); }
.klassen-box { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px; background: var(--surface-muted); }
.klassen-box input[type=search] { margin-bottom: 8px; }
.klassen { display: flex; flex-wrap: wrap; gap: 6px; max-height: 210px; overflow-y: auto; }
.klas { display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px; background: #fff; font-size: 13px; font-weight: 600; cursor: pointer; user-select: none; }
.klas { display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--surface); font-size: 13px; font-weight: 600; cursor: pointer; user-select: none; }
.klas input { width: 14px; height: 14px; }
.klas.on { background: var(--primary-light); border-color: var(--primary-color); color: var(--primary-color); }
.gekozen { font-size: 13px; color: var(--text-muted); margin-top: 6px; }
+1 -1
View File
@@ -21,7 +21,7 @@
.code-panel { margin-top: 18px; border: 2px solid var(--success); border-radius: var(--radius-lg); background: var(--success-bg); padding: 20px; text-align: center; }
.big-code { font-family: ui-monospace, Consolas, monospace; font-size: 40px; font-weight: 800; letter-spacing: 6px; color: var(--success-text); margin: 6px 0 4px; }
.code-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 6px; margin-top: 12px; }
.code-grid span { font-family: ui-monospace, Consolas, monospace; background: #fff; border: 1px solid var(--border); border-radius: 6px; padding: 6px; font-size: 15px; }
.code-grid span { font-family: ui-monospace, Consolas, monospace; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 6px; font-size: 15px; }
details summary { cursor: pointer; color: var(--text-muted); font-size: 14px; margin-top: 12px; }
.exception-active { margin-top: 14px; }
.pick-list { list-style: none; margin: 10px 0 0; padding: 0; }