feat: add message card style switch
This commit is contained in:
parent
2e9c7d0830
commit
41c3895da4
@ -28,3 +28,12 @@ export function useSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useMessageStyle() {
|
||||||
|
const { messageStyle } = useSettings()
|
||||||
|
const isBubbleStyle = messageStyle === 'bubble'
|
||||||
|
|
||||||
|
return {
|
||||||
|
isBubbleStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -64,7 +64,10 @@
|
|||||||
"upgrade.success.content": "Please restart the application to complete the upgrade",
|
"upgrade.success.content": "Please restart the application to complete the upgrade",
|
||||||
"upgrade.success.button": "Restart",
|
"upgrade.success.button": "Restart",
|
||||||
"topic.added": "New topic added",
|
"topic.added": "New topic added",
|
||||||
"save.success.title": "Saved successfully"
|
"save.success.title": "Saved successfully",
|
||||||
|
"message.style": "Message Style",
|
||||||
|
"message.style.bubble": "Bubble",
|
||||||
|
"message.style.plain": "Plain"
|
||||||
},
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
|||||||
@ -64,7 +64,10 @@
|
|||||||
"upgrade.success.content": "重启用以完成升级",
|
"upgrade.success.content": "重启用以完成升级",
|
||||||
"upgrade.success.button": "重启",
|
"upgrade.success.button": "重启",
|
||||||
"topic.added": "话题添加成功",
|
"topic.added": "话题添加成功",
|
||||||
"save.success.title": "保存成功"
|
"save.success.title": "保存成功",
|
||||||
|
"message.style": "消息样式",
|
||||||
|
"message.style.bubble": "气泡",
|
||||||
|
"message.style.plain": "简洁"
|
||||||
},
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
|
|||||||
@ -64,7 +64,10 @@
|
|||||||
"upgrade.success.content": "請重新啟動應用以完成升級",
|
"upgrade.success.content": "請重新啟動應用以完成升級",
|
||||||
"upgrade.success.button": "重新啟動",
|
"upgrade.success.button": "重新啟動",
|
||||||
"topic.added": "新話題已添加",
|
"topic.added": "新話題已添加",
|
||||||
"save.success.title": "保存成功"
|
"save.success.title": "保存成功",
|
||||||
|
"message.style": "消息樣式",
|
||||||
|
"message.style.bubble": "氣泡",
|
||||||
|
"message.style.plain": "簡潔"
|
||||||
},
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
|
|||||||
@ -19,11 +19,11 @@ interface Props {
|
|||||||
|
|
||||||
const Chat: FC<Props> = (props) => {
|
const Chat: FC<Props> = (props) => {
|
||||||
const { assistant } = useAssistant(props.assistant.id)
|
const { assistant } = useAssistant(props.assistant.id)
|
||||||
const { topicPosition } = useSettings()
|
const { topicPosition, messageStyle } = useSettings()
|
||||||
const { showTopics } = useShowTopics()
|
const { showTopics } = useShowTopics()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container id="chat">
|
<Container id="chat" className={messageStyle}>
|
||||||
<Main vertical flex={1} justify="space-between">
|
<Main vertical flex={1} justify="space-between">
|
||||||
<Messages
|
<Messages
|
||||||
key={props.activeTopic.id}
|
key={props.activeTopic.id}
|
||||||
@ -52,7 +52,35 @@ const Container = styled.div`
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background-color: var(--chat-background);
|
&.bubble {
|
||||||
|
background-color: var(--chat-background);
|
||||||
|
.system-prompt {
|
||||||
|
background-color: var(--chat-background-assistant);
|
||||||
|
}
|
||||||
|
.message-content-container {
|
||||||
|
margin: 5px 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 15px 0 15px;
|
||||||
|
}
|
||||||
|
.message-user {
|
||||||
|
.markdown,
|
||||||
|
.anticon,
|
||||||
|
.iconfont,
|
||||||
|
.message-tokens {
|
||||||
|
color: var(--chat-text-user);
|
||||||
|
}
|
||||||
|
.message-action-button:hover {
|
||||||
|
background-color: var(--color-white-soft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#inputbar {
|
||||||
|
border-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid var(--color-border-mute);
|
||||||
|
background: var(--color-background);
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Main = styled(Flex)`
|
const Main = styled(Flex)`
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { isVisionModel } from '@renderer/config/models'
|
|||||||
import db from '@renderer/databases'
|
import db from '@renderer/databases'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||||
import { addAssistantMessagesToTopic, getDefaultTopic } from '@renderer/services/AssistantService'
|
import { addAssistantMessagesToTopic, getDefaultTopic } from '@renderer/services/AssistantService'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
@ -58,6 +58,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
const containerRef = useRef(null)
|
const containerRef = useRef(null)
|
||||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||||
const { searching } = useRuntime()
|
const { searching } = useRuntime()
|
||||||
|
const { isBubbleStyle } = useMessageStyle()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const isVision = useMemo(() => isVisionModel(model), [model])
|
const isVision = useMemo(() => isVisionModel(model), [model])
|
||||||
@ -299,7 +300,7 @@ const Inputbar: FC<Props> = ({ assistant, setActiveTopic }) => {
|
|||||||
autoFocus
|
autoFocus
|
||||||
contextMenu="true"
|
contextMenu="true"
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
rows={2}
|
rows={isBubbleStyle ? 2 : 1}
|
||||||
ref={textareaRef}
|
ref={textareaRef}
|
||||||
style={{ fontSize }}
|
style={{ fontSize }}
|
||||||
styles={{ textarea: TextareaStyle }}
|
styles={{ textarea: TextareaStyle }}
|
||||||
@ -375,18 +376,19 @@ const Container = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const InputBarContainer = styled.div`
|
||||||
|
border: 1px solid var(--color-border-soft);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
margin: 0 20px 15px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
`
|
||||||
|
|
||||||
const TextareaStyle: CSSProperties = {
|
const TextareaStyle: CSSProperties = {
|
||||||
paddingLeft: 0,
|
paddingLeft: 0,
|
||||||
padding: '10px 15px 8px'
|
padding: '10px 15px 8px'
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputBarContainer = styled.div`
|
|
||||||
border-top: 1px solid var(--color-border-mute);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
position: relative;
|
|
||||||
background: var(--color-background);
|
|
||||||
`
|
|
||||||
|
|
||||||
const Textarea = styled(TextArea)`
|
const Textarea = styled(TextArea)`
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { FONT_FAMILY } from '@renderer/config/constant'
|
|||||||
import db from '@renderer/databases'
|
import db from '@renderer/databases'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { useModel } from '@renderer/hooks/useModel'
|
import { useModel } from '@renderer/hooks/useModel'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { fetchChatCompletion } from '@renderer/services/ApiService'
|
import { fetchChatCompletion } from '@renderer/services/ApiService'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
import { estimateMessageUsage } from '@renderer/services/TokenService'
|
import { estimateMessageUsage } from '@renderer/services/TokenService'
|
||||||
@ -42,11 +42,13 @@ const MessageItem: FC<Props> = ({
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { assistant, setModel } = useAssistant(message.assistantId)
|
const { assistant, setModel } = useAssistant(message.assistantId)
|
||||||
const model = useModel(message.modelId)
|
const model = useModel(message.modelId)
|
||||||
|
const { isBubbleStyle } = useMessageStyle()
|
||||||
const { showMessageDivider, messageFont, fontSize } = useSettings()
|
const { showMessageDivider, messageFont, fontSize } = useSettings()
|
||||||
const messageContainerRef = useRef<HTMLDivElement>(null)
|
const messageContainerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
const isLastMessage = index === 0
|
const isLastMessage = index === 0
|
||||||
const isAssistantMessage = message.role === 'assistant'
|
const isAssistantMessage = message.role === 'assistant'
|
||||||
|
|
||||||
const showMenubar = !message.status.includes('ing')
|
const showMenubar = !message.status.includes('ing')
|
||||||
|
|
||||||
const fontFamily = useMemo(() => {
|
const fontFamily = useMemo(() => {
|
||||||
@ -54,6 +56,11 @@ const MessageItem: FC<Props> = ({
|
|||||||
}, [messageFont])
|
}, [messageFont])
|
||||||
|
|
||||||
const messageBorder = showMessageDivider ? undefined : 'none'
|
const messageBorder = showMessageDivider ? undefined : 'none'
|
||||||
|
const messageBackground = isBubbleStyle
|
||||||
|
? isAssistantMessage
|
||||||
|
? 'var(--chat-background-assistant)'
|
||||||
|
: 'var(--chat-background-user)'
|
||||||
|
: undefined
|
||||||
|
|
||||||
const onEditMessage = useCallback(
|
const onEditMessage = useCallback(
|
||||||
(msg: Message) => {
|
(msg: Message) => {
|
||||||
@ -139,17 +146,19 @@ const MessageItem: FC<Props> = ({
|
|||||||
'message-user': !isAssistantMessage
|
'message-user': !isAssistantMessage
|
||||||
})}
|
})}
|
||||||
ref={messageContainerRef}
|
ref={messageContainerRef}
|
||||||
style={{ alignItems: isAssistantMessage ? 'start' : 'end' }}>
|
style={isBubbleStyle ? { alignItems: isAssistantMessage ? 'start' : 'end' } : undefined}>
|
||||||
<MessageHeader message={message} assistant={assistant} model={model} />
|
<MessageHeader message={message} assistant={assistant} model={model} />
|
||||||
<MessageContentContainer
|
<MessageContentContainer
|
||||||
style={{
|
className="message-content-container"
|
||||||
fontFamily,
|
style={{ fontFamily, fontSize, background: messageBackground }}>
|
||||||
fontSize,
|
|
||||||
background: isAssistantMessage ? 'var(--chat-background-assistant)' : 'var(--chat-background-user)'
|
|
||||||
}}>
|
|
||||||
<MessageContent message={message} model={model} />
|
<MessageContent message={message} model={model} />
|
||||||
{showMenubar && (
|
{showMenubar && (
|
||||||
<MessageFooter style={{ border: messageBorder }}>
|
<MessageFooter
|
||||||
|
style={{
|
||||||
|
border: messageBorder,
|
||||||
|
flexDirection: isLastMessage || isBubbleStyle ? 'row-reverse' : undefined
|
||||||
|
}}>
|
||||||
|
<MessageTokens message={message} isLastMessage={isLastMessage} />
|
||||||
<MessageMenubar
|
<MessageMenubar
|
||||||
message={message}
|
message={message}
|
||||||
model={model}
|
model={model}
|
||||||
@ -160,7 +169,6 @@ const MessageItem: FC<Props> = ({
|
|||||||
onEditMessage={onEditMessage}
|
onEditMessage={onEditMessage}
|
||||||
onDeleteMessage={onDeleteMessage}
|
onDeleteMessage={onDeleteMessage}
|
||||||
/>
|
/>
|
||||||
<MessageTokens message={message} isLastMessage={isLastMessage} />
|
|
||||||
</MessageFooter>
|
</MessageFooter>
|
||||||
)}
|
)}
|
||||||
</MessageContentContainer>
|
</MessageContentContainer>
|
||||||
@ -177,17 +185,6 @@ const MessageContainer = styled.div`
|
|||||||
&.message-highlight {
|
&.message-highlight {
|
||||||
background-color: var(--color-primary-mute);
|
background-color: var(--color-primary-mute);
|
||||||
}
|
}
|
||||||
&.message-user {
|
|
||||||
.markdown,
|
|
||||||
.anticon,
|
|
||||||
.iconfont,
|
|
||||||
.message-tokens {
|
|
||||||
color: var(--chat-text-user);
|
|
||||||
}
|
|
||||||
.message-action-button:hover {
|
|
||||||
background-color: var(--color-white-soft);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.menubar {
|
.menubar {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
@ -208,9 +205,8 @@ const MessageContentContainer = styled.div`
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 5px 0;
|
margin-left: 46px;
|
||||||
border-radius: 8px;
|
margin-top: 5px;
|
||||||
padding: 10px 15px 0 15px;
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const MessageFooter = styled.div`
|
const MessageFooter = styled.div`
|
||||||
|
|||||||
@ -4,12 +4,12 @@ import { startMinAppById } from '@renderer/config/minapps'
|
|||||||
import { getModelLogo } from '@renderer/config/models'
|
import { getModelLogo } from '@renderer/config/models'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import useAvatar from '@renderer/hooks/useAvatar'
|
import useAvatar from '@renderer/hooks/useAvatar'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useMessageStyle, useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { Assistant, Message, Model } from '@renderer/types'
|
import { Assistant, Message, Model } from '@renderer/types'
|
||||||
import { firstLetter, removeLeadingEmoji } from '@renderer/utils'
|
import { firstLetter, removeLeadingEmoji } from '@renderer/utils'
|
||||||
import { Avatar } from 'antd'
|
import { Avatar } from 'antd'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { FC, useCallback, useMemo } from 'react'
|
import { CSSProperties, FC, useCallback, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -24,8 +24,7 @@ const MessageHeader: FC<Props> = ({ assistant, model, message }) => {
|
|||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const { userName } = useSettings()
|
const { userName } = useSettings()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const { isBubbleStyle } = useMessageStyle()
|
||||||
const isAssistantMessage = message.role === 'assistant'
|
|
||||||
|
|
||||||
const avatarSource = useMemo(() => {
|
const avatarSource = useMemo(() => {
|
||||||
if (isLocalAi) return AppLogo
|
if (isLocalAi) return AppLogo
|
||||||
@ -39,19 +38,23 @@ const MessageHeader: FC<Props> = ({ assistant, model, message }) => {
|
|||||||
return userName || t('common.you')
|
return userName || t('common.you')
|
||||||
}, [message.role, model?.id, model?.name, t, userName])
|
}, [message.role, model?.id, model?.name, t, userName])
|
||||||
|
|
||||||
const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name])
|
const isAssistantMessage = message.role === 'assistant'
|
||||||
|
|
||||||
|
const avatarName = useMemo(() => firstLetter(assistant?.name).toUpperCase(), [assistant?.name])
|
||||||
const username = useMemo(() => removeLeadingEmoji(getUserName()), [getUserName])
|
const username = useMemo(() => removeLeadingEmoji(getUserName()), [getUserName])
|
||||||
|
|
||||||
const showMiniApp = () => model?.provider && startMinAppById(model?.provider)
|
const showMiniApp = () => model?.provider && startMinAppById(model?.provider)
|
||||||
|
|
||||||
|
const avatarStyle: CSSProperties | undefined = isBubbleStyle
|
||||||
|
? {
|
||||||
|
flexDirection: isAssistantMessage ? 'row' : 'row-reverse',
|
||||||
|
textAlign: isAssistantMessage ? 'left' : 'right'
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<AvatarWrapper
|
<AvatarWrapper style={avatarStyle}>
|
||||||
style={{
|
|
||||||
flexDirection: isAssistantMessage ? 'row' : 'row-reverse',
|
|
||||||
textAlign: isAssistantMessage ? 'left' : 'right'
|
|
||||||
}}>
|
|
||||||
{isAssistantMessage ? (
|
{isAssistantMessage ? (
|
||||||
<Avatar
|
<Avatar
|
||||||
src={avatarSource}
|
src={avatarSource}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ const Prompt: FC<Props> = ({ assistant }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container onClick={() => AssistantSettingsPopup.show({ assistant })}>
|
<Container className="system-prompt" onClick={() => AssistantSettingsPopup.show({ assistant })}>
|
||||||
<Text>{prompt}</Text>
|
<Text>{prompt}</Text>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
@ -26,7 +26,7 @@ const Prompt: FC<Props> = ({ assistant }) => {
|
|||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
background-color: var(--chat-background-assistant);
|
background-color: var(--color-background-soft);
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
margin: 0 20px 0 20px;
|
margin: 0 20px 0 20px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
setFontSize,
|
setFontSize,
|
||||||
setMathEngine,
|
setMathEngine,
|
||||||
setMessageFont,
|
setMessageFont,
|
||||||
|
setMessageStyle,
|
||||||
setPasteLongTextAsFile,
|
setPasteLongTextAsFile,
|
||||||
setRenderInputMessageAsMarkdown,
|
setRenderInputMessageAsMarkdown,
|
||||||
setShowInputEstimatedTokens,
|
setShowInputEstimatedTokens,
|
||||||
@ -35,6 +36,7 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
const [maxTokens, setMaxTokens] = useState(assistant?.settings?.maxTokens ?? 0)
|
const [maxTokens, setMaxTokens] = useState(assistant?.settings?.maxTokens ?? 0)
|
||||||
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true)
|
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput ?? true)
|
||||||
const [fontSizeValue, setFontSizeValue] = useState(fontSize)
|
const [fontSizeValue, setFontSizeValue] = useState(fontSize)
|
||||||
|
const { messageStyle } = useSettings()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@ -214,6 +216,18 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
|
<SettingRow>
|
||||||
|
<SettingRowTitleSmall>{t('message.message.style')}</SettingRowTitleSmall>
|
||||||
|
<Select
|
||||||
|
value={messageStyle}
|
||||||
|
onChange={(value) => dispatch(setMessageStyle(value))}
|
||||||
|
style={{ width: 100 }}
|
||||||
|
size="small">
|
||||||
|
<Select.Option value="plain">{t('message.message.style.plain')}</Select.Option>
|
||||||
|
<Select.Option value="bubble">{t('message.message.style.bubble')}</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitleSmall>{t('settings.messages.math_engine')}</SettingRowTitleSmall>
|
<SettingRowTitleSmall>{t('settings.messages.math_engine')}</SettingRowTitleSmall>
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@ -24,7 +24,7 @@ const persistedReducer = persistReducer(
|
|||||||
{
|
{
|
||||||
key: 'cherry-studio',
|
key: 'cherry-studio',
|
||||||
storage,
|
storage,
|
||||||
version: 36,
|
version: 37,
|
||||||
blacklist: ['runtime'],
|
blacklist: ['runtime'],
|
||||||
migrate
|
migrate
|
||||||
},
|
},
|
||||||
|
|||||||
@ -618,6 +618,10 @@ const migrateConfig = {
|
|||||||
'36': (state: RootState) => {
|
'36': (state: RootState) => {
|
||||||
state.settings.topicPosition = 'left'
|
state.settings.topicPosition = 'left'
|
||||||
return state
|
return state
|
||||||
|
},
|
||||||
|
'37': (state: RootState) => {
|
||||||
|
state.settings.messageStyle = 'plain'
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export interface SettingsState {
|
|||||||
renderInputMessageAsMarkdown: boolean
|
renderInputMessageAsMarkdown: boolean
|
||||||
codeShowLineNumbers: boolean
|
codeShowLineNumbers: boolean
|
||||||
mathEngine: 'MathJax' | 'KaTeX'
|
mathEngine: 'MathJax' | 'KaTeX'
|
||||||
|
messageStyle: 'plain' | 'bubble'
|
||||||
// webdav 配置 host, user, pass, path
|
// webdav 配置 host, user, pass, path
|
||||||
webdavHost: string
|
webdavHost: string
|
||||||
webdavUser: string
|
webdavUser: string
|
||||||
@ -52,6 +53,7 @@ const initialState: SettingsState = {
|
|||||||
renderInputMessageAsMarkdown: true,
|
renderInputMessageAsMarkdown: true,
|
||||||
codeShowLineNumbers: false,
|
codeShowLineNumbers: false,
|
||||||
mathEngine: 'MathJax',
|
mathEngine: 'MathJax',
|
||||||
|
messageStyle: 'plain',
|
||||||
webdavHost: '',
|
webdavHost: '',
|
||||||
webdavUser: '',
|
webdavUser: '',
|
||||||
webdavPass: '',
|
webdavPass: '',
|
||||||
@ -140,6 +142,9 @@ const settingsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
setMathEngine: (state, action: PayloadAction<'MathJax' | 'KaTeX'>) => {
|
setMathEngine: (state, action: PayloadAction<'MathJax' | 'KaTeX'>) => {
|
||||||
state.mathEngine = action.payload
|
state.mathEngine = action.payload
|
||||||
|
},
|
||||||
|
setMessageStyle: (state, action: PayloadAction<'plain' | 'bubble'>) => {
|
||||||
|
state.messageStyle = action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -170,7 +175,8 @@ export const {
|
|||||||
setWebdavPass,
|
setWebdavPass,
|
||||||
setWebdavPath,
|
setWebdavPath,
|
||||||
setCodeShowLineNumbers,
|
setCodeShowLineNumbers,
|
||||||
setMathEngine
|
setMathEngine,
|
||||||
|
setMessageStyle
|
||||||
} = settingsSlice.actions
|
} = settingsSlice.actions
|
||||||
|
|
||||||
export default settingsSlice.reducer
|
export default settingsSlice.reducer
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user