From 3e07267e10ee687c25ccc5dfe3a77fdd00088000 Mon Sep 17 00:00:00 2001 From: "Calum H." Date: Thu, 20 Aug 2026 08:23:01 +0100 Subject: [PATCH] feat: preferences syncing frontend (#7192) * feat: prefs frontend * fix: DI issue * fix: lint * feat: appearance settings cleanup + fix settings, remove pinia * fix: sync btn when logged out * fix: prepr * fix: sidebar issue * feat: language coverage + cleanup * feat: cleanup lang settings * fix: fmt * fix: CI * fix: ci * fix: storybook * feat: bring back loader/game version sort --------- Co-authored-by: tdgao --- .github/workflows/frontend-deploy.yml | 3 +- .github/workflows/frontend-preview.yml | 3 +- .gitignore | 1 + apps/app-frontend/package.json | 1 - apps/app-frontend/src/App.vue | 118 +++- .../src/components/ui/AccountsCard.vue | 2 +- .../src/components/ui/ErrorModal.vue | 2 +- .../src/components/ui/Instance.vue | 2 +- .../src/components/ui/WindowControls.vue | 6 +- .../src/components/ui/friends/FriendsList.vue | 8 +- .../install_flow/UnknownPackWarningModal.vue | 9 +- .../library/instance-group/instance-card.vue | 2 +- .../ui/library/library-toolbar/sort-menu.vue | 5 + .../src/components/ui/library/use-library.ts | 14 + .../MinecraftAuthErrorModal.vue | 2 +- .../MinecraftRequiredModal.vue | 2 +- .../components/ui/modal/AppSettingsModal.vue | 31 +- .../ui/settings/account/SocialSettings.vue | 20 + .../settings/display/AppearanceSettings.vue | 228 ++++--- .../ui/settings/display/BehaviorSettings.vue | 239 ++++--- .../settings/display/FeatureFlagSettings.vue | 21 +- .../ui/settings/display/LanguageSettings.vue | 91 +-- .../instances/ResourceManagementSettings.vue | 12 +- .../use-shared-instance-invite-handler.ts | 6 +- .../src/components/ui/world/InstanceItem.vue | 2 +- .../components/ui/world/RecentWorldsList.vue | 8 +- .../browse/install-job-notifications.ts | 6 +- .../src/composables/use-app-settings.ts | 52 ++ .../app-frontend/src/composables/use-error.js | 48 ++ .../app-frontend/src/composables/use-theme.ts | 47 ++ apps/app-frontend/src/helpers/settings.ts | 5 +- apps/app-frontend/src/helpers/types.d.ts | 2 + .../src/helpers/user-preferences.ts | 19 + .../app-frontend/src/locales/ar-SA/index.json | 12 - .../app-frontend/src/locales/cs-CZ/index.json | 12 - .../app-frontend/src/locales/da-DK/index.json | 6 - .../app-frontend/src/locales/de-CH/index.json | 18 - .../app-frontend/src/locales/de-DE/index.json | 18 - .../app-frontend/src/locales/en-US/index.json | 33 +- .../src/locales/es-419/index.json | 18 - .../app-frontend/src/locales/es-ES/index.json | 12 - .../app-frontend/src/locales/fi-FI/index.json | 12 - .../src/locales/fil-PH/index.json | 12 - .../app-frontend/src/locales/fr-FR/index.json | 18 - .../app-frontend/src/locales/hu-HU/index.json | 18 - .../app-frontend/src/locales/id-ID/index.json | 12 - .../app-frontend/src/locales/it-IT/index.json | 18 - .../app-frontend/src/locales/ja-JP/index.json | 18 - .../app-frontend/src/locales/ko-KR/index.json | 18 - .../app-frontend/src/locales/ms-MY/index.json | 12 - .../app-frontend/src/locales/nl-NL/index.json | 18 - .../app-frontend/src/locales/no-NO/index.json | 6 - .../app-frontend/src/locales/pl-PL/index.json | 18 - .../app-frontend/src/locales/pt-BR/index.json | 18 - .../app-frontend/src/locales/pt-PT/index.json | 12 - .../app-frontend/src/locales/ru-RU/index.json | 18 - .../app-frontend/src/locales/sr-CS/index.json | 18 - .../app-frontend/src/locales/sv-SE/index.json | 15 - .../app-frontend/src/locales/th-TH/index.json | 12 - .../app-frontend/src/locales/tr-TR/index.json | 18 - .../app-frontend/src/locales/uk-UA/index.json | 18 - .../app-frontend/src/locales/vi-VN/index.json | 12 - .../app-frontend/src/locales/zh-CN/index.json | 18 - .../app-frontend/src/locales/zh-TW/index.json | 18 - apps/app-frontend/src/main.js | 4 - apps/app-frontend/src/pages/Browse.vue | 18 +- apps/app-frontend/src/pages/Index.vue | 6 +- apps/app-frontend/src/pages/Skins.vue | 8 +- .../src/pages/hosting/manage/Index.vue | 6 +- .../settings-modal/installation-settings.vue | 6 +- .../src/pages/instance/content/index.vue | 11 +- .../src/pages/instance/layout.vue | 8 +- .../src/pages/instance/worlds/index.vue | 2 +- apps/app-frontend/src/pages/project/Index.vue | 6 +- .../src/pages/project/Versions.vue | 6 +- apps/app-frontend/src/plugins/i18n-debug.ts | 8 +- .../src/providers/content-install.ts | 6 +- .../src/providers/server-install.ts | 2 +- apps/app-frontend/src/providers/setup/auth.ts | 1 + .../src/providers/setup/creation-modal.ts | 6 +- .../src/providers/setup/loading-state.ts | 2 +- .../src/providers/setup/user-preferences.ts | 19 + apps/app-frontend/src/store/error.js | 49 -- apps/app-frontend/src/store/state.js | 3 - apps/app-frontend/src/store/theme.ts | 91 --- apps/app/build.rs | 4 + apps/app/src/api/users.rs | 15 + apps/app/tauri.conf.json | 2 +- apps/frontend/src/app.vue | 46 +- apps/frontend/src/components/ui/NavStack.vue | 36 +- apps/frontend/src/layouts/default.vue | 16 +- apps/frontend/src/locales/cs-CZ/index.json | 72 --- apps/frontend/src/locales/da-DK/index.json | 42 -- apps/frontend/src/locales/de-CH/index.json | 84 --- apps/frontend/src/locales/de-DE/index.json | 84 --- apps/frontend/src/locales/en-US/index.json | 84 --- apps/frontend/src/locales/es-419/index.json | 84 --- apps/frontend/src/locales/es-ES/index.json | 84 --- apps/frontend/src/locales/fi-FI/index.json | 15 - apps/frontend/src/locales/fil-PH/index.json | 84 --- apps/frontend/src/locales/fr-FR/index.json | 84 --- apps/frontend/src/locales/hu-HU/index.json | 84 --- apps/frontend/src/locales/id-ID/index.json | 75 --- apps/frontend/src/locales/it-IT/index.json | 84 --- apps/frontend/src/locales/ja-JP/index.json | 84 --- apps/frontend/src/locales/ko-KR/index.json | 84 --- apps/frontend/src/locales/ms-MY/index.json | 84 --- apps/frontend/src/locales/nl-NL/index.json | 84 --- apps/frontend/src/locales/no-NO/index.json | 84 --- apps/frontend/src/locales/pl-PL/index.json | 84 --- apps/frontend/src/locales/pt-BR/index.json | 84 --- apps/frontend/src/locales/pt-PT/index.json | 84 --- apps/frontend/src/locales/ro-RO/index.json | 72 --- apps/frontend/src/locales/ru-RU/index.json | 84 --- apps/frontend/src/locales/sr-CS/index.json | 84 --- apps/frontend/src/locales/sv-SE/index.json | 84 --- apps/frontend/src/locales/tr-TR/index.json | 84 --- apps/frontend/src/locales/uk-UA/index.json | 84 --- apps/frontend/src/locales/vi-VN/index.json | 84 --- apps/frontend/src/locales/zh-CN/index.json | 84 --- apps/frontend/src/locales/zh-TW/index.json | 84 --- .../src/pages/discover/[type]/index.vue | 26 +- apps/frontend/src/pages/settings/index.vue | 603 +++++++----------- apps/frontend/src/pages/settings/language.vue | 93 +-- apps/frontend/src/pages/settings/social.vue | 15 + apps/frontend/src/plugins/cosmetics.ts | 1 + apps/frontend/src/plugins/i18n.ts | 9 +- apps/frontend/src/plugins/theme/index.ts | 11 +- .../src/plugins/theme/theme-settings.ts | 7 + apps/frontend/src/providers/setup.ts | 18 +- apps/frontend/src/providers/setup/auth.ts | 1 + apps/labrinth/src/models/v3/preferences.rs | 27 + package.json | 9 +- .../api-client/src/modules/labrinth/types.ts | 63 ++ .../src/modules/labrinth/users/v3.ts | 37 ++ ...6f5b6a3155788880369af940fcd268d3cb94.json} | 18 +- ...c723b356263ffc83aabb645c9fb5b6d5aa7c.json} | 6 +- ...260818120000_sync-preferences-settings.sql | 5 + packages/app-lib/src/api/users.rs | 45 ++ packages/app-lib/src/state/settings.rs | 12 +- packages/ui/src/components/index.ts | 1 - .../ui/src/components/modal/TabbedModal.vue | 32 +- .../components/settings/LanguageSelector.vue | 250 -------- packages/ui/src/components/settings/index.ts | 2 - packages/ui/src/layouts/index.ts | 1 + .../components/AppearanceSettingRow.vue | 37 ++ .../components/ProjectLayoutSelector.vue | 76 +++ ...earance-settings-theme-selector.stories.ts | 31 + .../appearance-settings-theme-selector.vue} | 59 +- .../shared/appearance-settings/index.ts | 3 + .../shared/appearance-settings/layout.vue | 181 ++++++ .../shared/appearance-settings/messages.ts | 108 ++++ .../providers/appearance-settings.ts | 229 +++++++ .../appearance-settings/providers/index.ts | 1 + .../shared/appearance-settings/types.ts | 36 ++ .../src/layouts/shared/content-tab/layout.vue | 5 +- .../content-tab/providers/content-manager.ts | 2 +- packages/ui/src/layouts/wrapped/index.ts | 3 +- .../{ => settings}/AccountProfileSettings.vue | 0 .../{ => settings}/AccountSocialSettings.vue | 188 +++++- .../ui/src/layouts/wrapped/settings/index.ts | 3 + .../settings/language-settings/index.vue | 121 ++++ .../language-settings-coverage.generated.d.ts | 3 + .../language-settings-coverage.ts | 15 + .../language-settings-selector.vue | 335 ++++++++++ packages/ui/src/locales/de-CH/index.json | 3 - packages/ui/src/locales/de-DE/index.json | 3 - packages/ui/src/locales/en-US/index.json | 112 +++- packages/ui/src/locales/es-419/index.json | 3 - packages/ui/src/locales/es-ES/index.json | 3 - packages/ui/src/locales/fr-FR/index.json | 3 - packages/ui/src/locales/hu-HU/index.json | 3 - packages/ui/src/locales/it-IT/index.json | 3 - packages/ui/src/locales/ja-JP/index.json | 3 - packages/ui/src/locales/ko-KR/index.json | 3 - packages/ui/src/locales/nl-NL/index.json | 3 - packages/ui/src/locales/pl-PL/index.json | 3 - packages/ui/src/locales/pt-BR/index.json | 3 - packages/ui/src/locales/ru-RU/index.json | 3 - packages/ui/src/locales/sv-SE/index.json | 3 - packages/ui/src/locales/uk-UA/index.json | 3 - packages/ui/src/locales/zh-CN/index.json | 3 - packages/ui/src/locales/zh-TW/index.json | 3 - packages/ui/src/providers/i18n.ts | 2 +- packages/ui/src/providers/index.ts | 1 + packages/ui/src/providers/user-preferences.ts | 116 ++++ packages/ui/src/utils/savable.ts | 12 +- pnpm-lock.yaml | 193 ++---- scripts/coverage-i18n.ts | 215 ++++++- scripts/run.mjs | 11 +- turbo.jsonc | 21 +- 191 files changed, 3356 insertions(+), 4372 deletions(-) create mode 100644 apps/app-frontend/src/composables/use-app-settings.ts create mode 100644 apps/app-frontend/src/composables/use-error.js create mode 100644 apps/app-frontend/src/composables/use-theme.ts create mode 100644 apps/app-frontend/src/helpers/user-preferences.ts create mode 100644 apps/app-frontend/src/providers/setup/user-preferences.ts delete mode 100644 apps/app-frontend/src/store/error.js delete mode 100644 apps/app-frontend/src/store/state.js delete mode 100644 apps/app-frontend/src/store/theme.ts rename packages/app-lib/.sqlx/{query-6f8b76b839db48539a70664af549c12be71df20b8cf520019413f6ea751cd594.json => query-29df6a29d9221b9bbea45e024fb26f5b6a3155788880369af940fcd268d3cb94.json} (90%) rename packages/app-lib/.sqlx/{query-dfdc99cb5ec60bb08c566920628deec7e741eca9490811ebad6594abe8a6126d.json => query-88c6a22aa112f10dce9d42779f06c723b356263ffc83aabb645c9fb5b6d5aa7c.json} (85%) create mode 100644 packages/app-lib/migrations/20260818120000_sync-preferences-settings.sql delete mode 100644 packages/ui/src/components/settings/LanguageSelector.vue delete mode 100644 packages/ui/src/components/settings/index.ts create mode 100644 packages/ui/src/layouts/shared/appearance-settings/components/AppearanceSettingRow.vue create mode 100644 packages/ui/src/layouts/shared/appearance-settings/components/ProjectLayoutSelector.vue create mode 100644 packages/ui/src/layouts/shared/appearance-settings/components/appearance-settings-theme-selector.stories.ts rename packages/ui/src/{components/settings/ThemeSelector.vue => layouts/shared/appearance-settings/components/appearance-settings-theme-selector.vue} (67%) create mode 100644 packages/ui/src/layouts/shared/appearance-settings/index.ts create mode 100644 packages/ui/src/layouts/shared/appearance-settings/layout.vue create mode 100644 packages/ui/src/layouts/shared/appearance-settings/messages.ts create mode 100644 packages/ui/src/layouts/shared/appearance-settings/providers/appearance-settings.ts create mode 100644 packages/ui/src/layouts/shared/appearance-settings/providers/index.ts create mode 100644 packages/ui/src/layouts/shared/appearance-settings/types.ts rename packages/ui/src/layouts/wrapped/{ => settings}/AccountProfileSettings.vue (100%) rename packages/ui/src/layouts/wrapped/{ => settings}/AccountSocialSettings.vue (69%) create mode 100644 packages/ui/src/layouts/wrapped/settings/index.ts create mode 100644 packages/ui/src/layouts/wrapped/settings/language-settings/index.vue create mode 100644 packages/ui/src/layouts/wrapped/settings/language-settings/language-settings-coverage.generated.d.ts create mode 100644 packages/ui/src/layouts/wrapped/settings/language-settings/language-settings-coverage.ts create mode 100644 packages/ui/src/layouts/wrapped/settings/language-settings/language-settings-selector.vue create mode 100644 packages/ui/src/providers/user-preferences.ts diff --git a/.github/workflows/frontend-deploy.yml b/.github/workflows/frontend-deploy.yml index 703431d240..79b73c57ef 100644 --- a/.github/workflows/frontend-deploy.yml +++ b/.github/workflows/frontend-deploy.yml @@ -125,8 +125,7 @@ jobs: run: pnpm install - name: Build frontend - working-directory: ./apps/frontend - run: pnpm build + run: pnpm web:build env: CF_PAGES_BRANCH: ${{ inputs.head_ref || github.ref_name }} CF_PAGES_COMMIT_SHA: ${{ inputs.head_sha || github.sha }} diff --git a/.github/workflows/frontend-preview.yml b/.github/workflows/frontend-preview.yml index df17e1786c..16e76136fd 100644 --- a/.github/workflows/frontend-preview.yml +++ b/.github/workflows/frontend-preview.yml @@ -70,10 +70,9 @@ jobs: run: pnpm install - name: Build Storybook - working-directory: ./packages/ui env: NODE_OPTIONS: --max-old-space-size=6144 - run: pnpm run build-storybook + run: pnpm build-storybook - name: Configure short SHA id: meta diff --git a/.gitignore b/.gitignore index 9d27dcaf5e..d442251099 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ Thumbs.db # frontend generated files apps/frontend/src/generated +/packages/ui/src/layouts/wrapped/settings/language-settings/language-settings-coverage.generated.ts .turbo target diff --git a/apps/app-frontend/package.json b/apps/app-frontend/package.json index 5a88bd2d92..abe6e55c0f 100644 --- a/apps/app-frontend/package.json +++ b/apps/app-frontend/package.json @@ -38,7 +38,6 @@ "intl-messageformat": "^10.7.7", "ofetch": "^1.3.4", "overlayscrollbars": "^2.15.1", - "pinia": "^3.0.0", "posthog-js": "^1.158.2", "three": "^0.172.0", "vite-svg-loader": "^5.1.0", diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index eeb37273f6..7456fa2dec 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -94,6 +94,9 @@ import SurveyPopup from '@/components/ui/SurveyPopup.vue' import WindowControls from '@/components/ui/WindowControls.vue' import { useCheckDisableMouseover } from '@/composables/macCssFix.js' import { useAppEvent } from '@/composables/use-app-event' +import { useAppSettings } from '@/composables/use-app-settings.ts' +import { useError } from '@/composables/use-error.js' +import { useTheme } from '@/composables/use-theme.ts' import { config } from '@/config' import { hide_ads_window, @@ -147,8 +150,7 @@ import { setupProviders } from '@/providers/setup' import { setupAppEventsProvider } from '@/providers/setup/app-events' import { setupAuthProvider } from '@/providers/setup/auth' import { setupLoadingStateProvider } from '@/providers/setup/loading-state' -import { useError } from '@/store/error.js' -import { useTheming } from '@/store/state' +import { setupAppUserPreferencesProvider } from '@/providers/setup/user-preferences.ts' import { appMessages } from '@/utils/app-messages' import { generateSkinPreviews } from './helpers/rendering/batch-skin-renderer' @@ -157,7 +159,8 @@ import { AppNotificationManager } from './providers/app-notifications' import { AppPopupNotificationManager } from './providers/app-popup-notifications' import { appSettingsModalOpenProfileKey } from './providers/app-settings-modal' -const themeStore = useTheming() +const appSettings = useAppSettings() +const appTheme = useTheme() const router = useRouter() const route = useRoute() const { channel: appEventChannel, events: appEvents } = setupAppEventsProvider() @@ -201,7 +204,7 @@ const credentials = ref() let credentialsRefreshId = 0 const sidebarToggled = ref(true) watch( - () => themeStore.toggleSidebar, + () => appSettings.toggleSidebar, (toggleSidebar) => { sidebarToggled.value = !toggleSidebar }, @@ -221,7 +224,7 @@ const hostingUpdateRequired = computed( appUpdateState.updatesEnabled.value, ) const prideFundraiserEnabled = computed( - () => themeStore.getFeatureFlag('pride_fundraiser') && Date.now() < PRIDE_FUNDRAISER_END_DATE, + () => appSettings.getFeatureFlag('pride_fundraiser') && Date.now() < PRIDE_FUNDRAISER_END_DATE, ) const hostingIntercomIdentityKey = computed(() => { const rawServerId = route.params.id @@ -324,13 +327,13 @@ providePageContext({ intercomBubble: hostingIntercom.intercomBubble, featureFlags: { serverRamAsBytesAlwaysOn: computed(() => - themeStore.getFeatureFlag('server_ram_as_bytes_always_on'), + appSettings.getFeatureFlag('server_ram_as_bytes_always_on'), ), }, openExternalUrl: (url) => void openUrl(url), }) provideModalBehavior({ - noblur: computed(() => !themeStore.advancedRendering), + noblur: computed(() => !appTheme.advancedRendering), onShow: () => take_ads_window_hold(), onHide: () => release_ads_window_hold(), }) @@ -634,10 +637,11 @@ async function setupApp() { theme, locale, telemetry, - collapsed_navigation, hide_nametag_skins_page, advanced_rendering, toggle_sidebar, + sync_theme_across_devices, + sync_behavior_across_devices, developer_mode, feature_flags, pending_update_toast_for_version, @@ -655,13 +659,14 @@ async function setupApp() { nativeDecorations.value = native_decorations if (os.value !== 'MacOS') await getCurrentWindow().setDecorations(native_decorations) - themeStore.setThemeState(theme) - themeStore.collapsedNavigation = collapsed_navigation - themeStore.advancedRendering = advanced_rendering - themeStore.hideNametagSkinsPage = hide_nametag_skins_page - themeStore.toggleSidebar = toggle_sidebar - themeStore.devMode = developer_mode - themeStore.featureFlags = feature_flags + appTheme.preferred = theme + appTheme.advancedRendering = advanced_rendering + appTheme.syncAcrossDevices = sync_theme_across_devices + appSettings.syncBehaviorAcrossDevices = sync_behavior_across_devices + appSettings.hideNametagSkinsPage = hide_nametag_skins_page + appSettings.toggleSidebar = toggle_sidebar + appSettings.devMode = developer_mode + Object.assign(appSettings.featureFlags, feature_flags) stateInitialized.value = true isMaximized.value = await getCurrentWindow().isMaximized() @@ -959,7 +964,7 @@ watch(incompatibilityWarningModal, (modal) => { } }) -setupAuthProvider(credentials, async (_redirectPath, flow, options) => { +const authProvider = setupAuthProvider(credentials, async (_redirectPath, flow, options) => { if (options?.showModal === false) { await signIn(flow) } else { @@ -967,6 +972,79 @@ setupAuthProvider(credentials, async (_redirectPath, flow, options) => { } }) +const userPreferences = setupAppUserPreferencesProvider(authProvider, notificationManager) +let userPreferencesSync = Promise.resolve() + +watch( + [userPreferences.preferences, stateInitialized], + ([preferences, initialized]) => { + if (!preferences || !initialized) return + + userPreferencesSync = userPreferencesSync + .then(async () => { + const settings = await getSettings() + const selectedTheme = preferences.appearance.auto ? 'system' : preferences.appearance.theme + const locale = preferences.localization.locale + const behavior = preferences.behavior + let settingsChanged = false + + if (appTheme.syncAcrossDevices && appTheme.preferred !== selectedTheme) { + appTheme.preferred = selectedTheme + } + if (i18n.global.locale.value !== locale) { + i18n.global.locale.value = locale + } + + if (appTheme.syncAcrossDevices && settings.theme !== selectedTheme) { + settings.theme = selectedTheme + settingsChanged = true + } + if (settings.locale !== locale) { + settings.locale = locale + settingsChanged = true + } + + if (behavior && appSettings.syncBehaviorAcrossDevices) { + const behaviorFeatureFlags = { + worlds_in_home: behavior.show_jump_in, + show_instance_play_time: behavior.show_play_time, + skip_unknown_pack_warning: !behavior.warn_on_unknown_modpacks, + skip_non_essential_warnings: behavior.skip_non_essential_warnings, + } + + appSettings.toggleSidebar = behavior.hide_right_sidebar + appSettings.hideNametagSkinsPage = behavior.hide_nametag + Object.assign(appSettings.featureFlags, behaviorFeatureFlags) + + if (settings.hide_on_process_start !== behavior.minimize_app) { + settings.hide_on_process_start = behavior.minimize_app + settingsChanged = true + } + if (settings.toggle_sidebar !== behavior.hide_right_sidebar) { + settings.toggle_sidebar = behavior.hide_right_sidebar + settingsChanged = true + } + if (settings.hide_nametag_skins_page !== behavior.hide_nametag) { + settings.hide_nametag_skins_page = behavior.hide_nametag + settingsChanged = true + } + for (const [flag, value] of Object.entries(behaviorFeatureFlags)) { + if (settings.feature_flags[flag] !== value) { + settings.feature_flags[flag] = value + settingsChanged = true + } + } + } + + if (settingsChanged) { + await setSettings(settings) + } + }) + .catch(handleError) + }, + { immediate: true }, +) + async function validateSession(sessionToken) { try { const response = await tauriFetch(`${config.labrinthBaseUrl}/v2/user`, { @@ -1642,7 +1720,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
@@ -1867,7 +1945,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
{{ route.fullPath }} diff --git a/apps/app-frontend/src/components/ui/AccountsCard.vue b/apps/app-frontend/src/components/ui/AccountsCard.vue index ac9136f6c2..9e3631192d 100644 --- a/apps/app-frontend/src/components/ui/AccountsCard.vue +++ b/apps/app-frontend/src/components/ui/AccountsCard.vue @@ -107,6 +107,7 @@ import type { Ref } from 'vue' import { computed, ref } from 'vue' import { useAppEvent } from '@/composables/use-app-event' +import { handleSevereError } from '@/composables/use-error.js' import { trackEvent } from '@/helpers/analytics' import { get_default_user, @@ -118,7 +119,6 @@ import { import { getPlayerHeadUrl } from '@/helpers/rendering/batch-skin-renderer.ts' import type { Skin } from '@/helpers/skins' import { get_available_skins } from '@/helpers/skins' -import { handleSevereError } from '@/store/error.js' const { formatMessage } = useVIntl() const { handleError } = injectNotificationManager() diff --git a/apps/app-frontend/src/components/ui/ErrorModal.vue b/apps/app-frontend/src/components/ui/ErrorModal.vue index 475c1f3f76..efac61720c 100644 --- a/apps/app-frontend/src/components/ui/ErrorModal.vue +++ b/apps/app-frontend/src/components/ui/ErrorModal.vue @@ -20,11 +20,11 @@ import { computed, ref } from 'vue' import { ChatIcon } from '@/assets/icons' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' +import { handleSevereError } from '@/composables/use-error.js' import { trackEvent } from '@/helpers/analytics' import { login as login_flow, set_default_user } from '@/helpers/auth.js' import { install_existing_instance } from '@/helpers/install' import { cancel_directory_change } from '@/helpers/settings.ts' -import { handleSevereError } from '@/store/error.js' const { handleError } = injectNotificationManager() diff --git a/apps/app-frontend/src/components/ui/Instance.vue b/apps/app-frontend/src/components/ui/Instance.vue index 2bc32b67fc..9f8338df6d 100644 --- a/apps/app-frontend/src/components/ui/Instance.vue +++ b/apps/app-frontend/src/components/ui/Instance.vue @@ -20,12 +20,12 @@ import { computed, onMounted, ref } from 'vue' import { useRouter } from 'vue-router' import { useAppEvent } from '@/composables/use-app-event' +import { handleSevereError } from '@/composables/use-error.js' import { trackEvent } from '@/helpers/analytics' import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install' import { getInstanceIconUrl, kill, run } from '@/helpers/instance' import { get_by_instance_id } from '@/helpers/process' import { showInstanceInFolder } from '@/helpers/utils.js' -import { handleSevereError } from '@/store/error.js' const { handleError } = injectNotificationManager() const { formatMessage } = useVIntl() diff --git a/apps/app-frontend/src/components/ui/WindowControls.vue b/apps/app-frontend/src/components/ui/WindowControls.vue index 81797ba5fa..a10ccffff5 100644 --- a/apps/app-frontend/src/components/ui/WindowControls.vue +++ b/apps/app-frontend/src/components/ui/WindowControls.vue @@ -39,17 +39,17 @@ import { getCurrentWindow } from '@tauri-apps/api/window' import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state' import { computed, onMounted, onUnmounted, ref } from 'vue' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { get as getSettings } from '@/helpers/settings.ts' import { getOS } from '@/helpers/utils.js' -import { useTheming } from '@/store/state' -const themeStore = useTheming() +const appSettings = useAppSettings() const nativeDecorations = ref(true) const isMaximized = ref(false) const os = ref('') -const alwaysShowAppControls = computed(() => themeStore.getFeatureFlag('always_show_app_controls')) +const alwaysShowAppControls = computed(() => appSettings.getFeatureFlag('always_show_app_controls')) const showControls = computed( () => diff --git a/apps/app-frontend/src/components/ui/friends/FriendsList.vue b/apps/app-frontend/src/components/ui/friends/FriendsList.vue index 705b3c16a1..7294781e87 100644 --- a/apps/app-frontend/src/components/ui/friends/FriendsList.vue +++ b/apps/app-frontend/src/components/ui/friends/FriendsList.vue @@ -15,17 +15,17 @@ import { computed, ref } from 'vue' import FriendsSection from '@/components/ui/friends/FriendsSection.vue' import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { useFriends } from '@/composables/use-friends' import type { FriendWithUserData } from '@/helpers/friends.ts' import type { ModrinthCredentials } from '@/helpers/mr_auth' import { get as getSettings, set as setSettings } from '@/helpers/settings.ts' -import { useTheming } from '@/store/state' const { formatMessage } = useVIntl() const { handleError } = injectNotificationManager() const formatRelativeTime = useRelativeTime() -const themeStore = useTheming() +const appSettings = useAppSettings() const props = defineProps<{ credentials: ModrinthCredentials | null @@ -39,11 +39,11 @@ type FriendsSectionCollapsedFlag = | 'friends_pending_collapsed' function isFriendsSectionCollapsed(flag: FriendsSectionCollapsedFlag) { - return themeStore.getFeatureFlag(flag) + return appSettings.getFeatureFlag(flag) } function setFriendsSectionCollapsed(flag: FriendsSectionCollapsedFlag, collapsed: boolean) { - themeStore.featureFlags[flag] = collapsed + appSettings.featureFlags[flag] = collapsed getSettings() .then((settings) => { settings.feature_flags[flag] = collapsed diff --git a/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue b/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue index f1b929e050..b1063c805d 100644 --- a/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue +++ b/apps/app-frontend/src/components/ui/install_flow/UnknownPackWarningModal.vue @@ -13,11 +13,10 @@ import { UnknownFileWarningModal } from '@modrinth/ui' import { ref, useTemplateRef } from 'vue' +import { type FeatureFlag, useAppSettings } from '@/composables/use-app-settings.ts' import { get as getSettings, set as setSettings } from '@/helpers/settings' -import { useTheming } from '@/store/state' -import type { FeatureFlag } from '@/store/theme.ts' -const themeStore = useTheming() +const appSettings = useAppSettings() const skipUnknownPackWarningFeatureFlag = 'skip_unknown_pack_warning' as FeatureFlag const modal = useTemplateRef('modal') @@ -34,7 +33,7 @@ function show( fileName.value = selectedFileName externalFilesInModpack.value = selectedExternalFiles - if (themeStore.getFeatureFlag(skipUnknownPackWarningFeatureFlag)) { + if (appSettings.getFeatureFlag(skipUnknownPackWarningFeatureFlag)) { void createInstance() return } @@ -50,7 +49,7 @@ function reset() { async function proceed(dontShowAgain: boolean) { if (dontShowAgain) { - themeStore.featureFlags[skipUnknownPackWarningFeatureFlag] = true + appSettings.featureFlags[skipUnknownPackWarningFeatureFlag] = true const settings = await getSettings() settings.feature_flags[skipUnknownPackWarningFeatureFlag] = true await setSettings(settings) diff --git a/apps/app-frontend/src/components/ui/library/instance-group/instance-card.vue b/apps/app-frontend/src/components/ui/library/instance-group/instance-card.vue index 814cab72b4..49e2a15b36 100644 --- a/apps/app-frontend/src/components/ui/library/instance-group/instance-card.vue +++ b/apps/app-frontend/src/components/ui/library/instance-group/instance-card.vue @@ -9,13 +9,13 @@ import { useRouter } from 'vue-router' import InstanceCardView from '@/components/ui/library/instance-group/instance-card-view.vue' import { getLibraryInstanceSelectionKey, useLibrary } from '@/components/ui/library/use-library' import { useAppEvent } from '@/composables/use-app-event' +import { handleSevereError } from '@/composables/use-error.js' import { trackEvent } from '@/helpers/analytics' import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install' import { kill, run } from '@/helpers/instance' import { get_by_instance_id } from '@/helpers/process' import type { GameInstance } from '@/helpers/types' import { showInstanceInFolder } from '@/helpers/utils.js' -import { handleSevereError } from '@/store/error.js' type ProcessEvent = 'installing' | 'launched' | 'finished' diff --git a/apps/app-frontend/src/components/ui/library/library-toolbar/sort-menu.vue b/apps/app-frontend/src/components/ui/library/library-toolbar/sort-menu.vue index c24b5e26ba..457800e1ff 100644 --- a/apps/app-frontend/src/components/ui/library/library-toolbar/sort-menu.vue +++ b/apps/app-frontend/src/components/ui/library/library-toolbar/sort-menu.vue @@ -15,6 +15,8 @@ const { formatMessage } = useVIntl() const messages = defineMessages({ name: { id: 'app.library.sort.name', defaultMessage: 'Name' }, + loaderSort: { id: 'app.library.sort.loader', defaultMessage: 'Loader' }, + gameVersionSort: { id: 'app.library.sort.game-version', defaultMessage: 'Game version' }, lastPlayed: { id: 'app.library.sort.last-played', defaultMessage: 'Last played' }, hoursPlayed: { id: 'app.library.sort.hours-played', defaultMessage: 'Hours played' }, dateCreated: { id: 'app.library.sort.date-created', defaultMessage: 'Date created' }, @@ -34,6 +36,8 @@ const sortLabels = { 'Hours played': messages.hoursPlayed, 'Date created': messages.dateCreated, 'Date modified': messages.dateModified, + Loader: messages.loaderSort, + 'Game version': messages.gameVersionSort, } const groupLabels = { @@ -60,6 +64,7 @@ const groupOptions: ComboboxOption[] = libraryGroupOptions.map(( class="w-max" :options="sortOptions" :show-icon-in-selected="false" + :max-height="320" dropdown-min-width="160px" >
-

+

{{ formatMessage(developerModeEnabled) }}

@@ -306,8 +317,8 @@ const messages = defineMessages({ :aria-label="formatMessage(messages.developerModeButtonLabel)" class="p-0 m-0 bg-transparent border-none cursor-pointer button-animation" :class="{ - 'text-brand': themeStore.devMode, - 'text-secondary': !themeStore.devMode, + 'text-brand': appSettings.devMode, + 'text-secondary': !appSettings.devMode, }" @click="devModeCount" > diff --git a/apps/app-frontend/src/components/ui/settings/account/SocialSettings.vue b/apps/app-frontend/src/components/ui/settings/account/SocialSettings.vue index 15bb622c17..f74eae6598 100644 --- a/apps/app-frontend/src/components/ui/settings/account/SocialSettings.vue +++ b/apps/app-frontend/src/components/ui/settings/account/SocialSettings.vue @@ -1,5 +1,6 @@