Skip to content

Commit 10f4152

Browse files
committed
fix: adapt keyboad shortcuts and chartFilter
1 parent 794e6a3 commit 10f4152

9 files changed

Lines changed: 107 additions & 64 deletions

File tree

app/components/Package/TrendsChart.vue

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const props = withDefaults(
5555
5656
const { locale } = useI18n()
5757
const { accentColors, selectedAccentColor } = useAccentColor()
58-
const { settings } = useSettings()
58+
const { localSettings } = useUserLocalSettings()
5959
const { copy, copied } = useClipboard()
6060
6161
const colorMode = useColorMode()
@@ -965,7 +965,7 @@ const effectiveDataSingle = computed<EvolutionData>(() => {
965965
966966
if (isDownloadsMetric.value && data.length) {
967967
const pkg = effectivePackageNames.value[0] ?? props.packageName ?? ''
968-
if (settings.value.chartFilter.anomaliesFixed) {
968+
if (localSettings.value.chartFilter.anomaliesFixed) {
969969
data = applyBlocklistCorrection({
970970
data,
971971
packageName: pkg,
@@ -975,7 +975,7 @@ const effectiveDataSingle = computed<EvolutionData>(() => {
975975
976976
return applyDataCorrection(
977977
data as Array<{ value: number }>,
978-
settings.value.chartFilter,
978+
localSettings.value.chartFilter,
979979
) as EvolutionData
980980
}
981981
@@ -1018,12 +1018,12 @@ const chartData = computed<{
10181018
for (const pkg of names) {
10191019
let data = state.evolutionsByPackage[pkg] ?? []
10201020
if (isDownloadsMetric.value && data.length) {
1021-
if (settings.value.chartFilter.anomaliesFixed) {
1021+
if (localSettings.value.chartFilter.anomaliesFixed) {
10221022
data = applyBlocklistCorrection({ data, packageName: pkg, granularity })
10231023
}
10241024
data = applyDataCorrection(
10251025
data as Array<{ value: number }>,
1026-
settings.value.chartFilter,
1026+
localSettings.value.chartFilter,
10271027
) as EvolutionData
10281028
}
10291029
const points = extractSeriesPoints(granularity, data)
@@ -1801,10 +1801,10 @@ watch(selectedMetric, value => {
18011801
<label class="flex flex-col gap-1 flex-1">
18021802
<span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase">
18031803
{{ $t('package.trends.average_window') }}
1804-
<span class="text-fg-muted">({{ settings.chartFilter.averageWindow }})</span>
1804+
<span class="text-fg-muted">({{ localSettings.chartFilter.averageWindow }})</span>
18051805
</span>
18061806
<input
1807-
v-model.number="settings.chartFilter.averageWindow"
1807+
v-model.number="localSettings.chartFilter.averageWindow"
18081808
type="range"
18091809
min="0"
18101810
max="20"
@@ -1815,10 +1815,10 @@ watch(selectedMetric, value => {
18151815
<label class="flex flex-col gap-1 flex-1">
18161816
<span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase">
18171817
{{ $t('package.trends.smoothing') }}
1818-
<span class="text-fg-muted">({{ settings.chartFilter.smoothingTau }})</span>
1818+
<span class="text-fg-muted">({{ localSettings.chartFilter.smoothingTau }})</span>
18191819
</span>
18201820
<input
1821-
v-model.number="settings.chartFilter.smoothingTau"
1821+
v-model.number="localSettings.chartFilter.smoothingTau"
18221822
type="range"
18231823
min="0"
18241824
max="20"
@@ -1883,9 +1883,11 @@ watch(selectedMetric, value => {
18831883
:class="{ 'opacity-50 pointer-events-none': !hasAnomalies }"
18841884
>
18851885
<input
1886-
:checked="settings.chartFilter.anomaliesFixed && hasAnomalies"
1886+
:checked="localSettings.chartFilter.anomaliesFixed && hasAnomalies"
18871887
@change="
1888-
settings.chartFilter.anomaliesFixed = ($event.target as HTMLInputElement).checked
1888+
localSettings.chartFilter.anomaliesFixed = (
1889+
$event.target as HTMLInputElement
1890+
).checked
18891891
"
18901892
type="checkbox"
18911893
:disabled="!hasAnomalies"

app/components/Package/WeeklyDownloadStats.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,14 @@ watch(
185185
const correctedDownloads = computed<WeeklyDataPoint[]>(() => {
186186
let data = weeklyDownloads.value as WeeklyDataPoint[]
187187
if (!data.length) return data
188-
if (settings.value.chartFilter.anomaliesFixed) {
188+
if (localSettings.value.chartFilter.anomaliesFixed) {
189189
data = applyBlocklistCorrection({
190190
data,
191191
packageName: props.packageName,
192192
granularity: 'weekly',
193193
}) as WeeklyDataPoint[]
194194
}
195-
data = applyDataCorrection(data, settings.value.chartFilter) as WeeklyDataPoint[]
195+
data = applyDataCorrection(data, localSettings.value.chartFilter) as WeeklyDataPoint[]
196196
return data
197197
})
198198

app/composables/useUserLocalSettings.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export interface UserLocalSettings {
66
connector: {
77
autoOpenURL: boolean
88
}
9+
chartFilter: {
10+
averageWindow: number
11+
smoothingTau: number
12+
anomaliesFixed: boolean
13+
}
914
}
1015

1116
const STORAGE_KEY = 'npmx-settings'
@@ -17,6 +22,11 @@ const DEFAULT_USER_LOCAL_SETTINGS: UserLocalSettings = {
1722
connector: {
1823
autoOpenURL: false,
1924
},
25+
chartFilter: {
26+
averageWindow: 0,
27+
smoothingTau: 1,
28+
anomaliesFixed: true,
29+
},
2030
}
2131

2232
let localSettingsRef: Ref<UserLocalSettings> | null = null
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const useKeyboardShortcuts = createSharedComposable(function useKeyboardShortcuts() {
2+
const { preferences } = useUserPreferencesState()
3+
const enabled = computed(() => preferences.value.keyboardShortcuts ?? true)
4+
5+
if (import.meta.client) {
6+
watch(
7+
enabled,
8+
value => {
9+
if (value) {
10+
delete document.documentElement.dataset.kbdShortcuts
11+
} else {
12+
document.documentElement.dataset.kbdShortcuts = 'false'
13+
}
14+
},
15+
{ immediate: true },
16+
)
17+
}
18+
19+
return enabled
20+
})

app/pages/settings.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ const setLocale: typeof setNuxti18nLocale = locale => {
333333
<SettingsToggle
334334
:label="$t('settings.keyboard_shortcuts_enabled')"
335335
:description="$t('settings.keyboard_shortcuts_enabled_description')"
336-
v-model="settings.keyboardShortcuts"
336+
v-model="keyboardShortcutsEnabled"
337337
/>
338338
</div>
339339
</section>

shared/schemas/userPreferences.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export const UserPreferencesSchema = object({
2626
colorModePreference: optional(nullable(ColorModePreferenceSchema)),
2727
/** Search provider for package search: 'npm' or 'algolia' */
2828
searchProvider: optional(SearchProviderSchema),
29+
/** Whether keyboard shortcuts are enabled globally */
30+
keyboardShortcuts: optional(boolean()),
2931
/** Timestamp of last update (ISO 8601) - managed by server */
3032
updatedAt: optional(string()),
3133
})
@@ -49,7 +51,8 @@ export const DEFAULT_USER_PREFERENCES: Required<Omit<UserPreferences, 'updatedAt
4951
hidePlatformPackages: true,
5052
selectedLocale: null,
5153
colorModePreference: null,
52-
searchProvider: 'algolia',
54+
searchProvider: import.meta.test ? 'npm' : 'algolia',
55+
keyboardShortcuts: true,
5356
}
5457

5558
export const USER_PREFERENCES_STORAGE_BASE = 'npmx-kv-user-preferences'

test/e2e/interactions.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ test.describe('Keyboard Shortcuts', () => {
271271
test.describe('Keyboard Shortcuts disabled', () => {
272272
test.beforeEach(async ({ page }) => {
273273
await page.addInitScript(() => {
274-
localStorage.setItem('npmx-settings', JSON.stringify({ keyboardShortcuts: false }))
274+
localStorage.setItem('npmx-user-preferences', JSON.stringify({ keyboardShortcuts: false }))
275275
})
276276
})
277277

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
2+
import { nextTick } from 'vue'
3+
import { DEFAULT_USER_PREFERENCES } from '#shared/schemas/userPreferences'
4+
5+
describe('useKeyboardShortcuts', () => {
6+
beforeEach(() => {
7+
localStorage.clear()
8+
// Reset preferences to defaults
9+
const { preferences } = useUserPreferencesState()
10+
preferences.value = { ...DEFAULT_USER_PREFERENCES }
11+
})
12+
13+
afterEach(() => {
14+
delete document.documentElement.dataset.kbdShortcuts
15+
})
16+
17+
it('should return true by default', () => {
18+
const enabled = useKeyboardShortcuts()
19+
expect(enabled.value).toBe(true)
20+
})
21+
22+
it('should return false when preference is disabled', () => {
23+
const { preferences } = useUserPreferencesState()
24+
preferences.value = { ...preferences.value, keyboardShortcuts: false }
25+
26+
const enabled = useKeyboardShortcuts()
27+
expect(enabled.value).toBe(false)
28+
})
29+
30+
it('should reactively update when preferences change', () => {
31+
const enabled = useKeyboardShortcuts()
32+
const { preferences } = useUserPreferencesState()
33+
34+
expect(enabled.value).toBe(true)
35+
36+
preferences.value = { ...preferences.value, keyboardShortcuts: false }
37+
expect(enabled.value).toBe(false)
38+
39+
preferences.value = { ...preferences.value, keyboardShortcuts: true }
40+
expect(enabled.value).toBe(true)
41+
})
42+
43+
it('should set data-kbd-shortcuts attribute when disabled', async () => {
44+
const { preferences } = useUserPreferencesState()
45+
46+
useKeyboardShortcuts()
47+
48+
preferences.value = { ...preferences.value, keyboardShortcuts: false }
49+
await nextTick()
50+
expect(document.documentElement.dataset.kbdShortcuts).toBe('false')
51+
52+
preferences.value = { ...preferences.value, keyboardShortcuts: true }
53+
await nextTick()
54+
expect(document.documentElement.dataset.kbdShortcuts).toBeUndefined()
55+
})
56+
})

test/nuxt/composables/use-settings.spec.ts

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)