optimize excessive layout re-rendering due to react-router

This commit is contained in:
jeffvli
2025-11-25 01:40:11 -08:00
parent 0a6b9a1040
commit 359e442947
11 changed files with 166 additions and 161 deletions
@@ -1,4 +1,4 @@
import { useMemo } from 'react'; import { useEffect, useMemo, useRef } from 'react';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { getTitlePath } from '/@/renderer/components/item-list/helpers/get-title-path'; import { getTitlePath } from '/@/renderer/components/item-list/helpers/get-title-path';
@@ -32,6 +32,11 @@ const itemTypeMapping = {
export const useDefaultItemListControls = (args?: UseDefaultItemListControlsArgs) => { export const useDefaultItemListControls = (args?: UseDefaultItemListControlsArgs) => {
const player = usePlayer(); const player = usePlayer();
const navigate = useNavigate(); const navigate = useNavigate();
const navigateRef = useRef(navigate);
useEffect(() => {
navigateRef.current = navigate;
}, [navigate]);
const { onColumnReordered, onColumnResized, overrides } = args || {}; const { onColumnReordered, onColumnResized, overrides } = args || {};
@@ -202,7 +207,7 @@ export const useDefaultItemListControls = (args?: UseDefaultItemListControlsArgs
) { ) {
const path = getTitlePath(itemType, item.id); const path = getTitlePath(itemType, item.id);
if (path) { if (path) {
navigate(path, { state: { item } }); navigateRef.current(path, { state: { item } });
return; return;
} }
} }
@@ -330,7 +335,7 @@ export const useDefaultItemListControls = (args?: UseDefaultItemListControlsArgs
...overrides, ...overrides,
}; };
}, [onColumnReordered, onColumnResized, overrides, navigate, player]); }, [onColumnReordered, onColumnResized, overrides, player]);
return controls; return controls;
}; };
@@ -1,4 +1,4 @@
import { useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { ItemListHandle } from '/@/renderer/components/item-list/types'; import { ItemListHandle } from '/@/renderer/components/item-list/types';
import { NowPlayingHeader } from '/@/renderer/features/now-playing/components/now-playing-header'; import { NowPlayingHeader } from '/@/renderer/features/now-playing/components/now-playing-header';
@@ -7,11 +7,23 @@ import { PlayQueueListControls } from '/@/renderer/features/now-playing/componen
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page'; import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container'; import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary'; import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
import { useAppStoreActions } from '/@/renderer/store';
import { ItemListKey } from '/@/shared/types/types'; import { ItemListKey } from '/@/shared/types/types';
const NowPlayingRoute = () => { const NowPlayingRoute = () => {
const queueRef = useRef<ItemListHandle | null>(null); const queueRef = useRef<ItemListHandle | null>(null);
const [search, setSearch] = useState<string | undefined>(undefined); const [search, setSearch] = useState<string | undefined>(undefined);
const { setSideBar } = useAppStoreActions();
useEffect(() => {
// On page enter, set rightExpanded to false
setSideBar({ rightExpanded: false });
return () => {
// On page exit, set rightExpanded to true
setSideBar({ rightExpanded: true });
};
}, [setSideBar]);
return ( return (
<AnimatedPage> <AnimatedPage>
@@ -14,7 +14,6 @@ import { TextInput } from '/@/shared/components/text-input/text-input';
export const ActionBar = () => { export const ActionBar = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate();
const { open } = useCommandPalette(); const { open } = useCommandPalette();
return ( return (
@@ -50,15 +49,25 @@ export const ActionBar = () => {
<AppMenu /> <AppMenu />
</DropdownMenu.Dropdown> </DropdownMenu.Dropdown>
</DropdownMenu> </DropdownMenu>
<Button onClick={() => navigate(-1)} p="0.5rem"> <NavigateButtons />
<Icon icon="arrowLeftS" size="lg" />
</Button>
<Button onClick={() => navigate(1)} p="0.5rem">
<Icon icon="arrowRightS" size="lg" />
</Button>
</Group> </Group>
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</div> </div>
); );
}; };
const NavigateButtons = () => {
const navigate = useNavigate();
return (
<>
<Button onClick={() => navigate(-1)} p="0.5rem">
<Icon icon="arrowLeftS" size="lg" />
</Button>
<Button onClick={() => navigate(1)} p="0.5rem">
<Icon icon="arrowRightS" size="lg" />
</Button>
</>
);
};
@@ -19,10 +19,10 @@ export const SidebarItem = ({ children, className, to, ...props }: SidebarItemPr
<Button <Button
className={clsx( className={clsx(
{ {
[styles.active]: isActive,
[styles.disabled]: props.disabled, [styles.disabled]: props.disabled,
[styles.link]: true, [styles.link]: true,
[styles.root]: true, [styles.root]: true,
[styles.active]: isActive,
}, },
className, className,
)} )}
@@ -2,7 +2,6 @@ import clsx from 'clsx';
import { AnimatePresence, motion } from 'motion/react'; import { AnimatePresence, motion } from 'motion/react';
import { CSSProperties, MouseEvent, useMemo } from 'react'; import { CSSProperties, MouseEvent, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router';
import styles from './sidebar.module.css'; import styles from './sidebar.module.css';
@@ -39,7 +38,6 @@ import { Platform } from '/@/shared/types/types';
export const Sidebar = () => { export const Sidebar = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const location = useLocation();
const sidebar = useSidebarStore(); const sidebar = useSidebarStore();
const { setSideBar } = useAppStoreActions(); const { setSideBar } = useAppStoreActions();
const { sidebarPlaylistList } = useGeneralSettings(); const { sidebarPlaylistList } = useGeneralSettings();
@@ -60,6 +58,7 @@ export const Sidebar = () => {
}), }),
[t], [t],
); );
const upsizedImageUrl = currentSong?.imageUrl const upsizedImageUrl = currentSong?.imageUrl
?.replace(/size=\d+/, 'size=450') ?.replace(/size=\d+/, 'size=450')
.replace(/width=\d+/, 'width=450') .replace(/width=\d+/, 'width=450')
+1 -45
View File
@@ -1,24 +1,13 @@
import clsx from 'clsx'; import clsx from 'clsx';
import isElectron from 'is-electron'; import isElectron from 'is-electron';
import { lazy } from 'react'; import { lazy } from 'react';
import { useNavigate } from 'react-router';
import styles from './default-layout.module.css'; import styles from './default-layout.module.css';
import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller'; import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller';
import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
import { MainContent } from '/@/renderer/layouts/default-layout/main-content'; import { MainContent } from '/@/renderer/layouts/default-layout/main-content';
import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar'; import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar';
import { AppRoute } from '/@/renderer/router/routes'; import { useSettingsStore, useWindowSettings } from '/@/renderer/store/settings.store';
import { useCommandPalette } from '/@/renderer/store';
import {
useGeneralSettings,
useHotkeySettings,
useSettingsStore,
useSettingsStoreActions,
useWindowSettings,
} from '/@/renderer/store/settings.store';
import { HotkeyItem, useHotkeys } from '/@/shared/hooks/use-hotkeys';
import { Platform, PlayerType } from '/@/shared/types/types'; import { Platform, PlayerType } from '/@/shared/types/types';
if (!isElectron()) { if (!isElectron()) {
@@ -42,38 +31,6 @@ interface DefaultLayoutProps {
export const DefaultLayout = ({ shell }: DefaultLayoutProps) => { export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
const { windowBarStyle } = useWindowSettings(); const { windowBarStyle } = useWindowSettings();
const { opened, ...handlers } = useCommandPalette();
const { bindings } = useHotkeySettings();
const navigate = useNavigate();
const localSettings = isElectron() ? window.api.localSettings : null;
const settings = useGeneralSettings();
const { setSettings } = useSettingsStoreActions();
const updateZoom = (increase: number) => {
const newVal = settings.zoomFactor + increase;
if (newVal > 300 || newVal < 50 || !isElectron()) return;
setSettings({
general: {
...settings,
zoomFactor: newVal,
},
});
localSettings?.setZoomFactor(settings.zoomFactor);
};
localSettings?.setZoomFactor(settings.zoomFactor);
const zoomHotkeys: HotkeyItem[] = [
[bindings.zoomIn.hotkey, () => updateZoom(5)],
[bindings.zoomOut.hotkey, () => updateZoom(-5)],
];
useHotkeys([
[bindings.globalSearch.hotkey, () => handlers.open()],
[bindings.browserBack.hotkey, () => navigate(-1)],
[bindings.browserForward.hotkey, () => navigate(1)],
[bindings.navigateHome.hotkey, () => navigate(AppRoute.HOME)],
...(isElectron() ? zoomHotkeys : []),
]);
return ( return (
<> <>
@@ -88,7 +45,6 @@ export const DefaultLayout = ({ shell }: DefaultLayoutProps) => {
<MainContent shell={shell} /> <MainContent shell={shell} />
<PlayerBar /> <PlayerBar />
</div> </div>
<CommandPalette modalProps={{ handlers, opened }} />
<ContextMenuController.Root /> <ContextMenuController.Root />
</> </>
); );
@@ -1,14 +1,13 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { motion } from 'motion/react'; import { motion } from 'motion/react';
import { Suspense, useCallback, useEffect, useRef, useState } from 'react'; import { Suspense, useCallback, useEffect, useRef, useState } from 'react';
import { Outlet, useLocation } from 'react-router'; import { Outlet } from 'react-router';
import styles from './main-content.module.css'; import styles from './main-content.module.css';
import { FullScreenOverlay } from '/@/renderer/layouts/default-layout/full-screen-overlay'; import { FullScreenOverlay } from '/@/renderer/layouts/default-layout/full-screen-overlay';
import { LeftSidebar } from '/@/renderer/layouts/default-layout/left-sidebar'; import { LeftSidebar } from '/@/renderer/layouts/default-layout/left-sidebar';
import { RightSidebar } from '/@/renderer/layouts/default-layout/right-sidebar'; import { RightSidebar } from '/@/renderer/layouts/default-layout/right-sidebar';
import { AppRoute } from '/@/renderer/router/routes';
import { useAppStoreActions, useSidebarStore } from '/@/renderer/store'; import { useAppStoreActions, useSidebarStore } from '/@/renderer/store';
import { useGeneralSettings } from '/@/renderer/store/settings.store'; import { useGeneralSettings } from '/@/renderer/store/settings.store';
import { constrainRightSidebarWidth, constrainSidebarWidth } from '/@/renderer/utils'; import { constrainRightSidebarWidth, constrainSidebarWidth } from '/@/renderer/utils';
@@ -17,14 +16,12 @@ import { Spinner } from '/@/shared/components/spinner/spinner';
const MINIMUM_SIDEBAR_WIDTH = 260; const MINIMUM_SIDEBAR_WIDTH = 260;
export const MainContent = ({ shell }: { shell?: boolean }) => { export const MainContent = ({ shell }: { shell?: boolean }) => {
const location = useLocation();
const { collapsed, leftWidth, rightExpanded, rightWidth } = useSidebarStore(); const { collapsed, leftWidth, rightExpanded, rightWidth } = useSidebarStore();
const { setSideBar } = useAppStoreActions(); const { setSideBar } = useAppStoreActions();
const { sideQueueType } = useGeneralSettings(); const { sideQueueType } = useGeneralSettings();
const [isResizing, setIsResizing] = useState(false); const [isResizing, setIsResizing] = useState(false);
const [isResizingRight, setIsResizingRight] = useState(false); const [isResizingRight, setIsResizingRight] = useState(false);
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
const rightSidebarRef = useRef<HTMLDivElement | null>(null); const rightSidebarRef = useRef<HTMLDivElement | null>(null);
const mainContentRef = useRef<HTMLDivElement | null>(null); const mainContentRef = useRef<HTMLDivElement | null>(null);
const initialRightWidthRef = useRef<string>(rightWidth); const initialRightWidthRef = useRef<string>(rightWidth);
@@ -128,7 +125,7 @@ export const MainContent = ({ shell }: { shell?: boolean }) => {
return ( return (
<motion.div <motion.div
className={clsx(styles.mainContentContainer, { className={clsx(styles.mainContentContainer, {
[styles.rightExpanded]: showSideQueue && sideQueueType === 'sideQueue', [styles.rightExpanded]: rightExpanded && sideQueueType === 'sideQueue',
[styles.shell]: shell, [styles.shell]: shell,
[styles.sidebarCollapsed]: collapsed, [styles.sidebarCollapsed]: collapsed,
[styles.sidebarExpanded]: !collapsed, [styles.sidebarExpanded]: !collapsed,
@@ -1,53 +1,48 @@
import { AnimatePresence, motion, Variants } from 'motion/react';
import { forwardRef, Ref } from 'react'; import { forwardRef, Ref } from 'react';
import { useLocation } from 'react-router';
import styles from './right-sidebar.module.css'; import styles from './right-sidebar.module.css';
import { DrawerPlayQueue } from '/@/renderer/features/now-playing/components/drawer-play-queue';
import { SidebarPlayQueue } from '/@/renderer/features/now-playing/components/sidebar-play-queue'; import { SidebarPlayQueue } from '/@/renderer/features/now-playing/components/sidebar-play-queue';
import { ResizeHandle } from '/@/renderer/features/shared/components/resize-handle'; import { ResizeHandle } from '/@/renderer/features/shared/components/resize-handle';
import { AppRoute } from '/@/renderer/router/routes'; import { useGeneralSettings, useSidebarStore } from '/@/renderer/store';
import { useGeneralSettings, useSidebarStore, useWindowSettings } from '/@/renderer/store';
import { Platform } from '/@/shared/types/types';
const queueDrawerVariants: Variants = { // const queueDrawerVariants: Variants = {
closed: (windowBarStyle) => ({ // closed: (windowBarStyle) => ({
height: // height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS // windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)' // ? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)', // : 'calc(100vh - 175px)',
position: 'absolute', // position: 'absolute',
right: 0, // right: 0,
top: '75px', // top: '75px',
transition: { // transition: {
duration: 0.4, // duration: 0.4,
ease: 'anticipate', // ease: 'anticipate',
}, // },
width: '450px', // width: '450px',
x: '50vw', // x: '50vw',
}), // }),
open: (windowBarStyle) => ({ // open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)', // boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
height: // height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS // windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)' // ? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)', // : 'calc(100vh - 175px)',
position: 'absolute', // position: 'absolute',
right: '20px', // right: '20px',
top: '75px', // top: '75px',
transition: { // transition: {
damping: 10, // damping: 10,
delay: 0, // delay: 0,
duration: 0.4, // duration: 0.4,
ease: 'anticipate', // ease: 'anticipate',
mass: 0.5, // mass: 0.5,
}, // },
width: '450px', // width: '450px',
x: 0, // x: 0,
zIndex: 120, // zIndex: 120,
}), // }),
}; // };
interface RightSidebarProps { interface RightSidebarProps {
isResizing: boolean; isResizing: boolean;
@@ -59,50 +54,28 @@ export const RightSidebar = forwardRef(
{ isResizing: isResizingRight, startResizing }: RightSidebarProps, { isResizing: isResizingRight, startResizing }: RightSidebarProps,
ref: Ref<HTMLDivElement>, ref: Ref<HTMLDivElement>,
) => { ) => {
const { windowBarStyle } = useWindowSettings();
const { rightExpanded } = useSidebarStore(); const { rightExpanded } = useSidebarStore();
const { sideQueueType } = useGeneralSettings(); const { sideQueueType } = useGeneralSettings();
const location = useLocation();
const showSideQueue = rightExpanded && location.pathname !== AppRoute.NOW_PLAYING;
return ( return (
<> <>
{showSideQueue && ( {rightExpanded && sideQueueType === 'sideQueue' && (
<> <aside
{sideQueueType === 'sideQueue' ? ( className={styles.rightSidebarContainer}
<aside id="sidebar-queue"
className={styles.rightSidebarContainer} key="queue-sidebar"
id="sidebar-queue" >
key="queue-sidebar" <ResizeHandle
> isResizing={isResizingRight}
<ResizeHandle onMouseDown={(e) => {
isResizing={isResizingRight} e.preventDefault();
onMouseDown={(e) => { startResizing('right', e.nativeEvent);
e.preventDefault(); }}
startResizing('right', e.nativeEvent); placement="left"
}} ref={ref}
placement="left" />
ref={ref} <SidebarPlayQueue />
/> </aside>
<SidebarPlayQueue />
</aside>
) : (
<AnimatePresence initial={false} key="queue-drawer" mode="sync">
<motion.div
animate="open"
className={styles.queueDrawer}
custom={windowBarStyle}
exit="closed"
id="drawer-queue"
initial="closed"
key="queue-drawer"
variants={queueDrawerVariants}
>
<DrawerPlayQueue />
</motion.div>
</AnimatePresence>
)}
</>
)} )}
</> </>
); );
@@ -1,6 +1,6 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { lazy } from 'react'; import { lazy } from 'react';
import { Outlet, useNavigate } from 'react-router'; import { Outlet } from 'react-router';
import styles from './mobile-layout.module.css'; import styles from './mobile-layout.module.css';
@@ -9,14 +9,11 @@ import { MobileFullscreenPlayer } from '/@/renderer/features/player/components/m
import { CommandPalette } from '/@/renderer/features/search/components/command-palette'; import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
import { MobileSidebar } from '/@/renderer/features/sidebar/components/mobile-sidebar'; import { MobileSidebar } from '/@/renderer/features/sidebar/components/mobile-sidebar';
import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar'; import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar';
import { AppRoute } from '/@/renderer/router/routes';
import { useFullScreenPlayerStore } from '/@/renderer/store'; import { useFullScreenPlayerStore } from '/@/renderer/store';
import { useCommandPalette } from '/@/renderer/store'; import { useCommandPalette } from '/@/renderer/store';
import { useHotkeySettings } from '/@/renderer/store/settings.store';
import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
import { Drawer } from '/@/shared/components/drawer/drawer'; import { Drawer } from '/@/shared/components/drawer/drawer';
import { useDisclosure } from '/@/shared/hooks/use-disclosure'; import { useDisclosure } from '/@/shared/hooks/use-disclosure';
import { useHotkeys } from '/@/shared/hooks/use-hotkeys';
const WindowBar = lazy(() => const WindowBar = lazy(() =>
import('/@/renderer/layouts/window-bar').then((module) => ({ import('/@/renderer/layouts/window-bar').then((module) => ({
@@ -30,18 +27,9 @@ interface MobileLayoutProps {
export const MobileLayout = ({ shell }: MobileLayoutProps) => { export const MobileLayout = ({ shell }: MobileLayoutProps) => {
const { opened, ...handlers } = useCommandPalette(); const { opened, ...handlers } = useCommandPalette();
const { bindings } = useHotkeySettings();
const navigate = useNavigate();
const [sidebarOpened, { close: closeSidebar, open: openSidebar }] = useDisclosure(false); const [sidebarOpened, { close: closeSidebar, open: openSidebar }] = useDisclosure(false);
const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore(); const { expanded: isFullScreenPlayerExpanded } = useFullScreenPlayerStore();
useHotkeys([
[bindings.globalSearch.hotkey, () => handlers.open()],
[bindings.browserBack.hotkey, () => navigate(-1)],
[bindings.browserForward.hotkey, () => navigate(1)],
[bindings.navigateHome.hotkey, () => navigate(AppRoute.HOME)],
]);
return ( return (
<> <>
<div className={clsx(styles.layout)} id="mobile-layout"> <div className={clsx(styles.layout)} id="mobile-layout">
+59 -1
View File
@@ -1,12 +1,24 @@
import isElectron from 'is-electron';
import { useNavigate } from 'react-router';
import { CommandPalette } from '/@/renderer/features/search/components/command-palette';
import { useIsMobile } from '/@/renderer/hooks/use-is-mobile'; import { useIsMobile } from '/@/renderer/hooks/use-is-mobile';
import { DefaultLayout } from '/@/renderer/layouts/default-layout'; import { DefaultLayout } from '/@/renderer/layouts/default-layout';
import { MobileLayout } from '/@/renderer/layouts/mobile-layout/mobile-layout'; import { MobileLayout } from '/@/renderer/layouts/mobile-layout/mobile-layout';
import { AppRoute } from '/@/renderer/router/routes';
import {
useCommandPalette,
useGeneralSettings,
useHotkeySettings,
useSettingsStoreActions,
} from '/@/renderer/store';
import { HotkeyItem, useHotkeys } from '/@/shared/hooks/use-hotkeys';
interface ResponsiveLayoutProps { interface ResponsiveLayoutProps {
shell?: boolean; shell?: boolean;
} }
export const ResponsiveLayout = ({ shell }: ResponsiveLayoutProps) => { const ResponsiveLayoutBase = ({ shell }: ResponsiveLayoutProps) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
if (isMobile) { if (isMobile) {
@@ -15,3 +27,49 @@ export const ResponsiveLayout = ({ shell }: ResponsiveLayoutProps) => {
return <DefaultLayout shell={shell} />; return <DefaultLayout shell={shell} />;
}; };
export const ResponsiveLayout = ({ shell }: ResponsiveLayoutProps) => {
return (
<>
<ResponsiveLayoutBase shell={shell} />
<LayoutHotkeys />
</>
);
};
const LayoutHotkeys = () => {
const navigate = useNavigate();
const localSettings = isElectron() ? window.api.localSettings : null;
const settings = useGeneralSettings();
const { setSettings } = useSettingsStoreActions();
const { bindings } = useHotkeySettings();
const { opened, ...handlers } = useCommandPalette();
const updateZoom = (increase: number) => {
const newVal = settings.zoomFactor + increase;
if (newVal > 300 || newVal < 50 || !isElectron()) return;
setSettings({
general: {
...settings,
zoomFactor: newVal,
},
});
localSettings?.setZoomFactor(settings.zoomFactor);
};
localSettings?.setZoomFactor(settings.zoomFactor);
const zoomHotkeys: HotkeyItem[] = [
[bindings.zoomIn.hotkey, () => updateZoom(5)],
[bindings.zoomOut.hotkey, () => updateZoom(-5)],
];
useHotkeys([
[bindings.globalSearch.hotkey, () => handlers.open()],
[bindings.browserBack.hotkey, () => navigate(-1)],
[bindings.browserForward.hotkey, () => navigate(1)],
[bindings.navigateHome.hotkey, () => navigate(AppRoute.HOME)],
...(isElectron() ? zoomHotkeys : []),
]);
return <CommandPalette modalProps={{ handlers, opened }} />;
};
+9 -1
View File
@@ -112,7 +112,15 @@ export const useAuthStore = createWithEqualityFn<AuthSlice>()(
), ),
); );
export const useCurrentServerId = () => useAuthStore((state) => state.currentServer)?.id || ''; export const useCurrentServerId = () =>
useAuthStore((state) => {
const currentServer = state.currentServer;
if (!currentServer) {
return null;
}
return currentServer.id || '';
}, shallow);
export const useCurrentServer = () => export const useCurrentServer = () =>
useAuthStore((state) => { useAuthStore((state) => {