Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 40 additions & 11 deletions app/pages/@[org].vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
<script setup lang="ts">
import type { FilterChip, SortOption } from '#shared/types/preferences'
import type { FilterChip, SearchScope, SortOption } from '#shared/types/preferences'
import { debounce } from 'perfect-debounce'
import { normalizeSearchParam } from '#shared/utils/url'

// 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)
function buildSearchQuery({
text,
scope,
keywords,
}: {
text: string
scope: SearchScope
keywords: string[]
}): string {
const textWithScope = text ? (scope === 'all' ? text : `${scope}:${text}`) : ''
const keywordPart = keywords.map(kw => `keyword:${kw}`).join(' ')
return [textWithScope, keywordPart].filter(Boolean).join(' ')
}

definePageMeta({
name: 'org',
alias: ['/org/:org()'],
Expand All @@ -11,6 +26,10 @@ definePageMeta({
const route = useRoute('org')
const router = useRouter()

const parsedQuery = parseSearchOperators(normalizeSearchParam(route.query.q))
const initialScope: SearchScope =
(['name', 'description', 'keywords'] as const).find(k => parsedQuery[k]?.length) ?? 'all'

const orgName = computed(() => route.params.org)

const { isConnected } = useConnector()
Expand Down Expand Up @@ -52,7 +71,8 @@ const {
} = useStructuredFilters({
packages,
initialFilters: {
...parseSearchOperators(normalizeSearchParam(route.query.q)),
...parsedQuery,
searchScope: initialScope,
},
initialSort: (normalizeSearchParam(route.query.sort) as SortOption) ?? 'updated-desc',
})
Expand All @@ -72,6 +92,13 @@ watch([filters, sortOption], () => {
currentPage.value = 1
})

watch(
() => filters.value.searchScope,
() => {
filters.value.keywords = []
},
)

// Clamp current page when total pages decreases (e.g., after filtering)
watch(totalPages, newTotal => {
if (currentPage.value > newTotal && newTotal > 0) {
Expand All @@ -80,24 +107,26 @@ watch(totalPages, newTotal => {
})

// Debounced URL update for filter/sort
const updateUrl = debounce((updates: { filter?: string; sort?: string }) => {
const updateUrl = debounce((updates: { q?: string; sort?: string }) => {
router.replace({
query: {
...route.query,
q: updates.filter || undefined,
q: updates.q || undefined,
sort: updates.sort && updates.sort !== 'updated-desc' ? updates.sort : undefined,
},
})
}, 300)

// Update URL when filter/sort changes (debounced)
watch(
[() => filters.value.text, () => filters.value.keywords, () => sortOption.value] as const,
([text, keywords, sort]) => {
const filter = [text, ...keywords.map(keyword => `keyword:${keyword}`)]
.filter(Boolean)
.join(' ')
updateUrl({ filter, sort })
[
() => filters.value.text,
() => filters.value.keywords,
() => filters.value.searchScope,
() => sortOption.value,
] as const,
([text, keywords, scope, sort]) => {
const q = buildSearchQuery({ text, scope, keywords })
updateUrl({ q, sort })
},
)

Expand Down
Loading