Skip to content

Conversation

@gusa4grr
Copy link
Contributor

@gusa4grr gusa4grr commented Feb 8, 2026

MR summary

This is still WIP, happy to have any feedback on the approach.
I haven't fully tested the implementation, as soon as I verify that locally will change the MR state 👍🏻

Note: Came from a React background, I am a newbie to the Nuxt/Vue ecosystem. Please let me know if any patterns are misplaced. Happy to learn and adjust!

Core implementation details:

  • created a user-preference store factory
  • created a settings sync logic with 2 seconds debounce
  • added an interceptor to trigger update requests on route changes and beforeunload. (or we can remove this if it is deemed unnecessary overhead).
  • extract sidebar collapsed state into separate usePackageSidebarPreferences composable
  • add preferences-sync.client.ts plugin for early color mode + server sync init
  • wrap theme select in <ClientOnly> to prevent SSR hydration mismatch
  • show sync status indicator on settings page for authenticated users
  • add useColorModePreference composable to sync color mode with @nuxtjs/color-mode

ToDo:

  • add support for searchProvider, which was added while this MR was open
  • fully test locally all scenarios
  • preload and hydrate settings properly (advice needed. See questions below)

Questions:

  • I used client.ts suffix for useUserPreferencesSync.client.ts to ensure it is client-side only. Is this the standard convention to prevent server-side execution?
  • with this new logic, we need to fetch user preferences immediately upon/before the app loads. what is the recommended approach for this?

I noticed initPreferencesOnPrehydrate, which retrieves some settings from LS on the client, but it doesn't appear to support data fetching. Few other places also using onPrehydrate.
I am curious as we can load preferences during SSR too and can hydrate client with the preferences right away (if logged in). What files/places should I look at, any suggestions?

Needs to be discussed - Done ✅

During the implementation, I identified inconsistent local storage usage across the app:

image
  • npmx-color-mode - used for color mode. It is adjustable via the settings page, but is also evaluated by lighthouse and referenced in the nuxt.config colorMode property
  • npmx-list-prefs - used in search to modify the viewing experience
  • npmx-settings - contains settings found in /settings route as well as unrelated sidebar states on package page (see image below)
image

Based on the feature requirements, I decided to create the user-preferences schema specifically for the /settings page configuration. However, the current useSettings hook combines both user-preferences and "sidebar states".

I want to align with the team on the execution strategy before finalizing these changes.

Proposed plan:

  • color-mode - retain as-is (npmx-color-mode), but connect to user-preference service
  • npmx-list-prefs - retain as-is for now (or potentially merge into npmx-settings). We can add this to the user-preferences service as a follow-up and remove this LS key then.
  • npmx-settings - remove all user-preference related keys (leaving only the sidebar state). Merge with npmx-settings or leave as-is
  • npmx-user-preferences - new LS key for user preferences. This will serve as the source of truth for anonymous users. For logged-in users, it will sync with the server, where the server state takes precedence on load

The solution I am drafting centralizes these options into a single user-preference service. However, if we include items outside of /settings, we need to consider:

  • making it clear to the user what parts are persistent settings
  • defining the correct "sync" lifecycle

- introduce the foundational layer for persisting user preferences
to the server
- add UserPreferencesSchema and shared types for user preferences
- add client-only sync composable with debounced saves, route guard flush, and sendBeacon fallback
- integrate server sync into useSettings and migrate to shared UserPreferences type
- extract generic localStorage helpers, migrate consumers, remove usePreferencesProvider
@vercel
Copy link

vercel bot commented Feb 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 9, 2026 1:18am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 9, 2026 1:18am
npmx-lunaria Ignored Ignored Feb 9, 2026 1:18am

Request Review

@codecov
Copy link

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 12.26415% with 93 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/composables/useUserPreferencesSync.client.ts 6.66% 59 Missing and 11 partials ⚠️
app/composables/useSettings.ts 11.53% 19 Missing and 4 partials ⚠️

📢 Thoughts on this report? Let us know!

@43081j
Copy link
Contributor

43081j commented Feb 8, 2026

haven't reviewed the code yet, but on the proposed changes:

  • color-mode - i agree leave it where it is but possibly sync it
  • npmx-list-prefs - keep it clientside since it is likely to be changed often between views
  • npmx-settings - agree
  • npmx-user-preferences - agree

The usual pattern is this:

  • Anything that persists across pages, sync it to the backend
  • Anything that is one-time, temporary, or often toggled (like search filters), do not sync

we should then end up in a state where our prefs save to local storage and take effect immediately, but meanwhile get synced to the server in the background.

i think we probably also need a toggle somewhere to disable sync, in case you want different prefs per machine. same way chrome works today

@github-actions
Copy link

github-actions bot commented Feb 9, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
lunaria/files/en-GB.json Localization changed, will be marked as complete. 🔄️
lunaria/files/en-US.json Source changed, localizations will be marked as outdated.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@gusa4grr
Copy link
Contributor Author

gusa4grr commented Feb 9, 2026

@43081j 👋🏻

Updated the MR description and pushed one more commit.
I'll leave it as a draft for now, as I haven't validated all the scenarios, but the core things are working fine!

if you have time - please look throught the code 🙂 Much appreciated!

I will try to find time during the work week to finalise this, as not much is left 🤞🏻

- extract sidebar collapsed state into separate `usePackageSidebarPreferences` composable
- add `preferences-sync.client.ts` plugin for early color mode + server sync init
- wrap theme select in `<ClientOnly>` to prevent SSR hydration mismatch
- show sync status indicator on settings page for authenticated users
- add `useColorModePreference` composable to sync color mode with `@nuxtjs/color-mode`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants