mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
✨ feat: Introduce new features and styles for chat application
The changes include importing new components, modifying existing styles, and introducing new components. The code snippets provided show changes made to various files in a chat application, including changes to ActionIcon components, header components, session item components, and the structure and styling of the chat session list component. The code changes also involve the addition of new files for CSS overrides and global styles, as well as modifications to index pages and chat session selectors. The purpose of these changes is to enhance the functionality and user experience of the chat application by introducing new features and improving the overall styling.
This commit is contained in:
@@ -3,11 +3,15 @@ const i18n = require('./.i18nrc');
|
||||
/** @type {import('next-i18next').UserConfig} */
|
||||
module.exports = {
|
||||
debug: process.env.NODE_ENV === 'development',
|
||||
fallbackLng: {
|
||||
default: ['en'],
|
||||
zh_TW: ['zh_CN'],
|
||||
},
|
||||
i18n: {
|
||||
defaultLocale: i18n.entryLocale,
|
||||
locales: [i18n.entryLocale, ...i18n.outputLocales],
|
||||
},
|
||||
localePath:
|
||||
typeof window === 'undefined' ? require('node:path').resolve('./', i18n.output) : '/locales',
|
||||
typeof window === 'undefined' ? require('node:path').resolve('./public/locales') : '/locales',
|
||||
reloadOnPrerender: process.env.NODE_ENV === 'development',
|
||||
};
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
{
|
||||
"agentProfile": "Agent Profile",
|
||||
"archive": "Archive",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"confirmRemoveSessionItemAlert": "You are about to remove this agent. Once removed, it cannot be recovered. Please confirm your action.",
|
||||
"defaultAgent": "Default Agent",
|
||||
"edit": "Edit",
|
||||
"newAgent": "New Agent",
|
||||
"noDescription": "No description",
|
||||
"ok": "OK",
|
||||
"searchAgentPlaceholder": "Search agents and conversations...",
|
||||
"sessionSetting": "Session Setting",
|
||||
"setting": "Setting",
|
||||
"share": "Share"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
{
|
||||
"agentProfile": "エージェントプロファイル",
|
||||
"archive": "アーカイブ",
|
||||
"cancel": "キャンセル",
|
||||
"close": "閉じる",
|
||||
"confirmRemoveSessionItemAlert": "このエージェントを削除します。削除後は元に戻すことはできません。操作を確認してください",
|
||||
"defaultAgent": "デフォルトエージェント",
|
||||
"edit": "編集",
|
||||
"newAgent": "新しいエージェント",
|
||||
"noDescription": "説明はありません",
|
||||
"ok": "OK",
|
||||
"searchAgentPlaceholder": "エージェントと会話を検索...",
|
||||
"sessionSetting": "セッション設定",
|
||||
"setting": "設定",
|
||||
"share": "共有する"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
{
|
||||
"agentProfile": "도우미 프로필",
|
||||
"archive": "보관",
|
||||
"cancel": "취소",
|
||||
"close": "닫기",
|
||||
"confirmRemoveSessionItemAlert": "이 도우미를 삭제하려고 합니다. 삭제 후에는 복구할 수 없으므로 작업을 확인하십시오.",
|
||||
"defaultAgent": "기본 도우미",
|
||||
"edit": "편집",
|
||||
"newAgent": "새 도우미",
|
||||
"noDescription": "설명 없음",
|
||||
"ok": "확인",
|
||||
"searchAgentPlaceholder": "도우미 및 대화 검색...",
|
||||
"sessionSetting": "세션 설정",
|
||||
"setting": "설정",
|
||||
"share": "공유"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
{
|
||||
"agentProfile": "助手信息",
|
||||
"archive": "归档",
|
||||
"cancel": "取消",
|
||||
"close": "关闭",
|
||||
"confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作",
|
||||
"defaultAgent": "默认助手",
|
||||
"edit": "编辑",
|
||||
"newAgent": "新建助手",
|
||||
"noDescription": "暂无描述",
|
||||
"ok": "确定",
|
||||
"searchAgentPlaceholder": "搜索助手和对话...",
|
||||
"sessionSetting": "会话设置",
|
||||
"setting": "设置",
|
||||
"share": "分享"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
{
|
||||
"agentProfile": "助手資訊",
|
||||
"archive": "歸檔",
|
||||
"cancel": "取消",
|
||||
"close": "關閉",
|
||||
"confirmRemoveSessionItemAlert": "即將刪除該助手,刪除後將無法找回,請確認你的操作",
|
||||
"defaultAgent": "默認助手",
|
||||
"edit": "編輯",
|
||||
"newAgent": "新建助手",
|
||||
"noDescription": "暫無描述",
|
||||
"ok": "確定",
|
||||
"searchAgentPlaceholder": "搜索助手和對話...",
|
||||
"sessionSetting": "會話設置",
|
||||
"setting": "設置",
|
||||
"share": "分享"
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export const useStyles = createStyles(({ css, token }) => ({
|
||||
panel: css`
|
||||
height: 100vh;
|
||||
color: ${token.colorTextSecondary};
|
||||
background: ${token.colorBgContainer};
|
||||
`,
|
||||
}));
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@ import Zh_CN from 'antd/locale/zh_CN';
|
||||
import { PropsWithChildren, useEffect } from 'react';
|
||||
import { useChatStore } from 'src/store/session';
|
||||
|
||||
import { GlobalStyle, useStyles } from './style';
|
||||
import { GlobalStyle } from '@/styles';
|
||||
|
||||
import { useStyles } from './style';
|
||||
|
||||
const Layout = ({ children }: PropsWithChildren) => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { createGlobalStyle, createStyles } from 'antd-style';
|
||||
import { rgba } from 'polished';
|
||||
|
||||
export const NOTIFICATION_PRIMARY = 'notification-primary-info';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => ({
|
||||
bg: css`
|
||||
@@ -13,82 +10,9 @@ export const useStyles = createStyles(({ css, token }) => ({
|
||||
height: 100%;
|
||||
|
||||
background: ${token.colorBgLayout};
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
${token.colorBgContainer} 0%,
|
||||
rgba(255, 255, 255, 0%) 20%
|
||||
);
|
||||
|
||||
:has(#ChatLayout, #FlowLayout) {
|
||||
overflow: hidden;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
export const GlobalStyle = createGlobalStyle`
|
||||
.ant-btn {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#__next {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ant-btn-default:not(:disabled):not(.ant-btn-dangerous) {
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
color: ${(p) => p.theme.colorText};
|
||||
background: ${({ theme }) => (theme.isDarkMode ? theme.colorFill : theme.colorFillTertiary)};
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-popover {
|
||||
z-index: 1100;
|
||||
}
|
||||
|
||||
|
||||
/* 定义滚动槽的样式 */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-right: 4px;
|
||||
background-color: transparent; /* 定义滚动槽的背景色 */
|
||||
|
||||
&-thumb {
|
||||
background-color: ${({ theme }) => theme.colorFill}; /* 定义滚动块的背景色 */
|
||||
border-radius: 4px; /* 定义滚动块的圆角半径 */
|
||||
}
|
||||
|
||||
&-corner {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-notification .ant-notification-notice.${NOTIFICATION_PRIMARY} {
|
||||
background: ${(p) => p.theme.colorPrimary};
|
||||
box-shadow: 0 6px 16px 0 ${({ theme }) => rgba(theme.colorPrimary, 0.1)},
|
||||
0 3px 6px -4px ${({ theme }) => rgba(theme.colorPrimary, 0.2)},
|
||||
0 9px 28px 8px ${({ theme }) => rgba(theme.colorPrimary, 0.1)};
|
||||
|
||||
.anticon {
|
||||
color: ${(p) => p.theme.colorTextLightSolid}
|
||||
}
|
||||
|
||||
.ant-notification-notice-message {
|
||||
margin-bottom: 0;
|
||||
padding-right: 0;
|
||||
color: ${(p) => p.theme.colorTextLightSolid};
|
||||
}
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ActionIcon, DraggablePanel } from '@lobehub/ui';
|
||||
import { ActionIcon, DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { LucideEdit, LucideX } from 'lucide-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
@@ -8,9 +9,11 @@ import { useChatStore } from '@/store/session';
|
||||
|
||||
import ReadMode from './ReadMode';
|
||||
|
||||
const WIDTH = 280;
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
drawer: css`
|
||||
background: ${token.colorBgContainer};
|
||||
background: ${token.colorBgLayout};
|
||||
`,
|
||||
header: css`
|
||||
border-bottom: 1px solid ${token.colorBorder};
|
||||
@@ -18,6 +21,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
}));
|
||||
|
||||
const Config = () => {
|
||||
const { t } = useTranslation('common');
|
||||
const { styles } = useStyles();
|
||||
const [showAgentSettings, toggleConfig] = useChatStore(
|
||||
(s) => [s.showAgentSettings, s.toggleConfig],
|
||||
@@ -29,32 +33,41 @@ const Config = () => {
|
||||
className={styles.drawer}
|
||||
expand={showAgentSettings}
|
||||
expandable={false}
|
||||
minWidth={400}
|
||||
maxWidth={WIDTH}
|
||||
minWidth={WIDTH}
|
||||
mode={'float'}
|
||||
pin
|
||||
placement={'right'}
|
||||
resize={{ left: false }}
|
||||
>
|
||||
<Flexbox
|
||||
align={'center'}
|
||||
className={styles.header}
|
||||
distribution={'space-between'}
|
||||
horizontal
|
||||
padding={16}
|
||||
>
|
||||
<Flexbox>会话设置</Flexbox>
|
||||
<Flexbox horizontal>
|
||||
<ActionIcon icon={LucideEdit} title={'编辑'} />
|
||||
<ActionIcon
|
||||
icon={LucideX}
|
||||
onClick={() => {
|
||||
toggleConfig(false);
|
||||
}}
|
||||
title={'关闭'}
|
||||
/>
|
||||
<DraggablePanelContainer style={{ flex: 'none', minWidth: WIDTH }}>
|
||||
<Flexbox
|
||||
align={'center'}
|
||||
className={styles.header}
|
||||
distribution={'space-between'}
|
||||
horizontal
|
||||
padding={12}
|
||||
paddingInline={16}
|
||||
>
|
||||
<Flexbox>{t('agentProfile')}</Flexbox>
|
||||
<Flexbox gap={4} horizontal>
|
||||
<ActionIcon
|
||||
icon={LucideEdit}
|
||||
size={{ blockSize: 32, fontSize: 20 }}
|
||||
title={t('edit')}
|
||||
/>
|
||||
<ActionIcon
|
||||
icon={LucideX}
|
||||
onClick={() => {
|
||||
toggleConfig(false);
|
||||
}}
|
||||
size={{ blockSize: 32, fontSize: 20 }}
|
||||
title={t('close')}
|
||||
/>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
<ReadMode />
|
||||
<ReadMode />
|
||||
</DraggablePanelContainer>
|
||||
</DraggablePanel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -44,8 +44,7 @@ const Header = memo(() => {
|
||||
align={'center'}
|
||||
distribution={'space-between'}
|
||||
horizontal
|
||||
padding={8}
|
||||
paddingInline={16}
|
||||
padding="8px 8px 8px 16px"
|
||||
style={{
|
||||
borderBottom: `1px solid ${theme.colorSplit}`,
|
||||
gridArea: 'header',
|
||||
@@ -54,20 +53,26 @@ const Header = memo(() => {
|
||||
<Flexbox align={'center'} gap={12} horizontal>
|
||||
<Avatar avatar={meta && sessionSelectors.getAgentAvatar(meta)} size={40} title={'123'} />
|
||||
<Flexbox>
|
||||
<Flexbox className={styles.title}>{meta?.title}</Flexbox>
|
||||
<Flexbox className={styles.desc}>{meta?.description || '暂无描述'}</Flexbox>
|
||||
<Flexbox className={styles.title}>{meta?.title || t('defaultAgent')}</Flexbox>
|
||||
<Flexbox className={styles.desc}>{meta?.description || t('noDescription')}</Flexbox>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
<Flexbox gap={16} horizontal>
|
||||
<Flexbox gap={8} horizontal>
|
||||
<ActionIcon
|
||||
icon={Share2Icon}
|
||||
onClick={() => {
|
||||
// genShareUrl();
|
||||
}}
|
||||
size={{ fontSize: 24 }}
|
||||
title={t('share')}
|
||||
/>
|
||||
<ActionIcon icon={ArchiveIcon} title={'归档'} />
|
||||
<ActionIcon icon={MoreVerticalIcon} onClick={toggleConfig} />
|
||||
<ActionIcon icon={ArchiveIcon} size={{ fontSize: 24 }} title={t('archive')} />
|
||||
<ActionIcon
|
||||
icon={MoreVerticalIcon}
|
||||
onClick={toggleConfig}
|
||||
size={{ fontSize: 24 }}
|
||||
title={t('sessionSetting')}
|
||||
/>
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ActionIcon, Logo, SearchBar } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { MessageSquarePlus } from 'lucide-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import Link from 'next/link';
|
||||
import { memo } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
@@ -20,25 +21,32 @@ export const useStyles = createStyles(({ css, token }) => ({
|
||||
|
||||
const Header = memo(() => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
const { t } = useTranslation('common');
|
||||
const [keywords, createSession] = useChatStore(
|
||||
(s) => [s.searchKeywords, s.createSession],
|
||||
shallow,
|
||||
);
|
||||
|
||||
return (
|
||||
<Flexbox className={styles.top} gap={16} padding={'16px 12px 0 16px'}>
|
||||
<Flexbox className={styles.top} gap={16} padding={16}>
|
||||
<Flexbox distribution={'space-between'} horizontal>
|
||||
<Link href={'/'}>
|
||||
<Logo className={styles.logo} size={36} type={'text'} />
|
||||
</Link>
|
||||
<ActionIcon icon={Plus} onClick={createSession} style={{ minWidth: 32 }} title={'新对话'} />
|
||||
<ActionIcon
|
||||
icon={MessageSquarePlus}
|
||||
onClick={createSession}
|
||||
size={{ fontSize: 24 }}
|
||||
style={{ flex: 'none' }}
|
||||
title={t('newAgent')}
|
||||
/>
|
||||
</Flexbox>
|
||||
<SearchBar
|
||||
allowClear
|
||||
onChange={(e) => useChatStore.setState({ searchKeywords: e.target.value })}
|
||||
placeholder="Search..."
|
||||
type={'block'}
|
||||
placeholder={t('searchAgentPlaceholder')}
|
||||
spotlight
|
||||
type={'ghost'}
|
||||
value={keywords}
|
||||
/>
|
||||
</Flexbox>
|
||||
|
||||
@@ -1,66 +1,31 @@
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
import { Avatar, List } from '@lobehub/ui';
|
||||
import { ActionIcon, Avatar, List } from '@lobehub/ui';
|
||||
import { Popconfirm } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { X } from 'lucide-react';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { FC, memo } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { sessionSelectors, useChatStore } from '@/store/session';
|
||||
|
||||
const useStyles = createStyles(({ css, cx }) => {
|
||||
const closeCtn = css`
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 2px;
|
||||
transform: translateY(-50%);
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
font-size: 10px;
|
||||
|
||||
opacity: 0;
|
||||
`;
|
||||
return {
|
||||
active: css`
|
||||
opacity: 1;
|
||||
`,
|
||||
closeCtn,
|
||||
container: css`
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.${cx(closeCtn)} {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`,
|
||||
time: css`
|
||||
align-self: flex-start;
|
||||
`,
|
||||
};
|
||||
});
|
||||
import { useStyles } from './style';
|
||||
|
||||
interface SessionItemProps {
|
||||
active: boolean;
|
||||
id: string;
|
||||
loading: boolean;
|
||||
simple?: boolean;
|
||||
}
|
||||
|
||||
const SessionItem: FC<SessionItemProps> = memo(({ id, active, simple = true, loading }) => {
|
||||
const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading }) => {
|
||||
const { t } = useTranslation('common');
|
||||
const { styles, theme, cx } = useStyles();
|
||||
const [title, systemRole, avatar, avatarBackground, updateAt, switchAgent, removeSession] =
|
||||
useChatStore((s) => {
|
||||
const session = sessionSelectors.getSessionById(id)(s);
|
||||
const meta = session.meta;
|
||||
|
||||
const systemRole = session.config.systemRole;
|
||||
|
||||
return [
|
||||
meta.title || systemRole || '默认角色',
|
||||
systemRole,
|
||||
meta.title || t('noDescription'),
|
||||
systemRole || t('defaultAgent'),
|
||||
sessionSelectors.getAgentAvatar(meta),
|
||||
meta.backgroundColor,
|
||||
session?.updateAt,
|
||||
@@ -70,42 +35,43 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active, simple = true, loa
|
||||
}, shallow);
|
||||
|
||||
return (
|
||||
<Flexbox className={styles.container} gap={4} paddingBlock={4}>
|
||||
<List.Item
|
||||
active={active}
|
||||
avatar={
|
||||
<Avatar
|
||||
avatar={avatar}
|
||||
background={avatarBackground}
|
||||
shape="circle"
|
||||
size={46}
|
||||
title={title}
|
||||
/>
|
||||
}
|
||||
className={styles.container}
|
||||
classNames={{ time: cx('session-time', styles.time) }}
|
||||
date={updateAt}
|
||||
description={title}
|
||||
loading={loading}
|
||||
onClick={() => {
|
||||
switchAgent(id);
|
||||
}}
|
||||
style={{
|
||||
alignItems: 'center',
|
||||
color: theme.colorText,
|
||||
}}
|
||||
title={systemRole}
|
||||
>
|
||||
<Popconfirm
|
||||
arrow={false}
|
||||
cancelText={t('cancel')}
|
||||
okButtonProps={{ danger: true }}
|
||||
okText={t('ok')}
|
||||
onConfirm={() => removeSession(id)}
|
||||
overlayStyle={{ width: 280 }}
|
||||
placement={'right'}
|
||||
title={'即将删除该会话,删除后该将无法找回,请确认你的操作。'}
|
||||
title={t('confirmRemoveSessionItemAlert')}
|
||||
>
|
||||
<CloseOutlined className={cx(styles.closeCtn, active && styles.active)} />
|
||||
<ActionIcon className="session-remove" icon={X} size={'small'} />
|
||||
</Popconfirm>
|
||||
<List.Item
|
||||
active={active}
|
||||
avatar={
|
||||
<Avatar
|
||||
avatar={avatar}
|
||||
background={avatarBackground}
|
||||
shape="circle"
|
||||
size={46}
|
||||
title={title}
|
||||
/>
|
||||
}
|
||||
classNames={{ time: styles.time }}
|
||||
date={updateAt}
|
||||
description={simple ? undefined : systemRole}
|
||||
loading={loading}
|
||||
onClick={() => {
|
||||
switchAgent(id);
|
||||
}}
|
||||
style={{
|
||||
alignItems: 'center',
|
||||
color: theme.colorText,
|
||||
}}
|
||||
title={title}
|
||||
/>
|
||||
</Flexbox>
|
||||
</List.Item>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,49 +1,30 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { rgba } from 'polished';
|
||||
import { memo } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import { useStyles } from '@/pages/chat/SessionList/List/style';
|
||||
import { sessionSelectors, useChatStore } from '@/store/session';
|
||||
|
||||
import SessionItem from './SessionItem';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => ({
|
||||
button: css`
|
||||
position: sticky;
|
||||
z-index: 30;
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin-top: 8px;
|
||||
padding: 12px;
|
||||
|
||||
background: ${rgba(token.colorBgLayout, 0.5)};
|
||||
backdrop-filter: blur(8px);
|
||||
`,
|
||||
}));
|
||||
|
||||
const SessionList = memo(() => {
|
||||
const { styles, cx } = useStyles();
|
||||
const [list, activeId, loading] = useChatStore(
|
||||
(s) => [sessionSelectors.chatList(s), s.activeId, s.loading.summarizingTitle],
|
||||
shallow,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flexbox className={cx(styles.list)}>
|
||||
{list.map(({ id }) => (
|
||||
<SessionItem
|
||||
active={activeId === id}
|
||||
id={id}
|
||||
key={id}
|
||||
loading={loading && id === activeId}
|
||||
simple={false}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
77
src/pages/chat/SessionList/List/style.ts
Normal file
77
src/pages/chat/SessionList/List/style.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { rgba } from 'polished';
|
||||
|
||||
export const useStyles = createStyles(({ css, token, cx, stylish }) => {
|
||||
return {
|
||||
active: css`
|
||||
display: flex;
|
||||
`,
|
||||
button: css`
|
||||
position: sticky;
|
||||
z-index: 30;
|
||||
bottom: 0;
|
||||
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
margin-top: 8px;
|
||||
padding: 12px;
|
||||
|
||||
background: ${rgba(token.colorBgLayout, 0.5)};
|
||||
backdrop-filter: blur(8px);
|
||||
`,
|
||||
|
||||
container: css`
|
||||
position: relative;
|
||||
|
||||
.session-remove {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 16px;
|
||||
transform: translateY(-50%);
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
font-size: 10px;
|
||||
|
||||
opacity: 0;
|
||||
background-color: ${token.colorFillTertiary};
|
||||
|
||||
transition: color 600ms ${token.motionEaseOut}, scale 400ms ${token.motionEaseOut},
|
||||
background-color 100ms ${token.motionEaseOut}, opacity 100ms ${token.motionEaseOut};
|
||||
|
||||
&:hover {
|
||||
background-color: ${token.colorFill};
|
||||
}
|
||||
}
|
||||
|
||||
.session-time {
|
||||
opacity: 1;
|
||||
transition: opacity 100ms ${token.motionEaseOut};
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.session-time {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.session-remove {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`,
|
||||
list: cx(
|
||||
stylish.noScrollbar,
|
||||
css`
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
`,
|
||||
),
|
||||
time: css`
|
||||
align-self: flex-start;
|
||||
`,
|
||||
};
|
||||
});
|
||||
@@ -1,4 +1,3 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
@@ -7,24 +6,12 @@ import FolderPanel from '@/features/FolderPanel';
|
||||
import Header from './Header';
|
||||
import SessionList from './List';
|
||||
|
||||
export const useStyles = createStyles(({ css }) => ({
|
||||
center: css`
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
padding-inline: 4px 0;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const Sessions = memo(() => {
|
||||
const { styles, cx } = useStyles();
|
||||
|
||||
return (
|
||||
<FolderPanel>
|
||||
<Flexbox gap={8} height={'100%'}>
|
||||
<Header />
|
||||
<Flexbox className={cx(styles.center)}>
|
||||
<SessionList />
|
||||
</Flexbox>
|
||||
<SessionList />
|
||||
</Flexbox>
|
||||
</FolderPanel>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ActionIcon, Logo, SideNav } from '@lobehub/ui';
|
||||
import { Album, MessageSquare, Settings2 } from 'lucide-react';
|
||||
import { MessageSquare, Settings2, Sticker } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
@@ -22,7 +22,7 @@ const Sidebar = memo(() => {
|
||||
/>
|
||||
<ActionIcon
|
||||
active={tab === 'market'}
|
||||
icon={Album}
|
||||
icon={Sticker}
|
||||
onClick={() => setTab('market')}
|
||||
size="large"
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { GetStaticProps, InferGetStaticPropsType } from 'next';
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
|
||||
import { memo } from 'react';
|
||||
|
||||
import Chat from './chat/index.page';
|
||||
|
||||
@@ -14,4 +15,4 @@ export const getStaticProps: GetStaticProps = async ({ locale }) => ({
|
||||
},
|
||||
});
|
||||
|
||||
export default Index;
|
||||
export default memo(Index);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { MetaData } from '@/types/meta';
|
||||
|
||||
export const getAgentAvatar = (s: MetaData) =>
|
||||
s.avatar || 'https://npm.elemecdn.com/@lobehub/assets-logo/assets/logo-3d.webp';
|
||||
export const getAgentAvatar = (s: MetaData) => s.avatar || '😎';
|
||||
|
||||
39
src/styles/antdOverride.ts
Normal file
39
src/styles/antdOverride.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Theme, css } from 'antd-style';
|
||||
import { rgba } from 'polished';
|
||||
|
||||
export default (token: Theme) => css`
|
||||
.ant-btn {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.ant-btn-default:not(:disabled):not(.ant-btn-dangerous) {
|
||||
border-color: transparent;
|
||||
|
||||
&:hover {
|
||||
color: ${token.colorText};
|
||||
background: ${token.isDarkMode ? token.colorFill : token.colorFillTertiary};
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-popover {
|
||||
z-index: 1100;
|
||||
}
|
||||
|
||||
.ant-notification .ant-notification-notice.notification-primary-info {
|
||||
background: ${token.colorPrimary};
|
||||
box-shadow: 0 6px 16px 0 ${rgba(token.colorPrimary, 0.1)},
|
||||
0 3px 6px -4px ${rgba(token.colorPrimary, 0.2)},
|
||||
0 9px 28px 8px ${rgba(token.colorPrimary, 0.1)};
|
||||
|
||||
.anticon {
|
||||
color: ${token.colorTextLightSolid};
|
||||
}
|
||||
|
||||
.ant-notification-notice-message {
|
||||
margin-bottom: 0;
|
||||
padding-right: 0;
|
||||
color: ${token.colorTextLightSolid};
|
||||
}
|
||||
}
|
||||
`;
|
||||
23
src/styles/global.ts
Normal file
23
src/styles/global.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { css } from 'antd-style';
|
||||
|
||||
export default () => css`
|
||||
body,
|
||||
.ant-app {
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#__next {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
6
src/styles/index.ts
Normal file
6
src/styles/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { createGlobalStyle } from 'antd-style';
|
||||
|
||||
import antdOverride from './antdOverride';
|
||||
import global from './global';
|
||||
|
||||
export const GlobalStyle = createGlobalStyle(({ theme }) => [global(), antdOverride(theme)]);
|
||||
14
src/types/global.d.ts
vendored
Normal file
14
src/types/global.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { LobeCustomStylish, LobeCustomToken } from '@lobehub/ui';
|
||||
import 'antd-style';
|
||||
import { AntdToken } from 'antd-style/lib/types/theme';
|
||||
|
||||
declare module 'antd-style' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface CustomToken extends LobeCustomToken {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface CustomStylish extends LobeCustomStylish {}
|
||||
}
|
||||
|
||||
declare module 'styled-components' {
|
||||
export interface DefaultTheme extends AntdToken, LobeCustomToken {}
|
||||
}
|
||||
Reference in New Issue
Block a user