diff --git a/loko/inspections/locale/en/LC_MESSAGES/django.mo b/loko/inspections/locale/en/LC_MESSAGES/django.mo index 5a56431..c40ec1b 100644 Binary files a/loko/inspections/locale/en/LC_MESSAGES/django.mo and b/loko/inspections/locale/en/LC_MESSAGES/django.mo differ diff --git a/loko/inspections/locale/en/LC_MESSAGES/django.po b/loko/inspections/locale/en/LC_MESSAGES/django.po index a96e71c..4944fc8 100644 --- a/loko/inspections/locale/en/LC_MESSAGES/django.po +++ b/loko/inspections/locale/en/LC_MESSAGES/django.po @@ -2094,3 +2094,7 @@ msgstr "Previous" msgid "Suivant" msgstr "Next" +#: inspections/templates/inspections/inspections_index.html +msgid "Sélectionnez les critères à afficher sur la carte et dans le tableau" +msgstr "Select criteria to display on map and table" + diff --git a/loko/inspections/locale/fr/LC_MESSAGES/django.mo b/loko/inspections/locale/fr/LC_MESSAGES/django.mo index 14bce07..7def227 100644 Binary files a/loko/inspections/locale/fr/LC_MESSAGES/django.mo and b/loko/inspections/locale/fr/LC_MESSAGES/django.mo differ diff --git a/loko/inspections/locale/fr/LC_MESSAGES/django.po b/loko/inspections/locale/fr/LC_MESSAGES/django.po index 9c115f6..1841ce4 100644 --- a/loko/inspections/locale/fr/LC_MESSAGES/django.po +++ b/loko/inspections/locale/fr/LC_MESSAGES/django.po @@ -2107,3 +2107,7 @@ msgstr "Précédent" msgid "Suivant" msgstr "Suivant" +#: inspections/templates/inspections/inspections_index.html +msgid "Sélectionnez les critères à afficher sur la carte et dans le tableau" +msgstr "Sélectionnez les critères à afficher sur la carte et dans le tableau" + diff --git a/loko/inspections/locale/nl/LC_MESSAGES/django.mo b/loko/inspections/locale/nl/LC_MESSAGES/django.mo index 95d6201..b1812c6 100644 Binary files a/loko/inspections/locale/nl/LC_MESSAGES/django.mo and b/loko/inspections/locale/nl/LC_MESSAGES/django.mo differ diff --git a/loko/inspections/locale/nl/LC_MESSAGES/django.po b/loko/inspections/locale/nl/LC_MESSAGES/django.po index 642e15d..7b1f923 100644 --- a/loko/inspections/locale/nl/LC_MESSAGES/django.po +++ b/loko/inspections/locale/nl/LC_MESSAGES/django.po @@ -2095,3 +2095,7 @@ msgstr "Vorige" msgid "Suivant" msgstr "Volgende" +#: inspections/templates/inspections/inspections_index.html +msgid "Sélectionnez les critères à afficher sur la carte et dans le tableau" +msgstr "Selecteer criteria om weer te geven op de kaart en in de tabel" + diff --git a/loko/inspections/static/inspections/inspections_index.css b/loko/inspections/static/inspections/inspections_index.css index 33b801f..8a54e0a 100644 --- a/loko/inspections/static/inspections/inspections_index.css +++ b/loko/inspections/static/inspections/inspections_index.css @@ -1,3 +1,5 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600&display=swap'); + /* Layout helpers for Inspections desktop view */ .inspections-layout #inspections-table-container { position: relative; @@ -43,125 +45,255 @@ border-color: #dee2e6; } -/* Styles pour la modale de filtre */ +/* Filter badge */ +#filter-badge { + background-color: #0f172a !important; + color: #ffffff !important; + font-size: 0.72rem; + font-weight: 700; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); + top: 2px !important; + right: -6px !important; + left: auto !important; + transform: none !important; + min-width: 1.25rem; + height: 1.25rem; + padding: 0 4px !important; + line-height: 1.25rem; +} +#filter-badge:not(.d-none) { + display: inline-flex !important; + align-items: center; + justify-content: center; +} + +/* ─── Modern Airbnb-style Filter Modal ──────────────────── */ #filterModal .modal-dialog { - max-width: 95%; + max-width: 820px; + margin: 1.5rem auto; } #filterModal .modal-content { + border: 1px solid #e2e8f0; + border-radius: 18px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); display: flex; flex-direction: column; - max-height: 90vh; + max-height: 88vh; + overflow: hidden; + background-color: #ffffff; +} +#filterModal .modal-header { + padding: 1.25rem 1.5rem; + border-bottom: 1px solid #f1f5f9; + background-color: #ffffff; +} +#filterModal .modal-title { + font-size: 1.25rem; + font-weight: 700; + color: #0f172a; + letter-spacing: -0.02em; +} +#filterModal .btn-close { + font-size: 0.85rem; + padding: 0.5rem; + opacity: 0.5; + transition: opacity 0.15s ease; +} +#filterModal .btn-close:hover { + opacity: 1; } #filterModal .modal-body { + padding: 1.5rem; + background-color: #f8fafc; flex: 1; overflow-y: auto; } #filterModal .modal-footer { + padding: 1rem 1.5rem; + background-color: #ffffff; + border-top: 1px solid #f1f5f9; flex-shrink: 0; + display: flex; + justify-content: space-between; + align-items: center; } +/* Filter Section Cards */ .filter-section { + background-color: #ffffff; + border: 1px solid #e2e8f0; + border-radius: 14px; + padding: 1.15rem; margin-bottom: 1rem; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02); + transition: border-color 0.15s ease, box-shadow 0.15s ease; +} +.filter-section:hover { + border-color: #cbd5e1; +} +.filter-section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.85rem; + gap: 1rem; +} +.filter-section-header > label, +.filter-section-header > .section-title { + font-size: 0.95rem; + font-weight: 700; + color: #0f172a; + margin: 0; + letter-spacing: -0.01em; +} +.filter-section-buttons { + display: flex; + gap: 0.35rem; + margin-left: auto; +} +.filter-section-buttons button { + padding: 0.25rem 0.65rem; + font-size: 0.75rem; + font-weight: 500; + border-radius: 6px; + border: 1px solid #e2e8f0; + background-color: #ffffff; + color: #64748b; + transition: all 0.15s ease; +} +.filter-section-buttons button:hover { + background-color: #f1f5f9; + color: #0f172a; + border-color: #cbd5e1; } -/* Default badge styling */ +/* Filter Options (Chips & Tags) */ +.filter-options { + display: flex; + flex-wrap: wrap; + gap: 0.45rem; + background-color: transparent !important; + border: none !important; + padding: 0 !important; + min-height: auto !important; +} +.filter-option { + display: inline-flex; + align-items: center; +} +.filter-option input[type="checkbox"], +.filter-option input[type="radio"] { + position: absolute; + opacity: 0; + width: 0; + height: 0; + pointer-events: none; +} .filter-option label { display: inline-flex; align-items: center; justify-content: center; - margin: 0; + gap: 0.35rem; + padding: 0.4rem 0.85rem; + font-size: 0.82rem; font-weight: 500; + color: #334155; + background-color: #ffffff; + border: 1.5px solid #e2e8f0; + border-radius: 9999px; cursor: pointer; - background-color: #e7f1ff; - color: #0c5cc9; - border-radius: 1rem; - padding: 0.4rem 0.5rem; - font-size: 0.75rem; - border: 1px solid #b8d4f1; - transition: all 0.2s ease; - width: 140px; - flex: 1 1 auto; - text-align: center; + transition: all 0.15s ease; + user-select: none; white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + margin: 0; + width: auto; +} +.filter-option label:hover { + background-color: #f8fafc; + border-color: #94a3b8; + color: #0f172a; +} +.filter-option input[type="checkbox"]:checked + label:not(.context-badge) { + background-color: #0f172a !important; + border-color: #0f172a !important; + color: #ffffff !important; + font-weight: 600; + box-shadow: 0 2px 6px rgba(15, 23, 42, 0.16); } -/* Contextual color badges - inactive state */ +/* Contextual badges - inactive state (outline) */ .filter-option label.context-badge { background-color: #ffffff; border-width: 1.5px; border-style: solid; - cursor: pointer; - user-select: none; font-weight: 600; - transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; } .filter-option label.btn-outline-primary, -.filter-option label.status-primary { border-color: #0c5cc9; color: #0c5cc9; background-color: #ffffff; } +.filter-option label.status-primary { border-color: #0c5cc9; color: #0c5cc9; } .filter-option label.btn-outline-danger, -.filter-option label.status-damaged { border-color: #dc3545; color: #dc3545; background-color: #ffffff; } +.filter-option label.status-damaged { border-color: #dc3545; color: #dc3545; } .filter-option label.btn-outline-warning, -.filter-option label.status-non_compliant { border-color: #ffc107; color: #997404; background-color: #ffffff; } +.filter-option label.status-non_compliant { border-color: #f59e0b; color: #d97706; } .filter-option label.btn-outline-success, -.filter-option label.status-compliant { border-color: #198754; color: #198754; background-color: #ffffff; } -.filter-option label.btn-outline-info { border-color: #17a2b8; color: #17a2b8; background-color: #ffffff; } +.filter-option label.status-compliant { border-color: #198754; color: #198754; } +.filter-option label.btn-outline-info { border-color: #0284c7; color: #0284c7; } .filter-option label.btn-outline-dark, -.filter-option label.status-missing { border-color: #212529; color: #212529; background-color: #ffffff; } +.filter-option label.status-missing { border-color: #334155; color: #334155; } .filter-option label.btn-outline-secondary, -.filter-option label.status-cancelled { border-color: #6c757d; color: #6c757d; background-color: #ffffff; } +.filter-option label.status-cancelled { border-color: #64748b; color: #64748b; } -/* Default badges - checked state */ -.filter-option input[type="checkbox"]:checked + label:not(.context-badge) { - background-color: #0c5cc9 !important; color: white !important; border-color: #0c5cc9 !important; -} +/* Contextual badges - hover state */ +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-primary, +.filter-option input[type="checkbox"]:not(:checked):hover + label.status-primary { background-color: #eff6ff; } +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-danger, +.filter-option input[type="checkbox"]:not(:checked):hover + label.status-damaged { background-color: #fef2f2; } +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-warning, +.filter-option input[type="checkbox"]:not(:checked):hover + label.status-non_compliant { background-color: #fffbeb; } +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-success, +.filter-option input[type="checkbox"]:not(:checked):hover + label.status-compliant { background-color: #f0fdf4; } +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-info { background-color: #f0f9ff; } +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-dark, +.filter-option input[type="checkbox"]:not(:checked):hover + label.status-missing { background-color: #f8fafc; } +.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-secondary, +.filter-option input[type="checkbox"]:not(:checked):hover + label.status-cancelled { background-color: #f8fafc; } /* Contextual badges - checked state */ +.filter-option input[type="checkbox"]:checked + label.context-badge { + color: #ffffff !important; +} .filter-option input[type="checkbox"]:checked + label.btn-outline-primary, .filter-option input[type="checkbox"]:checked + label.status-primary { - background-color: #0c5cc9 !important; border-color: #0c5cc9 !important; color: #ffffff !important; + background-color: #0c5cc9 !important; border-color: #0c5cc9 !important; box-shadow: 0 2px 6px rgba(12, 92, 201, 0.2); } .filter-option input[type="checkbox"]:checked + label.btn-outline-danger, .filter-option input[type="checkbox"]:checked + label.status-damaged { - background-color: #dc3545 !important; border-color: #dc3545 !important; color: #ffffff !important; + background-color: #dc3545 !important; border-color: #dc3545 !important; box-shadow: 0 2px 6px rgba(220, 53, 69, 0.2); } .filter-option input[type="checkbox"]:checked + label.btn-outline-warning, .filter-option input[type="checkbox"]:checked + label.status-non_compliant { - background-color: #ffc107 !important; border-color: #ffc107 !important; color: #000000 !important; + background-color: #f59e0b !important; border-color: #f59e0b !important; box-shadow: 0 2px 6px rgba(245, 158, 11, 0.2); } .filter-option input[type="checkbox"]:checked + label.btn-outline-success, .filter-option input[type="checkbox"]:checked + label.status-compliant { - background-color: #198754 !important; border-color: #198754 !important; color: #ffffff !important; + background-color: #198754 !important; border-color: #198754 !important; box-shadow: 0 2px 6px rgba(25, 135, 84, 0.2); } .filter-option input[type="checkbox"]:checked + label.btn-outline-info { - background-color: #17a2b8 !important; border-color: #17a2b8 !important; color: #ffffff !important; + background-color: #0284c7 !important; border-color: #0284c7 !important; box-shadow: 0 2px 6px rgba(2, 132, 199, 0.2); } .filter-option input[type="checkbox"]:checked + label.btn-outline-dark, .filter-option input[type="checkbox"]:checked + label.status-missing { - background-color: #212529 !important; border-color: #212529 !important; color: #ffffff !important; + background-color: #1e293b !important; border-color: #1e293b !important; box-shadow: 0 2px 6px rgba(30, 41, 59, 0.2); } .filter-option input[type="checkbox"]:checked + label.btn-outline-secondary, .filter-option input[type="checkbox"]:checked + label.status-cancelled { - background-color: #6c757d !important; border-color: #6c757d !important; color: #ffffff !important; + background-color: #64748b !important; border-color: #64748b !important; box-shadow: 0 2px 6px rgba(100, 116, 139, 0.2); } -/* Hover states */ -.filter-option input[type="checkbox"]:hover + label:not(.context-badge) { background-color: #cfe2f3; } -.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-success, -.filter-option input[type="checkbox"]:not(:checked):hover + label.status-compliant { background-color: #d1e7dd; color: #0f5132; } -.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-warning, -.filter-option input[type="checkbox"]:not(:checked):hover + label.status-non_compliant { background-color: #fff3cd; color: #664d03; } -.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-danger, -.filter-option input[type="checkbox"]:not(:checked):hover + label.status-damaged { background-color: #f8d7da; color: #842029; } -.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-dark, -.filter-option input[type="checkbox"]:not(:checked):hover + label.status-missing { background-color: #e2e3e5; color: #141619; } -.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-secondary, -.filter-option input[type="checkbox"]:not(:checked):hover + label.status-cancelled { background-color: #e9ecef; color: #495057; } - +/* Subcategories */ .filter-option.subcategory-option label { - font-size: 0.875em; - color: #555; + font-size: 0.8rem; + color: #64748b; } .filter-option-break { flex-basis: 100%; @@ -173,53 +305,152 @@ gap: 0.25rem; } -.filter-section-header { - display: flex; - justify-content: space-between; +/* ─── Modern SaaS Table Styling ────────────────────────────────────── */ +.bootstrap-table { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important; +} + +.bootstrap-table.bootstrap5 .fixed-table-container { + border: 1px solid #e2e8f0 !important; + border-radius: 10px !important; + background-color: #ffffff; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.03); + overflow: hidden !important; +} + +.bootstrap-table.bootstrap5 .fixed-table-body { + overflow: auto !important; +} + +/* Subtle scrollbar */ +.bootstrap-table.bootstrap5 .fixed-table-body::-webkit-scrollbar { + width: 7px; + height: 7px; +} +.bootstrap-table.bootstrap5 .fixed-table-body::-webkit-scrollbar-track { + background: #f8fafc; +} +.bootstrap-table.bootstrap5 .fixed-table-body::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 4px; +} +.bootstrap-table.bootstrap5 .fixed-table-body::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} + +/* Headers */ +.bootstrap-table.bootstrap5 .fixed-table-header th, +.bootstrap-table.bootstrap5 #inspections-table th { + background-color: #f8fafc !important; + color: #475569 !important; + font-size: 0.74rem !important; + font-weight: 600 !important; + text-transform: uppercase !important; + letter-spacing: 0.04em !important; + border-bottom: 1.5px solid #e2e8f0 !important; + padding: 0.45rem 0.65rem !important; + vertical-align: middle !important; + white-space: nowrap !important; +} + +.bootstrap-table.bootstrap5 .fixed-table-header th .th-inner { + padding: 0 !important; + font-size: 0.74rem !important; + font-weight: 600 !important; + line-height: 1.3 !important; +} + +/* Rows & Cells */ +.bootstrap-table.bootstrap5 #inspections-table td { + padding: 0.35rem 0.65rem !important; + vertical-align: middle !important; + font-size: 0.82rem !important; + color: #334155; + border-bottom: 1px solid #f1f5f9 !important; + line-height: 1.35 !important; +} + +.bootstrap-table.bootstrap5 #inspections-table tbody tr { + transition: background-color 0.12s ease; +} + +.bootstrap-table.bootstrap5 #inspections-table tbody tr:hover { + background-color: #f8fafc !important; +} + +.bootstrap-table.bootstrap5 #inspections-table tbody tr.selected { + background-color: #f1f5f9 !important; +} + +/* Code link badge in table */ +.table-code-link { + font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace !important; + font-size: 0.79rem !important; + font-weight: 600 !important; + color: #0f172a !important; + text-decoration: none !important; + white-space: nowrap !important; + display: inline-block; + padding: 2px 6px; + border-radius: 5px; + background-color: #f8fafc; + border: 1px solid #e2e8f0; + transition: all 0.15s ease; +} +.table-code-link:hover { + color: #2563eb !important; + border-color: #93c5fd; + background-color: #eff6ff; +} + +/* Action button / Zoom button */ +.zoom-btn, +.table-action-btn { + display: inline-flex; align-items: center; - margin-bottom: 0.75rem; - gap: 1rem; + justify-content: center; + width: 28px; + height: 28px; + padding: 0; + border-radius: 6px; + color: #64748b; + background-color: transparent; + border: 1px solid transparent; + transition: all 0.15s ease; } -.filter-section-header label { - font-weight: 600; - color: #333; - margin: 0; - flex-shrink: 0; -} -.filter-section-buttons { - display: flex; - gap: 0.5rem; - margin-left: auto; - flex-shrink: 0; -} -.filter-section-buttons button { - padding: 0.25rem 0.5rem; - font-size: 0.75rem; - white-space: nowrap; +.zoom-btn:hover, +.table-action-btn:hover { + color: #0f172a; + background-color: #f1f5f9; + border-color: #cbd5e1; } -.filter-options { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - min-height: 2.5rem; - padding: 0.5rem; - background-color: #f8f9fa; - border-radius: 0.375rem; - border: 1px solid #dee2e6; +/* Pagination bar */ +.bootstrap-table.bootstrap5 .fixed-table-pagination { + padding: 0.65rem 0.25rem 0 0.25rem !important; + font-size: 0.82rem; + color: #64748b; } - -.filter-option { - display: flex; - align-items: center; +.bootstrap-table.bootstrap5 .pagination-detail .page-list .btn-group .btn { + border-radius: 6px; + border-color: #e2e8f0; + font-size: 0.8rem; + padding: 0.25rem 0.6rem; + background-color: #ffffff; + color: #334155; } - -.filter-option input[type="checkbox"] { - position: absolute; - opacity: 0; - width: 0; - height: 0; - cursor: pointer; +.bootstrap-table.bootstrap5 .pagination .page-item .page-link { + border-radius: 6px; + margin: 0 2px; + border-color: #e2e8f0; + color: #334155; + font-size: 0.8rem; + padding: 0.25rem 0.55rem; +} +.bootstrap-table.bootstrap5 .pagination .page-item.active .page-link { + background-color: #0f172a; + border-color: #0f172a; + color: #ffffff; } @media (max-width: 991.98px) { diff --git a/loko/inspections/static/inspections/inspections_index.js b/loko/inspections/static/inspections/inspections_index.js index 05c20e6..8baeff4 100644 --- a/loko/inspections/static/inspections/inspections_index.js +++ b/loko/inspections/static/inspections/inspections_index.js @@ -88,6 +88,7 @@ document.addEventListener('DOMContentLoaded', () => { inspectionsgeojsonloader.loadGeojson(initialUrl); _updateExportExcelUrl(query); + updateFilterBadge(); function checkAndOpenInspectionFromUrl() { let urlInspectionId = new URLSearchParams(window.location.search).get('inspection_id'); @@ -397,6 +398,7 @@ function setupFilterForm() { _applySearchToParams(params); savePreferencesFromForm(params); refreshListing(params); + updateFilterBadge(); const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal')); if (filterModal) filterModal.hide(); @@ -433,6 +435,7 @@ function setupFilterForm() { } refreshListing(params); + updateFilterBadge(); const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal')); if (filterModal) filterModal.hide(); @@ -763,19 +766,19 @@ function inspActionsFormatter(value, row) { if (row.lon && row.lat) { html += ` - `; } html += ` - `; if (row.can_edit) { html += ` - `; } @@ -786,7 +789,36 @@ function inspActionsFormatter(value, row) { function inspCodeFormatter(value, row) { const label = value || `INSP#${row.id}`; - return `${label}`; + return `${label}`; +} + +function countActiveFilters() { + const form = document.getElementById('filter-form'); + if (!form) return 0; + let count = 0; + if (form.querySelectorAll('input[name="thematic"]:checked').length > 0) count++; + if (form.querySelectorAll('input[name="category"]:checked').length > 0) count++; + if (form.querySelectorAll('input[name="result_status"]:checked').length > 0) count++; + if (form.querySelectorAll('input[name="nature"]:checked').length > 0) count++; + const dateFrom = form.querySelector('input[name="date_from"]')?.value; + const dateTo = form.querySelector('input[name="date_to"]')?.value; + if (dateFrom || dateTo) count++; + if (form.querySelector('input[name="mine"]')?.checked) count++; + return count; +} + +function updateFilterBadge() { + const count = countActiveFilters(); + const badge = document.getElementById('filter-badge'); + const countSpan = document.getElementById('filter-count'); + if (badge && countSpan) { + if (count > 0) { + countSpan.textContent = count; + badge.classList.remove('d-none'); + } else { + badge.classList.add('d-none'); + } + } } function inspDateFormatter(value, row) { diff --git a/loko/inspections/templates/inspections/inspections_index.html b/loko/inspections/templates/inspections/inspections_index.html index 0a8321d..c421c38 100644 --- a/loko/inspections/templates/inspections/inspections_index.html +++ b/loko/inspections/templates/inspections/inspections_index.html @@ -12,17 +12,20 @@