Skip to content

Commit 2c22012

Browse files
committed
chore: fix use settings
1 parent 671d13a commit 2c22012

2 files changed

Lines changed: 57 additions & 10 deletions

File tree

app/composables/useSettings.ts

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import type { RemovableRef } from '@vueuse/core'
2-
import { useLocalStorage } from '@vueuse/core'
31
import { ACCENT_COLORS } from '#shared/utils/constants'
42
import type { LocaleObject } from '@nuxtjs/i18n'
53
import { BACKGROUND_THEMES } from '#shared/utils/constants'
@@ -72,22 +70,66 @@ const DEFAULT_SETTINGS: AppSettings = {
7270

7371
const STORAGE_KEY = 'npmx-settings'
7472

75-
// Shared settings instance (singleton per app)
76-
let settingsRef: RemovableRef<AppSettings> | null = null
73+
/**
74+
* Read settings from localStorage and merge with defaults.
75+
*/
76+
function readFromLocalStorage(): AppSettings {
77+
try {
78+
const raw = localStorage.getItem(STORAGE_KEY)
79+
if (raw) {
80+
const stored = JSON.parse(raw)
81+
return {
82+
...DEFAULT_SETTINGS,
83+
...stored,
84+
connector: { ...DEFAULT_SETTINGS.connector, ...stored.connector },
85+
sidebar: { ...DEFAULT_SETTINGS.sidebar, ...stored.sidebar },
86+
chartFilter: { ...DEFAULT_SETTINGS.chartFilter, ...stored.chartFilter },
87+
}
88+
}
89+
} catch {}
90+
return { ...DEFAULT_SETTINGS }
91+
}
92+
93+
let syncInitialized = false
7794

7895
/**
79-
* Composable for managing application settings with localStorage persistence.
80-
* Settings are shared across all components that use this composable.
96+
* Composable for managing application settings.
97+
*
98+
* Uses useState for SSR-safe hydration (server and client agree on initial
99+
* values during hydration) and syncs with localStorage on the client.
100+
* The onPrehydrate script in prehydrate.ts handles DOM-level patches
101+
* (accent color, bg theme, collapsed sections, etc.) to prevent visual
102+
* flash before hydration.
81103
*/
82104
export function useSettings() {
83-
if (!settingsRef) {
84-
settingsRef = useLocalStorage<AppSettings>(STORAGE_KEY, DEFAULT_SETTINGS, {
85-
mergeDefaults: true,
105+
const settings = useState<AppSettings>(STORAGE_KEY, () => ({ ...DEFAULT_SETTINGS }))
106+
107+
if (import.meta.client && !syncInitialized) {
108+
syncInitialized = true
109+
110+
// Read localStorage eagerly but apply after mount to prevent hydration
111+
// mismatch. During hydration, useState provides server-matching defaults.
112+
// After mount, we swap in the user's actual preferences from localStorage.
113+
const stored = readFromLocalStorage()
114+
115+
onMounted(() => {
116+
settings.value = stored
86117
})
118+
119+
// Persist future changes back to localStorage
120+
watch(
121+
settings,
122+
value => {
123+
try {
124+
localStorage.setItem(STORAGE_KEY, JSON.stringify(value))
125+
} catch {}
126+
},
127+
{ deep: true },
128+
)
87129
}
88130

89131
return {
90-
settings: settingsRef,
132+
settings,
91133
}
92134
}
93135

app/utils/prehydrate.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,10 @@ export function initPreferencesOnPrehydrate() {
5858
if (settings.keyboardShortcuts === false) {
5959
document.documentElement.dataset.kbdShortcuts = 'false'
6060
}
61+
62+
// Search provider (default: algolia)
63+
if (settings.searchProvider === 'npm') {
64+
document.documentElement.dataset.searchProvider = 'npm'
65+
}
6166
})
6267
}

0 commit comments

Comments
 (0)