Report: filter-pill strip with × to clear individual filters
Three pills under the header: date range, project(s), team(s). Shows comma-joined names when multi-valued (project_name in context is already a comma-joined string from Task 6). × buttons on the project and team pills remove just that filter via a rebuilt querystring; the calendar pill has no × (date range is required). Helper context keys query_string_without_project / _without_team do the rebuild in the view via QueryDict.setlist so multi-value keys are properly stripped (pop() only removes the first occurrence). Pill CSS uses existing design tokens (--bg-inset, --accent, --text-primary, --border-default, --text-tertiary, --bg-card-hover) so dark and light themes work without overrides. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
702bba10ed
commit
ea481bfbf4
@ -30,6 +30,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{# === FILTER PILLS === #}
|
||||||
|
<div class="filter-pill-strip d-flex flex-wrap gap-2 mb-4 d-print-none">
|
||||||
|
<span class="filter-pill">
|
||||||
|
<i class="fas fa-calendar me-1"></i>{{ start_date|date:"d M Y" }} – {{ end_date|date:"d M Y" }}
|
||||||
|
</span>
|
||||||
|
<span class="filter-pill">
|
||||||
|
<i class="fas fa-folder me-1"></i>{{ project_name }}
|
||||||
|
{% if selected_project_ids %}
|
||||||
|
<a href="?{{ query_string_without_project|default:query_string }}" class="filter-pill__x" aria-label="Clear project filter">×</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<span class="filter-pill">
|
||||||
|
<i class="fas fa-users me-1"></i>{{ team_name }}
|
||||||
|
{% if selected_team_ids %}
|
||||||
|
<a href="?{{ query_string_without_team|default:query_string }}" class="filter-pill__x" aria-label="Clear team filter">×</a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- === PRINT HEADER === -->
|
<!-- === PRINT HEADER === -->
|
||||||
<div class="d-none d-print-block mb-4">
|
<div class="d-none d-print-block mb-4">
|
||||||
<h2 class="text-center fw-bold mb-1">FoxFitt Construction — Payroll Report</h2>
|
<h2 class="text-center fw-bold mb-1">FoxFitt Construction — Payroll Report</h2>
|
||||||
|
|||||||
@ -2382,6 +2382,17 @@ def generate_report(request):
|
|||||||
)
|
)
|
||||||
# Pass the raw query params so the "Download PDF" button can use them
|
# Pass the raw query params so the "Download PDF" button can use them
|
||||||
context['query_string'] = request.GET.urlencode()
|
context['query_string'] = request.GET.urlencode()
|
||||||
|
# === FILTER PILL CLEAR LINKS ===
|
||||||
|
# For the filter-pill x buttons: rebuild the querystring with one filter removed.
|
||||||
|
# QueryDict.pop() only removes the first occurrence, so for multi-value keys
|
||||||
|
# (e.g. project=1&project=2) we follow up with setlist(key, []) to strip them all.
|
||||||
|
def _qs_without(key):
|
||||||
|
qd = request.GET.copy()
|
||||||
|
qd.pop(key, None)
|
||||||
|
qd.setlist(key, [])
|
||||||
|
return qd.urlencode()
|
||||||
|
context['query_string_without_project'] = _qs_without('project')
|
||||||
|
context['query_string_without_team'] = _qs_without('team')
|
||||||
# Pass projects and teams so the "New Report" modal's dropdowns can
|
# Pass projects and teams so the "New Report" modal's dropdowns can
|
||||||
# populate (same lists the Dashboard modal uses)
|
# populate (same lists the Dashboard modal uses)
|
||||||
context['projects'] = Project.objects.all().order_by('name')
|
context['projects'] = Project.objects.all().order_by('name')
|
||||||
|
|||||||
@ -1491,3 +1491,34 @@ body, .card, .modal-content, .form-control, .form-select,
|
|||||||
.work-log-row:hover td {
|
.work-log-row:hover td {
|
||||||
background: var(--bg-card-hover);
|
background: var(--bg-card-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === Report filter pills === */
|
||||||
|
.filter-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.35rem 0.75rem;
|
||||||
|
font-size: 0.825rem;
|
||||||
|
background: var(--bg-inset);
|
||||||
|
color: var(--text-primary);
|
||||||
|
border: 1px solid var(--border-default);
|
||||||
|
border-radius: 999px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.filter-pill i {
|
||||||
|
color: var(--accent);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
.filter-pill__x {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
padding: 0 0.35rem;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 50%;
|
||||||
|
transition: color 120ms, background-color 120ms;
|
||||||
|
}
|
||||||
|
.filter-pill__x:hover {
|
||||||
|
color: var(--text-primary);
|
||||||
|
background: var(--bg-card-hover);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user