fix: optimize interface display style
This commit is contained in:
parent
5c95373a37
commit
c36075f0b5
@ -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'] {
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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': '确定要删除所有话题吗?',
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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 (
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
}))
|
}))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@ -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}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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 : []
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user