mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
♻️ refactor: centralize NavBar dev mode logic into useNavLayout hook (#13037)
* ♻️ refactor: centralize NavBar dev mode logic into useNavLayout hook Extract scattered isDevMode checks from Nav, BottomMenu, Footer, and UserPanel into a single useNavLayout hook with declarative devOnly metadata. Also restore dev-mode-gated home page modules and fix LangButton visual alignment in UserPanel. * ✅ test: update PanelContent test to match LangButton Menu removal
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { type DropdownMenuCheckboxItem, type DropdownMenuProps } from '@lobehub/ui';
|
||||
import { ActionIcon, DropdownMenu, Flexbox, Icon, Text } from '@lobehub/ui';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { ChevronRight, Languages } from 'lucide-react';
|
||||
import { memo, type ReactNode, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Menu from '@/components/Menu';
|
||||
import { localeOptions } from '@/locales/resources';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { globalGeneralSelectors } from '@/store/global/selectors';
|
||||
@@ -68,18 +68,30 @@ const LangButton = memo<{ placement?: DropdownMenuProps['placement']; size?: num
|
||||
trigger = <ActionIcon icon={Languages} size={size} />;
|
||||
} else {
|
||||
trigger = (
|
||||
<div>
|
||||
<Menu
|
||||
items={[
|
||||
{
|
||||
extra: <Icon icon={ChevronRight} size={'small'} />,
|
||||
icon: <Icon icon={Languages} />,
|
||||
key: 'language',
|
||||
label: t('settingCommon.lang.title'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<Flexbox
|
||||
horizontal
|
||||
align="center"
|
||||
gap={12}
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
boxSizing: 'content-box',
|
||||
cursor: 'pointer',
|
||||
height: 28,
|
||||
marginInline: 4,
|
||||
paddingBlock: 6,
|
||||
paddingInline: 12,
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = cssVar.colorFillTertiary as string;
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'transparent';
|
||||
}}
|
||||
>
|
||||
<Icon icon={Languages} size={'small'} style={{ color: cssVar.colorTextSecondary }} />
|
||||
<Flexbox flex={1}>{t('settingCommon.lang.title')}</Flexbox>
|
||||
<Icon icon={ChevronRight} size={'small'} style={{ color: cssVar.colorTextSecondary }} />
|
||||
</Flexbox>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -87,11 +99,13 @@ const LangButton = memo<{ placement?: DropdownMenuProps['placement']; size?: num
|
||||
<DropdownMenu
|
||||
items={items}
|
||||
placement={placement}
|
||||
trigger="hover"
|
||||
popupProps={{
|
||||
style: {
|
||||
maxHeight: 360,
|
||||
minWidth: 240,
|
||||
overflow: 'auto',
|
||||
transition: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { LOBE_CHAT_CLOUD, UTM_SOURCE } from '@lobechat/business-const';
|
||||
import { DOWNLOAD_URL, isDesktop } from '@lobechat/const';
|
||||
import { Flexbox, Hotkey, Icon, Tag } from '@lobehub/ui';
|
||||
import { type ItemType } from 'antd/es/menu/interface';
|
||||
import { BrainCircuit, Cloudy, Download, LogOut, Settings2 } from 'lucide-react';
|
||||
import { BrainCircuit, Cloudy, Download, HardDriveDownload, LogOut, Settings2 } from 'lucide-react';
|
||||
import { type PropsWithChildren } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -12,6 +12,8 @@ import getBusinessMenuItems from '@/business/client/features/User/getBusinessMen
|
||||
import { type MenuProps } from '@/components/Menu';
|
||||
import { DEFAULT_DESKTOP_HOTKEY_CONFIG } from '@/const/desktop';
|
||||
import { OFFICIAL_URL } from '@/const/url';
|
||||
import DataImporter from '@/features/DataImporter';
|
||||
import { useNavLayout } from '@/hooks/useNavLayout';
|
||||
import { usePlatform } from '@/hooks/usePlatform';
|
||||
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
import { useUserStore } from '@/store/user';
|
||||
@@ -51,6 +53,7 @@ export const useMenu = () => {
|
||||
authSelectors.isLogin(s),
|
||||
authSelectors.isLoginWithAuth(s),
|
||||
]);
|
||||
const { userPanel } = useNavLayout();
|
||||
const businessMenuItems = getBusinessMenuItems(isLogin);
|
||||
const { isIOS, isAndroid } = usePlatform();
|
||||
|
||||
@@ -75,11 +78,15 @@ export const useMenu = () => {
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: <Icon icon={BrainCircuit} />,
|
||||
key: 'memory',
|
||||
label: <Link to="/memory">{t('tab.memory')}</Link>,
|
||||
},
|
||||
...(userPanel.showMemory
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={BrainCircuit} />,
|
||||
key: 'memory',
|
||||
label: <Link to="/memory">{t('tab.memory')}</Link>,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
const getDesktopApp: MenuProps['items'] = [
|
||||
@@ -118,6 +125,18 @@ export const useMenu = () => {
|
||||
...(isLogin ? settings : []),
|
||||
...businessMenuItems,
|
||||
...(!isDesktop ? [{ type: 'divider' as const }, ...getDesktopApp] : []),
|
||||
...(userPanel.showDataImporter && isLogin
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={HardDriveDownload} />,
|
||||
key: 'import',
|
||||
label: <DataImporter>{t('importData')}</DataImporter>,
|
||||
},
|
||||
{
|
||||
type: 'divider' as const,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(!hideDocs ? helps : []),
|
||||
].filter(Boolean) as MenuProps['items'];
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('PanelContent', () => {
|
||||
|
||||
renderWithRouter(<PanelContent closePopover={closePopover} />);
|
||||
|
||||
expect(screen.getAllByText('Mocked Menu').length).toBe(3);
|
||||
expect(screen.getAllByText('Mocked Menu').length).toBe(2);
|
||||
});
|
||||
|
||||
it('should render SignInBlock when user is not signed in', () => {
|
||||
|
||||
163
src/hooks/useNavLayout.ts
Normal file
163
src/hooks/useNavLayout.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { HomeIcon, SearchIcon } from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { getRouteById } from '@/config/routes';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { SidebarTabKey } from '@/store/global/initialState';
|
||||
import {
|
||||
featureFlagsSelectors,
|
||||
serverConfigSelectors,
|
||||
useServerConfigStore,
|
||||
} from '@/store/serverConfig';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { userGeneralSettingsSelectors } from '@/store/user/slices/settings/selectors';
|
||||
|
||||
export interface NavItem {
|
||||
/**
|
||||
* true = dev mode only, false = simplified mode only, undefined = always
|
||||
*/
|
||||
devOnly?: boolean;
|
||||
hidden?: boolean;
|
||||
icon: any;
|
||||
isNew?: boolean;
|
||||
key: string;
|
||||
onClick?: () => void;
|
||||
title: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface NavLayout {
|
||||
bottomMenuItems: NavItem[];
|
||||
footer: {
|
||||
hideGitHub: boolean;
|
||||
layout: 'expanded' | 'compact';
|
||||
showEvalEntry: boolean;
|
||||
showSettingsEntry: boolean;
|
||||
};
|
||||
topNavItems: NavItem[];
|
||||
userPanel: {
|
||||
showDataImporter: boolean;
|
||||
showMemory: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const filterByMode = (items: NavItem[], isDevMode: boolean): NavItem[] =>
|
||||
items.filter((item) => item.devOnly === undefined || item.devOnly === isDevMode);
|
||||
|
||||
export const useNavLayout = (): NavLayout => {
|
||||
const { t } = useTranslation('common');
|
||||
const toggleCommandMenu = useGlobalStore((s) => s.toggleCommandMenu);
|
||||
const { showMarket, showAiImage, hideGitHub } = useServerConfigStore(featureFlagsSelectors);
|
||||
const enableBusinessFeatures = useServerConfigStore(serverConfigSelectors.enableBusinessFeatures);
|
||||
const isDevMode = useUserStore((s) => userGeneralSettingsSelectors.config(s).isDevMode);
|
||||
|
||||
const topNavItems = useMemo(
|
||||
() =>
|
||||
filterByMode(
|
||||
[
|
||||
{
|
||||
icon: SearchIcon,
|
||||
key: 'search',
|
||||
onClick: () => toggleCommandMenu(true),
|
||||
title: t('tab.search'),
|
||||
},
|
||||
{
|
||||
icon: HomeIcon,
|
||||
key: SidebarTabKey.Home,
|
||||
title: t('tab.home'),
|
||||
url: '/',
|
||||
},
|
||||
{
|
||||
devOnly: true,
|
||||
icon: getRouteById('page')!.icon,
|
||||
key: SidebarTabKey.Pages,
|
||||
title: t('tab.pages'),
|
||||
url: '/page',
|
||||
},
|
||||
{
|
||||
devOnly: true,
|
||||
hidden: !enableBusinessFeatures,
|
||||
icon: getRouteById('video')!.icon,
|
||||
key: SidebarTabKey.Video,
|
||||
title: t('tab.video'),
|
||||
url: '/video',
|
||||
},
|
||||
{
|
||||
devOnly: true,
|
||||
hidden: !showAiImage,
|
||||
icon: getRouteById('image')!.icon,
|
||||
key: SidebarTabKey.Image,
|
||||
title: t('tab.aiImage'),
|
||||
url: '/image',
|
||||
},
|
||||
{
|
||||
hidden: !showMarket,
|
||||
icon: getRouteById('community')!.icon,
|
||||
key: SidebarTabKey.Community,
|
||||
title: t('tab.marketplace'),
|
||||
url: '/community',
|
||||
},
|
||||
],
|
||||
isDevMode,
|
||||
),
|
||||
[t, toggleCommandMenu, showMarket, isDevMode, enableBusinessFeatures, showAiImage],
|
||||
);
|
||||
|
||||
const bottomMenuItems = useMemo(
|
||||
() =>
|
||||
filterByMode(
|
||||
[
|
||||
{
|
||||
devOnly: true,
|
||||
icon: getRouteById('settings')!.icon,
|
||||
key: SidebarTabKey.Setting,
|
||||
title: t('tab.setting'),
|
||||
url: '/settings',
|
||||
},
|
||||
{
|
||||
icon: getRouteById('resource')!.icon,
|
||||
key: SidebarTabKey.Resource,
|
||||
title: t('tab.resource'),
|
||||
url: '/resource',
|
||||
},
|
||||
{
|
||||
devOnly: true,
|
||||
icon: getRouteById('memory')!.icon,
|
||||
key: SidebarTabKey.Memory,
|
||||
title: t('tab.memory'),
|
||||
url: '/memory',
|
||||
},
|
||||
{
|
||||
devOnly: false,
|
||||
icon: getRouteById('page')!.icon,
|
||||
key: SidebarTabKey.Pages,
|
||||
title: t('tab.pages'),
|
||||
url: '/page',
|
||||
},
|
||||
],
|
||||
isDevMode,
|
||||
),
|
||||
[t, isDevMode],
|
||||
);
|
||||
|
||||
const footer = useMemo(
|
||||
() => ({
|
||||
hideGitHub: !!hideGitHub,
|
||||
layout: (isDevMode ? 'expanded' : 'compact') as 'expanded' | 'compact',
|
||||
showEvalEntry: isDevMode,
|
||||
showSettingsEntry: !isDevMode,
|
||||
}),
|
||||
[isDevMode, hideGitHub],
|
||||
);
|
||||
|
||||
const userPanel = useMemo(
|
||||
() => ({
|
||||
showDataImporter: isDevMode,
|
||||
showMemory: !isDevMode,
|
||||
}),
|
||||
[isDevMode],
|
||||
);
|
||||
|
||||
return { bottomMenuItems, footer, topNavItems, userPanel };
|
||||
};
|
||||
@@ -1,45 +1,16 @@
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { memo } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { getRouteById } from '@/config/routes';
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
||||
import { SidebarTabKey } from '@/store/global/initialState';
|
||||
import { useNavLayout } from '@/hooks/useNavLayout';
|
||||
import { isModifierClick } from '@/utils/navigation';
|
||||
|
||||
interface Item {
|
||||
icon: any;
|
||||
key: SidebarTabKey;
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const BottomMenu = memo(() => {
|
||||
const tab = useActiveTabKey();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation('common');
|
||||
|
||||
const items = useMemo(
|
||||
() =>
|
||||
[
|
||||
{
|
||||
icon: getRouteById('resource')!.icon,
|
||||
key: SidebarTabKey.Resource,
|
||||
title: t('tab.resource'),
|
||||
url: '/resource',
|
||||
},
|
||||
{
|
||||
icon: getRouteById('page')!.icon,
|
||||
key: SidebarTabKey.Pages,
|
||||
title: t('tab.pages'),
|
||||
url: '/page',
|
||||
},
|
||||
].filter(Boolean) as Item[],
|
||||
[t],
|
||||
);
|
||||
const { bottomMenuItems: items } = useNavLayout();
|
||||
|
||||
return (
|
||||
<Flexbox
|
||||
@@ -52,11 +23,11 @@ const BottomMenu = memo(() => {
|
||||
{items.map((item) => (
|
||||
<Link
|
||||
key={item.key}
|
||||
to={item.url}
|
||||
to={item.url!}
|
||||
onClick={(e) => {
|
||||
if (isModifierClick(e)) return;
|
||||
e.preventDefault();
|
||||
navigate(item.url);
|
||||
navigate(item.url!);
|
||||
}}
|
||||
>
|
||||
<NavItem active={tab === item.key} icon={item.icon} title={item.title} />
|
||||
|
||||
@@ -22,12 +22,11 @@ import { Link } from 'react-router-dom';
|
||||
import ChangelogModal from '@/components/ChangelogModal';
|
||||
import HighlightNotification from '@/components/HighlightNotification';
|
||||
import { DOCUMENTS_REFER_URL, GITHUB } from '@/const/url';
|
||||
import ThemeButton from '@/features/User/UserPanel/ThemeButton';
|
||||
import { useFeedbackModal } from '@/hooks/useFeedbackModal';
|
||||
import { useNavLayout } from '@/hooks/useNavLayout';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors/systemStatus';
|
||||
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { userGeneralSettingsSelectors } from '@/store/user/slices/settings/selectors';
|
||||
|
||||
const PRODUCT_HUNT_NOTIFICATION = {
|
||||
actionHref: 'https://www.producthunt.com/products/lobehub?launch=lobehub',
|
||||
@@ -40,8 +39,7 @@ const PRODUCT_HUNT_NOTIFICATION = {
|
||||
const Footer = memo(() => {
|
||||
const { t } = useTranslation('common');
|
||||
const { analytics } = useAnalytics();
|
||||
const { hideGitHub } = useServerConfigStore(featureFlagsSelectors);
|
||||
const isDevMode = useUserStore((s) => userGeneralSettingsSelectors.config(s).isDevMode);
|
||||
const { footer } = useNavLayout();
|
||||
const [shouldLoadChangelog, setShouldLoadChangelog] = useState(false);
|
||||
const [isChangelogModalOpen, setIsChangelogModalOpen] = useState(false);
|
||||
const [isProductHuntCardOpen, setIsProductHuntCardOpen] = useState(false);
|
||||
@@ -88,17 +86,17 @@ const Footer = memo(() => {
|
||||
setIsChangelogModalOpen(false);
|
||||
};
|
||||
|
||||
const handleOpenFeedbackModal = () => {
|
||||
const handleOpenFeedbackModal = useCallback(() => {
|
||||
openFeedbackModal();
|
||||
};
|
||||
}, [openFeedbackModal]);
|
||||
|
||||
const handleOpenProductHuntCard = () => {
|
||||
const handleOpenProductHuntCard = useCallback(() => {
|
||||
setIsProductHuntCardOpen(true);
|
||||
trackProductHuntEvent('product_hunt_card_viewed', {
|
||||
spm: 'homepage.product_hunt.viewed',
|
||||
trigger: 'menu_click',
|
||||
});
|
||||
};
|
||||
}, [setIsProductHuntCardOpen, trackProductHuntEvent]);
|
||||
|
||||
const handleCloseProductHuntCard = () => {
|
||||
setIsProductHuntCardOpen(false);
|
||||
@@ -121,14 +119,18 @@ const Footer = memo(() => {
|
||||
|
||||
const helpMenuItems: MenuProps['items'] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: <Icon icon={Settings2} />,
|
||||
key: 'setting',
|
||||
label: <Link to="/settings">{t('userPanel.setting')}</Link>,
|
||||
},
|
||||
{
|
||||
type: 'divider' as const,
|
||||
},
|
||||
...(footer.showSettingsEntry
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={Settings2} />,
|
||||
key: 'setting',
|
||||
label: <Link to="/settings">{t('userPanel.setting')}</Link>,
|
||||
},
|
||||
{
|
||||
type: 'divider' as const,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
icon: <Icon icon={Book} />,
|
||||
key: 'docs',
|
||||
@@ -162,7 +164,7 @@ const Footer = memo(() => {
|
||||
label: t('changelog'),
|
||||
onClick: handleOpenChangelogModal,
|
||||
},
|
||||
...(!hideGitHub
|
||||
...(footer.layout === 'compact' && !footer.hideGitHub
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={Github} />,
|
||||
@@ -175,7 +177,7 @@ const Footer = memo(() => {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(isDevMode
|
||||
...(footer.showEvalEntry && footer.layout === 'compact'
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={FlaskConical} />,
|
||||
@@ -195,16 +197,44 @@ const Footer = memo(() => {
|
||||
]
|
||||
: []),
|
||||
],
|
||||
[t, isWithinTimeWindow, hideGitHub, isDevMode],
|
||||
[
|
||||
footer.showSettingsEntry,
|
||||
footer.layout,
|
||||
footer.hideGitHub,
|
||||
footer.showEvalEntry,
|
||||
t,
|
||||
handleOpenFeedbackModal,
|
||||
isWithinTimeWindow,
|
||||
handleOpenProductHuntCard,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flexbox horizontal align={'center'} gap={2} padding={8}>
|
||||
<DropdownMenu items={helpMenuItems} placement="topLeft">
|
||||
<ActionIcon aria-label={t('userPanel.help')} icon={CircleHelp} size={16} />
|
||||
</DropdownMenu>
|
||||
</Flexbox>
|
||||
{footer.layout === 'expanded' ? (
|
||||
<Flexbox horizontal align={'center'} gap={2} justify={'space-between'} padding={8}>
|
||||
<Flexbox horizontal align={'center'} flex={1} gap={2}>
|
||||
<DropdownMenu items={helpMenuItems} placement="topLeft">
|
||||
<ActionIcon aria-label={t('userPanel.help')} icon={CircleHelp} size={16} />
|
||||
</DropdownMenu>
|
||||
{!footer.hideGitHub && (
|
||||
<a aria-label={'GitHub'} href={GITHUB} rel="noopener noreferrer" target={'_blank'}>
|
||||
<ActionIcon icon={Github} size={16} title={'GitHub'} />
|
||||
</a>
|
||||
)}
|
||||
<Link to="/eval">
|
||||
<ActionIcon icon={FlaskConical} size={16} title="Evaluation Lab" />
|
||||
</Link>
|
||||
</Flexbox>
|
||||
<ThemeButton placement={'topCenter'} size={16} />
|
||||
</Flexbox>
|
||||
) : (
|
||||
<Flexbox horizontal align={'center'} gap={2} padding={8}>
|
||||
<DropdownMenu items={helpMenuItems} placement="topLeft">
|
||||
<ActionIcon aria-label={t('userPanel.help')} icon={CircleHelp} size={16} />
|
||||
</DropdownMenu>
|
||||
</Flexbox>
|
||||
)}
|
||||
<ChangelogModal
|
||||
open={isChangelogModalOpen}
|
||||
shouldLoad={shouldLoadChangelog}
|
||||
|
||||
@@ -1,63 +1,21 @@
|
||||
'use client';
|
||||
|
||||
import { Flexbox, Tag } from '@lobehub/ui';
|
||||
import { HomeIcon, SearchIcon } from 'lucide-react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { getRouteById } from '@/config/routes';
|
||||
import { type NavItemProps } from '@/features/NavPanel/components/NavItem';
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { SidebarTabKey } from '@/store/global/initialState';
|
||||
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
import { useNavLayout } from '@/hooks/useNavLayout';
|
||||
import { isModifierClick } from '@/utils/navigation';
|
||||
|
||||
interface Item {
|
||||
hidden?: boolean | undefined;
|
||||
icon: NavItemProps['icon'];
|
||||
isNew?: boolean;
|
||||
key: string;
|
||||
onClick?: () => void;
|
||||
title: NavItemProps['title'];
|
||||
url?: string;
|
||||
}
|
||||
|
||||
const Nav = memo(() => {
|
||||
const tab = useActiveTabKey();
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation('common');
|
||||
const toggleCommandMenu = useGlobalStore((s) => s.toggleCommandMenu);
|
||||
const { showMarket } = useServerConfigStore(featureFlagsSelectors);
|
||||
|
||||
const items: Item[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
icon: SearchIcon,
|
||||
key: 'search',
|
||||
onClick: () => {
|
||||
toggleCommandMenu(true);
|
||||
},
|
||||
title: t('tab.search'),
|
||||
},
|
||||
{
|
||||
icon: HomeIcon,
|
||||
key: SidebarTabKey.Home,
|
||||
title: t('tab.home'),
|
||||
url: '/',
|
||||
},
|
||||
{
|
||||
hidden: !showMarket,
|
||||
icon: getRouteById('community')!.icon,
|
||||
key: SidebarTabKey.Community,
|
||||
title: t('tab.marketplace'),
|
||||
url: '/community',
|
||||
},
|
||||
],
|
||||
[t, showMarket],
|
||||
);
|
||||
const { topNavItems: items } = useNavLayout();
|
||||
|
||||
const newBadge = (
|
||||
<Tag color="blue" size="small">
|
||||
@@ -74,7 +32,7 @@ const Nav = memo(() => {
|
||||
active={tab === item.key}
|
||||
extra={extra}
|
||||
hidden={item.hidden}
|
||||
icon={item.icon}
|
||||
icon={item.icon as NavItemProps['icon']}
|
||||
key={item.key}
|
||||
title={item.title}
|
||||
onClick={item.onClick}
|
||||
@@ -99,7 +57,7 @@ const Nav = memo(() => {
|
||||
active={tab === item.key}
|
||||
extra={extra}
|
||||
hidden={item.hidden}
|
||||
icon={item.icon}
|
||||
icon={item.icon as NavItemProps['icon']}
|
||||
title={item.title}
|
||||
/>
|
||||
</Link>
|
||||
|
||||
@@ -7,13 +7,19 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useHomeStore } from '@/store/home';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { authSelectors } from '@/store/user/slices/auth/selectors';
|
||||
import { userGeneralSettingsSelectors } from '@/store/user/slices/settings/selectors';
|
||||
|
||||
import CommunityAgents from './CommunityAgents';
|
||||
import InputArea from './InputArea';
|
||||
import RecentPage from './RecentPage';
|
||||
import RecentResource from './RecentResource';
|
||||
import RecentTopic from './RecentTopic';
|
||||
import WelcomeText from './WelcomeText';
|
||||
|
||||
const Home = memo(() => {
|
||||
const { i18n } = useTranslation();
|
||||
const isLogin = useUserStore(authSelectors.isLogin);
|
||||
const isDevMode = useUserStore((s) => userGeneralSettingsSelectors.config(s).isDevMode);
|
||||
const inputActiveMode = useHomeStore((s) => s.inputActiveMode);
|
||||
|
||||
// Hide other modules when a starter mode is active
|
||||
@@ -28,15 +34,14 @@ const Home = memo(() => {
|
||||
<InputArea />
|
||||
{/* Use CSS visibility to hide instead of unmounting to prevent data re-fetching */}
|
||||
<Flexbox gap={40} style={{ display: hideOtherModules ? 'none' : undefined }}>
|
||||
{/* {isLogin && (
|
||||
{isDevMode && isLogin && (
|
||||
<>
|
||||
<RecentTopic />
|
||||
<RecentPage />
|
||||
</>
|
||||
)} */}
|
||||
{/* <CommunityAgents /> */}
|
||||
{/* <FeaturedPlugins /> */}
|
||||
{/* {isLogin && <RecentResource />} */}
|
||||
)}
|
||||
{isDevMode && <CommunityAgents />}
|
||||
{isDevMode && isLogin && <RecentResource />}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user