Skip to content

Commit 486acf8

Browse files
committed
Update FilterBar.svelte
1 parent 446ac6f commit 486acf8

1 file changed

Lines changed: 165 additions & 67 deletions

File tree

src/lib/FilterBar.svelte

Lines changed: 165 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script>
22
export let allRows = []
33
export let filters = {}
4+
export let clusterLabel = ''
45
export let onReset
56
67
$: grandAlliances = ['', ...unique(allRows, 'Grand Alliance')]
@@ -13,30 +14,30 @@
1314
$: types = unique(allRows, 'Type')
1415
$: mechanics = ['', ...unique(allRows, 'Mechanic').filter(m => m && m !== 'no effect')]
1516
17+
const COSTS = ['[Double]', '[Triple]', '[Quad]']
18+
1619
function unique(rows, key) {
1720
return [...new Set(rows.map(r => r[key]).filter(Boolean))].sort()
1821
}
1922
20-
function toggle(type) {
23+
function toggleType(type) {
2124
const sel = new Set(filters.types || [])
2225
sel.has(type) ? sel.delete(type) : sel.add(type)
2326
filters = { ...filters, types: [...sel] }
2427
}
2528
26-
function allSelected() {
27-
return !filters.types || filters.types.length === 0 || filters.types.length === types.length
28-
}
29-
30-
function toggleAll() {
31-
filters = { ...filters, types: [] }
29+
function toggleCost(cost) {
30+
const sel = new Set(filters.costs || [])
31+
sel.has(cost) ? sel.delete(cost) : sel.add(cost)
32+
filters = { ...filters, costs: [...sel] }
3233
}
3334
</script>
3435

3536
<aside class="filter-bar">
3637
<div class="filter-group">
3738
<label class="filter-label">Search</label>
3839
<input
39-
class="search-input"
40+
class="text-input"
4041
type="search"
4142
placeholder="Name or description…"
4243
value={filters.search || ''}
@@ -80,44 +81,91 @@
8081
</select>
8182
</div>
8283

84+
<div class="filter-group">
85+
<label class="filter-label">Duplicates</label>
86+
<div class="check-list">
87+
<label class="check-item" class:checked={filters.hasSimilar} title="Show only entries that have documented similar abilities in other warbands">
88+
<input
89+
type="checkbox"
90+
checked={filters.hasSimilar || false}
91+
on:change={() => filters = { ...filters, hasSimilar: !filters.hasSimilar, gapsOnly: false }}
92+
/>
93+
<span>≈ Has similar</span>
94+
</label>
95+
<label class="check-item" class:checked={filters.gapsOnly} title="Show entries that share mechanic and cost with others but have no documented similarities yet — potential undocumented duplicates">
96+
<input
97+
type="checkbox"
98+
checked={filters.gapsOnly || false}
99+
on:change={() => filters = { ...filters, gapsOnly: !filters.gapsOnly, hasSimilar: false }}
100+
/>
101+
<span>? Gaps only</span>
102+
</label>
103+
</div>
104+
</div>
105+
106+
<div class="filter-group">
107+
<label class="filter-label">Cost</label>
108+
<div class="check-list">
109+
{#each COSTS as cost}
110+
<label class="check-item" class:checked={(filters.costs || []).includes(cost)}>
111+
<input
112+
type="checkbox"
113+
checked={(filters.costs || []).includes(cost)}
114+
on:change={() => toggleCost(cost)}
115+
/>
116+
<span>{cost}</span>
117+
</label>
118+
{/each}
119+
</div>
120+
</div>
121+
83122
<div class="filter-group">
84123
<label class="filter-label">Type</label>
85-
<div class="type-chips">
86-
<button
87-
class="chip {allSelected() ? 'active' : ''}"
88-
on:click={toggleAll}
89-
>All</button>
124+
<div class="check-list">
90125
{#each types as type}
91-
<button
92-
class="chip {(filters.types || []).includes(type) ? 'active' : ''}"
93-
on:click={() => toggle(type)}
94-
>{type}</button>
126+
<label class="check-item" class:checked={(filters.types || []).includes(type)}>
127+
<input
128+
type="checkbox"
129+
checked={(filters.types || []).includes(type)}
130+
on:change={() => toggleType(type)}
131+
/>
132+
<span>{type}</span>
133+
</label>
95134
{/each}
96135
</div>
97136
</div>
98137

99138
{#if filters.similarCluster}
100139
<div class="filter-group">
101140
<label class="filter-label">Showing cluster</label>
102-
<button class="cluster-tag" on:click={() => filters = {}}>
103-
{filters._clusterLabel} <span class="dismiss">×</span>
141+
<button class="cluster-btn" on:click={() => filters = {}}>
142+
{clusterLabel} <span class="dismiss">×</span>
104143
</button>
105144
</div>
106145
{/if}
107146

147+
<details class="help">
148+
<summary>How to use</summary>
149+
<div class="help-body">
150+
<p><strong>≈</strong> on a row means similar abilities in other warbands are documented. Expand the row to see them, or click <em>Show all similar</em> to filter to that cluster.</p>
151+
<p><strong>?</strong> means this entry shares mechanic and cost with others but has no documented similarities yet — a potential duplicate to investigate.</p>
152+
<p>Use <strong>⊕</strong> to pin up to two rows for side-by-side description comparison.</p>
153+
</div>
154+
</details>
155+
108156
<button class="reset-btn" on:click={onReset}>Reset filters</button>
109157
</aside>
110158

111159
<style>
112160
.filter-bar {
113161
display: flex;
114162
flex-direction: column;
115-
gap: 1.25rem;
116-
padding: 1.25rem;
163+
gap: 1.75rem;
164+
padding: 1.5rem;
117165
background: var(--surface);
118166
border-right: 1px solid var(--border);
119-
min-width: 220px;
120-
width: 220px;
167+
min-width: 240px;
168+
width: 240px;
121169
overflow-y: auto;
122170
}
123171
@@ -128,10 +176,10 @@
128176
letter-spacing: 0.08em;
129177
text-transform: uppercase;
130178
color: var(--text-muted);
131-
margin-bottom: 0.4rem;
179+
margin-bottom: 0.6rem;
132180
}
133181
134-
.search-input,
182+
.text-input,
135183
select {
136184
width: 100%;
137185
padding: 0.45rem 0.6rem;
@@ -140,84 +188,134 @@
140188
background: var(--bg);
141189
color: var(--text);
142190
font-size: 0.875rem;
143-
box-sizing: border-box;
144191
}
145192
146-
.search-input:focus,
193+
.text-input:focus,
147194
select:focus {
148195
outline: 2px solid var(--accent);
149196
outline-offset: -1px;
150197
}
151198
152-
.type-chips {
199+
.check-list {
153200
display: flex;
154-
flex-wrap: wrap;
155-
gap: 0.35rem;
201+
flex-direction: column;
202+
gap: 0.5rem;
156203
}
157204
158-
.chip {
159-
padding: 0.25rem 0.6rem;
160-
border-radius: 99px;
161-
border: 1px solid var(--border);
162-
background: var(--bg);
205+
.check-item {
206+
display: flex;
207+
align-items: center;
208+
gap: 0.55rem;
209+
padding: 0.1rem 0;
163210
color: var(--text-muted);
164-
font-size: 0.75rem;
211+
font-size: 0.875rem;
165212
cursor: pointer;
166-
transition: background 0.15s, color 0.15s, border-color 0.15s;
167-
white-space: nowrap;
213+
transition: color 0.15s;
214+
user-select: none;
168215
}
169216
170-
.chip.active {
171-
background: var(--accent);
172-
border-color: var(--accent);
173-
color: #fff;
217+
.check-item:hover {
218+
color: var(--text);
174219
}
175220
176-
.chip:hover:not(.active) {
177-
border-color: var(--accent);
178-
color: var(--accent);
221+
.check-item.checked {
222+
color: var(--text);
179223
}
180224
181-
.reset-btn {
182-
margin-top: auto;
183-
padding: 0.5rem;
184-
background: transparent;
185-
border: 1px solid var(--border);
186-
border-radius: 6px;
187-
color: var(--text-muted);
188-
font-size: 0.8rem;
225+
.check-item input[type="checkbox"] {
226+
accent-color: var(--accent);
227+
width: 14px;
228+
height: 14px;
229+
margin: 0;
189230
cursor: pointer;
190-
transition: border-color 0.15s, color 0.15s;
191-
}
192-
193-
.reset-btn:hover {
194-
border-color: var(--accent);
195-
color: var(--accent);
231+
flex-shrink: 0;
196232
}
197233
198-
.cluster-tag {
234+
.cluster-btn {
199235
display: flex;
200236
align-items: center;
201237
justify-content: space-between;
202238
width: 100%;
203239
padding: 0.4rem 0.6rem;
204-
background: var(--accent);
205-
border: none;
240+
background: var(--bg);
241+
border: 1px solid var(--accent);
206242
border-radius: 6px;
207-
color: #fff;
208-
font-size: 0.8rem;
243+
color: var(--accent-hi);
244+
font-size: 0.875rem;
209245
cursor: pointer;
210-
text-align: left;
211246
gap: 0.5rem;
247+
transition: background 0.15s;
212248
}
213249
214-
.cluster-tag:hover {
215-
opacity: 0.85;
250+
.cluster-btn:hover {
251+
background: var(--surface-2);
216252
}
217253
218254
.dismiss {
219255
font-size: 1rem;
220256
line-height: 1;
221257
opacity: 0.8;
222258
}
259+
260+
.help {
261+
margin-top: auto;
262+
border: 1px solid var(--border);
263+
border-radius: 6px;
264+
padding: 0 0.6rem;
265+
}
266+
267+
.help summary {
268+
padding: 0.45rem 0;
269+
font-size: 0.75rem;
270+
font-weight: 700;
271+
letter-spacing: 0.06em;
272+
text-transform: uppercase;
273+
color: var(--text-muted);
274+
cursor: pointer;
275+
user-select: none;
276+
list-style: none;
277+
}
278+
279+
.help summary::before {
280+
content: '';
281+
font-size: 0.65rem;
282+
}
283+
284+
.help[open] summary::before {
285+
content: '';
286+
}
287+
288+
.help-body {
289+
padding: 0 0 0.6rem;
290+
display: flex;
291+
flex-direction: column;
292+
gap: 0.5rem;
293+
}
294+
295+
.help-body p {
296+
margin: 0;
297+
font-size: 0.82rem;
298+
line-height: 1.5;
299+
color: var(--text-muted);
300+
}
301+
302+
.help-body strong {
303+
color: var(--accent-hi);
304+
}
305+
306+
.reset-btn {
307+
padding: 0.5rem 0.6rem;
308+
background: transparent;
309+
border: 1px solid var(--border);
310+
border-radius: 6px;
311+
color: var(--text-muted);
312+
font-size: 0.875rem;
313+
cursor: pointer;
314+
transition: border-color 0.15s, color 0.15s;
315+
}
316+
317+
.reset-btn:hover {
318+
border-color: var(--accent);
319+
color: var(--text);
320+
}
223321
</style>

0 commit comments

Comments
 (0)