Skip to content

Commit 58b1b43

Browse files
committed
fix: small type fixes + tweaks
1 parent a24adba commit 58b1b43

9 files changed

Lines changed: 99 additions & 44 deletions

File tree

app/components/ColumnPicker.vue

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ const emit = defineEmits<{
1111
}>()
1212
1313
const isOpen = ref(false)
14-
const buttonRef = ref<HTMLButtonElement>()
14+
const buttonRef = useTemplateRef('buttonRef')
15+
const menuRef = useTemplateRef('menuRef')
1516
const menuId = useId()
1617
17-
// Close on click outside
18+
// Close on click outside (check both button and menu)
1819
function handleClickOutside(event: MouseEvent) {
19-
if (buttonRef.value && !buttonRef.value.contains(event.target as Node)) {
20+
const target = event.target as Node
21+
const isOutsideButton = buttonRef.value && !buttonRef.value.contains(target)
22+
const isOutsideMenu = !menuRef.value || !menuRef.value.contains(target)
23+
if (isOutsideButton && isOutsideMenu) {
2024
isOpen.value = false
2125
}
2226
}
@@ -89,11 +93,11 @@ function handleReset() {
8993
<Transition name="dropdown">
9094
<div
9195
v-if="isOpen"
96+
ref="menuRef"
9297
:id="menuId"
9398
class="absolute right-0 mt-2 w-56 bg-bg-subtle border border-border rounded-lg shadow-lg z-20"
9499
role="group"
95100
:aria-label="$t('filters.columns.show')"
96-
@click.stop
97101
>
98102
<div class="py-1">
99103
<div

app/components/FilterPanel.vue

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,41 +56,62 @@ const hasMoreKeywords = computed(() => {
5656
})
5757
5858
// i18n mappings for filter options
59-
const scopeLabelKey: Record<string, string> = {
59+
const scopeLabelKeys = {
6060
name: 'filters.scope_name',
6161
description: 'filters.scope_description',
6262
keywords: 'filters.scope_keywords',
6363
all: 'filters.scope_all',
64-
}
64+
} as const
6565
66-
const scopeDescriptionKey: Record<string, string> = {
66+
const scopeDescriptionKeys = {
6767
name: 'filters.scope_name_description',
6868
description: 'filters.scope_description_description',
6969
keywords: 'filters.scope_keywords_description',
7070
all: 'filters.scope_all_description',
71-
}
71+
} as const
7272
73-
const downloadRangeLabelKey: Record<string, string> = {
73+
const downloadRangeLabelKeys = {
7474
'any': 'filters.download_range.any',
7575
'lt100': 'filters.download_range.lt100',
7676
'100-1k': 'filters.download_range.100_1k',
7777
'1k-10k': 'filters.download_range.1k_10k',
7878
'10k-100k': 'filters.download_range.10k_100k',
7979
'gt100k': 'filters.download_range.gt100k',
80-
}
80+
} as const
8181
82-
const updatedWithinLabelKey: Record<string, string> = {
82+
const updatedWithinLabelKeys = {
8383
any: 'filters.updated.any',
8484
week: 'filters.updated.week',
8585
month: 'filters.updated.month',
8686
quarter: 'filters.updated.quarter',
8787
year: 'filters.updated.year',
88-
}
88+
} as const
8989
90-
const securityLabelKey: Record<string, string> = {
90+
const securityLabelKeys = {
9191
all: 'filters.security_options.all',
9292
secure: 'filters.security_options.secure',
9393
warnings: 'filters.security_options.insecure',
94+
} as const
95+
96+
// Type-safe accessor functions
97+
function getScopeLabelKey(value: SearchScope): string {
98+
return scopeLabelKeys[value]
99+
}
100+
101+
function getScopeDescriptionKey(value: SearchScope): string {
102+
return scopeDescriptionKeys[value]
103+
}
104+
105+
function getDownloadRangeLabelKey(value: DownloadRange): string {
106+
return downloadRangeLabelKeys[value]
107+
}
108+
109+
function getUpdatedWithinLabelKey(value: UpdatedWithin): string {
110+
return updatedWithinLabelKeys[value]
111+
}
112+
113+
function getSecurityLabelKey(value: SecurityFilter): string {
114+
return securityLabelKeys[value]
94115
}
95116
96117
function handleTextInput(event: Event) {
@@ -195,10 +216,10 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
195216
: 'text-fg-muted hover:text-fg'
196217
"
197218
:aria-pressed="filters.searchScope === option.value"
198-
:title="$t(scopeDescriptionKey[option.value])"
219+
:title="$t(getScopeDescriptionKey(option.value))"
199220
@click="emit('update:searchScope', option.value)"
200221
>
201-
{{ $t(scopeLabelKey[option.value]) }}
222+
{{ $t(getScopeLabelKey(option.value)) }}
202223
</button>
203224
</div>
204225
</div>
@@ -232,7 +253,7 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
232253
:class="filters.downloadRange === range.value ? 'bg-fg text-bg border-fg' : ''"
233254
@click="emit('update:downloadRange', range.value)"
234255
>
235-
{{ $t(downloadRangeLabelKey[range.value]) }}
256+
{{ $t(getDownloadRangeLabelKey(range.value)) }}
236257
</button>
237258
</div>
238259
</fieldset>
@@ -257,7 +278,7 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
257278
:class="filters.updatedWithin === option.value ? 'bg-fg text-bg border-fg' : ''"
258279
@click="emit('update:updatedWithin', option.value)"
259280
>
260-
{{ $t(updatedWithinLabelKey[option.value]) }}
281+
{{ $t(getUpdatedWithinLabelKey(option.value)) }}
261282
</button>
262283
</div>
263284
</fieldset>
@@ -281,7 +302,7 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
281302
class="tag transition-colors duration-200 opacity-50 cursor-not-allowed"
282303
:class="filters.security === option.value ? 'bg-fg text-bg border-fg' : ''"
283304
>
284-
{{ $t(securityLabelKey[option.value]) }}
305+
{{ $t(getSecurityLabelKey(option.value)) }}
285306
</button>
286307
</div>
287308
</fieldset>

app/components/PackageList.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ defineExpose({
234234
v-if="results.length === 0 && !isLoading && viewMode !== 'table'"
235235
class="py-12 text-center text-fg-subtle font-mono text-sm"
236236
>
237-
No packages found
237+
{{ $t('filters.table.no_packages') }}
238238
</p>
239239
</div>
240240
</template>

app/components/PackageListToolbar.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ function handleToggleDirection() {
8080
}
8181
8282
// Map sort key to i18n key
83-
const sortKeyLabelKey: Record<string, string> = {
83+
const sortKeyLabelKeys: Record<SortKey, string> = {
8484
'downloads-week': 'filters.sort.downloads_week',
8585
'downloads-day': 'filters.sort.downloads_day',
8686
'downloads-month': 'filters.sort.downloads_month',
@@ -92,6 +92,10 @@ const sortKeyLabelKey: Record<string, string> = {
9292
'maintenance': 'filters.sort.maintenance',
9393
'score': 'filters.sort.score',
9494
}
95+
96+
function getSortKeyLabelKey(key: SortKey): string {
97+
return sortKeyLabelKeys[key]
98+
}
9599
</script>
96100

97101
<template>
@@ -141,7 +145,7 @@ const sortKeyLabelKey: Record<string, string> = {
141145
:value="keyConfig.key"
142146
:disabled="keyConfig.disabled"
143147
>
144-
{{ $t(sortKeyLabelKey[keyConfig.key])
148+
{{ $t(getSortKeyLabelKey(keyConfig.key))
145149
}}{{ keyConfig.disabled ? ` (${$t('filters.columns.coming_soon')})` : '' }}
146150
</option>
147151
</select>

app/components/PackageTable.vue

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
22
import type { NpmSearchResult } from '~~/shared/types/npm-registry'
3-
import type { ColumnConfig, SortKey, SortOption } from '~~/shared/types/preferences'
3+
import type { ColumnConfig, ColumnId, SortKey, SortOption } from '~~/shared/types/preferences'
44
import { buildSortOption, parseSortOption, toggleDirection } from '~~/shared/types/preferences'
55
66
const props = defineProps<{
@@ -84,7 +84,7 @@ function toggleSort(id: string) {
8484
const { t } = useI18n()
8585
8686
// Map column IDs to i18n keys
87-
const columnLabelKey: Record<string, string> = {
87+
const columnLabelKeys: Record<ColumnId, string> = {
8888
name: 'filters.columns.name',
8989
version: 'filters.columns.version',
9090
description: 'filters.columns.description',
@@ -98,6 +98,10 @@ const columnLabelKey: Record<string, string> = {
9898
combinedScore: 'filters.columns.combined_score',
9999
security: 'filters.columns.security',
100100
}
101+
102+
function getColumnLabelKey(id: ColumnId): string {
103+
return columnLabelKeys[id]
104+
}
101105
</script>
102106

103107
<template>
@@ -126,7 +130,7 @@ const columnLabelKey: Record<string, string> = {
126130
@keydown.space.prevent="toggleSort('name')"
127131
>
128132
<span class="inline-flex items-center gap-1">
129-
{{ $t(columnLabelKey['name']) }}
133+
{{ $t(getColumnLabelKey('name')) }}
130134
<template v-if="isSortable('name')">
131135
<span
132136
v-if="isColumnSorted('name')"
@@ -144,15 +148,15 @@ const columnLabelKey: Record<string, string> = {
144148
scope="col"
145149
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider"
146150
>
147-
{{ $t(columnLabelKey['version']) }}
151+
{{ $t(getColumnLabelKey('version')) }}
148152
</th>
149153

150154
<th
151155
v-if="isColumnVisible('description')"
152156
scope="col"
153157
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider"
154158
>
155-
{{ $t(columnLabelKey['description']) }}
159+
{{ $t(getColumnLabelKey('description')) }}
156160
</th>
157161

158162
<th
@@ -177,7 +181,7 @@ const columnLabelKey: Record<string, string> = {
177181
@keydown.space.prevent="toggleSort('downloads')"
178182
>
179183
<span class="inline-flex items-center gap-1 justify-end">
180-
{{ $t(columnLabelKey['downloads']) }}
184+
{{ $t(getColumnLabelKey('downloads')) }}
181185
<template v-if="isSortable('downloads')">
182186
<span
183187
v-if="isColumnSorted('downloads')"
@@ -211,7 +215,7 @@ const columnLabelKey: Record<string, string> = {
211215
@keydown.space.prevent="toggleSort('updated')"
212216
>
213217
<span class="inline-flex items-center gap-1">
214-
{{ $t(columnLabelKey['updated']) }}
218+
{{ $t(getColumnLabelKey('updated')) }}
215219
<template v-if="isSortable('updated')">
216220
<span
217221
v-if="isColumnSorted('updated')"
@@ -229,55 +233,55 @@ const columnLabelKey: Record<string, string> = {
229233
scope="col"
230234
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider"
231235
>
232-
{{ $t(columnLabelKey['maintainers']) }}
236+
{{ $t(getColumnLabelKey('maintainers')) }}
233237
</th>
234238

235239
<th
236240
v-if="isColumnVisible('keywords')"
237241
scope="col"
238242
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider"
239243
>
240-
{{ $t(columnLabelKey['keywords']) }}
244+
{{ $t(getColumnLabelKey('keywords')) }}
241245
</th>
242246

243247
<th
244248
v-if="isColumnVisible('qualityScore')"
245249
scope="col"
246250
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider text-right"
247251
>
248-
{{ $t(columnLabelKey['qualityScore']) }}
252+
{{ $t(getColumnLabelKey('qualityScore')) }}
249253
</th>
250254

251255
<th
252256
v-if="isColumnVisible('popularityScore')"
253257
scope="col"
254258
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider text-right"
255259
>
256-
{{ $t(columnLabelKey['popularityScore']) }}
260+
{{ $t(getColumnLabelKey('popularityScore')) }}
257261
</th>
258262

259263
<th
260264
v-if="isColumnVisible('maintenanceScore')"
261265
scope="col"
262266
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider text-right"
263267
>
264-
{{ $t(columnLabelKey['maintenanceScore']) }}
268+
{{ $t(getColumnLabelKey('maintenanceScore')) }}
265269
</th>
266270

267271
<th
268272
v-if="isColumnVisible('combinedScore')"
269273
scope="col"
270274
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider text-right"
271275
>
272-
{{ $t(columnLabelKey['combinedScore']) }}
276+
{{ $t(getColumnLabelKey('combinedScore')) }}
273277
</th>
274278

275279
<th
276280
v-if="isColumnVisible('security')"
277281
scope="col"
278282
class="py-3 px-3 text-xs font-mono font-medium text-fg-muted uppercase tracking-wider"
279283
>
280-
{{ $t(columnLabelKey['security']) }}
284+
{{ $t(getColumnLabelKey('security')) }}
281285
</th>
282286
</tr>
283287
</thead>

app/composables/usePackageListPreferences.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function usePackageListPreferences() {
7777
}
7878

7979
function resetColumns() {
80-
preferences.value.columns = [...DEFAULT_COLUMNS]
80+
preferences.value.columns = DEFAULT_COLUMNS.map(col => ({ ...col }))
8181
save()
8282
}
8383

app/composables/useStructuredFilters.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export function parseSearchOperators(input: string): ParsedSearchOperators {
5050

5151
while ((match = operatorRegex.exec(input)) !== null) {
5252
const [fullMatch, operator, value] = match
53+
if (!operator || !value) continue
54+
5355
const values = value
5456
.split(',')
5557
.map(v => v.trim())

app/pages/search.vue

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,21 +177,22 @@ const {
177177
setSort,
178178
} = useStructuredFilters({
179179
packages: resultsArray,
180-
initialSort: 'score', // Default to search relevance (combined score)
180+
initialSort: 'score-desc', // Default to search relevance (combined score)
181181
})
182182
183183
// Client-side filtered/sorted results for display
184184
const displayResults = computed(() => {
185-
// Only apply client-side filtering if filters are active
185+
// Check if any client-side filters are active (including text filter from filter panel)
186186
const hasActiveClientFilters =
187+
filters.value.text !== '' ||
187188
filters.value.downloadRange !== 'any' ||
188189
filters.value.keywords.length > 0 ||
189190
filters.value.security !== 'all' ||
190191
filters.value.updatedWithin !== 'any'
191192
192-
// Don't apply text filter here as that's the main search query
193-
if (!hasActiveClientFilters && sortOption.value === 'score') {
194-
// Return original server-sorted results
193+
// When using default score sort (search relevance) and no client filters,
194+
// return original server-sorted results to preserve search ranking
195+
if (!hasActiveClientFilters && sortOption.value === 'score-desc') {
195196
return resultsArray.value
196197
}
197198

0 commit comments

Comments
 (0)