Skip to main content

max / makenotwork

7.8 KB · 155 lines History Blame Raw
1 {# The sidebar rides along on every results swap, out-of-band, so its counts
2 and drill-down always describe the results below. Without this the sidebar
3 is stale from the first filter click until a full page load, which is fatal
4 for faceted browsing: the numbers are what the user steers by.
5
6 htmx restores focus after a swap to an element with the same id, so every
7 control in the sidebar carries a stable one and keyboard position survives.
8 The typeahead input additionally uses hx-preserve, since its value is user
9 state the server does not render.
10
11 Guarded on `oob_sidebar`: the full page includes this same partial inside
12 #results-container, and rendering the sidebar there too would emit it twice
13 with duplicate ids. Only the standalone /discover/results response sets it. #}
14 {# #total-count sits in the page form, outside #results-container, so a plain
15 swap leaves it reading the previous filter's total. It said "13 items" beside
16 a list showing 3. #}
17 {% if oob_sidebar %}
18 <span class="table-meta" id="total-count" hx-swap-oob="true">{{ total_items }} {% if mode == "projects" %}projects{% else %}items{% endif %}</span>
19 {% endif %}
20 {% if oob_sidebar && mode == "items" %}
21 <div hx-swap-oob="outerHTML:#discover-sidebar">
22 {% include "partials/discover_sidebar.html" %}
23 </div>
24 {% endif %}
25
26 <div class="results-container results-list" id="results-container-inner">
27 <!-- List View -->
28 <div class="results-table" id="results-table">
29 {% if mode == "projects" %}
30 {% for project in projects %}
31 <a href="/p/{{ project.slug }}" class="table-row project-row">
32 <span class="row-info"><span class="row-name">{{ project.title }}</span><span class="row-creator">{{ project.creator }}</span></span>
33 <span class="row-category">{{ project.category_name.as_deref().unwrap_or(&project.project_type) }}</span>
34 <span class="row-items">{{ project.item_count }}</span>
35 <span class="row-date">{{ project.date }}</span>
36 </a>
37 {% endfor %}
38 {% if projects.is_empty() %}
39 <div class="empty-state">
40 <p>No projects found matching your filters.</p>
41 <p class="empty-state-hint">Try broadening your search or <a href="/discover">clearing all filters</a>.</p>
42 </div>
43 {% endif %}
44 {% else %}
45 {% for item in items %}
46 <div class="table-row table-row-item">
47 <a href="{% if item.is_free %}/i/{{ item.id }}{% else %}/purchase/{{ item.id }}{% endif %}" class="table-row-link">
48 <span class="row-type">{{ item.item_type }}</span>
49 <span class="row-info"><span class="row-name">{{ item.name }}</span><span class="row-creator">{{ item.project }} &middot; {{ item.creator }}</span></span>
50 <span class="row-category">{{ item.primary_tag }}</span>
51 <span class="row-price">{{ item.price }}</span>
52 <span class="row-date">{{ item.date }}</span>
53 <span class="discover-row-ai-tier">{{ item.ai_tier }}</span>
54 </a>
55 {% if is_authenticated %}
56 <button class="row-save collection-picker-anchor" data-collection-trigger data-item-id="{{ item.id }}"
57 data-action="onOpenCollectionPicker" data-stop title="Save to collection" aria-label="Save to collection">+</button>
58 {% endif %}
59 </div>
60 {% endfor %}
61 {% if items.is_empty() %}
62 <div class="empty-state">
63 <p>No items found matching your filters.</p>
64 <p class="empty-state-hint">Try broadening your search or <a href="/discover">clearing all filters</a>.</p>
65 </div>
66 {% endif %}
67 {% endif %}
68 </div>
69
70 <!-- Grid View -->
71 <div class="results-grid" id="results-grid">
72 {% if mode == "projects" %}
73 {% for project in projects %}
74 <a href="/p/{{ project.slug }}" class="grid-card">
75 <div class="grid-card-content">
76 <div class="grid-card-title">{{ project.title }}</div>
77 <div class="grid-card-meta">{{ project.creator }}</div>
78 <div class="grid-card-footer">
79 <span class="grid-card-category">{{ project.category_name.as_deref().unwrap_or(&project.project_type) }}</span>
80 <span class="grid-card-stat">{{ project.item_count }} items</span>
81 </div>
82 </div>
83 </a>
84 {% endfor %}
85 {% if projects.is_empty() %}
86 <div class="empty-state">
87 <p>No projects found matching your filters.</p>
88 <p class="empty-state-hint">Try broadening your search or <a href="/discover">clearing all filters</a>.</p>
89 </div>
90 {% endif %}
91 {% else %}
92 {% for item in items %}
93 <div class="grid-card discover-grid-card">
94 {% if is_authenticated %}
95 <button class="grid-card-save collection-picker-anchor" data-collection-trigger data-item-id="{{ item.id }}"
96 data-action="onOpenCollectionPicker" data-stop title="Save to collection" aria-label="Save to collection">+</button>
97 {% endif %}
98 <a href="{% if item.is_free %}/i/{{ item.id }}{% else %}/purchase/{{ item.id }}{% endif %}" class="discover-card-link">
99 <div class="grid-card-thumbnail">{{ item.item_type }}</div>
100 <div class="grid-card-content">
101 <div class="grid-card-title">{{ item.name }}</div>
102 <div class="grid-card-meta">{{ item.project }} &middot; {{ item.creator }}</div>
103 <div class="grid-card-footer">
104 <span class="grid-card-category">{{ item.primary_tag }}</span>
105 <span class="grid-card-price">{{ item.price }}</span>
106 <span class="discover-row-ai-tier">{{ item.ai_tier }}</span>
107 </div>
108 </div>
109 </a>
110 </div>
111 {% endfor %}
112 {% if items.is_empty() %}
113 <div class="empty-state">
114 <p>No items found matching your filters.</p>
115 <p class="empty-state-hint">Try broadening your search or <a href="/discover">clearing all filters</a>.</p>
116 </div>
117 {% endif %}
118 {% endif %}
119 </div>
120 </div>
121
122 <div class="table-footer">
123 <span class="page-info">Showing {{ showing_start }}-{{ showing_end }} of {{ total_items }}</span>
124 <div class="pagination">
125 {% if total_pages > 0 %}
126 <button {% if current_page == 1 %}disabled{% endif %}
127 hx-get="/discover/results"
128 hx-target="#results-container"
129 hx-include=".discover-filter"
130 hx-vals='{"page": {{ current_page - 1 }}}'
131 {% if current_page == 1 %}hx-disabled-elt="this"{% endif %}>Prev</button>
132 {% for p in pagination_range %}
133 <button {% if *p == current_page %}class="is-selected"{% endif %}
134 hx-get="/discover/results"
135 hx-target="#results-container"
136 hx-include=".discover-filter"
137 hx-vals='{"page": {{ p }}}'>{{ p }}</button>
138 {% endfor %}
139 {% if total_pages > 5 %}
140 <button disabled>...</button>
141 <button hx-get="/discover/results"
142 hx-target="#results-container"
143 hx-include=".discover-filter"
144 hx-vals='{"page": {{ total_pages }}}'>{{ total_pages }}</button>
145 {% endif %}
146 <button {% if current_page == total_pages || total_pages == 0 %}disabled{% endif %}
147 hx-get="/discover/results"
148 hx-target="#results-container"
149 hx-include=".discover-filter"
150 hx-vals='{"page": {{ current_page + 1 }}}'
151 {% if current_page == total_pages || total_pages == 0 %}hx-disabled-elt="this"{% endif %}>Next</button>
152 {% endif %}
153 </div>
154 </div>
155