mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-14 03:30:19 +00:00
✨ feat: improve pin mode about session group (#369)
* 🚧 wip: add pin group * 💄 style: improve styles * ✨ feat: improve pin mode session group
This commit is contained in:
@@ -7,7 +7,17 @@ import FolderPanel from '@/features/FolderPanel';
|
||||
import SessionListContent from '../../features/SessionListContent';
|
||||
import Header from './SessionHeader';
|
||||
|
||||
const useStyles = createStyles(({ stylish }) => stylish.noScrollbar);
|
||||
const useStyles = createStyles(({ stylish, css, cx }) =>
|
||||
cx(
|
||||
stylish.noScrollbar,
|
||||
css`
|
||||
padding: 0 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
`,
|
||||
),
|
||||
);
|
||||
|
||||
const Sessions = memo(() => {
|
||||
const { styles } = useStyles();
|
||||
@@ -15,7 +25,7 @@ const Sessions = memo(() => {
|
||||
return (
|
||||
<FolderPanel>
|
||||
<Header />
|
||||
<DraggablePanelBody className={styles} style={{ padding: 0 }}>
|
||||
<DraggablePanelBody className={styles}>
|
||||
<SessionListContent />
|
||||
</DraggablePanelBody>
|
||||
</FolderPanel>
|
||||
|
||||
@@ -6,10 +6,10 @@ import { memo } from 'react';
|
||||
|
||||
const useStyles = createStyles(({ css, prefixCls, token }) => ({
|
||||
container: css`
|
||||
border-radius: 0;
|
||||
.${prefixCls}-collapse-header {
|
||||
padding-inline: 16px !important;
|
||||
color: ${token.colorTextDescription} !important;
|
||||
border-radius: 8px !important;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorText} !important;
|
||||
|
||||
@@ -49,7 +49,7 @@ const Inbox = memo(() => {
|
||||
active={mobile ? false : activeId === INBOX_SESSION_ID}
|
||||
avatar={avatarRender}
|
||||
ref={ref}
|
||||
style={{ alignItems: 'center' }}
|
||||
style={{ alignItems: 'center', borderRadius: 8 }}
|
||||
title={t('inbox.title')}
|
||||
/>
|
||||
</Link>
|
||||
|
||||
@@ -18,6 +18,7 @@ const useStyles = createStyles(({ css }) => {
|
||||
return {
|
||||
container: css`
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
`,
|
||||
|
||||
modalRoot: css`
|
||||
@@ -96,21 +97,23 @@ const SessionItem = memo<SessionItemProps>(({ id }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Item
|
||||
actions={actions}
|
||||
// needn't active state in mobile
|
||||
active={mobile ? false : active}
|
||||
addon={addon}
|
||||
avatar={avatarRender}
|
||||
className={styles.container}
|
||||
date={updateAt}
|
||||
description={description || systemRole}
|
||||
loading={loading}
|
||||
pin={pin}
|
||||
ref={ref}
|
||||
showAction={open || isHovering}
|
||||
title={title}
|
||||
/>
|
||||
<Flexbox paddingBlock={1}>
|
||||
<Item
|
||||
actions={actions}
|
||||
// needn't active state in mobile
|
||||
active={mobile ? false : active}
|
||||
addon={addon}
|
||||
avatar={avatarRender}
|
||||
className={styles.container}
|
||||
date={updateAt}
|
||||
description={description || systemRole}
|
||||
loading={loading}
|
||||
pin={pin}
|
||||
ref={ref}
|
||||
showAction={open || isHovering}
|
||||
title={title}
|
||||
/>
|
||||
</Flexbox>
|
||||
);
|
||||
}, shallow);
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { createStyles, useResponsive } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
import LazyLoad from 'react-lazy-load';
|
||||
|
||||
import { SESSION_CHAT_URL } from '@/const/url';
|
||||
import { useSessionHydrated, useSessionStore } from '@/store/session';
|
||||
import { sessionSelectors } from '@/store/session/selectors';
|
||||
import { LobeAgentSession } from '@/types/session';
|
||||
|
||||
import AddButton from './AddButton';
|
||||
import SessionItem from './Item';
|
||||
@@ -18,8 +17,10 @@ const useStyles = createStyles(
|
||||
`,
|
||||
);
|
||||
|
||||
const SessionList = memo(() => {
|
||||
const list = useSessionStore(sessionSelectors.sessionList, isEqual);
|
||||
interface SessionListProps {
|
||||
dataSource: LobeAgentSession[];
|
||||
}
|
||||
const SessionList = memo<SessionListProps>(({ dataSource }) => {
|
||||
const [activeSession, switchSession] = useSessionStore((s) => [s.activeSession, s.switchSession]);
|
||||
const { styles } = useStyles();
|
||||
const isInit = useSessionHydrated();
|
||||
@@ -28,8 +29,8 @@ const SessionList = memo(() => {
|
||||
|
||||
return !isInit ? (
|
||||
<SkeletonList />
|
||||
) : list.length > 0 ? (
|
||||
list.map(({ id }) => (
|
||||
) : dataSource.length > 0 ? (
|
||||
dataSource.map(({ id }) => (
|
||||
<LazyLoad className={styles} key={id}>
|
||||
<Link
|
||||
aria-label={id}
|
||||
|
||||
@@ -1,28 +1,52 @@
|
||||
import { CollapseProps } from 'antd';
|
||||
import { memo, useMemo } from 'react';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { preferenceSelectors, useGlobalStore } from '@/store/global';
|
||||
import { useSessionStore } from '@/store/session';
|
||||
import { sessionSelectors } from '@/store/session/selectors';
|
||||
|
||||
import CollapseGroup from './CollapseGroup';
|
||||
import Inbox from './Inbox';
|
||||
import SessionList from './List';
|
||||
|
||||
const SessionListContent = memo(() => {
|
||||
const { t } = useTranslation('common');
|
||||
const items: CollapseProps['items'] = useMemo(
|
||||
() => [
|
||||
{
|
||||
children: <SessionList />,
|
||||
key: 'sessionList',
|
||||
label: t('sessionList'),
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
const { t } = useTranslation('chat');
|
||||
const unpinnedSessionList = useSessionStore(sessionSelectors.unpinnedSessionList, isEqual);
|
||||
const pinnedList = useSessionStore(sessionSelectors.pinnedSessionList, isEqual);
|
||||
const hasPinnedSessionList = useSessionStore(sessionSelectors.hasPinnedSessionList);
|
||||
|
||||
const [sessionGroupKeys, updatePreference] = useGlobalStore((s) => [
|
||||
preferenceSelectors.sessionGroupKeys(s),
|
||||
s.updatePreference,
|
||||
]);
|
||||
|
||||
const items = [
|
||||
hasPinnedSessionList && {
|
||||
children: <SessionList dataSource={pinnedList} />,
|
||||
key: 'pinned',
|
||||
label: t('pin'),
|
||||
},
|
||||
{
|
||||
children: <SessionList dataSource={unpinnedSessionList} />,
|
||||
key: 'sessionList',
|
||||
label: t('sessionList'),
|
||||
},
|
||||
].filter(Boolean) as CollapseProps['items'];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Inbox />
|
||||
<CollapseGroup defaultActiveKey={['sessionList']} items={items} />
|
||||
<CollapseGroup
|
||||
activeKey={sessionGroupKeys}
|
||||
items={items}
|
||||
onChange={(keys) => {
|
||||
const sessionGroupKeys = typeof keys === 'string' ? [keys] : keys;
|
||||
|
||||
updatePreference({ sessionGroupKeys });
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -18,12 +18,14 @@ export default {
|
||||
newAgent: '新建助手',
|
||||
noDescription: '暂无描述',
|
||||
|
||||
pin: '置顶',
|
||||
pinOff: '取消置顶',
|
||||
regenerate: '重新生成',
|
||||
|
||||
roleAndArchive: '角色与记录',
|
||||
searchAgentPlaceholder: '搜索助手和对话...',
|
||||
send: '发送',
|
||||
sendPlaceholder: '输入聊天内容...',
|
||||
sessionList: '助手列表',
|
||||
shareModal: {
|
||||
download: '下载截图',
|
||||
imageType: '图片格式',
|
||||
|
||||
@@ -45,6 +45,7 @@ export default {
|
||||
noDescription: '暂无描述',
|
||||
ok: '确定',
|
||||
password: '密码',
|
||||
|
||||
pin: '置顶',
|
||||
pinOff: '取消置顶',
|
||||
regenerate: '重新生成',
|
||||
@@ -52,7 +53,6 @@ export default {
|
||||
reset: '重置',
|
||||
retry: '重试',
|
||||
send: '发送',
|
||||
sessionList: '助手列表',
|
||||
setting: '设置',
|
||||
share: '分享',
|
||||
stop: '停止',
|
||||
@@ -62,7 +62,6 @@ export default {
|
||||
setting: '设置',
|
||||
},
|
||||
temp: '临时',
|
||||
|
||||
updateAgent: '更新助理信息',
|
||||
upgradeVersion: {
|
||||
action: '立即升级',
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface GlobalPreference {
|
||||
guide?: Guide;
|
||||
inputHeight: number;
|
||||
mobileShowTopic?: boolean;
|
||||
sessionGroupKeys: string[];
|
||||
sessionsWidth: number;
|
||||
showChatSideBar?: boolean;
|
||||
showSessionPanel?: boolean;
|
||||
@@ -49,6 +50,7 @@ export const initialState: GlobalState = {
|
||||
guide: {},
|
||||
inputHeight: 200,
|
||||
mobileShowTopic: false,
|
||||
sessionGroupKeys: ['pinned', 'sessionList'],
|
||||
sessionsWidth: 320,
|
||||
showChatSideBar: true,
|
||||
showSessionPanel: true,
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './selectors/preference';
|
||||
export * from './selectors/settings';
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { GlobalStore } from '@/store/global';
|
||||
|
||||
import { initialState } from '../initialState';
|
||||
|
||||
const sessionGroupKeys = (s: GlobalStore): string[] =>
|
||||
s.preference.sessionGroupKeys || initialState.preference.sessionGroupKeys;
|
||||
|
||||
export const preferenceSelectors = {
|
||||
sessionGroupKeys: sessionGroupKeys,
|
||||
};
|
||||
@@ -7,8 +7,11 @@ import {
|
||||
currentSessionSafe,
|
||||
getSessionById,
|
||||
getSessionMetaById,
|
||||
hasPinnedSessionList,
|
||||
hasSessionList,
|
||||
pinnedSessionList,
|
||||
sessionList,
|
||||
unpinnedSessionList,
|
||||
} from './list';
|
||||
|
||||
const isInboxSession = (s: SessionStore) => s.activeId === INBOX_SESSION_ID;
|
||||
@@ -21,7 +24,10 @@ export const sessionSelectors = {
|
||||
getExportAgent,
|
||||
getSessionById,
|
||||
getSessionMetaById,
|
||||
hasPinnedSessionList,
|
||||
hasSessionList,
|
||||
isInboxSession,
|
||||
pinnedSessionList,
|
||||
sessionList,
|
||||
unpinnedSessionList,
|
||||
};
|
||||
|
||||
@@ -39,10 +39,17 @@ export const sessionList = (s: SessionStore) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const pinnedSessionList = (s: SessionStore) => sessionList(s).filter((s) => s.pinned);
|
||||
export const unpinnedSessionList = (s: SessionStore) => sessionList(s).filter((s) => !s.pinned);
|
||||
|
||||
export const hasSessionList = (s: SessionStore) => {
|
||||
const list = sessionList(s);
|
||||
return list?.length > 0;
|
||||
};
|
||||
export const hasPinnedSessionList = (s: SessionStore) => {
|
||||
const list = pinnedSessionList(s);
|
||||
return list?.length > 0;
|
||||
};
|
||||
|
||||
export const getSessionById =
|
||||
(id: string) =>
|
||||
|
||||
Reference in New Issue
Block a user