Skip to content

Commit c298e8b

Browse files
committed
feat: add sorting functionality to plugins page, by name
1 parent d7f8465 commit c298e8b

File tree

1 file changed

+72
-7
lines changed

1 file changed

+72
-7
lines changed

src/pages/plugins/index.astro

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ const hasFeaturedPlugins = featured.length > 0;
4545
{TAGS.map(v => <option value={v}>{v}</option>)}
4646
</select>
4747
</LabelValue>
48+
49+
<LabelValue label="Sort by">
50+
<select aria-label="Sort by" id="sort">
51+
<option value="name-asc" selected>Name (A-Z)</option>
52+
<option value="name-desc">Name (Z-A)</option>
53+
</select>
54+
</LabelValue>
4855
</div>
4956
<div id="store" class="plugin-grid">
5057
{plugins.map(v => <Plugin plugin={v}/>)}
@@ -60,7 +67,7 @@ const hasFeaturedPlugins = featured.length > 0;
6067

6168
.controls {
6269
display: grid;
63-
grid-template-columns: repeat(2, 1fr);
70+
grid-template-columns: repeat(3, 1fr);
6471
gap: 24px;
6572
margin-top: 24px;
6673
position: sticky;
@@ -101,36 +108,59 @@ import {TAGS} from "@/constants";
101108

102109
const searchInput = document.querySelector("#search") as HTMLInputElement;
103110
const tagsSelect = document.querySelector("#tags") as HTMLSelectElement;
111+
const sortSelect = document.querySelector("#sort") as HTMLSelectElement;
104112
const notFound = document.querySelector("#not-found") as HTMLElement;
113+
const store = document.querySelector("#store") as HTMLElement;
105114

106115
const plugins = document.querySelectorAll("#store > .plugin") as NodeListOf<HTMLElement>;
116+
const defaultSortValue = "name-asc";
117+
const allowedSortValues = ["name-asc", "name-desc"];
107118

108-
searchInput.addEventListener("input", filterPlugins);
109-
tagsSelect.addEventListener("change", filterPlugins);
119+
searchInput.addEventListener("input", onFilterChange);
120+
tagsSelect.addEventListener("change", onFilterChange);
121+
sortSelect.addEventListener("change", onSortChange);
110122

111123
const url = new URL(window.location.href);
112124

113125
const searchParam = url.searchParams.get("search") ?? "";
114126
let tagsParam: any = url.searchParams.get("tags") ?? "";
127+
let sortParam = url.searchParams.get("sort") ?? defaultSortValue;
115128

116129
if (!TAGS.includes(tagsParam)) {
117130
tagsParam = "";
118131
}
119132

133+
if (!allowedSortValues.includes(sortParam)) {
134+
sortParam = defaultSortValue;
135+
}
136+
120137
searchInput.value = searchParam;
121138
tagsSelect.value = tagsParam;
139+
sortSelect.value = sortParam;
122140

123141
filterPlugins();
142+
applySort();
143+
updateUrlParams();
124144

125-
function filterPlugins(): void {
126-
let foundAtLeastOnePlugin = false;
145+
function onFilterChange(): void {
146+
filterPlugins();
147+
applySort();
148+
updateUrlParams();
149+
}
127150

128-
const searchValue = searchInput.value.toLowerCase();
151+
function onSortChange(): void {
152+
applySort();
153+
updateUrlParams();
154+
}
155+
156+
function updateUrlParams(): void {
157+
const searchValue = searchInput.value;
129158
const tagsValue = tagsSelect.value;
159+
const sortValue = sortSelect.value;
130160

131161
const url = new URL(window.location.href);
132162
if (searchValue.length > 0) {
133-
url.searchParams.set("search", searchInput.value);
163+
url.searchParams.set("search", searchValue);
134164
} else {
135165
url.searchParams.delete("search");
136166
}
@@ -141,7 +171,20 @@ function filterPlugins(): void {
141171
url.searchParams.delete("tags");
142172
}
143173

174+
if (allowedSortValues.includes(sortValue)) {
175+
url.searchParams.set("sort", sortValue);
176+
} else {
177+
url.searchParams.delete("sort");
178+
}
179+
144180
history.replaceState(null, "", url);
181+
}
182+
183+
function filterPlugins(): void {
184+
let foundAtLeastOnePlugin = false;
185+
186+
const searchValue = searchInput.value.toLowerCase();
187+
const tagsValue = tagsSelect.value;
145188

146189
for (const plugin of plugins) {
147190
const title = plugin.querySelector(".name")!.textContent!.toLowerCase();
@@ -168,4 +211,26 @@ function filterPlugins(): void {
168211
notFound.style.display = "block";
169212
}
170213
}
214+
215+
function applySort(): void {
216+
const sortValue = sortSelect.value;
217+
218+
if (!allowedSortValues.includes(sortValue)) {
219+
return;
220+
}
221+
222+
const sortedPlugins = Array.from(plugins).sort((a, b) => {
223+
const titleA = a.querySelector(".name")!.textContent!.trim().toLowerCase();
224+
const titleB = b.querySelector(".name")!.textContent!.trim().toLowerCase();
225+
226+
if (sortValue === "name-desc") {
227+
return titleB.localeCompare(titleA);
228+
}
229+
230+
return titleA.localeCompare(titleB);
231+
});
232+
233+
// Re-appending existing plugin nodes moves them into sorted order (no duplicates)
234+
store.append(...sortedPlugins);
235+
}
171236
</script>

0 commit comments

Comments
 (0)