Skip to content

Commit a0aaf4e

Browse files
committed
fix: guard JSON.parse with try/catch
1 parent 9c65d93 commit a0aaf4e

File tree

4 files changed

+25
-7
lines changed

4 files changed

+25
-7
lines changed

app/components/Settings/AccentColorPicker.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
<script setup lang="ts">
2+
import type { UserPreferences } from '#shared/schemas/userPreferences'
3+
24
const { accentColors, selectedAccentColor, setAccentColor } = useAccentColor()
35
46
onPrehydrate(el => {
5-
const preferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
7+
let preferences: UserPreferences = {}
68
const defaultId = 'sky'
9+
try {
10+
preferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
11+
} catch {}
712
const id = preferences.accentColorId
813
if (id) {
914
const input = el.querySelector<HTMLInputElement>(`input[value="${id}"]`)

app/components/Settings/BgThemePicker.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
<script setup lang="ts">
2+
import type { UserPreferences } from '#shared/schemas/userPreferences'
3+
24
const { backgroundThemes, selectedBackgroundTheme, setBackgroundTheme } = useBackgroundTheme()
35
46
onPrehydrate(el => {
5-
const preferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
7+
let preferences: UserPreferences = {}
68
const defaultId = 'neutral'
9+
try {
10+
preferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
11+
} catch {}
712
const id = preferences.preferredBackgroundTheme
813
if (id) {
914
const input = el.querySelector<HTMLInputElement>(`input[value="${id}"]`)

app/composables/useUserLocalSettings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
interface UserLocalSettings {
1+
export interface UserLocalSettings {
22
sidebar: {
33
collapsed: string[]
44
animateSparkline: boolean

app/utils/prehydrate.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import type { UserPreferences } from '#shared/schemas/userPreferences'
2+
import type { UserLocalSettings } from '~/composables/useUserLocalSettings'
3+
14
/**
25
* Initialize user preferences before hydration to prevent flash/layout shift.
36
* This sets CSS custom properties and data attributes that CSS can use
@@ -16,7 +19,10 @@ export function initPreferencesOnPrehydrate() {
1619
const validPMs = new Set(['npm', 'pnpm', 'yarn', 'bun', 'deno', 'vlt'])
1720

1821
// Read user preferences from localStorage
19-
const preferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
22+
let preferences: UserPreferences = {}
23+
try {
24+
preferences = JSON.parse(localStorage.getItem('npmx-user-preferences') || '{}')
25+
} catch {}
2026

2127
const accentColorId = preferences.accentColorId
2228
if (accentColorId && accentColorIds.has(accentColorId)) {
@@ -50,8 +56,10 @@ export function initPreferencesOnPrehydrate() {
5056
// Set data attribute for CSS-based visibility
5157
document.documentElement.dataset.pm = pm
5258

53-
// Read sidebar preferences from separate localStorage key
54-
const sidebar = JSON.parse(localStorage.getItem('npmx-sidebar-preferences') || '{}')
55-
document.documentElement.dataset.collapsed = sidebar.collapsed?.join(' ') ?? ''
59+
let localSettings: Partial<UserLocalSettings> = {}
60+
try {
61+
localSettings = JSON.parse(localStorage.getItem('npmx-settings') || '{}')
62+
} catch {}
63+
document.documentElement.dataset.collapsed = localSettings.sidebar?.collapsed?.join(' ') ?? ''
5664
})
5765
}

0 commit comments

Comments
 (0)