Skip to content

Commit fa3b685

Browse files
Merge pull request #56 from MaddyGuthridge/maddy-item-filter
Re-add filter to item page
2 parents bd723d6 + fd7f220 commit fa3b685

File tree

6 files changed

+240
-180
lines changed

6 files changed

+240
-180
lines changed

src/components/chip/ItemChipList.svelte

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@
103103
104104
// Update filter status
105105
function updateFilterStatus(outerIdx: number, innerIdx: number) {
106-
const newItems = items;
106+
// Need to snapshot the value since it's a proxy
107+
// https://github.com/sveltejs/svelte/issues/13562
108+
const newItems = structuredClone($state.snapshot(items));
107109
newItems[outerIdx][innerIdx].selected = !items[outerIdx][innerIdx].selected;
108110
onfilter?.(newItems);
109111
}
@@ -135,6 +137,7 @@
135137
<style>
136138
.chip-list {
137139
margin: 0 5px;
140+
padding-bottom: 7px;
138141
display: flex;
139142
gap: 5px;
140143
align-items: center;

src/routes/[...item]/+page.svelte

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@
33
import Background from '$components/Background.svelte';
44
import { Button } from '$components/base';
55
import { ItemCardGrid } from '$components/card';
6+
import ItemChipList from '$components/chip/ItemChipList.svelte';
67
import Favicon from '$components/Favicon.svelte';
78
import EditableMarkdown from '$components/markdown';
89
import { NewItemModal } from '$components/modals';
910
import api from '$endpoints';
1011
import consts from '$lib/consts';
1112
import DelayedUpdater from '$lib/delayedUpdate';
13+
import {
14+
applyFiltersToItemChildren,
15+
createItemFilter,
16+
} from '$lib/itemFilter';
1217
import itemId from '$lib/itemId';
1318
import { generateKeywords } from '$lib/seo';
1419
import type { ItemInfo } from '$lib/server/data/item';
@@ -30,18 +35,37 @@
3035
3136
let newItemModalShown = $state(false);
3237
38+
let infoUpdater = new DelayedUpdater(async (info: ItemInfo) => {
39+
await api().item(data.itemId).info.put(info);
40+
}, consts.EDIT_COMMIT_HESITATION);
41+
3342
let thisItem = $state(data.item);
43+
44+
let filterItems = $state(createItemFilter(data.portfolio, data.itemId));
45+
46+
let displayedItems = $derived.by(() => {
47+
const items = thisItem.info.children.map((id) =>
48+
itemId.child(data.itemId, id),
49+
);
50+
if (editing) {
51+
return items;
52+
} else {
53+
return applyFiltersToItemChildren(
54+
data.portfolio,
55+
data.itemId,
56+
filterItems,
57+
);
58+
}
59+
});
3460
// Janky workaround for allowing PageData to be bindable.
3561
// Based on https://www.reddit.com/r/sveltejs/comments/1gx65ho/comment/lykrc6c/
3662
$effect.pre(() => {
3763
thisItem = data.item;
3864
// When item data changes, also disable editing
3965
editing = false;
66+
// Reset the filter items
67+
filterItems = createItemFilter(data.portfolio, data.itemId);
4068
});
41-
42-
let infoUpdater = new DelayedUpdater(async (info: ItemInfo) => {
43-
await api().item(data.itemId).info.put(info);
44-
}, consts.EDIT_COMMIT_HESITATION);
4569
</script>
4670

4771
<svelte:head>
@@ -150,12 +174,19 @@
150174
<div id="children">
151175
{#if editing}
152176
<h2>Children</h2>
177+
{:else}
178+
<!-- Filters -->
179+
<ItemChipList
180+
portfolio={data.portfolio}
181+
items={filterItems}
182+
onfilter={(newFilter) => {
183+
filterItems = newFilter;
184+
}}
185+
/>
153186
{/if}
154187
<ItemCardGrid
155188
portfolio={data.portfolio}
156-
itemIds={thisItem.info.children.map((id) =>
157-
itemId.child(data.itemId, id),
158-
)}
189+
itemIds={displayedItems}
159190
{editing}
160191
dndId={`${data.itemId}:children`}
161192
onReorder={(items) => {

src/routes/[...item]/sections/Package.svelte

Lines changed: 71 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -115,78 +115,83 @@
115115
</div>
116116
{/snippet}
117117

118-
{#if !editing}
119-
{@render display(true)}
120-
{:else}
121-
<div class="edit-outer">
122-
<div class="edit-grid">
123-
<label for="repo-label-text">Label text</label>
124-
<TextInput
125-
id="repo-label-text"
126-
bind:value={section.label}
127-
oninput={commitChange}
128-
placeholder={callToAction}
129-
/>
130-
<label for="repo-provider">Repo provider</label>
131-
<Select
132-
id="repo-provider"
133-
bind:value={() => section.info.provider,
134-
(newProvider) => changePackageProvider(newProvider)}
135-
>
136-
<option value="custom">- Custom -</option>
137-
{#each Object.entries(packageProviders) as [provider, info]}
138-
<option value={provider}>{info.name}</option>
139-
{/each}
140-
</Select>
141-
{#if section.info.provider === 'custom'}
142-
<label for="provider-name">Provider name</label>
143-
<TextInput
144-
id="provider-name"
145-
bind:value={section.info.providerName}
146-
oninput={commitChange}
147-
placeholder="Provider name"
148-
required
149-
/>
150-
<label for="install-command">Installation command</label>
151-
<TextInput
152-
id="install-command"
153-
bind:value={section.info.command}
154-
oninput={commitChange}
155-
placeholder="Installation command"
156-
required
157-
/>
158-
<label for="package-url">Package URL</label>
159-
<TextInput
160-
id="package-url"
161-
bind:value={section.info.url}
162-
oninput={commitChange}
163-
placeholder="Package URL"
164-
required
165-
/>
166-
<label for="package-icon">Icon</label>
118+
<div class="section-main">
119+
{#if !editing}
120+
{@render display(true)}
121+
{:else}
122+
<div class="edit-outer">
123+
<div class="edit-grid">
124+
<label for="repo-label-text">Label text</label>
167125
<TextInput
168-
id="package-icon"
169-
bind:value={section.info.command}
126+
id="repo-label-text"
127+
bind:value={section.label}
170128
oninput={commitChange}
171-
placeholder="Icon"
129+
placeholder={callToAction}
172130
/>
173-
{:else}
174-
<label for="package-id">Package ID</label>
175-
<TextInput
176-
id="package-id"
177-
bind:value={section.info.id}
178-
oninput={commitChange}
179-
placeholder="Package ID"
180-
required
181-
/>
182-
{/if}
131+
<label for="repo-provider">Repo provider</label>
132+
<Select
133+
id="repo-provider"
134+
bind:value={() => section.info.provider,
135+
(newProvider) => changePackageProvider(newProvider)}
136+
>
137+
<option value="custom">- Custom -</option>
138+
{#each Object.entries(packageProviders) as [provider, info]}
139+
<option value={provider}>{info.name}</option>
140+
{/each}
141+
</Select>
142+
{#if section.info.provider === 'custom'}
143+
<label for="provider-name">Provider name</label>
144+
<TextInput
145+
id="provider-name"
146+
bind:value={section.info.providerName}
147+
oninput={commitChange}
148+
placeholder="Provider name"
149+
required
150+
/>
151+
<label for="install-command">Installation command</label>
152+
<TextInput
153+
id="install-command"
154+
bind:value={section.info.command}
155+
oninput={commitChange}
156+
placeholder="Installation command"
157+
required
158+
/>
159+
<label for="package-url">Package URL</label>
160+
<TextInput
161+
id="package-url"
162+
bind:value={section.info.url}
163+
oninput={commitChange}
164+
placeholder="Package URL"
165+
required
166+
/>
167+
<label for="package-icon">Icon</label>
168+
<TextInput
169+
id="package-icon"
170+
bind:value={section.info.command}
171+
oninput={commitChange}
172+
placeholder="Icon"
173+
/>
174+
{:else}
175+
<label for="package-id">Package ID</label>
176+
<TextInput
177+
id="package-id"
178+
bind:value={section.info.id}
179+
oninput={commitChange}
180+
placeholder="Package ID"
181+
required
182+
/>
183+
{/if}
184+
</div>
185+
<Separator />
186+
{@render display(false)}
183187
</div>
184-
<Separator />
185-
{@render display(false)}
186-
</div>
187-
{/if}
188+
{/if}
189+
</div>
188190

189191
<style>
192+
.section-main {
193+
margin: 10px 0;
194+
}
190195
.display-outer {
191196
display: flex;
192197
gap: 10px;

0 commit comments

Comments
 (0)