changes to implement a filter option for the student cards
This commit is contained in:
@@ -1,11 +1,3 @@
|
|||||||
<!--
|
|
||||||
Copyright 2025-2026 AIIrondev
|
|
||||||
|
|
||||||
Licensed under the Inventarsystem EULA (Endbenutzer-Lizenzvertrag).
|
|
||||||
See Legal/LICENSE for the full license text.
|
|
||||||
Unauthorized commercial use, SaaS hosting, or removal of branding is prohibited.
|
|
||||||
For commercial licensing inquiries: https://github.com/AIIrondev
|
|
||||||
-->
|
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}Bibliotheksausweise - Inventarsystem{% endblock %}
|
{% block title %}Bibliotheksausweise - Inventarsystem{% endblock %}
|
||||||
@@ -21,7 +13,6 @@
|
|||||||
gap: 15px;
|
gap: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Neu strukturiertes Layout für Formular & Import */
|
|
||||||
.dashboard-grid {
|
.dashboard-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr;
|
grid-template-columns: 2fr 1fr;
|
||||||
@@ -145,6 +136,38 @@
|
|||||||
background: #5a6268;
|
background: #5a6268;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filter Controls Styling */
|
||||||
|
.filter-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--ui-bg);
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar input,
|
||||||
|
.filter-bar select {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-bar input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-counter {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.cards-table {
|
.cards-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@@ -255,7 +278,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root[data-theme="dark"] .student-card-form,
|
:root[data-theme="dark"] .student-card-form,
|
||||||
:root[data-theme="dark"] .import-card {
|
:root[data-theme="dark"] .import-card,
|
||||||
|
:root[data-theme="dark"] .filter-bar {
|
||||||
background: var(--ui-surface) !important;
|
background: var(--ui-surface) !important;
|
||||||
color: var(--ui-text) !important;
|
color: var(--ui-text) !important;
|
||||||
border-color: var(--ui-border) !important;
|
border-color: var(--ui-border) !important;
|
||||||
@@ -269,7 +293,8 @@
|
|||||||
:root[data-theme="dark"] .import-card p,
|
:root[data-theme="dark"] .import-card p,
|
||||||
:root[data-theme="dark"] .rollover-hint,
|
:root[data-theme="dark"] .rollover-hint,
|
||||||
:root[data-theme="dark"] .empty-state,
|
:root[data-theme="dark"] .empty-state,
|
||||||
:root[data-theme="dark"] .empty-state p {
|
:root[data-theme="dark"] .empty-state p,
|
||||||
|
:root[data-theme="dark"] .filter-counter {
|
||||||
color: var(--ui-text-muted) !important;
|
color: var(--ui-text-muted) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +311,8 @@
|
|||||||
:root[data-theme="dark"] .form-group input,
|
:root[data-theme="dark"] .form-group input,
|
||||||
:root[data-theme="dark"] .form-group select,
|
:root[data-theme="dark"] .form-group select,
|
||||||
:root[data-theme="dark"] .form-group textarea,
|
:root[data-theme="dark"] .form-group textarea,
|
||||||
|
:root[data-theme="dark"] .filter-bar input,
|
||||||
|
:root[data-theme="dark"] .filter-bar select,
|
||||||
:root[data-theme="dark"] .export-buttons form,
|
:root[data-theme="dark"] .export-buttons form,
|
||||||
:root[data-theme="dark"] .export-buttons select {
|
:root[data-theme="dark"] .export-buttons select {
|
||||||
background: var(--ui-bg) !important;
|
background: var(--ui-bg) !important;
|
||||||
@@ -297,6 +324,8 @@
|
|||||||
:root[data-theme="dark"] .form-group input:focus,
|
:root[data-theme="dark"] .form-group input:focus,
|
||||||
:root[data-theme="dark"] .form-group select:focus,
|
:root[data-theme="dark"] .form-group select:focus,
|
||||||
:root[data-theme="dark"] .form-group textarea:focus,
|
:root[data-theme="dark"] .form-group textarea:focus,
|
||||||
|
:root[data-theme="dark"] .filter-bar input:focus,
|
||||||
|
:root[data-theme="dark"] .filter-bar select:focus,
|
||||||
:root[data-theme="dark"] .export-buttons select:focus {
|
:root[data-theme="dark"] .export-buttons select:focus {
|
||||||
border-color: #60a5fa !important;
|
border-color: #60a5fa !important;
|
||||||
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.22) !important;
|
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.22) !important;
|
||||||
@@ -334,6 +363,16 @@
|
|||||||
.export-buttons > a {
|
.export-buttons > a {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-bar {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-counter {
|
||||||
|
margin-left: 0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
@@ -503,7 +542,20 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2 style="margin-bottom: 15px;">Registrierte Ausweise</h2>
|
<h2 style="margin-bottom: 15px;">Registrierte Ausweise</h2>
|
||||||
{% if student_cards %}
|
{% if student_cards %}
|
||||||
<table class="cards-table">
|
<!-- Filter Options -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<input type="text" id="cardSearchInput" placeholder="🔍 Name oder Ausweis-ID suchen...">
|
||||||
|
<select id="classFilterSelect">
|
||||||
|
<option value="">Alle Klassen</option>
|
||||||
|
{% for cls in available_classes %}
|
||||||
|
<option value="{{ cls }}">{{ cls }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<button type="button" id="clearFilterBtn" class="btn-cancel" style="padding: 8px 12px; font-size: 13px;">Zurücksetzen</button>
|
||||||
|
<span class="filter-counter" id="filterCounter">Angezeigt: {{ student_cards|length }} / {{ student_cards|length }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="cards-table" id="cardsTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Ausweis-ID</th>
|
<th>Ausweis-ID</th>
|
||||||
@@ -516,7 +568,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for card in student_cards %}
|
{% for card in student_cards %}
|
||||||
<tr>
|
<tr class="card-row" data-id="{{ card.AusweisId|lower }}" data-name="{{ card.SchülerName|lower }}" data-class="{{ card.Klasse or '' }}">
|
||||||
<td><strong>{{ card.AusweisId }}</strong></td>
|
<td><strong>{{ card.AusweisId }}</strong></td>
|
||||||
<td>{{ card.SchülerName }}</td>
|
<td>{{ card.SchülerName }}</td>
|
||||||
<td>{{ card.Klasse or '—' }}</td>
|
<td>{{ card.Klasse or '—' }}</td>
|
||||||
@@ -546,6 +598,10 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div id="noResultsMsg" class="empty-state" style="display: none;">
|
||||||
|
<p>Keine passende Ausweise für diesen Filter gefunden.</p>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<p>Keine Bibliotheksausweise registriert.</p>
|
<p>Keine Bibliotheksausweise registriert.</p>
|
||||||
@@ -557,7 +613,56 @@
|
|||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/qrcode.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/qrcode.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// All PDF exports now go through backend routes
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const searchInput = document.getElementById('cardSearchInput');
|
||||||
|
const classSelect = document.getElementById('classFilterSelect');
|
||||||
|
const clearBtn = document.getElementById('clearFilterBtn');
|
||||||
|
const filterCounter = document.getElementById('filterCounter');
|
||||||
|
const rows = document.querySelectorAll('.card-row');
|
||||||
|
const noResultsMsg = document.getElementById('noResultsMsg');
|
||||||
|
const totalRows = rows.length;
|
||||||
|
|
||||||
|
function filterCards() {
|
||||||
|
const query = searchInput ? searchInput.value.toLowerCase().trim() : '';
|
||||||
|
const selectedClass = classSelect ? classSelect.value : '';
|
||||||
|
let visibleCount = 0;
|
||||||
|
|
||||||
|
rows.forEach(row => {
|
||||||
|
const id = row.getAttribute('data-id') || '';
|
||||||
|
const name = row.getAttribute('data-name') || '';
|
||||||
|
const cardClass = row.getAttribute('data-class') || '';
|
||||||
|
|
||||||
|
const matchesQuery = !query || id.includes(query) || name.includes(query);
|
||||||
|
const matchesClass = !selectedClass || cardClass === selectedClass;
|
||||||
|
|
||||||
|
if (matchesQuery && matchesClass) {
|
||||||
|
row.style.display = '';
|
||||||
|
visibleCount++;
|
||||||
|
} else {
|
||||||
|
row.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filterCounter) {
|
||||||
|
filterCounter.textContent = `Angezeigt: ${visibleCount} / ${totalRows}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noResultsMsg) {
|
||||||
|
noResultsMsg.style.display = (visibleCount === 0 && totalRows > 0) ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchInput) searchInput.addEventListener('input', filterCards);
|
||||||
|
if (classSelect) classSelect.addEventListener('change', filterCards);
|
||||||
|
|
||||||
|
if (clearBtn) {
|
||||||
|
clearBtn.addEventListener('click', function() {
|
||||||
|
if (searchInput) searchInput.value = '';
|
||||||
|
if (classSelect) classSelect.value = '';
|
||||||
|
filterCards();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user