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:
+2
-2
@@ -2,10 +2,10 @@
|
||||
import ChatFormActionAddButton from './ChatFormActionAddButton.svelte';
|
||||
import ChatFormActionAddDropdown from './ChatFormActionAddDropdown.svelte';
|
||||
import ChatFormActionAddSheet from './ChatFormActionAddSheet.svelte';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { deviceStore } from '$lib/stores';
|
||||
</script>
|
||||
|
||||
{#if isMobile.current}
|
||||
{#if deviceStore.isMobile}
|
||||
<ChatFormActionAddSheet>
|
||||
{#snippet trigger({ disabled, onclick })}
|
||||
<ChatFormActionAddButton {disabled} {onclick} />
|
||||
|
||||
+8
-2
@@ -1,6 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { ModelsSelectorDropdown, ModelsSelectorSheet } from '$lib/components/app';
|
||||
import { chatStore, conversationsStore, isMobile, modelsStore, serverStore } from '$lib/stores';
|
||||
import {
|
||||
chatStore,
|
||||
conversationsStore,
|
||||
deviceStore,
|
||||
modelsStore,
|
||||
serverStore
|
||||
} from '$lib/stores';
|
||||
|
||||
interface Props {
|
||||
disabled?: boolean;
|
||||
@@ -170,7 +176,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if isMobile.current}
|
||||
{#if deviceStore.isMobile}
|
||||
<ModelsSelectorSheet
|
||||
disabled={disabled || isOffline}
|
||||
bind:this={selectorModelRef}
|
||||
|
||||
+3
-4
@@ -1,15 +1,14 @@
|
||||
<script lang="ts">
|
||||
import ContextGaugeDial from './ContextGaugeDial.svelte';
|
||||
import { useContextGauge } from '$lib/hooks/use-context-gauge.svelte';
|
||||
import {
|
||||
chatStore,
|
||||
conversationsStore,
|
||||
gaugeTriggerClick,
|
||||
gaugeTriggerEnter,
|
||||
gaugeTriggerKeydown,
|
||||
gaugeTriggerLeave,
|
||||
gaugeTriggerPointerDown
|
||||
} from '$lib/stores';
|
||||
} from './gauge-popup.svelte';
|
||||
import { useContextGauge } from '$lib/hooks/use-context-gauge.svelte';
|
||||
import { chatStore, conversationsStore } from '$lib/stores';
|
||||
import { untrack } from 'svelte';
|
||||
|
||||
const gauge = useContextGauge();
|
||||
|
||||
+1
-1
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import ContextGaugeDetailRow from './ContextGaugeDetailRow.svelte';
|
||||
import { gaugePopup } from './gauge-popup.svelte';
|
||||
import { ChevronDown } from '@lucide/svelte';
|
||||
import * as Collapsible from '$lib/components/ui/collapsible';
|
||||
import { STATS_UNITS } from '$lib/constants';
|
||||
import { gaugePopup } from '$lib/stores/context-gauge-popup.svelte';
|
||||
|
||||
interface Props {
|
||||
currentRead: number;
|
||||
|
||||
+6
-1
@@ -2,8 +2,13 @@
|
||||
import { colorLevelBgClass, colorLevelTextClass } from './context-gauge';
|
||||
import ContextGaugeDetails from './ContextGaugeDetails.svelte';
|
||||
import ContextGaugeLoadModel from './ContextGaugeLoadModel.svelte';
|
||||
import {
|
||||
gaugeCardEnter,
|
||||
gaugeCardLeave,
|
||||
gaugePopup,
|
||||
gaugePopupClose
|
||||
} from './gauge-popup.svelte';
|
||||
import { useContextGauge } from '$lib/hooks/use-context-gauge.svelte';
|
||||
import { gaugeCardEnter, gaugeCardLeave, gaugePopup, gaugePopupClose } from '$lib/stores';
|
||||
import { formatParameters } from '$lib/utils/formatters';
|
||||
|
||||
const gauge = useContextGauge();
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
// Shared state for the context gauge popup. The dial and the card live in
|
||||
// different DOM subtrees, so open state and placement are coordinated here.
|
||||
// centerX and bottom place the card just above the dial: both are measured
|
||||
// once at open time, relative to the closest form ancestor; the dial and
|
||||
// the card share that positioning frame, so the values stay exact for the
|
||||
// whole time the card is open.
|
||||
// Mouse pointers open on hover with a short grace delay to travel from
|
||||
// dial to card; touch pointers toggle on tap.
|
||||
import {
|
||||
CONTEXT_GAUGE_CARD_HALF_WIDTH_PX,
|
||||
CONTEXT_GAUGE_CLOSE_GRACE_MS,
|
||||
CONTEXT_GAUGE_DIAL_GAP_PX,
|
||||
CONTEXT_GAUGE_EDGE_MARGIN_PX
|
||||
} from '$lib/constants';
|
||||
|
||||
let closeTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
let lastPointerType = '';
|
||||
|
||||
export const gaugePopup = $state({ bottom: 0, centerX: 0, detailsOpen: false, open: false });
|
||||
|
||||
function openFrom(trigger: HTMLElement): void {
|
||||
clearTimeout(closeTimer);
|
||||
const frame = trigger.closest('form');
|
||||
|
||||
if (frame) {
|
||||
const frameRect = frame.getBoundingClientRect();
|
||||
const triggerRect = trigger.getBoundingClientRect();
|
||||
const centerX = triggerRect.left + triggerRect.width / 2 - frameRect.left;
|
||||
const min = CONTEXT_GAUGE_CARD_HALF_WIDTH_PX + CONTEXT_GAUGE_EDGE_MARGIN_PX;
|
||||
const max = frameRect.width - CONTEXT_GAUGE_CARD_HALF_WIDTH_PX - CONTEXT_GAUGE_EDGE_MARGIN_PX;
|
||||
|
||||
gaugePopup.centerX = Math.min(Math.max(centerX, min), Math.max(min, max));
|
||||
gaugePopup.bottom = frameRect.bottom - triggerRect.top + CONTEXT_GAUGE_DIAL_GAP_PX;
|
||||
}
|
||||
|
||||
gaugePopup.open = true;
|
||||
}
|
||||
|
||||
function toggleFrom(trigger: HTMLElement): void {
|
||||
if (gaugePopup.open) {
|
||||
clearTimeout(closeTimer);
|
||||
gaugePopup.open = false;
|
||||
} else {
|
||||
openFrom(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
export function gaugePopupClose(): void {
|
||||
clearTimeout(closeTimer);
|
||||
gaugePopup.open = false;
|
||||
}
|
||||
|
||||
export function gaugeTriggerPointerDown(event: PointerEvent): void {
|
||||
lastPointerType = event.pointerType;
|
||||
}
|
||||
|
||||
export function gaugeTriggerClick(event: MouseEvent): void {
|
||||
if (lastPointerType !== 'touch') return;
|
||||
|
||||
toggleFrom(event.currentTarget as HTMLElement);
|
||||
}
|
||||
|
||||
export function gaugeTriggerKeydown(event: KeyboardEvent): void {
|
||||
if (event.key !== 'Enter' && event.key !== ' ') return;
|
||||
|
||||
event.preventDefault();
|
||||
toggleFrom(event.currentTarget as HTMLElement);
|
||||
}
|
||||
|
||||
export function gaugeTriggerEnter(event: PointerEvent): void {
|
||||
if (event.pointerType !== 'mouse') return;
|
||||
|
||||
openFrom(event.currentTarget as HTMLElement);
|
||||
}
|
||||
|
||||
export function gaugeTriggerLeave(event: PointerEvent): void {
|
||||
if (event.pointerType !== 'mouse') return;
|
||||
|
||||
scheduleClose();
|
||||
}
|
||||
|
||||
export function gaugeCardEnter(event: PointerEvent): void {
|
||||
if (event.pointerType !== 'mouse') return;
|
||||
|
||||
clearTimeout(closeTimer);
|
||||
}
|
||||
|
||||
export function gaugeCardLeave(event: PointerEvent): void {
|
||||
if (event.pointerType !== 'mouse') return;
|
||||
|
||||
scheduleClose();
|
||||
}
|
||||
|
||||
function scheduleClose(): void {
|
||||
clearTimeout(closeTimer);
|
||||
closeTimer = setTimeout(() => {
|
||||
gaugePopup.open = false;
|
||||
}, CONTEXT_GAUGE_CLOSE_GRACE_MS);
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { deviceStore } from '$lib/stores';
|
||||
import { autoResizeTextarea } from '$lib/utils';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
|
||||
export function focus() {
|
||||
if (isMobile.current) return;
|
||||
if (deviceStore.isMobile) return;
|
||||
|
||||
textareaElement?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { CODE_BLOCK, CODE_TOKEN_ATTR, UI_DATA_ATTRS } from '$lib/constants';
|
||||
import { BooleanString, ChatFormInputRichTokenKind, ColorMode } from '$lib/enums';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { deviceStore } from '$lib/stores';
|
||||
import type { ChatFormInputRichToken } from '$lib/types';
|
||||
import type { SourceHistoryEntry } from '$lib/utils';
|
||||
import {
|
||||
@@ -750,7 +750,7 @@
|
||||
syncEmptyState();
|
||||
document.addEventListener('selectionchange', handleSelectionChange);
|
||||
|
||||
if (!isMobile.current) {
|
||||
if (!deviceStore.isMobile) {
|
||||
rootElement?.focus({ preventScroll: true });
|
||||
}
|
||||
});
|
||||
@@ -792,7 +792,7 @@
|
||||
}
|
||||
|
||||
export function focus() {
|
||||
if (isMobile.current) return;
|
||||
if (deviceStore.isMobile) return;
|
||||
|
||||
rootElement?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
import { BuiltInTool, FileMentionEntryType, GlobSearchType, KeyboardKey } from '$lib/enums';
|
||||
import { useDebouncedSearch } from '$lib/hooks/use-debounced-search.svelte';
|
||||
import { usePickerNavigation } from '$lib/hooks/use-picker-navigation.svelte';
|
||||
import { isMobile, settingsStore, toolsStore } from '$lib/stores';
|
||||
import { deviceStore, settingsStore, toolsStore } from '$lib/stores';
|
||||
import type { FileMentionEntry, GlobEntryResult } from '$lib/types';
|
||||
import { abbreviateHome, runGlobSearchWithChildren } from '$lib/utils';
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
return searchError ? `Search failed - ${searchError}` : 'No matching files or folders';
|
||||
});
|
||||
|
||||
const showTooltip = $derived(!isMobile.current);
|
||||
const showTooltip = $derived(!deviceStore.isMobile);
|
||||
|
||||
$effect(() => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import { setChatMessageActionsContext, setChatMessageEditContext } from '$lib/contexts';
|
||||
import { AgenticSectionType, AttachmentType, MessageRole } from '$lib/enums';
|
||||
import { DatabaseService } from '$lib/services/database.service';
|
||||
import { chatStore, conversationsStore, isMobile } from '$lib/stores';
|
||||
import { chatStore, conversationsStore, deviceStore } from '$lib/stores';
|
||||
import type {
|
||||
ChatMessageActions,
|
||||
ChatMessageDeletionInfo,
|
||||
@@ -304,7 +304,7 @@
|
||||
|
||||
// After the system message flow ends, hand focus to the main chat form
|
||||
function focusMainChatForm() {
|
||||
if (isMobile.current) return;
|
||||
if (deviceStore.isMobile) return;
|
||||
|
||||
document.querySelector<HTMLTextAreaElement>('.chat-screen-form-wrapper textarea')?.focus();
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
import {
|
||||
chatStore,
|
||||
conversationsStore,
|
||||
device,
|
||||
isMobile,
|
||||
deviceStore,
|
||||
serverStore,
|
||||
settingsStore
|
||||
} from '$lib/stores';
|
||||
@@ -32,7 +31,7 @@
|
||||
let { showCenteredEmpty = false } = $props();
|
||||
|
||||
let disableAutoScroll = $derived(
|
||||
Boolean(settingsStore.config.disableAutoScroll) || isMobile.current
|
||||
Boolean(settingsStore.config.disableAutoScroll) || deviceStore.isMobile
|
||||
);
|
||||
let isMobileUserScrolledUp = $state(false);
|
||||
let mobileScrollDownHint = $state(false);
|
||||
@@ -52,11 +51,11 @@
|
||||
let hasPropsError = $derived(!!serverStore.error);
|
||||
let isCurrentConversationLoading = $derived(chatStore.isLoading || chatStore.isStreaming());
|
||||
let chatFormBottomPosition = $derived.by(() => {
|
||||
if (!isMobile.current) return '1rem';
|
||||
if (!deviceStore.isMobile) return '1rem';
|
||||
|
||||
if (device.isStandalone) return '1.5rem';
|
||||
if (deviceStore.isStandalone) return '1.5rem';
|
||||
|
||||
if (device.isIOSSafari) return '0.25rem';
|
||||
if (deviceStore.isIOSSafari) return '0.25rem';
|
||||
|
||||
return '0.5rem';
|
||||
});
|
||||
@@ -84,7 +83,7 @@
|
||||
});
|
||||
|
||||
function handleMobileScroll() {
|
||||
if (!isMobile.current) return;
|
||||
if (!deviceStore.isMobile) return;
|
||||
|
||||
const container = scroll.chatScrollContainer;
|
||||
|
||||
@@ -184,7 +183,7 @@
|
||||
}
|
||||
|
||||
function handleSendLikeScroll() {
|
||||
if (!isMobile.current) {
|
||||
if (!deviceStore.isMobile) {
|
||||
autoScroll.enable();
|
||||
}
|
||||
|
||||
@@ -197,7 +196,7 @@
|
||||
'.chat-message:nth-last-child(2) .chat-message-user .chat-message-user-bubble'
|
||||
) as HTMLElement | null;
|
||||
|
||||
if (isMobile.current) {
|
||||
if (deviceStore.isMobile) {
|
||||
// Keep the last user message bubble just above the input on mobile
|
||||
const bubbleHeight = lastUserBubble?.scrollHeight ?? 0;
|
||||
const baseHeight = container.scrollHeight - innerHeight;
|
||||
@@ -220,7 +219,7 @@
|
||||
}
|
||||
}, 100);
|
||||
|
||||
if (isMobile.current) {
|
||||
if (deviceStore.isMobile) {
|
||||
autoScroll.setDisabled(disableAutoScroll);
|
||||
mobileScrollDownHint = true;
|
||||
mobileScrollDownHintLockedUntil = Date.now() + 500;
|
||||
@@ -243,7 +242,8 @@
|
||||
|
||||
$effect(() => {
|
||||
const shouldDisableAutoScroll =
|
||||
settingsStore.config.disableAutoScroll || (isMobile.current && isCurrentConversationLoading);
|
||||
settingsStore.config.disableAutoScroll ||
|
||||
(deviceStore.isMobile && isCurrentConversationLoading);
|
||||
|
||||
autoScroll.setDisabled(shouldDisableAutoScroll);
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
autoScroll.enable();
|
||||
}
|
||||
|
||||
if (isMobile.current && isCurrentConversationLoading) {
|
||||
if (deviceStore.isMobile && isCurrentConversationLoading) {
|
||||
mobileScrollDownHint = true;
|
||||
mobileScrollDownHintLockedUntil = Date.now() + 500;
|
||||
}
|
||||
@@ -318,9 +318,9 @@
|
||||
<div
|
||||
class={[
|
||||
'pointer-events-none md:sticky fixed mt-auto transition-all duration-200',
|
||||
device.isStandalone
|
||||
deviceStore.isStandalone
|
||||
? 'bottom-6 right-4 left-4'
|
||||
: device.isIOSSafari
|
||||
: deviceStore.isIOSSafari
|
||||
? 'bottom-1 left-2 right-2'
|
||||
: 'bottom-2 right-2 left-2',
|
||||
isEmpty ? 'md:bottom-[calc(50dvh-7rem)] 2xl:bottom-[calc(50dvh-4rem)]' : 'md:bottom-4'
|
||||
@@ -336,7 +336,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="pointer-events-none flex flex-col gap-6 items-center w-full">
|
||||
{#if (isMobile.current ? mobileScrollDownHint || isMobileUserScrolledUp : autoScroll.userScrolledUp) && page.url.hash.includes(ROUTES.CHAT) && page.params.id}
|
||||
{#if (deviceStore.isMobile ? mobileScrollDownHint || isMobileUserScrolledUp : autoScroll.userScrolledUp) && page.url.hash.includes(ROUTES.CHAT) && page.params.id}
|
||||
<ChatScreenActionScrollDown
|
||||
onclick={() => {
|
||||
mobileScrollDownHint = false;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { page } from '$app/state';
|
||||
import { ChatForm } from '$lib/components/app';
|
||||
import { useDraftMessages } from '$lib/hooks/use-draft-messages.svelte';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { deviceStore } from '$lib/stores';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
@@ -120,13 +120,13 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (!isMobile.current) {
|
||||
if (!deviceStore.isMobile) {
|
||||
setTimeout(focusFormUnlessCaptured, 100);
|
||||
}
|
||||
});
|
||||
|
||||
afterNavigate((navigation) => {
|
||||
if (navigation?.from != null && !isMobile.current) {
|
||||
if (navigation?.from != null && !deviceStore.isMobile) {
|
||||
setTimeout(focusFormUnlessCaptured, 100);
|
||||
}
|
||||
});
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@
|
||||
import { useKeyboardShortcuts } from '$lib/hooks/use-keyboard-shortcuts.svelte';
|
||||
import { useMarqueeSelection } from '$lib/hooks/use-marquee-selection.svelte';
|
||||
import { RouterService } from '$lib/services/router.service';
|
||||
import { chatStore, conversationsStore, device, isMobile, settingsStore } from '$lib/stores';
|
||||
import { chatStore, conversationsStore, deviceStore, settingsStore } from '$lib/stores';
|
||||
import { buildConversationTree } from '$lib/utils';
|
||||
import { circIn } from 'svelte/easing';
|
||||
import { SvelteSet } from 'svelte/reactivity';
|
||||
@@ -36,7 +36,7 @@
|
||||
let logoHovered = $state(false);
|
||||
|
||||
const isStripExpanded = $derived(isExpandedMode || hoveredTooltip !== null);
|
||||
const isOnMobile = $derived(isMobile.current);
|
||||
const isOnMobile = $derived(deviceStore.isMobile);
|
||||
const alwaysShowOnDesktop = $derived(settingsStore.config.alwaysShowSidebarOnDesktop as boolean);
|
||||
|
||||
$effect(() => {
|
||||
@@ -65,7 +65,7 @@
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (isMobile.current && page.url.hash.includes(ROUTES.SEARCH)) {
|
||||
if (deviceStore.isMobile && page.url.hash.includes(ROUTES.SEARCH)) {
|
||||
isExpandedMode = false;
|
||||
}
|
||||
});
|
||||
@@ -227,7 +227,7 @@
|
||||
}
|
||||
|
||||
async function selectConversation(id: string) {
|
||||
if (isMobile.current) {
|
||||
if (deviceStore.isMobile) {
|
||||
scheduleMobileCollapse();
|
||||
}
|
||||
|
||||
@@ -315,9 +315,9 @@
|
||||
'fixed md:sticky top-2 left-2 md:left-0 md:ml-2 md:mt-2 pt-2 z-10 w-[calc(100dvw-1rem)]',
|
||||
'md:h-[calc(100dvh-1.125rem)]',
|
||||
isExpandedMode &&
|
||||
(device.isStandalone
|
||||
(deviceStore.isStandalone
|
||||
? 'h-[calc(100dvh-2rem)]'
|
||||
: device.isIOSDevice
|
||||
: deviceStore.isIOSDevice
|
||||
? 'h-[calc(100dvh-0.5rem)]'
|
||||
: 'h-[calc(100dvh-1rem)]'),
|
||||
'rounded-3xl md:rounded-2xl',
|
||||
@@ -353,7 +353,7 @@
|
||||
|
||||
{#if isOnMobile || (isExpandedMode && !alwaysShowOnDesktop)}
|
||||
<div
|
||||
class="flex items-center transition-all duration-150 ease-out {isMobile.current &&
|
||||
class="flex items-center transition-all duration-150 ease-out {deviceStore.isMobile &&
|
||||
!isExpandedMode
|
||||
? 'opacity-0 h-0!'
|
||||
: ''}"
|
||||
@@ -361,7 +361,7 @@
|
||||
out:fade={{ duration: 100 }}
|
||||
>
|
||||
<ActionIcon
|
||||
icon={isMobile.current ? X : PanelLeftClose}
|
||||
icon={deviceStore.isMobile ? X : PanelLeftClose}
|
||||
size="lg"
|
||||
iconSize="h-4.5 w-4.5 md:h-4 md:w-4"
|
||||
class="backdrop-blur-none md:h-9 md:w-9 h-10 w-10 rounded-full mr-1 hover:bg-accent!"
|
||||
@@ -375,9 +375,9 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-2 flex min-h-0 flex-1 flex-col gap-4 md:gap-1 {isMobile.current
|
||||
class="mt-2 flex min-h-0 flex-1 flex-col gap-4 md:gap-1 {deviceStore.isMobile
|
||||
? 'transition-[opacity,height] duration-200 ease-out'
|
||||
: ''} {isMobile.current && !isExpandedMode ? 'opacity-0 !h-0' : ''}"
|
||||
: ''} {deviceStore.isMobile && !isExpandedMode ? 'opacity-0 !h-0' : ''}"
|
||||
in:fade={{ duration: 200 }}
|
||||
out:fade={{ duration: 200 }}
|
||||
>
|
||||
@@ -395,7 +395,7 @@
|
||||
isSearchModeActive = true;
|
||||
}}
|
||||
onNewChat={() => {
|
||||
if (isMobile.current) {
|
||||
if (deviceStore.isMobile) {
|
||||
scheduleMobileCollapse();
|
||||
}
|
||||
}}
|
||||
|
||||
+4
-4
@@ -12,7 +12,7 @@
|
||||
SIDEBAR_ACTIONS_ITEMS
|
||||
} from '$lib/constants';
|
||||
import { TooltipSide } from '$lib/enums';
|
||||
import { isMobile } from '$lib/stores';
|
||||
import { deviceStore } from '$lib/stores';
|
||||
import type { Component } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { circIn } from 'svelte/easing';
|
||||
@@ -42,7 +42,7 @@
|
||||
let showIcons = $state(false);
|
||||
let searchInputRef = $state<HTMLInputElement | null>(null);
|
||||
|
||||
const isOnMobile = $derived(isMobile.current);
|
||||
const isOnMobile = $derived(deviceStore.isMobile);
|
||||
|
||||
$effect(() => {
|
||||
if (isSearchModeActive && searchInputRef) {
|
||||
@@ -107,7 +107,7 @@
|
||||
>
|
||||
{#each SIDEBAR_ACTIONS_ITEMS as item, i (item.tooltip)}
|
||||
{@const isActive = isItemActive(item)}
|
||||
{@const isSearchOnMobile = item.icon === Search && isMobile.current}
|
||||
{@const isSearchOnMobile = item.icon === Search && deviceStore.isMobile}
|
||||
{@const itemHref = isSearchOnMobile ? ROUTES.SEARCH : item.route}
|
||||
{@const itemOnClick = item.route
|
||||
? () => {
|
||||
@@ -156,7 +156,7 @@
|
||||
<div class="{className} flex-col gap-1 hidden md:flex">
|
||||
{#each SIDEBAR_ACTIONS_ITEMS as item, i (item.tooltip)}
|
||||
{@const isActive = isItemActive(item)}
|
||||
{@const isSearchOnMobile = item.icon === Search && isMobile.current}
|
||||
{@const isSearchOnMobile = item.icon === Search && deviceStore.isMobile}
|
||||
{@const itemOnClick = item.route
|
||||
? () => {
|
||||
onNewChat?.();
|
||||
|
||||
Reference in New Issue
Block a user