Skip to content

Commit 8f8088d

Browse files
authored
docs(awesome): Use query-string url for search filters (#2843)
1 parent 7fa2012 commit 8f8088d

File tree

4 files changed

+2749
-965
lines changed

4 files changed

+2749
-965
lines changed

docs/ecosystem/Packages.vue

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<script setup lang="ts">
22
import PackageCard from './PackageCard.vue'
3-
import { PackageOutput, PackagesInput } from './types'
3+
import { PackageOutput } from './types'
44
import { ref, computed, onMounted } from 'vue'
55
import { uniqBy } from './helpers'
6+
import { useQuery } from './useQuery'
67
78
const packageSource = 'https://ecosystem.feathershq.workers.dev/'
89
@@ -28,10 +29,6 @@ async function getPackageStats(): Promise<PackageOutput[]> {
2829
return uniq
2930
}
3031
31-
onMounted(async () => {
32-
fetchedPackages.value = await getPackageStats()
33-
})
34-
3532
const categories: CategoryOption[] = [
3633
{ label: 'Authentication', value: ['authentication'] },
3734
{ label: 'Authorization', value: ['authorization'] },
@@ -57,8 +54,8 @@ const categories: CategoryOption[] = [
5754
]
5855
5956
const keyToSortBy = ref<'stars' | 'downloads' | 'lastPublish'>('lastPublish')
60-
6157
const showCore = ref(true)
58+
6259
function filterCore(pkg: PackageOutput) {
6360
return pkg.ownerName === 'feathersjs'
6461
}
@@ -68,6 +65,7 @@ const coreCount = computed(() => {
6865
6966
const packagesAreOldIfOlderThan = 1000 * 60 * 60 * 24 * 365 * 2.9 // 3 years
7067
const showOld = ref(false)
68+
7169
function filterOld(pkg: PackageOutput) {
7270
return pkg.lastPublish.getTime() < Date.now() - packagesAreOldIfOlderThan
7371
}
@@ -86,7 +84,15 @@ const countByCategory = computed(() => {
8684
return counts
8785
})
8886
89-
const categoriesToShow = ref<CategoryOption[]>([])
87+
const categoriesToFilter = ref<string[]>([])
88+
89+
const categoriesToShow = computed(() => {
90+
const cats = categories.filter((category) => {
91+
return categoriesToFilter.value.includes(category.label)
92+
})
93+
return cats
94+
})
95+
9096
type Category = string[]
9197
type CategoryOption = {
9298
label: string
@@ -143,6 +149,17 @@ const packagesToShow = computed(() => {
143149
})
144150
return result
145151
})
152+
153+
onMounted(async () => {
154+
fetchedPackages.value = await getPackageStats()
155+
156+
// sync values with URL
157+
useQuery(keyToSortBy, 'sort', 'string')
158+
useQuery(showCore, 'core', 'boolean')
159+
useQuery(showOld, 'old', 'boolean')
160+
useQuery(search, 's', 'string')
161+
useQuery(categoriesToFilter, 'cat', 'string[]')
162+
})
146163
</script>
147164

148165
<template>
@@ -158,7 +175,7 @@ const packagesToShow = computed(() => {
158175
>
159176
</div>
160177
<el-select
161-
v-model="categoriesToShow"
178+
v-model="categoriesToFilter"
162179
multiple
163180
collapse-tags
164181
collapse-tags-tooltip
@@ -171,7 +188,7 @@ const packagesToShow = computed(() => {
171188
v-for="option in categories"
172189
:key="option.label"
173190
:label="option.label"
174-
:value="option"
191+
:value="option.label"
175192
:title="option.value.join(', ')"
176193
>
177194
{{ option.label }} ({{ countByCategory[option.label] }})

docs/ecosystem/useQuery.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Ref, watch } from 'vue'
2+
import queryString from 'query-string'
3+
4+
type MaybeArray<T> = T | T[]
5+
6+
type FieldType = MaybeArray<'string' | 'number' | 'boolean'>
7+
8+
export const useQuery = <T extends FieldType>(reference: Ref<T>, field: string) => {
9+
function getQuery() {
10+
return queryString.parse(window.location.search, {
11+
parseNumbers: true,
12+
parseBooleans: true,
13+
arrayFormat: 'none'
14+
})
15+
}
16+
17+
function getFromUrl() {
18+
const q = getQuery()
19+
const result = q[field]
20+
// explicitly return false instead of undefined
21+
if (typeof reference.value === 'boolean' && !result) {
22+
return false
23+
}
24+
if (result == null) return
25+
if (Array.isArray(reference.value)) {
26+
return Array.isArray(result) ? result : [result]
27+
}
28+
return result
29+
}
30+
31+
const fromUrl = getFromUrl()
32+
33+
if (fromUrl != null) {
34+
// @ts-expect-error arbitrary type
35+
reference.value = fromUrl
36+
}
37+
38+
function setToUrl(val: any) {
39+
const q = getQuery()
40+
if (val && (!Array.isArray(reference.value) || (Array.isArray(val) && val.length > 0))) {
41+
q[field] = val
42+
} else {
43+
delete q[field]
44+
}
45+
const prepend = Object.keys(q).length ? '?' : ''
46+
const newQuery = `${prepend}${queryString.stringify(q, { skipNull: true })}`
47+
window.history.replaceState(null, '', newQuery)
48+
}
49+
50+
watch(
51+
reference,
52+
(val) => {
53+
setToUrl(val)
54+
},
55+
{ immediate: true }
56+
)
57+
}

0 commit comments

Comments
 (0)