fix: optimize interface display style

This commit is contained in:
kangfenmao 2024-07-31 19:23:19 +08:00
parent 5c95373a37
commit c36075f0b5
21 changed files with 71 additions and 49 deletions

View File

@ -1,6 +1,7 @@
@import '../fonts/icon-fonts/iconfont.css'; @import '../fonts/icon-fonts/iconfont.css';
@import './markdown.scss'; @import './markdown.scss';
@import './scrollbar.scss'; @import './scrollbar.scss';
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
:root { :root {
--color-white: #ffffff; --color-white: #ffffff;
@ -45,7 +46,7 @@
--topic-list-width: 260px; --topic-list-width: 260px;
--settings-width: var(--assistants-width); --settings-width: var(--assistants-width);
--status-bar-height: 40px; --status-bar-height: 40px;
--input-bar-height: 135px; --input-bar-height: 130px;
} }
body[theme-mode='light'] { body[theme-mode='light'] {

View File

@ -83,4 +83,14 @@
code { code {
white-space: pre-wrap; white-space: pre-wrap;
} }
p code {
background: var(--color-background-mute);
padding: 3px 5px;
border-radius: 5px;
}
pre pre {
margin: 0 !important;
}
} }

View File

@ -3,7 +3,7 @@ import Logo from '@renderer/assets/images/logo.png'
import styled from 'styled-components' import styled from 'styled-components'
import { Link, useLocation } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
import useAvatar from '@renderer/hooks/useAvatar' import useAvatar from '@renderer/hooks/useAvatar'
import { isMac, isWindows } from '@renderer/config/constant' import { isWindows } from '@renderer/config/constant'
import { TranslationOutlined } from '@ant-design/icons' import { TranslationOutlined } from '@ant-design/icons'
const Sidebar: FC = () => { const Sidebar: FC = () => {
@ -67,7 +67,7 @@ const AvatarImg = styled.img`
height: 28px; height: 28px;
background-color: var(--color-background-soft); background-color: var(--color-background-soft);
margin: 5px 0; margin: 5px 0;
margin-top: ${isMac ? '16px' : '9px'}; margin-top: 5px;
` `
const MainMenus = styled.div` const MainMenus = styled.div`
display: flex; display: flex;

View File

@ -58,6 +58,10 @@ export function getProviderLogo(providerId: string) {
} }
export function getModelLogo(modelId: string) { export function getModelLogo(modelId: string) {
if (!modelId) {
return undefined
}
const logoMap = { const logoMap = {
gpt: ChatGPTModelLogo, gpt: ChatGPTModelLogo,
glm: ChatGLMModelLogo, glm: ChatGLMModelLogo,

View File

@ -17,7 +17,7 @@ const selectEnabledProviders = createSelector(
) )
export function useProviders() { export function useProviders() {
const providers = useAppSelector(selectEnabledProviders) const providers: Provider[] = useAppSelector(selectEnabledProviders)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
return { return {

View File

@ -2,12 +2,12 @@ import { Assistant, Topic } from '@renderer/types'
import { find } from 'lodash' import { find } from 'lodash'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
let _activeTopic: Topic const activeTopicsMap = new Map<string, Topic>()
export function useActiveTopic(assistant: Assistant) { export function useActiveTopic(assistant: Assistant) {
const [activeTopic, setActiveTopic] = useState(_activeTopic || assistant?.topics[0]) const [activeTopic, setActiveTopic] = useState(activeTopicsMap.get(assistant.id) || assistant?.topics[0])
_activeTopic = activeTopic activeTopicsMap.set(assistant.id, activeTopic)
useEffect(() => { useEffect(() => {
// activeTopic not in assistant.topics // activeTopic not in assistant.topics

View File

@ -239,8 +239,8 @@ const resources = {
'default.description': '你好,我是默认助手。你可以立刻开始跟我聊天。', 'default.description': '你好,我是默认助手。你可以立刻开始跟我聊天。',
'default.topic.name': '默认话题', 'default.topic.name': '默认话题',
'topics.title': '话题', 'topics.title': '话题',
'topics.auto_rename': 'AI 重命名', 'topics.auto_rename': '生成话题名',
'topics.edit.title': '重命名', 'topics.edit.title': '编辑话题名',
'topics.edit.placeholder': '输入新名称', 'topics.edit.placeholder': '输入新名称',
'topics.delete.all.title': '删除所有话题', 'topics.delete.all.title': '删除所有话题',
'topics.delete.all.content': '确定要删除所有话题吗?', 'topics.delete.all.content': '确定要删除所有话题吗?',

View File

@ -129,9 +129,10 @@ const AssistantItem = styled.div`
flex-direction: column; flex-direction: column;
padding: 7px 10px; padding: 7px 10px;
position: relative; position: relative;
border-radius: 5px; border-radius: 3px;
margin-bottom: 5px; margin-bottom: 5px;
cursor: pointer; cursor: pointer;
font-family: Poppins;
.anticon { .anticon {
display: none; display: none;
} }
@ -146,7 +147,7 @@ const AssistantItem = styled.div`
background-color: var(--color-background-mute); background-color: var(--color-background-mute);
cursor: pointer; cursor: pointer;
.name { .name {
font-weight: bolder; font-weight: 500;
} }
} }
` `

View File

@ -217,7 +217,7 @@ const Container = styled.div`
width: 100%; width: 100%;
height: var(--input-bar-height); height: var(--input-bar-height);
border-top: 0.5px solid var(--color-border); border-top: 0.5px solid var(--color-border);
padding: 5px 15px; padding: 5px 10px;
transition: all 0.3s ease; transition: all 0.3s ease;
position: relative; position: relative;
` `
@ -227,21 +227,21 @@ const Textarea = styled(TextArea)`
border-radius: 0; border-radius: 0;
display: flex; display: flex;
flex: 1; flex: 1;
margin-left: 6px;
` `
const Toolbar = styled.div` const Toolbar = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
margin: 0 -5px;
margin-bottom: 5px; margin-bottom: 5px;
margin-right: -8px;
` `
const ToolbarMenu = styled.div` const ToolbarMenu = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 6px;
` `
const ToolbarButton = styled(Button)` const ToolbarButton = styled(Button)`
@ -250,7 +250,6 @@ const ToolbarButton = styled(Button)`
font-size: 18px; font-size: 18px;
border-radius: 50%; border-radius: 50%;
transition: all 0.3s ease; transition: all 0.3s ease;
margin-right: 6px;
color: var(--color-icon); color: var(--color-icon);
&.anticon { &.anticon {
transition: all 0.3s ease; transition: all 0.3s ease;
@ -269,7 +268,7 @@ const Footer = styled.div`
flex-direction: row; flex-direction: row;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
margin-bottom: 8px; margin-bottom: 5px;
` `
const TextCount = styled.div` const TextCount = styled.div`

View File

@ -107,7 +107,9 @@ const MessageItem: FC<Props> = ({ message, index, showMenu, onDeleteMessage }) =
[t] [t]
) )
const fontFamily = messageFont === 'serif' ? "Georgia, Cambria, 'Times New Roman', Times, serif" : undefined const fontFamily =
messageFont === 'serif' ? "Georgia, Cambria, 'Times New Roman', Times, serif" : 'Poppins, -apple-system, sans-serif'
const messageBorder = showMessageDivider ? undefined : 'none' const messageBorder = showMessageDivider ? undefined : 'none'
return ( return (

View File

@ -129,9 +129,6 @@ const Container = styled.div`
overflow-y: auto; overflow-y: auto;
flex-direction: column-reverse; flex-direction: column-reverse;
max-height: calc(100vh - var(--input-bar-height) - var(--navbar-height)); max-height: calc(100vh - var(--input-bar-height) - var(--navbar-height));
.message:first-child {
border: none;
}
` `
export default Messages export default Messages

View File

@ -6,7 +6,7 @@ import { useProviders } from '@renderer/hooks/useProvider'
import { useShowAssistants } from '@renderer/hooks/useStore' import { useShowAssistants } from '@renderer/hooks/useStore'
import { Assistant } from '@renderer/types' import { Assistant } from '@renderer/types'
import { Avatar, Button, Dropdown, MenuProps } from 'antd' import { Avatar, Button, Dropdown, MenuProps } from 'antd'
import { upperFirst } from 'lodash' import { first, upperFirst } from 'lodash'
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
@ -32,11 +32,15 @@ const NavigationCenter: FC<Props> = ({ activeAssistant }) => {
label: p.isSystem ? t(`provider.${p.id}`) : p.name, label: p.isSystem ? t(`provider.${p.id}`) : p.name,
type: 'group', type: 'group',
children: p.models.map((m) => ({ children: p.models.map((m) => ({
key: m.id, key: m?.id,
label: upperFirst(m.name), label: upperFirst(m?.name),
style: m.id === model?.id ? { color: 'var(--color-primary)' } : undefined, style: m?.id === model?.id ? { color: 'var(--color-primary)' } : undefined,
icon: <Avatar src={getModelLogo(m.id)} size={24} />, icon: (
onClick: () => setModel(m) <Avatar src={getModelLogo(m?.id || '')} size={24}>
{first(m?.name)}
</Avatar>
),
onClick: () => m && setModel(m)
})) }))
})) }))

View File

@ -65,7 +65,7 @@ const RightSidebar: FC<Props> = (props) => {
const Container = styled.div` const Container = styled.div`
width: var(--topic-list-width); width: var(--topic-list-width);
height: 100%; height: calc(100vh - var(--navbar-height));
border-left: 0.5px solid var(--color-border); border-left: 0.5px solid var(--color-border);
overflow-y: auto; overflow-y: auto;
.collapsed { .collapsed {

View File

@ -2,11 +2,11 @@ import { Assistant } from '@renderer/types'
import styled from 'styled-components' import styled from 'styled-components'
import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant' import { DEFAULT_CONEXTCOUNT, DEFAULT_TEMPERATURE } from '@renderer/config/constant'
import { useAssistant } from '@renderer/hooks/useAssistant' import { useAssistant } from '@renderer/hooks/useAssistant'
import { Button, Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd' import { Col, InputNumber, Row, Slider, Switch, Tooltip } from 'antd'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import { FC, useCallback, useEffect, useState } from 'react' import { FC, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { QuestionCircleOutlined } from '@ant-design/icons' import { QuestionCircleOutlined, ReloadOutlined } from '@ant-design/icons'
import { SettingDivider, SettingRow, SettingRowTitle, SettingSubtitle } from '@renderer/pages/settings/components' import { SettingDivider, SettingRow, SettingRowTitle, SettingSubtitle } from '@renderer/pages/settings/components'
import { useSettings } from '@renderer/hooks/useSettings' import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
@ -78,11 +78,11 @@ const SettingsTab: FC<Props> = (props) => {
return ( return (
<Container> <Container>
<SettingSubtitle style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}> <SettingSubtitle>
{t('settings.messages.model.title')}{' '} {t('settings.messages.model.title')}{' '}
<Button size="small" onClick={onReset}> <Tooltip title={t('assistant.settings.reset')}>
{t('assistant.settings.reset')} <ReloadOutlined onClick={onReset} style={{ cursor: 'pointer', fontSize: 13, padding: '0 3px' }} />
</Button> </Tooltip>
</SettingSubtitle> </SettingSubtitle>
<SettingDivider /> <SettingDivider />
<Row align="middle"> <Row align="middle">

View File

@ -67,7 +67,7 @@ const Suggestions: FC<Props> = ({ assistant, messages, lastMessage }) => {
} }
if (suggestions.length === 0) { if (suggestions.length === 0) {
return null return <Container style={{ paddingBottom: 10 }} />
} }
return ( return (
@ -86,28 +86,28 @@ const Suggestions: FC<Props> = ({ assistant, messages, lastMessage }) => {
const Container = styled.div` const Container = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 20px; padding: 10px 10px 20px 55px;
display: flex; display: flex;
width: 100%; width: 100%;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
gap: 15px; gap: 15px;
padding-left: 55px;
` `
const SuggestionsContainer = styled.div` const SuggestionsContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: row;
gap: 15px; flex-wrap: wrap;
gap: 10px;
` `
const SuggestionItem = styled.div` const SuggestionItem = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
width: fit-content; width: fit-content;
padding: 7px 15px; padding: 5px 10px;
border-radius: 12px; border-radius: 12px;
font-size: 13px; font-size: 12px;
color: var(--color-text); color: var(--color-text);
background: var(--color-background-mute); background: var(--color-background-mute);
cursor: pointer; cursor: pointer;

View File

@ -6,7 +6,7 @@ import { Assistant, Topic } from '@renderer/types'
import { Dropdown, MenuProps } from 'antd' import { Dropdown, MenuProps } from 'antd'
import { FC } from 'react' import { FC } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { DeleteOutlined, EditOutlined, SignatureOutlined } from '@ant-design/icons' import { DeleteOutlined, EditOutlined, OpenAIOutlined } from '@ant-design/icons'
import LocalStorage from '@renderer/services/storage' import LocalStorage from '@renderer/services/storage'
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd' import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd'
import { droppableReorder } from '@renderer/utils' import { droppableReorder } from '@renderer/utils'
@ -30,7 +30,7 @@ const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTop
{ {
label: t('assistant.topics.auto_rename'), label: t('assistant.topics.auto_rename'),
key: 'auto-rename', key: 'auto-rename',
icon: <SignatureOutlined />, icon: <OpenAIOutlined />,
async onClick() { async onClick() {
const messages = await LocalStorage.getTopicMessages(topic.id) const messages = await LocalStorage.getTopicMessages(topic.id)
if (messages.length >= 2) { if (messages.length >= 2) {
@ -42,13 +42,13 @@ const TopicsTab: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTop
} }
}, },
{ {
label: t('common.rename'), label: t('assistant.topics.edit.title'),
key: 'rename', key: 'rename',
icon: <EditOutlined />, icon: <EditOutlined />,
async onClick() { async onClick() {
const name = await PromptPopup.show({ const name = await PromptPopup.show({
title: t('assistant.topics.edit.title'), title: t('assistant.topics.edit.title'),
message: t('assistant.topics.edit.placeholder'), message: '',
defaultValue: topic?.name || '' defaultValue: topic?.name || ''
}) })
if (name && topic?.name !== name) { if (name && topic?.name !== name) {
@ -129,7 +129,7 @@ const TopicListItem = styled.div`
padding: 8px 10px; padding: 8px 10px;
margin-bottom: 5px; margin-bottom: 5px;
cursor: pointer; cursor: pointer;
border-radius: 5px; border-radius: 3px;
font-size: 14px; font-size: 14px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@ -139,7 +139,6 @@ const TopicListItem = styled.div`
} }
&.active { &.active {
background-color: var(--color-background-mute); background-color: var(--color-background-mute);
font-weight: bolder;
} }
` `

View File

@ -15,7 +15,7 @@ const AntdProvider: FC<PropsWithChildren> = ({ children }) => {
algorithm: [_theme === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm], algorithm: [_theme === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm],
token: { token: {
colorPrimary: '#00b96b', colorPrimary: '#00b96b',
borderRadius: 5 borderRadius: 3
} }
}}> }}>
{children} {children}

View File

@ -130,6 +130,10 @@ export async function fetchSuggestions({
return [] return []
} }
if (model.id.endsWith('global')) {
return []
}
try { try {
return await providerSdk.suggestions(messages, assistant) return await providerSdk.suggestions(messages, assistant)
} catch (error: any) { } catch (error: any) {

View File

@ -8,6 +8,7 @@ export default class LocalStorage {
static async getTopic(id: string) { static async getTopic(id: string) {
return localforage.getItem<Topic>(`topic:${id}`) return localforage.getItem<Topic>(`topic:${id}`)
} }
static async getTopicMessages(id: string) { static async getTopicMessages(id: string) {
const topic = await this.getTopic(id) const topic = await this.getTopic(id)
return topic ? topic.messages : [] return topic ? topic.messages : []

View File

@ -141,7 +141,7 @@ export function removeQuotes(str) {
return str.replace(/['"]+/g, '') return str.replace(/['"]+/g, '')
} }
export function generateColorFromChar(char) { export function generateColorFromChar(char: string) {
// 使用字符的Unicode值作为随机种子 // 使用字符的Unicode值作为随机种子
const seed = char.charCodeAt(0) const seed = char.charCodeAt(0)