Skip to content

Commit 21882ac

Browse files
committed
refactor: split user-preferences composables and streamline sync flow
1 parent 6108722 commit 21882ac

31 files changed

+345
-295
lines changed

app/components/CollapsibleSection.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ const props = withDefaults(defineProps<Props>(), {
1515
headingLevel: 'h2',
1616
})
1717
18-
const { userLocalSettings } = useUserLocalSettings()
18+
const { localSettings } = useUserLocalSettings()
1919
2020
const buttonId = `${props.id}-collapsible-button`
2121
const contentId = `${props.id}-collapsible-content`
2222
2323
const isOpen = shallowRef(true)
2424
2525
onPrehydrate(() => {
26-
const sidebar = JSON.parse(localStorage.getItem('npmx-settings') || '{}')
27-
const collapsed: string[] = sidebar?.sidebar?.collapsed || []
26+
const settings = JSON.parse(localStorage.getItem('npmx-settings') || '{}')
27+
const collapsed: string[] = settings?.sidebar?.collapsed || []
2828
for (const id of collapsed) {
2929
if (!document.documentElement.dataset.collapsed?.split(' ').includes(id)) {
3030
document.documentElement.dataset.collapsed = (
@@ -47,16 +47,16 @@ onMounted(() => {
4747
function toggle() {
4848
isOpen.value = !isOpen.value
4949
50-
const removed = userLocalSettings.value.sidebar.collapsed.filter(c => c !== props.id)
50+
const removed = localSettings.value.sidebar.collapsed.filter(c => c !== props.id)
5151
5252
if (isOpen.value) {
53-
userLocalSettings.value.sidebar.collapsed = removed
53+
localSettings.value.sidebar.collapsed = removed
5454
} else {
5555
removed.push(props.id)
56-
userLocalSettings.value.sidebar.collapsed = removed
56+
localSettings.value.sidebar.collapsed = removed
5757
}
5858
59-
document.documentElement.dataset.collapsed = userLocalSettings.value.sidebar.collapsed.join(' ')
59+
document.documentElement.dataset.collapsed = localSettings.value.sidebar.collapsed.join(' ')
6060
}
6161
6262
const ariaLabel = computed(() => {

app/components/Header/ConnectorModal.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
const { isConnected, isConnecting, npmUser, error, hasOperations, connect, disconnect } =
33
useConnector()
44
5-
const { userLocalSettings } = useUserLocalSettings()
5+
const { localSettings } = useUserLocalSettings()
66
77
const tokenInput = shallowRef('')
88
const portInput = shallowRef('31415')
@@ -67,7 +67,7 @@ function handleDisconnect() {
6767
<div class="flex flex-col gap-2">
6868
<SettingsToggle
6969
:label="$t('connector.modal.auto_open_url')"
70-
v-model="userLocalSettings.connector.autoOpenURL"
70+
v-model="localSettings.connector.autoOpenURL"
7171
/>
7272
</div>
7373

@@ -201,7 +201,7 @@ function handleDisconnect() {
201201
<div class="flex flex-col gap-2">
202202
<SettingsToggle
203203
:label="$t('connector.modal.auto_open_url')"
204-
v-model="userLocalSettings.connector.autoOpenURL"
204+
v-model="localSettings.connector.autoOpenURL"
205205
/>
206206
</div>
207207
</div>

app/components/Settings/AccentColorPicker.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
<script setup lang="ts">
2-
import { useAccentColor } from '~/composables/useUserPreferences'
3-
42
const { accentColors, selectedAccentColor, setAccentColor } = useAccentColor()
53
64
onPrehydrate(el => {

app/composables/npm/useSearch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { NpmSearchResponse, NpmSearchResult } from '#shared/types'
2-
import type { SearchProvider } from '~/composables/useSettings'
2+
import type { SearchProvider } from '#shared/schemas/userPreferences'
33
import type { AlgoliaMultiSearchChecks } from './useAlgoliaSearch'
44
import { type SearchSuggestion, emptySearchResponse, parseSuggestionIntent } from './search-utils'
55
import { isValidNewPackageName, checkPackageExists } from '~/utils/package-name'

app/composables/useConnector.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const STORAGE_KEY = 'npmx-connector'
5757
const DEFAULT_PORT = 31415
5858

5959
export const useConnector = createSharedComposable(function useConnector() {
60-
const { userLocalSettings } = useUserLocalSettings()
60+
const { localSettings } = useUserLocalSettings()
6161

6262
// Persisted connection config
6363
const config = useState<{ token: string; port: number } | null>('connector-config', () => null)
@@ -308,7 +308,7 @@ export const useConnector = createSharedComposable(function useConnector() {
308308
body: {
309309
otp,
310310
interactive: !otp,
311-
openUrls: userLocalSettings.value.connector.autoOpenURL,
311+
openUrls: localSettings.value.connector.autoOpenURL,
312312
},
313313
})
314314
if (response?.success) {

app/composables/useInstallCommand.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function useInstallCommand(
1212
installVersionOverride?: MaybeRefOrGetter<string | null>,
1313
) {
1414
const selectedPM = useSelectedPackageManager()
15-
const { preferences } = useUserPreferences()
15+
const { preferences } = useUserPreferencesState()
1616

1717
// Check if we should show @types in install command
1818
const showTypesInInstall = computed(() => {

app/composables/useUserLocalSettings.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const DEFAULT_USER_LOCAL_SETTINGS: UserLocalSettings = {
1717
},
1818
}
1919

20-
let userLocalSettingsRef: Ref<UserLocalSettings> | null = null
20+
let localSettingsRef: Ref<UserLocalSettings> | null = null
2121

2222
/**
2323
* Composable for managing local user settings.
@@ -26,8 +26,8 @@ let userLocalSettingsRef: Ref<UserLocalSettings> | null = null
2626
* This is for settings that are purely local and don't need to be synced
2727
*/
2828
export function useUserLocalSettings() {
29-
if (!userLocalSettingsRef) {
30-
userLocalSettingsRef = useLocalStorage<UserLocalSettings>(
29+
if (!localSettingsRef) {
30+
localSettingsRef = useLocalStorage<UserLocalSettings>(
3131
STORAGE_KEY,
3232
DEFAULT_USER_LOCAL_SETTINGS,
3333
{
@@ -37,6 +37,6 @@ export function useUserLocalSettings() {
3737
}
3838

3939
return {
40-
userLocalSettings: userLocalSettingsRef,
40+
localSettings: localSettingsRef,
4141
}
4242
}

app/composables/useUserPreferences.ts

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

app/composables/useUserPreferencesProvider.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,24 @@
1313

1414
import type { RemovableRef } from '@vueuse/core'
1515
import { useLocalStorage } from '@vueuse/core'
16-
import type { UserPreferences } from '#shared/schemas/userPreferences'
16+
import { DEFAULT_USER_PREFERENCES, type UserPreferences } from '#shared/schemas/userPreferences'
1717

1818
const STORAGE_KEY = 'npmx-user-preferences'
1919

20+
function arePreferencesEqual(a: UserPreferences, b: UserPreferences): boolean {
21+
const keys = Object.keys(DEFAULT_USER_PREFERENCES) as (keyof typeof DEFAULT_USER_PREFERENCES)[]
22+
return keys.every(key => a[key] === b[key])
23+
}
24+
2025
export type HydratedUserPreferences = Required<Omit<UserPreferences, 'updatedAt'>> &
2126
Pick<UserPreferences, 'updatedAt'>
2227

2328
let dataRef: RemovableRef<HydratedUserPreferences> | null = null
2429
let syncInitialized = false
2530

26-
/**
27-
* User preferences provider with server sync support.
28-
*/
29-
export function useUserPreferencesProvider(defaultValue: HydratedUserPreferences) {
31+
export function useUserPreferencesProvider(
32+
defaultValue: HydratedUserPreferences = DEFAULT_USER_PREFERENCES,
33+
) {
3034
if (!dataRef) {
3135
dataRef = useLocalStorage<HydratedUserPreferences>(STORAGE_KEY, defaultValue, {
3236
mergeDefaults: true,
@@ -63,7 +67,10 @@ export function useUserPreferencesProvider(defaultValue: HydratedUserPreferences
6367
if (isAuthenticated.value) {
6468
const serverPrefs = await loadFromServer()
6569
if (serverPrefs) {
66-
preferences.value = { ...preferences.value, ...serverPrefs }
70+
const merged = { ...preferences.value, ...serverPrefs }
71+
if (!arePreferencesEqual(preferences.value, merged)) {
72+
preferences.value = merged
73+
}
6774
}
6875
}
6976

@@ -81,7 +88,10 @@ export function useUserPreferencesProvider(defaultValue: HydratedUserPreferences
8188
if (newIsAuth) {
8289
const serverPrefs = await loadFromServer()
8390
if (serverPrefs) {
84-
preferences.value = { ...defaultValue, ...preferences.value, ...serverPrefs }
91+
const merged = { ...defaultValue, ...preferences.value, ...serverPrefs }
92+
if (!arePreferencesEqual(preferences.value, merged)) {
93+
preferences.value = merged
94+
}
8595
}
8696
}
8797
})

0 commit comments

Comments
 (0)