Skip to content

Commit

Permalink
♻️ refactor: Move NavBar to @nav slot route (lobehub#2306)
Browse files Browse the repository at this point in the history
* ♻️ refactor: Move NavBar to `@nav` slot route

* πŸ› fix: Fix sub routes layout

* πŸ› fix: Fix MobileSessionHeader

* πŸ”§ chore: Merge error page

* βœ… test: Update tests

* πŸ› fix: Fix ServerLayout

* πŸ› fix: Fix Mobile Header

* πŸ’„ style: Rename components

* βœ… test: Update test
  • Loading branch information
canisminor1990 committed Apr 30, 2024
1 parent 7ef77fc commit aee7231
Show file tree
Hide file tree
Showing 35 changed files with 312 additions and 207 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
'use client';

import { SideNav } from '@lobehub/ui';
import { memo } from 'react';

import { SidebarTabKey } from '@/store/global/initialState';
import { useActiveTabKey } from '@/hooks/useActiveTabKey';

import Avatar from './Avatar';
import BottomActions from './BottomActions';
import TopActions from './TopActions';

interface Props {
sidebarKey?: SidebarTabKey;
}

export default memo<Props>(({ sidebarKey }) => {
const Nav = memo(() => {
const sidebarKey = useActiveTabKey();
return (
<SideNav
avatar={<Avatar />}
Expand All @@ -21,3 +20,7 @@ export default memo<Props>(({ sidebarKey }) => {
/>
);
});

Nav.displayName = 'DesktopNav';

export default Nav;
71 changes: 71 additions & 0 deletions src/app/(main)/@nav/_layout/Mobile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use client';

import { Icon, MobileTabBar, type MobileTabBarProps } from '@lobehub/ui';
import { createStyles } from 'antd-style';
import { Bot, MessageSquare, User } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { rgba } from 'polished';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { useActiveTabKey } from '@/hooks/useActiveTabKey';
import { SidebarTabKey } from '@/store/global/initialState';

const useStyles = createStyles(({ css, token }) => ({
active: css`
svg {
fill: ${rgba(token.colorPrimary, 0.33)};
}
`,
container: css`
position: fixed;
z-index: 100;
right: 0;
bottom: 0;
left: 0;
`,
}));

const Nav = memo(() => {
const { t } = useTranslation('common');
const { styles } = useStyles();
const activeKey = useActiveTabKey();
const router = useRouter();
const items: MobileTabBarProps['items'] = useMemo(
() => [
{
icon: (active) => (
<Icon className={active ? styles.active : undefined} icon={MessageSquare} />
),
key: SidebarTabKey.Chat,
onClick: () => {
router.push('/chat');
},
title: t('tab.chat'),
},
{
icon: (active) => <Icon className={active ? styles.active : undefined} icon={Bot} />,
key: SidebarTabKey.Market,
onClick: () => {
router.push('/market');
},
title: t('tab.market'),
},
{
icon: (active) => <Icon className={active ? styles.active : undefined} icon={User} />,
key: SidebarTabKey.Setting,
onClick: () => {
router.push('/settings');
},
title: t('tab.setting'),
},
],
[t],
);

return <MobileTabBar activeKey={activeKey} className={styles.container} items={items} safeArea />;
});

Nav.displayName = 'MobileNav';

export default Nav;
10 changes: 10 additions & 0 deletions src/app/(main)/@nav/default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import ServerLayout from '@/components/server/ServerLayout';

import Desktop from './_layout/Desktop';
import Mobile from './_layout/Mobile';

const Nav = ServerLayout({ Desktop, Mobile });

Nav.displayName = 'Nav';

export default Nav;
33 changes: 33 additions & 0 deletions src/app/(main)/_layout/Desktop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client';

import { useTheme } from 'antd-style';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { useIsPWA } from '@/hooks/useIsPWA';

import { LayoutProps } from './type';

const Layout = memo<LayoutProps>(({ children, nav }) => {
const isPWA = useIsPWA();
const theme = useTheme();

return (
<Flexbox
height={'100%'}
horizontal
style={{
borderTop: isPWA ? `1px solid ${theme.colorBorder}` : undefined,
position: 'relative',
}}
width={'100%'}
>
{nav}
{children}
</Flexbox>
);
});

Layout.displayName = 'DesktopMainLayout';

export default Layout;
24 changes: 24 additions & 0 deletions src/app/(main)/_layout/Mobile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client';

import { usePathname } from 'next/navigation';
import { memo } from 'react';

import { LayoutProps } from './type';

const MOBILE_IGNORE_NAV_ROUTES = ['/settings/', '/chat/'];

const Layout = memo(({ children, nav }: LayoutProps) => {
const pathname = usePathname();
const hideNav = MOBILE_IGNORE_NAV_ROUTES.some((path) => pathname.startsWith(path));

return (
<>
{children}
{!hideNav && nav}
</>
);
});

Layout.displayName = 'MobileMainLayout';

export default Layout;
6 changes: 6 additions & 0 deletions src/app/(main)/_layout/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ReactNode } from 'react';

export interface LayoutProps {
children: ReactNode;
nav: ReactNode;
}
2 changes: 1 addition & 1 deletion src/app/(main)/chat/(mobile)/features/ChatInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const ChatInputMobileLayout = memo(() => {
setExpand={setExpand}
style={{
background: `linear-gradient(to bottom, ${theme.colorFillQuaternary}, transparent)`,
width: '100vw',
width: '100%',
}}
textAreaLeftAddons={<STT mobile />}
textAreaRightAddons={
Expand Down
7 changes: 4 additions & 3 deletions src/app/(main)/chat/(mobile)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import { useRouter } from 'next/navigation';
import { memo, useEffect } from 'react';

import MobileContentLayout from '@/components/server/MobileNavLayout';

import SessionHeader from './features/SessionHeader';
import SessionList from './features/SessionList';

Expand All @@ -15,10 +17,9 @@ const ChatMobilePage = memo(() => {
}, []);

return (
<>
<SessionHeader />
<MobileContentLayout header={<SessionHeader />} withNav>
<SessionList />
</>
</MobileContentLayout>
);
});

Expand Down
1 change: 1 addition & 0 deletions src/app/(main)/chat/(mobile)/mobile/ChatHeader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const MobileHeader = memo(() => {
</>
}
showBackButton
style={{ width: '100%' }}
/>
);
});
Expand Down
15 changes: 6 additions & 9 deletions src/app/(main)/chat/(mobile)/mobile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import dynamic from 'next/dynamic';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import MobileContentLayout from '@/components/server/MobileNavLayout';
import Conversation from '@/features/Conversation';

import SessionHydration from '../../components/SessionHydration';
Expand All @@ -15,15 +15,12 @@ const TopicList = dynamic(() => import('../features/TopicList'));

const Chat = memo(() => {
return (
<>
<ChatHeader />
<Flexbox height={'calc(100% - 44px)'} horizontal>
<Conversation chatInput={<ChatInput />} mobile />
<TopicList />
<TelemetryNotification mobile />
</Flexbox>
<MobileContentLayout header={<ChatHeader />}>
<Conversation chatInput={<ChatInput />} mobile />
<TopicList />
<TelemetryNotification mobile />
<SessionHydration />
</>
</MobileContentLayout>
);
});
export default Chat;
7 changes: 4 additions & 3 deletions src/app/(main)/chat/settings/(mobile)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

import { memo } from 'react';

import MobileContentLayout from '@/components/server/MobileNavLayout';

import EditPage from '../features/EditPage';
import Header from './Header';

const ChatSettings = memo(() => (
<>
<Header />
<MobileContentLayout header={<Header />} withNav={false}>
<EditPage />
</>
</MobileContentLayout>
));

export default ChatSettings;
5 changes: 5 additions & 0 deletions src/app/(main)/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use client';

import dynamic from 'next/dynamic';

export default dynamic(() => import('@/components/Error'));
11 changes: 11 additions & 0 deletions src/app/(main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ServerLayout from '@/components/server/ServerLayout';

import Desktop from './_layout/Desktop';
import Mobile from './_layout/Mobile';
import { LayoutProps } from './_layout/type';

const MainLayout = ServerLayout<LayoutProps>({ Desktop, Mobile });

MainLayout.displayName = 'MainLayout';

export default MainLayout;
14 changes: 6 additions & 8 deletions src/app/(main)/market/_layout/Mobile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { PropsWithChildren } from 'react';
import { Flexbox } from 'react-layout-kit';

import MobileContentLayout from '@/components/server/MobileNavLayout';

import AgentSearchBar from '../../features/AgentSearchBar';
import Header from './Header';

const MobileLayout = ({ children }: PropsWithChildren) => {
return (
<>
<Header />
<Flexbox flex={1} gap={16} style={{ padding: 16 }}>
<AgentSearchBar mobile />
{children}
</Flexbox>
</>
<MobileContentLayout gap={16} header={<Header />} style={{ paddingInline: 16 }} withNav>
<AgentSearchBar mobile />
{children}
</MobileContentLayout>
);
};

Expand Down
27 changes: 15 additions & 12 deletions src/app/(main)/market/features/AgentSearchBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { SearchBar } from '@lobehub/ui';
import { memo, useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';

import { useIsMobile } from '@/hooks/useIsMobile';
import { useMarketStore } from '@/store/market';
Expand All @@ -19,18 +20,20 @@ const AgentSearchBar = memo<{ mobile?: boolean }>(({ mobile: controlledMobile })
}, [value, setKeywords]);

return (
<SearchBar
allowClear
enableShortKey={!mobile}
onChange={(e) => setValue(e.target.value)}
onPressEnter={handleSearch}
onSubmit={handleSearch}
placeholder={t('search.placeholder')}
shortKey={'k'}
spotlight={!mobile}
type={mobile ? 'block' : 'ghost'}
value={value}
/>
<Flexbox flex={'none'} paddingBlock={mobile ? 8 : 0}>
<SearchBar
allowClear
enableShortKey={!mobile}
onChange={(e) => setValue(e.target.value)}
onPressEnter={handleSearch}
onSubmit={handleSearch}
placeholder={t('search.placeholder')}
shortKey={'k'}
spotlight={!mobile}
type={mobile ? 'block' : 'ghost'}
value={value}
/>
</Flexbox>
);
});

Expand Down
3 changes: 3 additions & 0 deletions src/app/(main)/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import dynamic from 'next/dynamic';

export default dynamic(() => import('@/components/404'));
6 changes: 3 additions & 3 deletions src/app/(main)/settings/_layout/Mobile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { PropsWithChildren } from 'react';

import MobileContentLayout from '@/components/server/MobileNavLayout';
import { useIsSubSlug } from '@/hooks/useIsSubSlug';

import SubSettingHeader from './SubSettingHeader';
Expand All @@ -11,10 +12,9 @@ const MobileLayout = ({ children }: PropsWithChildren) => {

if (isSubPath)
return (
<>
<SubSettingHeader />
<MobileContentLayout header={<SubSettingHeader />} withNav={false}>
{children}
</>
</MobileContentLayout>
);

return children;
Expand Down
5 changes: 1 addition & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Analytics from '@/components/Analytics';
import { DEFAULT_LANG, LOBE_LOCALE_COOKIE } from '@/const/locale';
import AuthProvider from '@/layout/AuthProvider';
import GlobalProvider from '@/layout/GlobalProvider';
import LayoutRoutes from '@/layout/routes';
import { isMobileDevice } from '@/utils/responsive';

const RootLayout = async ({ children }: PropsWithChildren) => {
Expand All @@ -21,9 +20,7 @@ const RootLayout = async ({ children }: PropsWithChildren) => {
<html dir={direction} lang={lang?.value || DEFAULT_LANG} suppressHydrationWarning>
<body>
<GlobalProvider>
<AuthProvider>
<LayoutRoutes>{children}</LayoutRoutes>
</AuthProvider>
<AuthProvider>{children}</AuthProvider>
</GlobalProvider>
<Analytics />
<SpeedInsights />
Expand Down
Loading

0 comments on commit aee7231

Please sign in to comment.