feat: improve mobile catalog filters
Quality / test (push) Canceled after 0s

This commit is contained in:
2026-09-10 03:05:49 -04:00
parent 81705af6e3
commit ffb86ce21a
2 changed files with 94 additions and 2 deletions
+93 -2
View File
@@ -1,5 +1,5 @@
<script setup> <script setup>
import { onMounted, ref, watch } from "vue"; import { computed, onMounted, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useCatalogSearch } from "@/composables/useCatalogSearch.js"; import { useCatalogSearch } from "@/composables/useCatalogSearch.js";
@@ -16,6 +16,7 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
const categories = ref([]); const categories = ref([]);
const conditions = ref([]); const conditions = ref([]);
const filtersOpen = ref(false);
const { const {
query, query,
category, category,
@@ -52,6 +53,33 @@ const {
initialPage: Number.parseInt(route.query.page, 10) || 1, initialPage: Number.parseInt(route.query.page, 10) || 1,
}); });
const activeFilterCount = computed(() => [
category.value,
conditionId.value,
setName.value,
eventName.value,
tag.value,
status.value,
newlyAdded.value,
typeof minPriceMinor.value === "number",
typeof maxPriceMinor.value === "number",
sort.value !== "recent",
].filter(Boolean).length);
function resetFilters() {
category.value = "";
conditionId.value = "";
setName.value = "";
eventName.value = "";
tag.value = "";
status.value = "";
newlyAdded.value = false;
minPriceMinor.value = undefined;
maxPriceMinor.value = undefined;
sort.value = "recent";
page.value = 1;
}
onMounted(async () => { onMounted(async () => {
await Promise.all([ await Promise.all([
load(), load(),
@@ -120,7 +148,29 @@ watch(
placeholder="Try Charizard, 151, plush..." placeholder="Try Charizard, 151, plush..."
/> />
</label> </label>
<div class="catalog-filters"> <div class="catalog-filter-toolbar">
<button
class="catalog-filter-toggle"
type="button"
:aria-expanded="filtersOpen"
aria-controls="catalog-filter-panel"
@click="filtersOpen = !filtersOpen"
>
Filters<span v-if="activeFilterCount"> ({{ activeFilterCount }})</span>
</button>
<button
v-if="activeFilterCount"
class="catalog-filter-reset"
type="button"
@click="resetFilters"
>
Reset filters
</button>
</div>
<div
id="catalog-filter-panel"
:class="['catalog-filters', { 'catalog-filters--open': filtersOpen }]"
>
<CatalogTextFilter v-model="setName" label="Set" placeholder="SV151" /> <CatalogTextFilter v-model="setName" label="Set" placeholder="SV151" />
<CatalogTextFilter v-model="eventName" label="Event" placeholder="Worlds" /> <CatalogTextFilter v-model="eventName" label="Event" placeholder="Worlds" />
<CatalogTextFilter v-model="tag" label="Tag" placeholder="binder" /> <CatalogTextFilter v-model="tag" label="Tag" placeholder="binder" />
@@ -212,3 +262,44 @@ watch(
</section> </section>
</main> </main>
</template> </template>
<style scoped lang="scss">
.catalog-filter-toolbar {
display: flex;
align-items: center;
gap: var(--space-3);
margin-top: var(--space-4);
}
.catalog-filter-toggle,
.catalog-filter-reset {
min-height: 44px;
border: var(--border-thin) solid var(--color-border-strong);
border-radius: var(--radius-md);
padding: var(--space-2) var(--space-3);
background: var(--color-surface);
color: var(--color-text);
cursor: pointer;
}
.catalog-filter-reset {
border-color: transparent;
color: var(--color-interactive-text);
}
@media (max-width: 767px) {
.catalog-filters {
display: none;
}
.catalog-filters.catalog-filters--open {
display: grid;
}
}
@media (min-width: 768px) {
.catalog-filter-toolbar {
display: none;
}
}
</style>
+1
View File
@@ -167,6 +167,7 @@ Remaining roadmap areas are approved external provider credentials/adapters, bro
- Public catalog filtering now supports URL-synchronized set, event, and tag text filters through a reusable atomic text-filter control and the shared search API. - Public catalog filtering now supports URL-synchronized set, event, and tag text filters through a reusable atomic text-filter control and the shared search API.
- Public catalog filtering now supports explicit Available, Pending, Sold, and All status modes plus a 30-day Newly added toggle through the shared search API and atomic controls. - Public catalog filtering now supports explicit Available, Pending, Sold, and All status modes plus a 30-day Newly added toggle through the shared search API and atomic controls.
- Public catalog sorting now supports latest manual/calculated market value low-to-high and high-to-low, with null values placed last. - Public catalog sorting now supports latest manual/calculated market value low-to-high and high-to-low, with null values placed last.
- Public catalog filters now collapse behind an accessible mobile disclosure, show an active-filter count, and provide a reset action while preserving URL synchronization.
## Local Commands ## Local Commands