Skip to content

Commit d672144

Browse files
committed
feat(org): embed search scope as operator in url
Search scope is now part of the q= param using operator syntax like ?q=description:core instead of separate scope= param in preparation for multi-scope search; currently left in single-scope mode
1 parent 44c6c4c commit d672144

File tree

1 file changed

+40
-11
lines changed

1 file changed

+40
-11
lines changed

app/pages/@[org].vue

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
<script setup lang="ts">
2-
import type { FilterChip, SortOption } from '#shared/types/preferences'
2+
import type { FilterChip, SearchScope, SortOption } from '#shared/types/preferences'
33
import { debounce } from 'perfect-debounce'
44
import { normalizeSearchParam } from '#shared/utils/url'
55
6+
// INFO: a custom search query builder for single scope search (multi scope q=foo:bar+baz:qux could later be introduced but needs appropriate multi-select UI refactor)
7+
function buildSearchQuery({
8+
text,
9+
scope,
10+
keywords,
11+
}: {
12+
text: string
13+
scope: SearchScope
14+
keywords: string[]
15+
}): string {
16+
const textWithScope = text ? (scope === 'all' ? text : `${scope}:${text}`) : ''
17+
const keywordPart = keywords.map(kw => `keyword:${kw}`).join(' ')
18+
return [textWithScope, keywordPart].filter(Boolean).join(' ')
19+
}
20+
621
definePageMeta({
722
name: 'org',
823
alias: ['/org/:org()'],
@@ -11,6 +26,10 @@ definePageMeta({
1126
const route = useRoute('org')
1227
const router = useRouter()
1328
29+
const parsedQuery = parseSearchOperators(normalizeSearchParam(route.query.q))
30+
const initialScope: SearchScope =
31+
(['name', 'description', 'keywords'] as const).find(k => parsedQuery[k]?.length) ?? 'all'
32+
1433
const orgName = computed(() => route.params.org)
1534
1635
const { isConnected } = useConnector()
@@ -52,7 +71,8 @@ const {
5271
} = useStructuredFilters({
5372
packages,
5473
initialFilters: {
55-
...parseSearchOperators(normalizeSearchParam(route.query.q)),
74+
...parsedQuery,
75+
searchScope: initialScope,
5676
},
5777
initialSort: (normalizeSearchParam(route.query.sort) as SortOption) ?? 'updated-desc',
5878
})
@@ -72,6 +92,13 @@ watch([filters, sortOption], () => {
7292
currentPage.value = 1
7393
})
7494
95+
watch(
96+
() => filters.value.searchScope,
97+
() => {
98+
filters.value.keywords = []
99+
},
100+
)
101+
75102
// Clamp current page when total pages decreases (e.g., after filtering)
76103
watch(totalPages, newTotal => {
77104
if (currentPage.value > newTotal && newTotal > 0) {
@@ -80,24 +107,26 @@ watch(totalPages, newTotal => {
80107
})
81108
82109
// Debounced URL update for filter/sort
83-
const updateUrl = debounce((updates: { filter?: string; sort?: string }) => {
110+
const updateUrl = debounce((updates: { q?: string; sort?: string }) => {
84111
router.replace({
85112
query: {
86113
...route.query,
87-
q: updates.filter || undefined,
114+
q: updates.q || undefined,
88115
sort: updates.sort && updates.sort !== 'updated-desc' ? updates.sort : undefined,
89116
},
90117
})
91118
}, 300)
92-
93119
// Update URL when filter/sort changes (debounced)
94120
watch(
95-
[() => filters.value.text, () => filters.value.keywords, () => sortOption.value] as const,
96-
([text, keywords, sort]) => {
97-
const filter = [text, ...keywords.map(keyword => `keyword:${keyword}`)]
98-
.filter(Boolean)
99-
.join(' ')
100-
updateUrl({ filter, sort })
121+
[
122+
() => filters.value.text,
123+
() => filters.value.keywords,
124+
() => filters.value.searchScope,
125+
() => sortOption.value,
126+
] as const,
127+
([text, keywords, scope, sort]) => {
128+
const q = buildSearchQuery({ text, scope, keywords })
129+
updateUrl({ q, sort })
101130
},
102131
)
103132

0 commit comments

Comments
 (0)