De schoolnaam werd afgekapt op 200px. Nu wordt ze volledig getoond en enkel nog ingekort met … als er geen plaats meer is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
196 lines
9.5 KiB
HTML
196 lines
9.5 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="nl">
|
||
<head>
|
||
<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 %}
|
||
<style>.header-school { display: inline-block; min-width: 0; flex-shrink: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; vertical-align: middle; }</style>
|
||
{% block extra_css %}{% endblock %}
|
||
</head>
|
||
<body class="{% block body_class %}{% endblock %}">
|
||
|
||
{# ---------- Laadscherm (gedeeld) ---------- #}
|
||
<div id="loader-overlay" aria-live="polite">
|
||
<div class="spinner"></div>
|
||
<div class="loader-text" id="loader-text">{% block loader_text %}Verwerken...{% endblock %}</div>
|
||
{% block loader_sub %}{% endblock %}
|
||
</div>
|
||
|
||
{# ---------- Header ---------- #}
|
||
{% block header %}
|
||
<header class="app-header {% block header_class %}{% endblock %}">
|
||
<div class="header-left">
|
||
<a href="{{ url_for('main.dashboard') }}" class="brand" title="Naar het dashboard">
|
||
<span class="brand-mark"><img src="{{ url_for('static', filename='pivot_mark.png') }}" alt=""></span>
|
||
<span class="brand-name">PIVOT</span>
|
||
</a>
|
||
{% block header_nav %}
|
||
<a href="{{ url_for('main.dashboard') }}" class="home-btn">🏠 Home</a>
|
||
{% endblock %}
|
||
</div>
|
||
|
||
<h1 class="page-title">{% block page_title %}{% endblock %}</h1>
|
||
|
||
<div class="header-right">
|
||
{% if school %}
|
||
{% if is_superbeheerder %}
|
||
<a href="{{ url_for('scholen.overzicht') }}" class="header-user header-school" style="color:inherit;text-decoration:none" title="{{ school.naam }} – andere school kiezen">🏫 {{ school.naam }} ⇄</a>
|
||
{% elif andere_scholen %}
|
||
<select class="header-user header-school" title="Andere school kiezen" aria-label="School kiezen"
|
||
style="width:auto;color:inherit;background:transparent;border:0;cursor:pointer"
|
||
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:var(--text)">{{ s.naam }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
{% else %}
|
||
<span class="header-user header-school" title="{{ school.naam }}">🏫 {{ school.naam }}</span>
|
||
{% endif %}
|
||
{% endif %}
|
||
{% if session.get('user') %}
|
||
<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>
|
||
</form>
|
||
</div>
|
||
</header>
|
||
{% endblock %}
|
||
|
||
<main class="app-main {% block main_class %}{% endblock %}">
|
||
{# ---------- Flash-berichten (gedeeld) ---------- #}
|
||
{% block flashes %}
|
||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||
{% if messages %}
|
||
<div class="flash-container">
|
||
{% for category, message in messages %}
|
||
<div class="flash-message {{ category if category else 'info' }}" role="alert">
|
||
<span>{{ message }}</span>
|
||
<button type="button" class="flash-close" aria-label="Sluiten" onclick="this.parentElement.remove()">×</button>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
{% endwith %}
|
||
{% endblock %}
|
||
|
||
{% block content %}{% endblock %}
|
||
</main>
|
||
|
||
{% block modals %}{% endblock %}
|
||
|
||
{% block footer %}
|
||
<footer class="app-footer">
|
||
{% if school %}{{ school.naam }} – {% endif %}PIVOT – Versie {{ version }}
|
||
</footer>
|
||
{% endblock %}
|
||
|
||
<script>
|
||
/* Gedeelde helpers – beschikbaar op elke pagina */
|
||
|
||
/* Aantal rijen per pagina in tabellen: 10 / 25 / 50 / 100 / alles (0). Standaard 25 (of de opgegeven standaard).
|
||
De keuze wordt per tabel onthouden in deze browser. */
|
||
const PER_PAGINA_KEUZES = [10, 25, 50, 100, 0];
|
||
function perPagina(sleutel, standaard = 25) {
|
||
try {
|
||
const v = localStorage.getItem('pivot.perpagina.' + sleutel);
|
||
if (v !== null && PER_PAGINA_KEUZES.includes(+v)) return +v;
|
||
} catch (e) { /* geen opslag beschikbaar */ }
|
||
return standaard;
|
||
}
|
||
function perPaginaKiezer(container, sleutel, opWijzig, standaard = 25) {
|
||
if (!container) return;
|
||
const huidig = perPagina(sleutel, standaard);
|
||
container.innerHTML = '<label class="per-pagina">Toon <select aria-label="Aantal per pagina">'
|
||
+ PER_PAGINA_KEUZES.map(n => `<option value="${n}" ${n === huidig ? 'selected' : ''}>${n || 'alles'}</option>`).join('')
|
||
+ '</select> per pagina</label>';
|
||
container.querySelector('select').addEventListener('change', e => {
|
||
const n = +e.target.value;
|
||
try { localStorage.setItem('pivot.perpagina.' + sleutel, n); } catch (err) { /* negeren */ }
|
||
opWijzig(n);
|
||
});
|
||
}
|
||
|
||
function showLoader(text) {
|
||
if (text) document.getElementById('loader-text').innerText = text;
|
||
document.getElementById('loader-overlay').style.display = 'flex';
|
||
}
|
||
function hideLoader() {
|
||
document.getElementById('loader-overlay').style.display = 'none';
|
||
}
|
||
// Loader verbergen wanneer de pagina via 'terug' uit de cache komt
|
||
window.addEventListener('pageshow', function (e) { if (e.persisted) hideLoader(); });
|
||
|
||
// Succes- en infoberichten verdwijnen na 6 seconden; foutmeldingen blijven staan
|
||
setTimeout(function () {
|
||
document.querySelectorAll('.flash-message:not(.error):not(.danger)').forEach(function (f) {
|
||
f.style.transition = 'opacity .5s ease';
|
||
f.style.opacity = '0';
|
||
setTimeout(function () { f.remove(); }, 500);
|
||
});
|
||
}, 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;
|
||
document.querySelectorAll('.modal, .modal-overlay').forEach(function (m) {
|
||
if (m.style.display && m.style.display !== 'none') m.style.display = 'none';
|
||
});
|
||
});
|
||
</script>
|
||
{% block scripts %}{% endblock %}
|
||
</body>
|
||
</html>
|