Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c6043399e | |||
| acfb633cda | |||
| 23dfb7d719 |
+9
-1
@@ -2188,7 +2188,7 @@ def _upload_student_cards_excel():
|
||||
|
||||
current_permissions = us.get_effective_permissions(session['username'])
|
||||
|
||||
if not current_permissions['actions'].get('can_manage_user', False):
|
||||
if not current_permissions['actions'].get('can_manage_users', False):
|
||||
flash('Ihnen fehlen die nötigen Berechtigungen, um diese Aktion auszuführen.', 'error')
|
||||
return redirect(url_for('library_view'))
|
||||
|
||||
@@ -4276,6 +4276,7 @@ def api_library_scan_action():
|
||||
- scan student card id
|
||||
- scan media code (ISBN/Code_4)
|
||||
- borrow if available, otherwise return (toggle behavior)
|
||||
- action='borrow' can be used by scan modes that must never return an item
|
||||
"""
|
||||
if 'username' not in session:
|
||||
return jsonify({'ok': False, 'message': 'Nicht angemeldet.'}), 401
|
||||
@@ -4285,6 +4286,7 @@ def api_library_scan_action():
|
||||
return jsonify({'ok': False, 'message': 'Schülerausweis-Modul ist deaktiviert.'}), 403
|
||||
|
||||
payload = request.get_json(silent=True) or {}
|
||||
requested_action = str(payload.get('action') or 'toggle').strip().lower()
|
||||
student_card_id = us.normalize_student_card_id(payload.get('student_card_id') or payload.get('card_id'))
|
||||
item_code_raw = str(payload.get('item_code') or payload.get('code') or '').strip()
|
||||
duration_raw = str(payload.get('borrow_duration_days') or '').strip()
|
||||
@@ -4388,6 +4390,12 @@ def api_library_scan_action():
|
||||
'message': f"{item_doc.get('Name', 'Medium')} wurde ausgeliehen."
|
||||
}), 200
|
||||
|
||||
if requested_action == 'borrow':
|
||||
return jsonify({
|
||||
'ok': False,
|
||||
'message': f"Medium ist bereits ausgeliehen und wurde nicht verändert.",
|
||||
}), 409
|
||||
|
||||
# Toggle back: item is currently borrowed -> return
|
||||
current_borrower = str(item_doc.get('User') or '').strip()
|
||||
current_permissions = us.get_effective_permissions(session['username'])
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
--ui-text: #f8fafc;
|
||||
--ui-text-muted: #94a3b8;
|
||||
--ui-title: #ffffff;
|
||||
--ui-overlay: #020617;
|
||||
--ui-overlay-surface: #1e293b;
|
||||
--ui-overlay-border: #64748b;
|
||||
--ui-shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.4), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
||||
--ui-shadow-md: 0 10px 30px rgba(0, 0, 0, 0.6), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
|
||||
|
||||
@@ -39,6 +42,10 @@
|
||||
--ui-btn-radius: 99px; /* Pillenform für Buttons */
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
/* Safe Area Support for iPad notches, Dynamic Island, and rounded corners */
|
||||
html {
|
||||
/* Ensure viewport-fit is respected */
|
||||
@@ -1002,3 +1009,104 @@ html, body {
|
||||
:root[data-theme="dark"] .favorite-item {
|
||||
outline: 2px solid #f59e0b !important;
|
||||
}
|
||||
|
||||
/* Keep overlays and dialogs sufficiently opaque for readable content. */
|
||||
:root[data-theme="dark"] .modal,
|
||||
:root[data-theme="dark"] .modal-backdrop,
|
||||
:root[data-theme="dark"] .ui-modal-overlay,
|
||||
:root[data-theme="dark"] .item-modal,
|
||||
:root[data-theme="dark"] .reset-modal-overlay,
|
||||
:root[data-theme="dark"] #onboarding-overlay,
|
||||
:root[data-theme="dark"] [id$="-modal"][style*="inset"],
|
||||
:root[data-theme="dark"] [id$="Modal"][style*="inset"] {
|
||||
background-color: var(--ui-overlay) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .modal-content,
|
||||
:root[data-theme="dark"] .ui-modal-surface,
|
||||
:root[data-theme="dark"] .reset-modal-container,
|
||||
:root[data-theme="dark"] #onboarding-modal,
|
||||
:root[data-theme="dark"] [id$="-modal"] > div,
|
||||
:root[data-theme="dark"] [id$="Modal"] > div {
|
||||
background-color: var(--ui-overlay-surface) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-overlay-border) !important;
|
||||
}
|
||||
|
||||
/* Inline light surfaces must not become translucent or low-contrast in dark mode. */
|
||||
:root[data-theme="dark"] [style*="background: white"],
|
||||
:root[data-theme="dark"] [style*="background:#fff"],
|
||||
:root[data-theme="dark"] [style*="background: #fff"],
|
||||
:root[data-theme="dark"] [style*="background-color: white"],
|
||||
:root[data-theme="dark"] [style*="background-color:#fff"],
|
||||
:root[data-theme="dark"] [style*="background-color: #fff"] {
|
||||
background-color: var(--ui-surface) !important;
|
||||
color: var(--ui-text) !important;
|
||||
}
|
||||
|
||||
/* Shared dark-mode surfaces for every template that extends base.html. */
|
||||
:root[data-theme="dark"] .container,
|
||||
:root[data-theme="dark"] .card,
|
||||
:root[data-theme="dark"] .card-body,
|
||||
:root[data-theme="dark"] .card-header,
|
||||
:root[data-theme="dark"] .card-footer,
|
||||
:root[data-theme="dark"] .content,
|
||||
:root[data-theme="dark"] .form-card,
|
||||
:root[data-theme="dark"] .form-container,
|
||||
:root[data-theme="dark"] .upload-container,
|
||||
:root[data-theme="dark"] .edit-container,
|
||||
:root[data-theme="dark"] .admin-content-container,
|
||||
:root[data-theme="dark"] .calendar-container,
|
||||
:root[data-theme="dark"] .table-container,
|
||||
:root[data-theme="dark"] .notice-card,
|
||||
:root[data-theme="dark"] .settings-card,
|
||||
:root[data-theme="dark"] .summary-card,
|
||||
:root[data-theme="dark"] .invoice-card,
|
||||
:root[data-theme="dark"] .student-card-form,
|
||||
:root[data-theme="dark"] .user-management-container,
|
||||
:root[data-theme="dark"] .error-container,
|
||||
:root[data-theme="dark"] .library-filter-panel,
|
||||
:root[data-theme="dark"] .library-items-table,
|
||||
:root[data-theme="dark"] .info-box {
|
||||
background-color: var(--ui-surface) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .table,
|
||||
:root[data-theme="dark"] .table-responsive,
|
||||
:root[data-theme="dark"] .table > :not(caption) > *,
|
||||
:root[data-theme="dark"] .table > :not(caption) > * > *,
|
||||
:root[data-theme="dark"] .library-items-table td,
|
||||
:root[data-theme="dark"] .library-items-table th {
|
||||
background-color: var(--ui-surface) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .table-striped > tbody > tr:nth-of-type(odd) > *,
|
||||
:root[data-theme="dark"] .table-light,
|
||||
:root[data-theme="dark"] .table-light > *,
|
||||
:root[data-theme="dark"] .bg-white,
|
||||
:root[data-theme="dark"] .bg-light,
|
||||
:root[data-theme="dark"] .bg-body,
|
||||
:root[data-theme="dark"] .bg-body-secondary {
|
||||
background-color: var(--ui-surface-soft) !important;
|
||||
color: var(--ui-text) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .form-text,
|
||||
:root[data-theme="dark"] .text-muted,
|
||||
:root[data-theme="dark"] small,
|
||||
:root[data-theme="dark"] .library-load-hint {
|
||||
color: var(--ui-text-muted) !important;
|
||||
}
|
||||
|
||||
/* White translucent template decorations become stable, readable surfaces. */
|
||||
:root[data-theme="dark"] [style*="background: rgba(255,255,255"],
|
||||
:root[data-theme="dark"] [style*="background: rgba(255, 255, 255"],
|
||||
:root[data-theme="dark"] [style*="background-color: rgba(255,255,255"],
|
||||
:root[data-theme="dark"] [style*="background-color: rgba(255, 255, 255"] {
|
||||
background-color: var(--ui-surface-soft) !important;
|
||||
color: var(--ui-text) !important;
|
||||
}
|
||||
|
||||
+147
-1
@@ -1376,7 +1376,7 @@
|
||||
<li><a class="dropdown-item" href="{{ url_for('mahnungen_admin') }}">Mahnungen</a></li>
|
||||
{% endif %}
|
||||
{% if student_cards_module_enabled %}
|
||||
{% if current_permissions.actions.get('can_manage_users', False) %}
|
||||
{% if current_permissions.actions.get('can_manage_settings', False) %}
|
||||
<li><a class="dropdown-item" href="{{ url_for('student_cards_admin') }}">Bibliotheksausweis</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -2396,5 +2396,151 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style id="dark-mode-component-overrides">
|
||||
:root[data-theme="dark"] .mahnungen-head,
|
||||
:root[data-theme="dark"] .mahnungen-card,
|
||||
:root[data-theme="dark"] .tutorial-side,
|
||||
:root[data-theme="dark"] .workflow-step,
|
||||
:root[data-theme="dark"] .tutorial-note,
|
||||
:root[data-theme="dark"] .tutorial-tooltip-toggle,
|
||||
:root[data-theme="dark"] .bulk-delete-drawer,
|
||||
:root[data-theme="dark"] .filter-group,
|
||||
:root[data-theme="dark"] .filter-dropdown,
|
||||
:root[data-theme="dark"] .calendar-wrapper,
|
||||
:root[data-theme="dark"] .calendar-day-details,
|
||||
:root[data-theme="dark"] .cal-booking-item,
|
||||
:root[data-theme="dark"] .edit-form,
|
||||
:root[data-theme="dark"] .password-change-form,
|
||||
:root[data-theme="dark"] .upload-form,
|
||||
:root[data-theme="dark"] .book-info-container,
|
||||
:root[data-theme="dark"] .student-card-form,
|
||||
:root[data-theme="dark"] .user-management-container {
|
||||
background: var(--ui-surface) !important;
|
||||
background-color: var(--ui-surface) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .mahnungen-table th,
|
||||
:root[data-theme="dark"] .calendar-header,
|
||||
:root[data-theme="dark"] .filter-inputs,
|
||||
:root[data-theme="dark"] .items-loading-indicator,
|
||||
:root[data-theme="dark"] .detail-group.full-width .detail-value,
|
||||
:root[data-theme="dark"] .library-filter-panel,
|
||||
:root[data-theme="dark"] .card-header,
|
||||
:root[data-theme="dark"] .modal-header,
|
||||
:root[data-theme="dark"] .modal-footer {
|
||||
background: var(--ui-surface-soft) !important;
|
||||
background-color: var(--ui-surface-soft) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .mahnungen-table tr:hover td,
|
||||
:root[data-theme="dark"] .filter-option:hover,
|
||||
:root[data-theme="dark"] .calendar-header button:hover,
|
||||
:root[data-theme="dark"] .workflow-nav button:hover {
|
||||
background: var(--ui-bg-accent) !important;
|
||||
background-color: var(--ui-bg-accent) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .mahnungen-head h1,
|
||||
:root[data-theme="dark"] .tutorial-side h2,
|
||||
:root[data-theme="dark"] .workflow-step h3,
|
||||
:root[data-theme="dark"] .calendar-header span,
|
||||
:root[data-theme="dark"] .calendar-day-details h5,
|
||||
:root[data-theme="dark"] .detail-value,
|
||||
:root[data-theme="dark"] .cal-booking-time,
|
||||
:root[data-theme="dark"] .cal-booking-user,
|
||||
:root[data-theme="dark"] .cal-booking-note,
|
||||
:root[data-theme="dark"] .form-group label,
|
||||
:root[data-theme="dark"] .page-header h1,
|
||||
:root[data-theme="dark"] .card-header h2 {
|
||||
color: var(--ui-title) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .mahnungen-head p,
|
||||
:root[data-theme="dark"] .tutorial-side p,
|
||||
:root[data-theme="dark"] .workflow-step p,
|
||||
:root[data-theme="dark"] .workflow-step li,
|
||||
:root[data-theme="dark"] .tutorial-tooltip-toggle label,
|
||||
:root[data-theme="dark"] .tooltip-description,
|
||||
:root[data-theme="dark"] .page-header p,
|
||||
:root[data-theme="dark"] .form-group small,
|
||||
:root[data-theme="dark"] .cal-booking-label,
|
||||
:root[data-theme="dark"] .cal-empty-state {
|
||||
color: var(--ui-text-muted) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .workflow-nav button,
|
||||
:root[data-theme="dark"] .bulk-delete-actions button,
|
||||
:root[data-theme="dark"] .filter-toggle,
|
||||
:root[data-theme="dark"] .clear-filter {
|
||||
background: var(--ui-surface-soft) !important;
|
||||
background-color: var(--ui-surface-soft) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .workflow-nav button.active,
|
||||
:root[data-theme="dark"] .filter-toggle.is-open {
|
||||
background: #1d4ed8 !important;
|
||||
color: #ffffff !important;
|
||||
border-color: #60a5fa !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .badge-light,
|
||||
:root[data-theme="dark"] .badge.bg-light,
|
||||
:root[data-theme="dark"] .badge.bg-secondary,
|
||||
:root[data-theme="dark"] .filter-tag,
|
||||
:root[data-theme="dark"] .tutorial-pill {
|
||||
background: var(--ui-surface-soft) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .form-control,
|
||||
:root[data-theme="dark"] .form-select,
|
||||
:root[data-theme="dark"] input,
|
||||
:root[data-theme="dark"] select,
|
||||
:root[data-theme="dark"] textarea {
|
||||
background-color: var(--ui-bg) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] ::placeholder {
|
||||
color: #b7c4d6 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .modal-content,
|
||||
:root[data-theme="dark"] .modal-dialog-white,
|
||||
:root[data-theme="dark"] .modal-body,
|
||||
:root[data-theme="dark"] .modal-content-margin {
|
||||
background: var(--ui-overlay-surface) !important;
|
||||
background-color: var(--ui-overlay-surface) !important;
|
||||
color: var(--ui-text) !important;
|
||||
border-color: var(--ui-overlay-border) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .modal-content h1,
|
||||
:root[data-theme="dark"] .modal-content h2,
|
||||
:root[data-theme="dark"] .modal-content h3,
|
||||
:root[data-theme="dark"] .modal-content h4,
|
||||
:root[data-theme="dark"] .modal-content h5,
|
||||
:root[data-theme="dark"] .modal-content h6,
|
||||
:root[data-theme="dark"] .modal-content label,
|
||||
:root[data-theme="dark"] .modal-content p,
|
||||
:root[data-theme="dark"] .modal-content span {
|
||||
color: var(--ui-text) !important;
|
||||
}
|
||||
|
||||
:root[data-theme="dark"] .guest-impressum-footer a {
|
||||
color: #dbeafe !important;
|
||||
border-bottom-color: #93c5fd !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -650,6 +650,7 @@
|
||||
// =========================================================================
|
||||
function createModalOverlay() {
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'ui-modal-overlay';
|
||||
overlay.style.position = 'fixed';
|
||||
overlay.style.top = '0';
|
||||
overlay.style.left = '0';
|
||||
@@ -665,6 +666,7 @@
|
||||
|
||||
function createModalBox() {
|
||||
const box = document.createElement('div');
|
||||
box.className = 'ui-modal-surface';
|
||||
box.style.backgroundColor = '#fff';
|
||||
box.style.padding = '24px';
|
||||
box.style.borderRadius = '8px';
|
||||
@@ -1414,7 +1416,8 @@
|
||||
},
|
||||
body: JSON.stringify({
|
||||
student_card_id: activeStudentCardId,
|
||||
item_code: scannedCode
|
||||
item_code: scannedCode,
|
||||
action: 'borrow'
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user