feat(UI): Enhance ListItem and DataSettings with icons and styling improvements

- Add titleStyle prop to ListItem for custom text styling
- Reduce gap in ListItem and MenuList components
- Integrate icons for DataSettings menu items
- Add Notion icon to iconfont
- Improve visual hierarchy and spacing in settings navigation
This commit is contained in:
kangfenmao 2025-03-12 09:42:19 +08:00
parent f5d3c07161
commit ee653b1032
5 changed files with 42 additions and 26 deletions

View File

@ -1,6 +1,6 @@
@font-face { @font-face {
font-family: 'iconfont'; /* Project id 4753420 */ font-family: 'iconfont'; /* Project id 4753420 */
src: url('iconfont.woff2?t=1738750230250') format('woff2'); src: url('iconfont.woff2?t=1741743579060') format('woff2');
} }
.iconfont { .iconfont {
@ -11,6 +11,10 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-notion:before {
content: '\e690';
}
.icon-thinking:before { .icon-thinking:before {
content: '\e65b'; content: '\e65b';
} }
@ -19,10 +23,6 @@
content: '\e623'; content: '\e623';
} }
.icon-mcp:before {
content: '\e78e';
}
.icon-icon-adaptive-width:before { .icon-icon-adaptive-width:before {
content: '\e87a'; content: '\e87a';
} }
@ -31,10 +31,6 @@
content: '\e630'; content: '\e630';
} }
.icon-a-darkmode:before {
content: '\e6cd';
}
.icon-ai-model:before { .icon-ai-model:before {
content: '\e827'; content: '\e827';
} }

View File

@ -6,16 +6,17 @@ interface ListItemProps {
icon?: ReactNode icon?: ReactNode
title: string title: string
subtitle?: string subtitle?: string
titleStyle?: React.CSSProperties
onClick?: () => void onClick?: () => void
} }
const ListItem = ({ active, icon, title, subtitle, onClick }: ListItemProps) => { const ListItem = ({ active, icon, title, subtitle, titleStyle, onClick }: ListItemProps) => {
return ( return (
<ListItemContainer className={active ? 'active' : ''} onClick={onClick}> <ListItemContainer className={active ? 'active' : ''} onClick={onClick}>
<ListItemContent> <ListItemContent>
{icon && <IconWrapper>{icon}</IconWrapper>} {icon && <IconWrapper>{icon}</IconWrapper>}
<TextContainer> <TextContainer>
<TitleText>{title}</TitleText> <TitleText style={titleStyle}>{title}</TitleText>
{subtitle && <SubtitleText>{subtitle}</SubtitleText>} {subtitle && <SubtitleText>{subtitle}</SubtitleText>}
</TextContainer> </TextContainer>
</ListItemContent> </ListItemContent>
@ -48,7 +49,7 @@ const ListItemContainer = styled.div`
const ListItemContent = styled.div` const ListItemContent = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 5px;
overflow: hidden; overflow: hidden;
font-size: 13px; font-size: 13px;
` `

View File

@ -104,21 +104,21 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
const assistantMessages = findAssistantMessages() const assistantMessages = findAssistantMessages()
if (userMessages.length === 0 && assistantMessages.length === 0) { if (userMessages.length === 0 && assistantMessages.length === 0) {
window.message.info({ content: t('chat.navigation.last'), key: 'navigation-info' }) // window.message.info({ content: t('chat.navigation.last'), key: 'navigation-info' })
return scrollToBottom() return scrollToBottom()
} }
const visibleIndex = getCurrentVisibleIndex('down') const visibleIndex = getCurrentVisibleIndex('down')
if (visibleIndex === -1) { if (visibleIndex === -1) {
window.message.info({ content: t('chat.navigation.last'), key: 'navigation-info' }) // window.message.info({ content: t('chat.navigation.last'), key: 'navigation-info' })
return scrollToBottom() return scrollToBottom()
} }
const targetIndex = visibleIndex - 1 const targetIndex = visibleIndex - 1
if (targetIndex < 0) { if (targetIndex < 0) {
window.message.info({ content: t('chat.navigation.last'), key: 'navigation-info' }) // window.message.info({ content: t('chat.navigation.last'), key: 'navigation-info' })
return scrollToBottom() return scrollToBottom()
} }
@ -130,21 +130,21 @@ const ChatNavigation: FC<ChatNavigationProps> = ({ containerId }) => {
const userMessages = findUserMessages() const userMessages = findUserMessages()
const assistantMessages = findAssistantMessages() const assistantMessages = findAssistantMessages()
if (userMessages.length === 0 && assistantMessages.length === 0) { if (userMessages.length === 0 && assistantMessages.length === 0) {
window.message.info({ content: t('chat.navigation.first'), key: 'navigation-info' }) // window.message.info({ content: t('chat.navigation.first'), key: 'navigation-info' })
return scrollToTop() return scrollToTop()
} }
const visibleIndex = getCurrentVisibleIndex('up') const visibleIndex = getCurrentVisibleIndex('up')
if (visibleIndex === -1) { if (visibleIndex === -1) {
window.message.info({ content: t('chat.navigation.first'), key: 'navigation-info' }) // window.message.info({ content: t('chat.navigation.first'), key: 'navigation-info' })
return scrollToTop() return scrollToTop()
} }
const targetIndex = visibleIndex + 1 const targetIndex = visibleIndex + 1
if (targetIndex >= userMessages.length) { if (targetIndex >= userMessages.length) {
window.message.info({ content: t('chat.navigation.first'), key: 'navigation-info' }) // window.message.info({ content: t('chat.navigation.first'), key: 'navigation-info' })
return scrollToTop() return scrollToTop()
} }

View File

@ -1,4 +1,12 @@
import { FileSearchOutlined, FolderOpenOutlined, SaveOutlined } from '@ant-design/icons' import {
CloudSyncOutlined,
DatabaseOutlined,
FileMarkdownOutlined,
FileSearchOutlined,
FolderOpenOutlined,
SaveOutlined,
YuqueOutlined
} from '@ant-design/icons'
import { HStack } from '@renderer/components/Layout' import { HStack } from '@renderer/components/Layout'
import ListItem from '@renderer/components/ListItem' import ListItem from '@renderer/components/ListItem'
import BackupPopup from '@renderer/components/Popups/BackupPopup' import BackupPopup from '@renderer/components/Popups/BackupPopup'
@ -27,11 +35,15 @@ const DataSettings: FC = () => {
const [menu, setMenu] = useState<string>('data') const [menu, setMenu] = useState<string>('data')
const menuItems = [ const menuItems = [
{ key: 'data', title: 'settings.data.data.title' }, { key: 'data', title: 'settings.data.data.title', icon: <DatabaseOutlined style={{ fontSize: 16 }} /> },
{ key: 'webdav', title: 'settings.data.webdav.title' }, { key: 'webdav', title: 'settings.data.webdav.title', icon: <CloudSyncOutlined style={{ fontSize: 16 }} /> },
{ key: 'markdown_export', title: 'settings.data.markdown_export.title' }, {
{ key: 'notion', title: 'settings.data.notion.title' }, key: 'markdown_export',
{ key: 'yuque', title: 'settings.data.yuque.title' } title: 'settings.data.markdown_export.title',
icon: <FileMarkdownOutlined style={{ fontSize: 16 }} />
},
{ key: 'notion', title: 'settings.data.notion.title', icon: <i className="iconfont icon-notion" /> },
{ key: 'yuque', title: 'settings.data.yuque.title', icon: <YuqueOutlined style={{ fontSize: 16 }} /> }
] ]
useEffect(() => { useEffect(() => {
@ -88,7 +100,14 @@ const DataSettings: FC = () => {
<Container> <Container>
<MenuList> <MenuList>
{menuItems.map((item) => ( {menuItems.map((item) => (
<ListItem key={item.key} title={t(item.title)} active={menu === item.key} onClick={() => setMenu(item.key)} /> <ListItem
key={item.key}
title={t(item.title)}
active={menu === item.key}
onClick={() => setMenu(item.key)}
titleStyle={{ fontWeight: 500 }}
icon={item.icon}
/>
))} ))}
</MenuList> </MenuList>
<SettingContainer theme={theme} style={{ display: 'flex', flex: 1 }}> <SettingContainer theme={theme} style={{ display: 'flex', flex: 1 }}>
@ -183,7 +202,7 @@ const StyledIcon = styled(FileSearchOutlined)`
const MenuList = styled.div` const MenuList = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 5px;
width: var(--settings-width); width: var(--settings-width);
padding: 12px; padding: 12px;
border-right: 0.5px solid var(--color-border); border-right: 0.5px solid var(--color-border);