Initial commit
This commit is contained in:
commit
536ff43ce4
158 files changed
+30355
No files matched your search
@@ -0,0 +1,166 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Verzendlijsten{% endblock %}
|
||||
{% block page_title %}Verzendlijsten{% endblock %}
|
||||
{% block loader_text %}Verzendlijsten ophalen bij Google...{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.nieuw-grid { display: grid; grid-template-columns: 1.4fr 1.2fr 1.6fr; gap: 12px; align-items: end; }
|
||||
.nieuw-grid .breed { grid-column: 1 / -1; }
|
||||
.nieuw-grid .field { margin: 0; }
|
||||
.adres-veld { display: flex; align-items: stretch; }
|
||||
.adres-veld input { border-top-right-radius: 0; border-bottom-right-radius: 0; flex: 1; min-width: 0; }
|
||||
.adres-veld select, .adres-veld .at { border-top-left-radius: 0; border-bottom-left-radius: 0; }
|
||||
.adres-veld .at { display: grid; place-items: center; padding: 0 8px; background: var(--surface-muted);
|
||||
border: 1px solid var(--border); border-left: 0; border-right: 0; color: var(--text-muted); }
|
||||
.adres-veld select { width: auto; max-width: 55%; }
|
||||
@media (max-width: 760px) { .nieuw-grid { grid-template-columns: 1fr; } }
|
||||
details.nieuw > summary { cursor: pointer; list-style: none; display: inline-flex; }
|
||||
details.nieuw > summary::-webkit-details-marker { display: none; }
|
||||
details.nieuw[open] > summary { margin-bottom: 14px; }
|
||||
.zoekbalk { display: flex; gap: 10px; margin-bottom: 12px; }
|
||||
.zoekbalk input { flex: 1; }
|
||||
th.sorteer { cursor: pointer; user-select: none; white-space: nowrap; }
|
||||
th.sorteer:hover { color: var(--primary-color); }
|
||||
th.sorteer .pijl::after { content: "↕"; opacity: .35; margin-left: 2px; }
|
||||
th.sorteer.op .pijl::after { content: "▲"; opacity: 1; }
|
||||
th.sorteer.af .pijl::after { content: "▼"; opacity: 1; }
|
||||
.tabel-voet { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; margin-top: 12px; }
|
||||
.paginering { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
||||
td.mail { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88em; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<details class="nieuw" {% if not lijsten and not fout %}open{% endif %}>
|
||||
<summary class="btn btn-success">➕ Nieuwe verzendlijst</summary>
|
||||
<form method="POST" action="{{ url_for('verzendlijsten.nieuw') }}" class="nieuw-grid" onsubmit="showLoader('Verzendlijst aanmaken...')">
|
||||
<div class="field">
|
||||
<label for="adres">E-mailadres</label>
|
||||
<div class="adres-veld">
|
||||
<input type="text" id="adres" name="adres" required placeholder="bv. leerkrachten-1ste-graad" autocomplete="off">
|
||||
{% if domeinen %}
|
||||
<span class="at">@</span>
|
||||
<select name="domein" aria-label="Domein">
|
||||
{% for d in domeinen %}<option>{{ d }}</option>{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="naam">Naam</label>
|
||||
<input type="text" id="naam" name="naam" required placeholder="bv. Leerkrachten 1ste graad">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="wie_mailt_n">Wie mag mailen naar de lijst?</label>
|
||||
<select id="wie_mailt_n" name="wie_mailt">
|
||||
<option value="">Standaard van Google</option>
|
||||
{% for w, l in wie_mailt %}<option value="{{ w }}">{{ l }}</option>{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field breed">
|
||||
<label for="beschrijving">Beschrijving</label>
|
||||
<input type="text" id="beschrijving" name="beschrijving" placeholder="Waarvoor dient deze lijst? (optioneel)">
|
||||
</div>
|
||||
<div class="breed"><button type="submit">💾 Verzendlijst aanmaken</button></div>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="page-head">
|
||||
<h2>📮 Verzendlijsten</h2>
|
||||
<a class="btn btn-light btn-sm" href="{{ url_for('verzendlijsten.overzicht') }}" onclick="showLoader()">🔄 Vernieuwen</a>
|
||||
</div>
|
||||
|
||||
{% if fout %}
|
||||
<div class="alert alert-danger">{{ fout }}</div>
|
||||
{% else %}
|
||||
<div class="zoekbalk">
|
||||
<input type="search" id="zoek" placeholder="Zoek op naam, adres of beschrijving..." aria-label="Zoeken">
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sorteer" data-kol="0">Naam <span class="pijl"></span></th>
|
||||
<th class="sorteer" data-kol="1">E-mailadres <span class="pijl"></span></th>
|
||||
<th class="sorteer text-right" data-kol="2">Leden <span class="pijl"></span></th>
|
||||
<th class="sorteer" data-kol="3">Beschrijving <span class="pijl"></span></th>
|
||||
<th class="actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="lijstBody">
|
||||
{% for g in lijsten %}
|
||||
<tr data-zoek="{{ [g.naam, g.email, g.beschrijving]|join(' ')|lower }}">
|
||||
<td data-sort="{{ g.naam }}"><strong>{{ g.naam }}</strong></td>
|
||||
<td class="mail" data-sort="{{ g.email }}">{{ g.email }}{% if g.aliassen %}<br><span class="muted small">ook: {{ g.aliassen|join(', ') }}</span>{% endif %}</td>
|
||||
<td class="text-right" data-sort="{{ '%06d'|format(g.leden) }}">{{ g.leden }}</td>
|
||||
<td class="muted small" data-sort="{{ g.beschrijving }}">{{ g.beschrijving }}</td>
|
||||
<td class="actions"><a class="btn btn-sm btn-secondary" href="{{ url_for('verzendlijsten.detail', email=g.email) }}" onclick="showLoader('Leden ophalen...')">✏️ Openen</a></td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="empty-row"><td colspan="5">Er zijn nog geen verzendlijsten in Google.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tabel-voet">
|
||||
<div style="display:flex;align-items:center;gap:14px;flex-wrap:wrap">
|
||||
<div class="muted small" id="teller"></div>
|
||||
<span id="perPagina"></span>
|
||||
</div>
|
||||
<nav class="paginering" id="paginering" aria-label="Pagina's"></nav>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
(function () {
|
||||
const body = document.getElementById('lijstBody');
|
||||
if (!body || body.querySelector('.empty-row')) return;
|
||||
let PER_PAGINA = perPagina('verzendlijsten'), pagina = 1, kol = null, op = true, zoek = '';
|
||||
const zichtbaar = () => Array.from(body.rows).filter(tr => !zoek || tr.dataset.zoek.includes(zoek));
|
||||
function toon() {
|
||||
const rijen = zichtbaar(), grootte = PER_PAGINA || Infinity;
|
||||
const paginas = Math.max(1, Math.ceil(rijen.length / grootte));
|
||||
pagina = Math.min(Math.max(1, pagina), paginas);
|
||||
const van = PER_PAGINA ? (pagina - 1) * PER_PAGINA : 0, tot = van + grootte;
|
||||
Array.from(body.rows).forEach(tr => tr.style.display = 'none');
|
||||
rijen.forEach((tr, i) => tr.style.display = (i >= van && i < tot) ? '' : 'none');
|
||||
document.getElementById('teller').textContent = rijen.length
|
||||
? `${van + 1}–${Math.min(tot, rijen.length)} van ${rijen.length} verzendlijst(en)` : 'Geen verzendlijsten gevonden';
|
||||
const nav = document.getElementById('paginering');
|
||||
nav.innerHTML = '';
|
||||
if (paginas <= 1) return;
|
||||
const knop = (label, p, actief) => {
|
||||
const b = document.createElement('button');
|
||||
b.type = 'button'; b.textContent = label; b.className = 'btn-sm ' + (actief ? 'btn-secondary' : 'btn-light');
|
||||
b.onclick = () => { pagina = p; toon(); };
|
||||
nav.appendChild(b);
|
||||
};
|
||||
if (pagina > 1) { knop('«', 1); knop('‹ Vorige', pagina - 1); }
|
||||
for (let p = Math.max(1, pagina - 2); p <= Math.min(paginas, pagina + 2); p++) knop(String(p), p, p === pagina);
|
||||
if (pagina < paginas) { knop('Volgende ›', pagina + 1); knop('»', paginas); }
|
||||
}
|
||||
document.getElementById('zoek').addEventListener('input', e => { zoek = e.target.value.trim().toLowerCase(); pagina = 1; toon(); });
|
||||
document.querySelectorAll('th.sorteer').forEach(th => th.addEventListener('click', () => {
|
||||
const k = +th.dataset.kol;
|
||||
op = kol === k ? !op : (k !== 2); kol = k;
|
||||
document.querySelectorAll('th.sorteer').forEach(x => x.classList.remove('op', 'af'));
|
||||
th.classList.add(op ? 'op' : 'af');
|
||||
Array.from(body.rows).sort((a, b) => {
|
||||
const c = (a.cells[k].dataset.sort || '').localeCompare(b.cells[k].dataset.sort || '', 'nl', { numeric: true, sensitivity: 'base' });
|
||||
return op ? c : -c;
|
||||
}).forEach(tr => body.appendChild(tr));
|
||||
pagina = 1; toon();
|
||||
}));
|
||||
perPaginaKiezer(document.getElementById('perPagina'), 'verzendlijsten', n => { PER_PAGINA = n; pagina = 1; toon(); });
|
||||
toon();
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user