diff --git a/src/app/chat/SideBar/index.tsx b/src/app/chat/SideBar/index.tsx new file mode 100644 index 00000000..248f4204 --- /dev/null +++ b/src/app/chat/SideBar/index.tsx @@ -0,0 +1,30 @@ +import { DraggablePanel } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; + +import { SIDEBAR_MAX_WIDTH, SIDEBAR_WIDTH } from '@/constants/common'; +import SessionList from '@/features/SessionList'; + +const useStyles = createStyles(({ css }) => ({ + sidebar: css` + display: flex; + flex-direction: column; + `, +})); + +const SideBar = () => { + const { styles } = useStyles(); + + return ( + + + + ); +}; + +export default SideBar; diff --git a/src/app/chat/page.tsx b/src/app/chat/page.tsx index 050574cc..54e7353c 100644 --- a/src/app/chat/page.tsx +++ b/src/app/chat/page.tsx @@ -9,9 +9,9 @@ import ChatHeader from '@/features/ChatHeader'; import ChatInfo from '@/features/ChatInfo'; import MessageInput from '@/features/ChatInput/MessageInput'; import ChatList from '@/features/ChatList'; -import SessionList from '@/features/SessionList'; import { useSessionStore } from '@/store/session'; +import SideBar from './SideBar'; import { useStyles } from './style'; const Chat = () => { @@ -20,14 +20,20 @@ const Chat = () => { return ( - + - - {viewerMode === true ? : } + + {viewerMode === true ? ( + + ) : ( + + + + )} -
+
diff --git a/src/app/chat/style.ts b/src/app/chat/style.ts index 675fe87e..6a07154d 100644 --- a/src/app/chat/style.ts +++ b/src/app/chat/style.ts @@ -6,11 +6,17 @@ import { CHAT_INPUT_MIN_HEIGHT, CHAT_INPUT_WIDTH } from '@/constants/common'; export const useStyles = createStyles(({ css, token }) => ({ docker: css` height: ${CHAT_INPUT_MIN_HEIGHT}px; + padding: 0 ${token.paddingSM}px; background-color: ${rgba(token.colorBgLayout, 0.8)}; backdrop-filter: saturate(180%) blur(10px); `, - input: css` + content: css` width: ${CHAT_INPUT_WIDTH}; + max-width: 100vw; + + @media (max-width: 768px) { + width: 100%; + } `, alert: css` margin-top: ${token.marginXS}px; diff --git a/src/constants/common.ts b/src/constants/common.ts index 81ca90e2..6b7f4dda 100644 --- a/src/constants/common.ts +++ b/src/constants/common.ts @@ -27,7 +27,7 @@ export const SIDEBAR_MAX_WIDTH = 400; export const CHAT_HEADER_HEIGHT = 64; -export const CHAT_INPUT_WIDTH = '42vw'; +export const CHAT_INPUT_WIDTH = '48rem'; export const DEFAULT_USER_AVATAR = '😀'; diff --git a/src/features/Actions/Agent.tsx b/src/features/Actions/Agent.tsx new file mode 100644 index 00000000..408bc2c9 --- /dev/null +++ b/src/features/Actions/Agent.tsx @@ -0,0 +1,11 @@ +import { ActionIcon } from '@lobehub/ui'; +import { Plus } from 'lucide-react'; + +import { useConfigStore } from '@/store/config'; + +// eslint-disable-next-line react/display-name +export default () => { + const openPanel = useConfigStore((s) => s.openPanel); + + return openPanel('agent')} title={'新的会话'} />; +}; diff --git a/src/features/AgentViewer/style.ts b/src/features/AgentViewer/style.ts index ee3491d6..3bc558a9 100644 --- a/src/features/AgentViewer/style.ts +++ b/src/features/AgentViewer/style.ts @@ -23,6 +23,10 @@ export const useStyles = createStyles(({ css, token }) => ({ display: flex; max-width: ${CHAT_INPUT_WIDTH}; + + @media (max-width: 768px) { + width: 100%; + } `, viewer: css` min-height: 0; diff --git a/src/features/ChatHeader/index.tsx b/src/features/ChatHeader/index.tsx index bb85f482..8b7ebcbe 100644 --- a/src/features/ChatHeader/index.tsx +++ b/src/features/ChatHeader/index.tsx @@ -1,10 +1,13 @@ +import { ActionIcon } from '@lobehub/ui'; import { Space } from 'antd'; +import { SlidersHorizontal } from 'lucide-react'; import React from 'react'; import { Flexbox } from 'react-layout-kit'; import AgentMeta from '@/components/agent/AgentMeta'; import Video from '@/features/Actions/Video'; import Voice from '@/features/Actions/Voice'; +import { useGlobalStore } from '@/store/global'; import { sessionSelectors, useSessionStore } from '@/store/session'; import { useStyles } from './style'; @@ -12,6 +15,7 @@ import { useStyles } from './style'; const Header = () => { const { styles } = useStyles(); const [currentAgent] = useSessionStore((s) => [sessionSelectors.currentAgent(s)]); + const [toggleChatSideBar] = useGlobalStore((s) => [s.toggleChatSideBar]); return ( @@ -19,6 +23,11 @@ const Header = () => { ); diff --git a/src/features/ChatHeader/style.ts b/src/features/ChatHeader/style.ts index 08f3b2ec..9e3717f6 100644 --- a/src/features/ChatHeader/style.ts +++ b/src/features/ChatHeader/style.ts @@ -6,7 +6,6 @@ const useStyles = createStyles(({ token, css }) => ({ header: css` height: ${CHAT_HEADER_HEIGHT}px; padding: ${token.paddingSM}px; - border-bottom: 1px solid ${token.colorBorderSecondary}; `, player: css` min-width: 480px; diff --git a/src/features/ChatInfo/index.tsx b/src/features/ChatInfo/index.tsx index e1f3839f..94e715e2 100644 --- a/src/features/ChatInfo/index.tsx +++ b/src/features/ChatInfo/index.tsx @@ -7,6 +7,7 @@ import React from 'react'; import AgentCard from '@/components/agent/AgentCard'; import { SIDEBAR_WIDTH } from '@/constants/common'; import MiniPlayer from '@/features/AudioPlayer/MiniPlayer'; +import { useGlobalStore } from '@/store/global'; import { sessionSelectors, useSessionStore } from '@/store/session'; import Operations from './Operations'; @@ -22,7 +23,11 @@ const useStyles = createStyles(({ css, token }) => ({ `, })); -const Header = () => { +export default () => { + const [showChatSidebar, setChatSidebar] = useGlobalStore((s) => [ + s.showChatSidebar, + s.setChatSidebar, + ]); const { styles } = useStyles(); const [currentAgent] = useSessionStore((s) => [sessionSelectors.currentAgent(s)]); @@ -32,11 +37,11 @@ const Header = () => { minWidth={SIDEBAR_WIDTH} maxWidth={SIDEBAR_WIDTH} mode={'fixed'} + onExpandChange={(expand) => setChatSidebar(expand)} + expand={showChatSidebar} placement={'right'} > } footer={} /> ); }; - -export default Header; diff --git a/src/features/ChatList/index.tsx b/src/features/ChatList/index.tsx index 0783e814..c2c297aa 100644 --- a/src/features/ChatList/index.tsx +++ b/src/features/ChatList/index.tsx @@ -35,7 +35,7 @@ const VirtualizedList = memo(({ mobile }) => { const overscan = typeof window !== 'undefined' ? window.innerHeight * 1.5 : 0; return chatLoading && data.length === 2 ? null : ( - + void; - value?: string; -} - -// eslint-disable-next-line react/display-name -const Index = memo((props: HeaderProps) => { - const { value, onChange } = props; - const { styles } = useStyles(); - const openPanel = useConfigStore((s) => s.openPanel); - - return ( - - { - if (onChange) onChange(e.target.value); - }} - placeholder="搜索" - shortKey="f" - value={value} - style={{ width: '100%' }} - /> - openPanel('agent')} title={'创建对话'} /> - - ); -}); - -export default Index; diff --git a/src/features/SessionList/List/SessionItem/Actions.tsx b/src/features/SessionList/List/Item/Actions.tsx similarity index 100% rename from src/features/SessionList/List/SessionItem/Actions.tsx rename to src/features/SessionList/List/Item/Actions.tsx diff --git a/src/features/SessionList/List/SessionItem/index.tsx b/src/features/SessionList/List/Item/index.tsx similarity index 95% rename from src/features/SessionList/List/SessionItem/index.tsx rename to src/features/SessionList/List/Item/index.tsx index bdd74e8b..779cec68 100644 --- a/src/features/SessionList/List/SessionItem/index.tsx +++ b/src/features/SessionList/List/Item/index.tsx @@ -1,9 +1,9 @@ import { memo, useMemo, useState } from 'react'; import { shallow } from 'zustand/shallow'; -import ListItem from '@/features/SessionList/ListItem'; import { sessionSelectors, useSessionStore } from '@/store/session'; +import ListItem from '../../ListItem'; import Actions from './Actions'; interface SessionItemProps { diff --git a/src/features/SessionList/List/index.tsx b/src/features/SessionList/List/index.tsx index f03fb926..60eb10d8 100644 --- a/src/features/SessionList/List/index.tsx +++ b/src/features/SessionList/List/index.tsx @@ -5,7 +5,7 @@ import LazyLoad from 'react-lazy-load'; import { useSessionStore } from '@/store/session'; import { sessionSelectors } from '@/store/session/selectors'; -import SessionItem from './SessionItem'; +import SessionItem from './Item'; const useStyles = createStyles( ({ css }) => css` diff --git a/src/features/SessionList/SearchBar/index.tsx b/src/features/SessionList/SearchBar/index.tsx new file mode 100644 index 00000000..102b266f --- /dev/null +++ b/src/features/SessionList/SearchBar/index.tsx @@ -0,0 +1,28 @@ +import { SearchBar } from '@lobehub/ui'; +import React, { memo } from 'react'; + +interface Props { + className?: string; + onChange?: (value: string) => void; + style?: React.CSSProperties; + value?: string; +} + +// eslint-disable-next-line react/display-name +export default memo((props: Props) => { + const { value, onChange, style, className } = props; + + return ( + { + if (onChange) onChange(e.target.value); + }} + placeholder="搜索" + shortKey="f" + value={value} + style={style} + className={className} + /> + ); +}); diff --git a/src/features/SessionList/Header/style.ts b/src/features/SessionList/SearchBar/style.ts similarity index 66% rename from src/features/SessionList/Header/style.ts rename to src/features/SessionList/SearchBar/style.ts index 1828790f..298fa9dd 100644 --- a/src/features/SessionList/Header/style.ts +++ b/src/features/SessionList/SearchBar/style.ts @@ -1,10 +1,7 @@ import { createStyles } from 'antd-style'; -import { HEADER_HEIGHT } from '@/constants/common'; - export const useStyles = createStyles(({ css, token }) => ({ header: css` - height: ${HEADER_HEIGHT}px; padding: ${token.paddingXS}px; `, })); diff --git a/src/features/SessionList/index.tsx b/src/features/SessionList/index.tsx index 67624f68..61b34e3d 100644 --- a/src/features/SessionList/index.tsx +++ b/src/features/SessionList/index.tsx @@ -1,20 +1,14 @@ -import { DraggablePanel, Icon } from '@lobehub/ui'; +import { Icon } from '@lobehub/ui'; import { Collapse } from 'antd'; import { createStyles } from 'antd-style'; import { ChevronDown } from 'lucide-react'; import { useState } from 'react'; -import { SIDEBAR_MAX_WIDTH, SIDEBAR_WIDTH } from '@/constants/common'; -import V from '@/features/SessionList/V'; - -import Header from './Header'; import List from './List'; +import SearchBar from './SearchBar'; +import V from './V'; const useStyles = createStyles(({ css, token, prefixCls }) => ({ - content: css` - display: flex; - flex-direction: column; - `, list: css` padding: 8px; `, @@ -52,46 +46,39 @@ const SideBar = () => { const [searchName, setSearchName] = useState(); return ( - -
+ { setSearchName(value); }} value={searchName} + style={{ marginBottom: 8 }} + /> + + ( + + )} + expandIconPosition={'end'} + ghost + size={'small'} + items={[ + { + children: , + label: '默认列表', + key: 'default', + }, + ]} /> -
- - ( - - )} - expandIconPosition={'end'} - ghost - size={'small'} - items={[ - { - children: , - label: '会话列表', - key: 'default', - }, - ]} - /> -
- +
); }; diff --git a/src/hooks/useIsMobile.ts b/src/hooks/useIsMobile.ts new file mode 100644 index 00000000..e24d4336 --- /dev/null +++ b/src/hooks/useIsMobile.ts @@ -0,0 +1,7 @@ +import { useResponsive } from 'antd-style'; + +export const useIsMobile = (): boolean => { + const { mobile } = useResponsive(); + + return !!mobile; +}; diff --git a/src/layout/Header/index.tsx b/src/layout/Header/index.tsx index 6bf67fc3..cee6d6a3 100644 --- a/src/layout/Header/index.tsx +++ b/src/layout/Header/index.tsx @@ -33,7 +33,7 @@ const Header = (props: Props) => { size="large" />, ]} - logo={} + logo={} nav={ { className={className} panelKey="agent" style={style} - title="角色列表" + title="我的角色" extra={} >
diff --git a/src/store/global.ts b/src/store/global.ts new file mode 100644 index 00000000..84ead8dd --- /dev/null +++ b/src/store/global.ts @@ -0,0 +1,21 @@ +import { shallow } from 'zustand/shallow'; +import { createWithEqualityFn } from 'zustand/traditional'; + +interface GlobalStore { + setChatSidebar: (show: boolean) => void; + showChatSidebar: boolean; + toggleChatSideBar: () => void; +} + +export const useGlobalStore = createWithEqualityFn()( + (set) => ({ + setChatSidebar: (show) => { + set({ showChatSidebar: show }); + }, + toggleChatSideBar: () => { + set((state) => ({ showChatSidebar: !state.showChatSidebar })); + }, + showChatSidebar: true, + }), + shallow, +);