ui: Stores consolidation refactor (#27238)

* ui: Remove dead code from stores

- persisted() helper was exported but never used
- messageUpdateCallback / registerMessageUpdateCallback were never wired up
- conversationsStore.initialize() alias, single caller moved to init()

* ui: Merge device, theme and viewport into a single deviceStore

All three are reactive browser-environment signals, now exposed as one
class store: deviceStore.isMobile, deviceStore.isIOSDevice / isIOSSafari
/ isWKWebView / isStandalone and deviceStore.systemTheme.isDark. The
systemTheme name disambiguates the OS preference from the user theme
preference in settingsStore. Drops the unused viewport export (only
isMobile was consumed).

* ui: Merge build info into version store

One VersionStore class with build (llama.cpp build number from
build.json) and frontend (PWA version from _app/version.json),
matching the class pattern of the other stores.

* ui: Colocate context gauge popup state with its components

The gauge popup state is local UI state shared only by the
ChatFormContextGauge subtree, so it lives next to its consumers
instead of the app-scope stores barrel.
This commit is contained in:
Aleksander Grygier
2026-08-18 16:37:26 +02:00
committed by GitHub
parent 04b569142d
commit fdf4c64604
28 changed files with 181 additions and 303 deletions
+1 -1
View File
@@ -77,7 +77,7 @@
onMount(async () => {
if (!conversationsStore.isInitialized) {
await conversationsStore.initialize();
await conversationsStore.init();
}
conversationsStore.clearActiveConversation();
+7 -8
View File
@@ -19,15 +19,14 @@
import { usePwa } from '$lib/hooks/use-pwa.svelte';
import { RouterService } from '$lib/services/router.service';
import {
buildInfoStore,
chatStore,
conversationsStore,
isMobile,
deviceStore,
mcpStore,
modelsStore,
serverStore,
settingsStore,
theme
versionStore
} from '$lib/stores';
import { ModeWatcher } from 'mode-watcher';
import { untrack } from 'svelte';
@@ -55,7 +54,7 @@
const { needRefresh, updateServiceWorker } = pwa;
function updateFavicon() {
const dark = theme.isSystemDark;
const dark = deviceStore.systemTheme.isDark;
let icoLink = document.querySelector(FAVICON_SELECTORS.ICO_48X48) as HTMLLinkElement | null;
@@ -153,7 +152,7 @@
}
$effect(() => {
void theme.isSystemDark;
void deviceStore.systemTheme.isDark;
updateFavicon();
});
@@ -274,7 +273,7 @@
<div class="flex flex-col md:flex-row">
<SidebarNavigation
onSearchClick={() => {
if (isMobile.current) {
if (deviceStore.isMobile) {
goto(ROUTES.SEARCH);
} else if (chatSidebar?.activateSearchMode) {
chatSidebar.activateSearchMode();
@@ -294,8 +293,8 @@
<!-- PWA update prompt + version -->
<div class="fixed right-4 bottom-4 z-9999 flex flex-col items-end gap-1">
{#if showBuildVersion && buildInfoStore.value}
<span class="text-[10px] tabular-nums text-muted-foreground">{buildInfoStore.value}</span>
{#if showBuildVersion && versionStore.build}
<span class="text-[10px] tabular-nums text-muted-foreground">{versionStore.build}</span>
{/if}
<PwaRefreshAlert
+2 -2
View File
@@ -5,7 +5,7 @@
import { SearchInput, SidebarNavigationSearchResults } from '$lib/components/app';
import { ROUTES } from '$lib/constants';
import { RouterService } from '$lib/services/router.service';
import { chatStore, conversationsStore, isMobile } from '$lib/stores';
import { chatStore, conversationsStore, deviceStore } from '$lib/stores';
let searchQuery = $state('');
let searchInputRef = $state<HTMLInputElement | null>(null);
@@ -23,7 +23,7 @@
// Search page is intended for mobile; on desktop the sidebar already exposes
// in-place search, so bounce back to a chat.
$effect(() => {
if (browser && !isMobile.current) {
if (browser && !deviceStore.isMobile) {
goto(ROUTES.NEW_CHAT, { replaceState: true });
}
});