Template: interactive filter-pill markup + popover shells
Replaces the three static filter pills with clickable buttons and
inline popover shells below each one. Popovers remain hidden by
default (hidden attribute) — the JS module in Task 4 will wire up
open/close, dirty state, and Apply behaviour.
Structure per pill:
- .filter-pill-wrap (position-relative container)
- <button class="filter-pill filter-pill--editable" data-filter="...">
with chevron indicating clickability
- <a class="filter-pill__x"> (existing × clear-filter link, preserved)
- .filter-popover (the editable widget — date picker for the Date
pill, Choices.js multi-select for Projects/Teams pills)
Apply + Reset buttons sit in .apply-filters-group at the right end,
initially hidden. A <div id="filter-toast-container"> is pre-placed
for the cross-filter auto-removal notices.
Three json_script blocks embed the data the JS needs:
- projectTeamPairs: (project_id, team_id) pairs for cross-filter
- urlSelectedProjectIds / urlSelectedTeamIds: current URL state for
dirty diffing + reset
No visible behaviour change yet (no CSS, no JS). Page renders same
as before until Tasks 3-4 light it up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
06f2e71d87
commit
acbad1558e
@ -30,25 +30,152 @@
|
||||
</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 }}
|
||||
{# === FILTER PILLS (interactive — pill-as-dropdown) === #}
|
||||
{# Each pill is a clickable button that opens an inline popover with the #}
|
||||
{# relevant editor. The Apply button appears only when at least one pill #}
|
||||
{# has uncommitted changes. See the JS module lower in this file. #}
|
||||
<div class="filter-pill-strip d-flex flex-wrap gap-2 mb-4 d-print-none" id="filter-pill-strip">
|
||||
|
||||
{# --- Date pill --- #}
|
||||
<div class="filter-pill-wrap position-relative">
|
||||
<button type="button"
|
||||
class="filter-pill filter-pill--editable"
|
||||
id="filter-pill-date"
|
||||
data-filter="date"
|
||||
aria-expanded="false"
|
||||
aria-controls="popover-date">
|
||||
<i class="fas fa-calendar me-1"></i>
|
||||
<span class="filter-pill__label">{{ start_date|date:"d M Y" }} – {{ end_date|date:"d M Y" }}</span>
|
||||
<i class="fas fa-chevron-down ms-2 small filter-pill__chevron"></i>
|
||||
</button>
|
||||
<div class="filter-popover" id="popover-date" role="dialog" aria-label="Edit date range" hidden>
|
||||
<div class="filter-popover__body">
|
||||
<label class="form-label fw-semibold small">Date Selection</label>
|
||||
<div class="btn-group w-100 mb-3" role="group">
|
||||
<input type="radio" class="btn-check" name="popover_date_mode" id="popDateModeMonth" value="month" checked>
|
||||
<label class="btn btn-outline-secondary btn-sm" for="popDateModeMonth">
|
||||
<i class="fas fa-calendar-alt me-1"></i>Month(s)
|
||||
</label>
|
||||
<input type="radio" class="btn-check" name="popover_date_mode" id="popDateModeCustom" value="custom">
|
||||
<label class="btn btn-outline-secondary btn-sm" for="popDateModeCustom">
|
||||
<i class="fas fa-calendar-week me-1"></i>Custom Dates
|
||||
</label>
|
||||
</div>
|
||||
<div class="row g-2" id="popoverMonthFields">
|
||||
<div class="col-6">
|
||||
<label class="form-label small">From</label>
|
||||
<input type="month" id="popoverFromMonth" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">To</label>
|
||||
<input type="month" id="popoverToMonth" class="form-control form-control-sm">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 d-none" id="popoverCustomFields">
|
||||
<div class="col-6">
|
||||
<label class="form-label small">Start</label>
|
||||
<input type="date" id="popoverStartDate" class="form-control form-control-sm">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small">End</label>
|
||||
<input type="date" id="popoverEndDate" class="form-control form-control-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-popover__footer">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary popover-cancel">Cancel</button>
|
||||
<button type="button" class="btn btn-sm btn-accent popover-ok">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- Projects pill --- #}
|
||||
<div class="filter-pill-wrap position-relative">
|
||||
<button type="button"
|
||||
class="filter-pill filter-pill--editable"
|
||||
id="filter-pill-projects"
|
||||
data-filter="projects"
|
||||
aria-expanded="false"
|
||||
aria-controls="popover-projects">
|
||||
<i class="fas fa-folder me-1"></i>
|
||||
<span class="filter-pill__label">{{ project_name }}</span>
|
||||
<i class="fas fa-chevron-down ms-2 small filter-pill__chevron"></i>
|
||||
</button>
|
||||
{% if selected_project_ids %}
|
||||
<a href="?{{ query_string_without_project|default:query_string }}" class="filter-pill__x" aria-label="Clear project filter">×</a>
|
||||
<a href="?{{ query_string_without_project|default:query_string }}"
|
||||
class="filter-pill__x"
|
||||
aria-label="Clear project filter"
|
||||
title="Clear project filter">×</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="filter-pill">
|
||||
<i class="fas fa-users me-1"></i>{{ team_name }}
|
||||
<div class="filter-popover" id="popover-projects" role="dialog" aria-label="Edit projects" hidden>
|
||||
<div class="filter-popover__body">
|
||||
<label class="form-label fw-semibold small">Projects</label>
|
||||
<select id="popoverProjects" class="form-select report-multi" multiple data-placeholder="All projects (leave empty for all)">
|
||||
{% for p in projects %}
|
||||
<option value="{{ p.id }}"{% if p.id|stringformat:"s" in selected_project_ids %} selected{% endif %}>{{ p.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-popover__footer">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary popover-cancel">Cancel</button>
|
||||
<button type="button" class="btn btn-sm btn-accent popover-ok">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- Teams pill --- #}
|
||||
<div class="filter-pill-wrap position-relative">
|
||||
<button type="button"
|
||||
class="filter-pill filter-pill--editable"
|
||||
id="filter-pill-teams"
|
||||
data-filter="teams"
|
||||
aria-expanded="false"
|
||||
aria-controls="popover-teams">
|
||||
<i class="fas fa-users me-1"></i>
|
||||
<span class="filter-pill__label">{{ team_name }}</span>
|
||||
<i class="fas fa-chevron-down ms-2 small filter-pill__chevron"></i>
|
||||
</button>
|
||||
{% if selected_team_ids %}
|
||||
<a href="?{{ query_string_without_team|default:query_string }}" class="filter-pill__x" aria-label="Clear team filter">×</a>
|
||||
<a href="?{{ query_string_without_team|default:query_string }}"
|
||||
class="filter-pill__x"
|
||||
aria-label="Clear team filter"
|
||||
title="Clear team filter">×</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
<div class="filter-popover" id="popover-teams" role="dialog" aria-label="Edit teams" hidden>
|
||||
<div class="filter-popover__body">
|
||||
<label class="form-label fw-semibold small">Teams</label>
|
||||
<select id="popoverTeams" class="form-select report-multi" multiple data-placeholder="All teams (leave empty for all)">
|
||||
{% for t in teams %}
|
||||
<option value="{{ t.id }}"{% if t.id|stringformat:"s" in selected_team_ids %} selected{% endif %}>{{ t.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="filter-popover__footer">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary popover-cancel">Cancel</button>
|
||||
<button type="button" class="btn btn-sm btn-accent popover-ok">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- Apply / Cancel buttons (shown only when dirty) --- #}
|
||||
<div class="apply-filters-group ms-auto" id="apply-filters-group" hidden>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="cancel-filters-btn">Reset</button>
|
||||
<button type="button" class="btn btn-sm btn-accent ms-1" id="apply-filters-btn">
|
||||
<i class="fas fa-check me-1"></i>Apply
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# --- Toast container (for cross-filter auto-removal notices) --- #}
|
||||
<div id="filter-toast-container" class="filter-toast-container d-print-none" aria-live="polite"></div>
|
||||
|
||||
{# --- Cross-filter data for the JS module --- #}
|
||||
{{ project_team_pairs_json|json_script:"projectTeamPairs" }}
|
||||
|
||||
{# --- Expose current URL filter state for JS reset + dirty diffing --- #}
|
||||
{{ selected_project_ids|json_script:"urlSelectedProjectIds" }}
|
||||
{{ selected_team_ids|json_script:"urlSelectedTeamIds" }}
|
||||
|
||||
<!-- === PRINT HEADER === -->
|
||||
<div class="d-none d-print-block mb-4">
|
||||
<h2 class="text-center fw-bold mb-1">FoxFitt Construction — Payroll Report</h2>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user