style(ui): align table and filter modal styles in observations and inspections with assets
This commit is contained in:
parent
af411b2105
commit
7761f22b77
18 changed files with 911 additions and 312 deletions
Binary file not shown.
|
|
@ -2094,3 +2094,7 @@ msgstr "Previous"
|
||||||
msgid "Suivant"
|
msgid "Suivant"
|
||||||
msgstr "Next"
|
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"
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2107,3 +2107,7 @@ msgstr "Précédent"
|
||||||
msgid "Suivant"
|
msgid "Suivant"
|
||||||
msgstr "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"
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2095,3 +2095,7 @@ msgstr "Vorige"
|
||||||
msgid "Suivant"
|
msgid "Suivant"
|
||||||
msgstr "Volgende"
|
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"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
/* Layout helpers for Inspections desktop view */
|
||||||
.inspections-layout #inspections-table-container {
|
.inspections-layout #inspections-table-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -43,125 +45,255 @@
|
||||||
border-color: #dee2e6;
|
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 {
|
#filterModal .modal-dialog {
|
||||||
max-width: 95%;
|
max-width: 820px;
|
||||||
|
margin: 1.5rem auto;
|
||||||
}
|
}
|
||||||
#filterModal .modal-content {
|
#filterModal .modal-content {
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 18px;
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
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 {
|
#filterModal .modal-body {
|
||||||
|
padding: 1.5rem;
|
||||||
|
background-color: #f8fafc;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
#filterModal .modal-footer {
|
#filterModal .modal-footer {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-top: 1px solid #f1f5f9;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filter Section Cards */
|
||||||
.filter-section {
|
.filter-section {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 1.15rem;
|
||||||
margin-bottom: 1rem;
|
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 {
|
.filter-option label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 0;
|
gap: 0.35rem;
|
||||||
|
padding: 0.4rem 0.85rem;
|
||||||
|
font-size: 0.82rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
color: #334155;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1.5px solid #e2e8f0;
|
||||||
|
border-radius: 9999px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #e7f1ff;
|
transition: all 0.15s ease;
|
||||||
color: #0c5cc9;
|
user-select: none;
|
||||||
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;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
margin: 0;
|
||||||
text-overflow: ellipsis;
|
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 {
|
.filter-option label.context-badge {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-width: 1.5px;
|
border-width: 1.5px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
font-weight: 600;
|
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.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.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.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.btn-outline-success,
|
||||||
.filter-option label.status-compliant { border-color: #198754; color: #198754; background-color: #ffffff; }
|
.filter-option label.status-compliant { border-color: #198754; color: #198754; }
|
||||||
.filter-option label.btn-outline-info { border-color: #17a2b8; color: #17a2b8; background-color: #ffffff; }
|
.filter-option label.btn-outline-info { border-color: #0284c7; color: #0284c7; }
|
||||||
.filter-option label.btn-outline-dark,
|
.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.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 */
|
/* Contextual badges - hover state */
|
||||||
.filter-option input[type="checkbox"]:checked + label:not(.context-badge) {
|
.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-primary,
|
||||||
background-color: #0c5cc9 !important; color: white !important; border-color: #0c5cc9 !important;
|
.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 */
|
/* 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.btn-outline-primary,
|
||||||
.filter-option input[type="checkbox"]:checked + label.status-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.btn-outline-danger,
|
||||||
.filter-option input[type="checkbox"]:checked + label.status-damaged {
|
.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.btn-outline-warning,
|
||||||
.filter-option input[type="checkbox"]:checked + label.status-non_compliant {
|
.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.btn-outline-success,
|
||||||
.filter-option input[type="checkbox"]:checked + label.status-compliant {
|
.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 {
|
.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.btn-outline-dark,
|
||||||
.filter-option input[type="checkbox"]:checked + label.status-missing {
|
.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.btn-outline-secondary,
|
||||||
.filter-option input[type="checkbox"]:checked + label.status-cancelled {
|
.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 */
|
/* Subcategories */
|
||||||
.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; }
|
|
||||||
|
|
||||||
.filter-option.subcategory-option label {
|
.filter-option.subcategory-option label {
|
||||||
font-size: 0.875em;
|
font-size: 0.8rem;
|
||||||
color: #555;
|
color: #64748b;
|
||||||
}
|
}
|
||||||
.filter-option-break {
|
.filter-option-break {
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
|
|
@ -173,53 +305,152 @@
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-section-header {
|
/* ─── Modern SaaS Table Styling ────────────────────────────────────── */
|
||||||
display: flex;
|
.bootstrap-table {
|
||||||
justify-content: space-between;
|
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;
|
align-items: center;
|
||||||
margin-bottom: 0.75rem;
|
justify-content: center;
|
||||||
gap: 1rem;
|
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 {
|
.zoom-btn:hover,
|
||||||
font-weight: 600;
|
.table-action-btn:hover {
|
||||||
color: #333;
|
color: #0f172a;
|
||||||
margin: 0;
|
background-color: #f1f5f9;
|
||||||
flex-shrink: 0;
|
border-color: #cbd5e1;
|
||||||
}
|
|
||||||
.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-options {
|
/* Pagination bar */
|
||||||
display: flex;
|
.bootstrap-table.bootstrap5 .fixed-table-pagination {
|
||||||
flex-wrap: wrap;
|
padding: 0.65rem 0.25rem 0 0.25rem !important;
|
||||||
gap: 0.5rem;
|
font-size: 0.82rem;
|
||||||
min-height: 2.5rem;
|
color: #64748b;
|
||||||
padding: 0.5rem;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
}
|
}
|
||||||
|
.bootstrap-table.bootstrap5 .pagination-detail .page-list .btn-group .btn {
|
||||||
.filter-option {
|
border-radius: 6px;
|
||||||
display: flex;
|
border-color: #e2e8f0;
|
||||||
align-items: center;
|
font-size: 0.8rem;
|
||||||
|
padding: 0.25rem 0.6rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #334155;
|
||||||
}
|
}
|
||||||
|
.bootstrap-table.bootstrap5 .pagination .page-item .page-link {
|
||||||
.filter-option input[type="checkbox"] {
|
border-radius: 6px;
|
||||||
position: absolute;
|
margin: 0 2px;
|
||||||
opacity: 0;
|
border-color: #e2e8f0;
|
||||||
width: 0;
|
color: #334155;
|
||||||
height: 0;
|
font-size: 0.8rem;
|
||||||
cursor: pointer;
|
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) {
|
@media (max-width: 991.98px) {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
inspectionsgeojsonloader.loadGeojson(initialUrl);
|
inspectionsgeojsonloader.loadGeojson(initialUrl);
|
||||||
|
|
||||||
_updateExportExcelUrl(query);
|
_updateExportExcelUrl(query);
|
||||||
|
updateFilterBadge();
|
||||||
|
|
||||||
function checkAndOpenInspectionFromUrl() {
|
function checkAndOpenInspectionFromUrl() {
|
||||||
let urlInspectionId = new URLSearchParams(window.location.search).get('inspection_id');
|
let urlInspectionId = new URLSearchParams(window.location.search).get('inspection_id');
|
||||||
|
|
@ -397,6 +398,7 @@ function setupFilterForm() {
|
||||||
_applySearchToParams(params);
|
_applySearchToParams(params);
|
||||||
savePreferencesFromForm(params);
|
savePreferencesFromForm(params);
|
||||||
refreshListing(params);
|
refreshListing(params);
|
||||||
|
updateFilterBadge();
|
||||||
|
|
||||||
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
||||||
if (filterModal) filterModal.hide();
|
if (filterModal) filterModal.hide();
|
||||||
|
|
@ -433,6 +435,7 @@ function setupFilterForm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshListing(params);
|
refreshListing(params);
|
||||||
|
updateFilterBadge();
|
||||||
|
|
||||||
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
||||||
if (filterModal) filterModal.hide();
|
if (filterModal) filterModal.hide();
|
||||||
|
|
@ -763,19 +766,19 @@ function inspActionsFormatter(value, row) {
|
||||||
|
|
||||||
if (row.lon && row.lat) {
|
if (row.lon && row.lat) {
|
||||||
html += `
|
html += `
|
||||||
<button class="btn btn-sm btn-light zoom-btn py-0 px-1" data-lon="${row.lon}" data-lat="${row.lat}" title="${gettext('Zoomer sur la carte')}">
|
<button class="zoom-btn" data-lon="${row.lon}" data-lat="${row.lat}" title="${gettext('Zoomer sur la carte')}">
|
||||||
<i class="bi bi-geo-alt"></i>
|
<i class="bi bi-geo-alt"></i>
|
||||||
</button>`;
|
</button>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<button class="btn btn-sm btn-light py-0 px-1" onclick="openInspectionDetailModal(${row.id})" title="${gettext('Voir le détail')}">
|
<button class="table-action-btn" onclick="openInspectionDetailModal(${row.id})" title="${gettext('Voir le détail')}">
|
||||||
<i class="bi bi-eye"></i>
|
<i class="bi bi-eye"></i>
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|
||||||
if (row.can_edit) {
|
if (row.can_edit) {
|
||||||
html += `
|
html += `
|
||||||
<button class="btn btn-sm btn-light py-0 px-1" onclick="openEditInspectionModal(${row.id})" title="${gettext('Modifier')}">
|
<button class="table-action-btn" onclick="openEditInspectionModal(${row.id})" title="${gettext('Modifier')}">
|
||||||
<i class="bi bi-pencil"></i>
|
<i class="bi bi-pencil"></i>
|
||||||
</button>`;
|
</button>`;
|
||||||
}
|
}
|
||||||
|
|
@ -786,7 +789,36 @@ function inspActionsFormatter(value, row) {
|
||||||
|
|
||||||
function inspCodeFormatter(value, row) {
|
function inspCodeFormatter(value, row) {
|
||||||
const label = value || `INSP#${row.id}`;
|
const label = value || `INSP#${row.id}`;
|
||||||
return `<a href="javascript:void(0)" onclick="openInspectionDetailModal(${row.id})" class="fw-semibold text-decoration-none text-nowrap">${label}</a>`;
|
return `<a href="javascript:void(0)" onclick="openInspectionDetailModal(${row.id})" class="table-code-link">${label}</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
function inspDateFormatter(value, row) {
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,20 @@
|
||||||
|
|
||||||
<!-- Modale de filtre des inspections -->
|
<!-- Modale de filtre des inspections -->
|
||||||
<div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true">
|
<div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les inspections" %}</h5>
|
<div>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les inspections" %}</h5>
|
||||||
|
<div class="text-muted small" style="font-size: 0.8rem;">{% translate "Sélectionnez les critères à afficher sur la carte et dans le tableau" %}</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form method="get" id="filter-form" class="mb-4">
|
<form method="get" id="filter-form" class="mb-0">
|
||||||
|
|
||||||
<!-- Thématique -->
|
<!-- Thématique -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Thématique" %}</label>
|
<label>{% translate "Thématique" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -43,7 +46,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Catégorie / Type d'asset -->
|
<!-- Catégorie / Type d'asset -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Catégorie / Type d'asset" %}</label>
|
<label>{% translate "Catégorie / Type d'asset" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -63,7 +66,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Résultat du contrôle -->
|
<!-- Résultat du contrôle -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Résultat du contrôle" %}</label>
|
<label>{% translate "Résultat du contrôle" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -84,7 +87,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Nature -->
|
<!-- Nature -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Nature" %}</label>
|
<label>{% translate "Nature" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -103,19 +106,23 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Période & Mes inspections -->
|
<!-- Période & Mes inspections -->
|
||||||
<div class="row mt-3">
|
<div class="filter-section mb-0">
|
||||||
<div class="col-md-6">
|
<div class="row g-3 align-items-center">
|
||||||
<label class="form-label">{% translate "Période" %}</label>
|
<div class="col-md-6">
|
||||||
<div class="d-flex gap-2 align-items-center">
|
<label class="form-label fw-bold mb-2 text-dark" style="font-size: 0.9rem;">{% translate "Période" %}</label>
|
||||||
<input type="date" name="date_from" id="date_from" class="form-control" value="{{ date_from }}" title="{% translate 'Du' %}">
|
<div class="d-flex gap-2 align-items-center">
|
||||||
<span class="text-muted small">–</span>
|
<input type="date" name="date_from" id="date_from" class="form-control form-control-sm" value="{{ date_from }}" title="{% translate 'Du' %}">
|
||||||
<input type="date" name="date_to" id="date_to" class="form-control" value="{{ date_to }}" title="{% translate 'Au' %}">
|
<span class="text-muted small">–</span>
|
||||||
|
<input type="date" name="date_to" id="date_to" class="form-control form-control-sm" value="{{ date_to }}" title="{% translate 'Au' %}">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-md-6">
|
||||||
<div class="col-md-6">
|
<div class="pt-md-4">
|
||||||
<div class="form-check mt-4">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" name="mine" value="1" id="mine" {% if show_mine_only %}checked{% endif %}>
|
<input class="form-check-input" type="checkbox" name="mine" value="1" id="mine" {% if show_mine_only %}checked{% endif %}>
|
||||||
<label class="form-check-label" for="mine">{% translate "Mes inspections" %}</label>
|
<label class="form-check-label small fw-medium" for="mine">{% translate "Mes inspections" %}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,9 +130,15 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" id="reset-filters" class="btn btn-secondary">{% translate "Réinitialiser" %}</button>
|
<button type="button" id="reset-filters" class="btn btn-link text-muted p-0 text-decoration-none d-flex align-items-center gap-1" style="font-size: 0.85rem; font-weight: 500;">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<i class="bi bi-arrow-counterclockwise"></i> {% translate "Réinitialiser" %}
|
||||||
<button type="button" id="apply-filters" class="btn btn-primary">{% translate "Filtrer" %}</button>
|
</button>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary px-3 py-2" data-bs-dismiss="modal" style="border-radius: 8px; font-weight: 500;">{% translate "Annuler" %}</button>
|
||||||
|
<button type="button" id="apply-filters" class="btn btn-sm btn-dark px-4 py-2" style="background-color: #0f172a; border-color: #0f172a; border-radius: 8px; font-weight: 600;">
|
||||||
|
<i class="bi bi-check2 me-1"></i>{% translate "Filtrer" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -215,8 +228,11 @@
|
||||||
|
|
||||||
<div id="inspections-table-container" class="d-none">
|
<div id="inspections-table-container" class="d-none">
|
||||||
<div id="filter-dropdown-wrapper" class="d-flex align-items-center gap-2">
|
<div id="filter-dropdown-wrapper" class="d-flex align-items-center gap-2">
|
||||||
<button type="button" class="btn btn-light" data-bs-toggle="modal" data-bs-target="#filterModal">
|
<button type="button" class="btn btn-light position-relative" data-bs-toggle="modal" data-bs-target="#filterModal">
|
||||||
{% translate "Filtre" %}
|
<i class="bi bi-funnel"></i> {% translate "Filtre" %}
|
||||||
|
<span id="filter-badge" class="position-absolute badge rounded-pill bg-primary d-none">
|
||||||
|
<span id="filter-count">0</span>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<a id="export-excel-btn" href="{% url 'inspections:inspections_export_excel' %}" class="btn btn-light" title="{% translate 'Exporter en Excel' %}">
|
<a id="export-excel-btn" href="{% url 'inspections:inspections_export_excel' %}" class="btn btn-light" title="{% translate 'Exporter en Excel' %}">
|
||||||
<i class="bi bi-file-earmark-spreadsheet"></i>
|
<i class="bi bi-file-earmark-spreadsheet"></i>
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1447,3 +1447,7 @@ msgstr "The observation was linked to project %(code)s."
|
||||||
#: observations/views.py:2031
|
#: observations/views.py:2031
|
||||||
msgid "Le lien avec le projet a été supprimé."
|
msgid "Le lien avec le projet a été supprimé."
|
||||||
msgstr "The link to the project has been removed."
|
msgstr "The link to the project has been removed."
|
||||||
|
|
||||||
|
#: observations/templates/observations/observations_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"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1462,3 +1462,7 @@ msgstr "L'observation a été liée au projet %(code)s."
|
||||||
#: observations/views.py:2031
|
#: observations/views.py:2031
|
||||||
msgid "Le lien avec le projet a été supprimé."
|
msgid "Le lien avec le projet a été supprimé."
|
||||||
msgstr "Le lien avec le projet a été supprimé."
|
msgstr "Le lien avec le projet a été supprimé."
|
||||||
|
|
||||||
|
#: observations/templates/observations/observations_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"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1454,3 +1454,7 @@ msgstr "De waarneming was gekoppeld aan project %(code)s."
|
||||||
#: observations/views.py:2031
|
#: observations/views.py:2031
|
||||||
msgid "Le lien avec le projet a été supprimé."
|
msgid "Le lien avec le projet a été supprimé."
|
||||||
msgstr "De link naar het project is verwijderd."
|
msgstr "De link naar het project is verwijderd."
|
||||||
|
|
||||||
|
#: observations/templates/observations/observations_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"
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
/* Layout helpers */
|
||||||
.observations-layout #observations-table-container {
|
.observations-layout #observations-table-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -36,6 +38,388 @@
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Supprime le contour bleu Bootstrap au focus sur l'input de recherche */
|
||||||
|
#observations-search-input:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
border-color: #dee2e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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: 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: 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
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;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
user-select: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
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 badges - inactive state (outline) */
|
||||||
|
.filter-option label.context-badge {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-width: 1.5px;
|
||||||
|
border-style: solid;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.filter-option label.btn-outline-primary { border-color: #0c5cc9; color: #0c5cc9; }
|
||||||
|
.filter-option label.btn-outline-danger { border-color: #dc3545; color: #dc3545; }
|
||||||
|
.filter-option label.btn-outline-warning { border-color: #f59e0b; color: #d97706; }
|
||||||
|
.filter-option label.btn-outline-success { border-color: #198754; color: #198754; }
|
||||||
|
.filter-option label.btn-outline-info { border-color: #0284c7; color: #0284c7; }
|
||||||
|
.filter-option label.btn-outline-dark { border-color: #334155; color: #334155; }
|
||||||
|
.filter-option label.btn-outline-secondary { border-color: #64748b; color: #64748b; }
|
||||||
|
|
||||||
|
/* Contextual badges - hover state */
|
||||||
|
.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-primary { background-color: #eff6ff; }
|
||||||
|
.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-danger { background-color: #fef2f2; }
|
||||||
|
.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-warning { background-color: #fffbeb; }
|
||||||
|
.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-success { 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 { background-color: #f8fafc; }
|
||||||
|
.filter-option input[type="checkbox"]:not(:checked):hover + label.btn-outline-secondary { 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 { 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 { 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 { 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 { 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: #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 { 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 { background-color: #64748b !important; border-color: #64748b !important; box-shadow: 0 2px 6px rgba(100, 116, 139, 0.2); }
|
||||||
|
|
||||||
|
/* Subcategories */
|
||||||
|
.filter-option.subcategory-option label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
.filter-option-break {
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.filter-subcat-controls {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── 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 #observations-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 #observations-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 #observations-table tbody tr {
|
||||||
|
transition: background-color 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-table.bootstrap5 #observations-table tbody tr:hover {
|
||||||
|
background-color: #f8fafc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-table.bootstrap5 #observations-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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
.zoom-btn:hover,
|
||||||
|
.table-action-btn:hover {
|
||||||
|
color: #0f172a;
|
||||||
|
background-color: #f1f5f9;
|
||||||
|
border-color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pagination bar */
|
||||||
|
.bootstrap-table.bootstrap5 .fixed-table-pagination {
|
||||||
|
padding: 0.65rem 0.25rem 0 0.25rem !important;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: #64748b;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
.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) {
|
@media (max-width: 991.98px) {
|
||||||
.observations-layout #filter-dropdown-wrapper {
|
.observations-layout #filter-dropdown-wrapper {
|
||||||
position: static;
|
position: static;
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
// Sync export button with initial URL filters
|
// Sync export button with initial URL filters
|
||||||
_updateExportExcelUrl(query);
|
_updateExportExcelUrl(query);
|
||||||
|
updateFilterBadge();
|
||||||
});
|
});
|
||||||
|
|
||||||
observationsgeojsonloader.addEventListener('geojsonLoaded', (event) => {
|
observationsgeojsonloader.addEventListener('geojsonLoaded', (event) => {
|
||||||
|
|
@ -361,6 +362,7 @@ function setupFilterForm() {
|
||||||
_applySearchToParams(params);
|
_applySearchToParams(params);
|
||||||
savePreferencesFromForm(params);
|
savePreferencesFromForm(params);
|
||||||
refreshListing(params);
|
refreshListing(params);
|
||||||
|
updateFilterBadge();
|
||||||
|
|
||||||
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
||||||
if (filterModal) filterModal.hide();
|
if (filterModal) filterModal.hide();
|
||||||
|
|
@ -411,6 +413,7 @@ function setupFilterForm() {
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshListing(params);
|
refreshListing(params);
|
||||||
|
updateFilterBadge();
|
||||||
|
|
||||||
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
const filterModal = bootstrap.Modal.getInstance(document.getElementById('filterModal'));
|
||||||
if (filterModal) filterModal.hide();
|
if (filterModal) filterModal.hide();
|
||||||
|
|
@ -864,7 +867,7 @@ function actionsFormatter(value, row) {
|
||||||
|
|
||||||
if (row.lon && row.lat) {
|
if (row.lon && row.lat) {
|
||||||
html += `
|
html += `
|
||||||
<button class="btn btn-sm btn-light zoom-btn" data-lon="${row.lon}" data-lat="${row.lat}" title="${gettext('Zoomer sur la carte')}">
|
<button class="zoom-btn" data-lon="${row.lon}" data-lat="${row.lat}" title="${gettext('Zoomer sur la carte')}">
|
||||||
<i class="bi bi-geo-alt"></i>
|
<i class="bi bi-geo-alt"></i>
|
||||||
</button>`;
|
</button>`;
|
||||||
}
|
}
|
||||||
|
|
@ -874,7 +877,53 @@ function actionsFormatter(value, row) {
|
||||||
|
|
||||||
function codeFormatter(value, row) {
|
function codeFormatter(value, row) {
|
||||||
const label = value || '-';
|
const label = value || '-';
|
||||||
return `<a href="${observationsIndexUrl}${row.id}/" class="fw-semibold text-decoration-none text-nowrap">${label}</a>`;
|
return `<a href="${observationsIndexUrl}${row.id}/" class="table-code-link">${label}</a>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
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="symptom"]:checked').length > 0) count++;
|
||||||
|
|
||||||
|
// Type: default is all except 'inventory'
|
||||||
|
const typeChecked = Array.from(form.querySelectorAll('input[name="type"]:checked')).map(cb => cb.value);
|
||||||
|
const typeAll = Array.from(form.querySelectorAll('input[name="type"]')).map(cb => cb.value);
|
||||||
|
const defaultTypes = typeAll.filter(v => v !== 'inventory');
|
||||||
|
const isDefaultTypes = typeChecked.length === defaultTypes.length && typeChecked.every(v => defaultTypes.includes(v));
|
||||||
|
if (!isDefaultTypes && typeChecked.length > 0) count++;
|
||||||
|
|
||||||
|
// Status: default is all except 'archived'
|
||||||
|
const statusChecked = Array.from(form.querySelectorAll('input[name="status"]:checked')).map(cb => cb.value);
|
||||||
|
const statusAll = Array.from(form.querySelectorAll('input[name="status"]')).map(cb => cb.value);
|
||||||
|
const defaultStatuses = statusAll.filter(v => v !== 'archived');
|
||||||
|
const isDefaultStatuses = statusChecked.length === defaultStatuses.length && statusChecked.every(v => defaultStatuses.includes(v));
|
||||||
|
if (!isDefaultStatuses && statusChecked.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++;
|
||||||
|
if (form.querySelector('input[name="team"]')?.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 descriptionFormatter(value, row) {
|
function descriptionFormatter(value, row) {
|
||||||
|
|
|
||||||
|
|
@ -4,176 +4,26 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link rel="stylesheet" href="{% static 'observations/observations_index.css' %}">
|
<link rel="stylesheet" href="{% static 'observations/observations_index.css' %}">
|
||||||
<style>
|
|
||||||
/* Supprime le contour bleu Bootstrap au focus sur l'input de recherche */
|
|
||||||
#observations-search-input:focus {
|
|
||||||
outline: none;
|
|
||||||
box-shadow: none;
|
|
||||||
border-color: #dee2e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styles pour la modale de filtre */
|
|
||||||
#filterModal .modal-dialog {
|
|
||||||
max-width: 95%;
|
|
||||||
}
|
|
||||||
#filterModal .modal-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-height: 90vh;
|
|
||||||
}
|
|
||||||
#filterModal .modal-body {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
#filterModal .modal-footer {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-section {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default badge styling */
|
|
||||||
.filter-option label {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 0;
|
|
||||||
font-weight: 500;
|
|
||||||
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;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Contextual color badges - inactive state */
|
|
||||||
.filter-option label.context-badge {
|
|
||||||
border-color: currentColor;
|
|
||||||
color: inherit;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-option label.btn-outline-primary { border-color: #0c5cc9; color: #0c5cc9; }
|
|
||||||
.filter-option label.btn-outline-danger { border-color: #dc3545; color: #dc3545; }
|
|
||||||
.filter-option label.btn-outline-warning { border-color: #ffc107; color: #ffc107; }
|
|
||||||
.filter-option label.btn-outline-success { border-color: #28a745; color: #28a745; }
|
|
||||||
.filter-option label.btn-outline-info { border-color: #17a2b8; color: #17a2b8; }
|
|
||||||
.filter-option label.btn-outline-dark { border-color: #343a40; color: #343a40; }
|
|
||||||
.filter-option label.btn-outline-secondary { border-color: #6c757d; color: #6c757d; }
|
|
||||||
|
|
||||||
/* Default badges - checked state */
|
|
||||||
.filter-option input[type="checkbox"]:checked + label:not(.context-badge) {
|
|
||||||
background-color: #0c5cc9; color: white; border-color: #0c5cc9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Contextual badges - checked state */
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.context-badge { color: white; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-primary { background-color: #0c5cc9; border-color: #0c5cc9; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-danger { background-color: #dc3545; border-color: #dc3545; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-warning { background-color: #ffc107; border-color: #ffc107; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-success { background-color: #28a745; border-color: #28a745; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-info { background-color: #17a2b8; border-color: #17a2b8; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-dark { background-color: #343a40; border-color: #343a40; }
|
|
||||||
.filter-option input[type="checkbox"]:checked + label.btn-outline-secondary { background-color: #6c757d; border-color: #6c757d; }
|
|
||||||
|
|
||||||
/* Default badges - hover */
|
|
||||||
.filter-option input[type="checkbox"]:hover + label:not(.context-badge) { background-color: #cfe2f3; }
|
|
||||||
|
|
||||||
.filter-option.subcategory-option label {
|
|
||||||
font-size: 0.875em;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
.filter-option-break {
|
|
||||||
flex-basis: 100%;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
.filter-subcat-controls {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-section-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-option {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-option input[type="checkbox"] {
|
|
||||||
position: absolute;
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Symptômes : boutons deux fois plus larges */
|
|
||||||
.filter-options[data-field="symptom"] .filter-option label {
|
|
||||||
width: 280px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<!-- Modale de filtre des observations -->
|
<!-- Modale de filtre des observations -->
|
||||||
<div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true">
|
<div class="modal fade" id="filterModal" tabindex="-1" aria-labelledby="filterModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les observations" %}</h5>
|
<div>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
<h5 class="modal-title" id="filterModalLabel">{% translate "Filtrer les observations" %}</h5>
|
||||||
|
<div class="text-muted small" style="font-size: 0.8rem;">{% translate "Sélectionnez les critères à afficher sur la carte et dans le tableau" %}</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% translate 'Fermer' %}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form method="get" id="filter-form" class="mb-4">
|
<form method="get" id="filter-form" class="mb-0">
|
||||||
|
|
||||||
<!-- Thématique -->
|
<!-- Thématique -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Thématique" %}</label>
|
<label>{% translate "Thématique" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -194,7 +44,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Catégorie -->
|
<!-- Catégorie -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Catégorie" %}</label>
|
<label>{% translate "Catégorie" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -214,7 +64,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Symptôme -->
|
<!-- Symptôme -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Symptôme" %}</label>
|
<label>{% translate "Symptôme" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -233,7 +83,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Type d'observation -->
|
<!-- Type d'observation -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Type d'observation" %}</label>
|
<label>{% translate "Type d'observation" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -252,7 +102,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Statut -->
|
<!-- Statut -->
|
||||||
<div class="col-12 filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-section-header">
|
<div class="filter-section-header">
|
||||||
<label>{% translate "Statut" %}</label>
|
<label>{% translate "Statut" %}</label>
|
||||||
<div class="filter-section-buttons">
|
<div class="filter-section-buttons">
|
||||||
|
|
@ -270,36 +120,46 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Période -->
|
<!-- Période & Assignation -->
|
||||||
<div class="row mt-3">
|
<div class="filter-section mb-0">
|
||||||
<div class="col-md-6">
|
<div class="row g-3 align-items-center">
|
||||||
<label class="form-label">{% translate "Période" %}</label>
|
<div class="col-md-6">
|
||||||
<div class="d-flex gap-2 align-items-center">
|
<label class="form-label fw-bold mb-2 text-dark" style="font-size: 0.9rem;">{% translate "Période" %}</label>
|
||||||
<input type="date" name="date_from" id="date_from" class="form-control" value="{{ date_from }}" title="{% translate 'Du' %}">
|
<div class="d-flex gap-2 align-items-center">
|
||||||
<span class="text-muted small">–</span>
|
<input type="date" name="date_from" id="date_from" class="form-control form-control-sm" value="{{ date_from }}" title="{% translate 'Du' %}">
|
||||||
<input type="date" name="date_to" id="date_to" class="form-control" value="{{ date_to }}" title="{% translate 'Au' %}">
|
<span class="text-muted small">–</span>
|
||||||
|
<input type="date" name="date_to" id="date_to" class="form-control form-control-sm" value="{{ date_to }}" title="{% translate 'Au' %}">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-md-6">
|
||||||
<div class="col-md-6">
|
<div class="pt-md-4">
|
||||||
<div class="form-check mt-4">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" name="mine" value="1" id="mine" {% if show_mine_only %}checked{% endif %}>
|
<input class="form-check-input" type="checkbox" name="mine" value="1" id="mine" {% if show_mine_only %}checked{% endif %}>
|
||||||
<label class="form-check-label" for="mine">{% translate "Mes observations" %}</label>
|
<label class="form-check-label small fw-medium" for="mine">{% translate "Mes observations" %}</label>
|
||||||
|
</div>
|
||||||
|
{% if user_has_team %}
|
||||||
|
<div class="form-check mt-1">
|
||||||
|
<input class="form-check-input" type="checkbox" name="team" value="1" id="my-team" {% if show_my_team %}checked{% endif %}>
|
||||||
|
<label class="form-check-label small fw-medium" for="my-team">{% translate "À traiter par mon équipe" %}</label>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if user_has_team %}
|
|
||||||
<div class="form-check mt-2">
|
|
||||||
<input class="form-check-input" type="checkbox" name="team" value="1" id="my-team" {% if show_my_team %}checked{% endif %}>
|
|
||||||
<label class="form-check-label" for="my-team">{% translate "À traiter par mon équipe" %}</label>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" id="reset-filters" class="btn btn-secondary">{% translate "Réinitialiser" %}</button>
|
<button type="button" id="reset-filters" class="btn btn-link text-muted p-0 text-decoration-none d-flex align-items-center gap-1" style="font-size: 0.85rem; font-weight: 500;">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% translate "Annuler" %}</button>
|
<i class="bi bi-arrow-counterclockwise"></i> {% translate "Réinitialiser" %}
|
||||||
<button type="button" id="apply-filters" class="btn btn-primary">{% translate "Filtrer" %}</button>
|
</button>
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-secondary px-3 py-2" data-bs-dismiss="modal" style="border-radius: 8px; font-weight: 500;">{% translate "Annuler" %}</button>
|
||||||
|
<button type="button" id="apply-filters" class="btn btn-sm btn-dark px-4 py-2" style="background-color: #0f172a; border-color: #0f172a; border-radius: 8px; font-weight: 600;">
|
||||||
|
<i class="bi bi-check2 me-1"></i>{% translate "Filtrer" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -387,8 +247,11 @@
|
||||||
|
|
||||||
<div id="observations-table-container" class="d-none">
|
<div id="observations-table-container" class="d-none">
|
||||||
<div id="filter-dropdown-wrapper" class="d-flex align-items-center gap-2">
|
<div id="filter-dropdown-wrapper" class="d-flex align-items-center gap-2">
|
||||||
<button type="button" class="btn btn-light" data-bs-toggle="modal" data-bs-target="#filterModal">
|
<button type="button" class="btn btn-light position-relative" data-bs-toggle="modal" data-bs-target="#filterModal">
|
||||||
{% translate "Filtre" %}
|
<i class="bi bi-funnel"></i> {% translate "Filtre" %}
|
||||||
|
<span id="filter-badge" class="position-absolute badge rounded-pill bg-primary d-none">
|
||||||
|
<span id="filter-count">0</span>
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<a id="export-excel-btn" href="{% url 'observations:observations_export_excel' %}" class="btn btn-light" title="{% translate 'Exporter en Excel' %}">
|
<a id="export-excel-btn" href="{% url 'observations:observations_export_excel' %}" class="btn btn-light" title="{% translate 'Exporter en Excel' %}">
|
||||||
<i class="bi bi-file-earmark-spreadsheet"></i>
|
<i class="bi bi-file-earmark-spreadsheet"></i>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue