mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-07 22:10:21 +08:00
refactor: sidebar minapps
This commit is contained in:
parent
7633d70435
commit
49a5bc7900
@ -47,19 +47,22 @@ const DragableList: FC<Props<any>> = ({
|
|||||||
<Droppable droppableId="droppable" {...droppableProps}>
|
<Droppable droppableId="droppable" {...droppableProps}>
|
||||||
{(provided) => (
|
{(provided) => (
|
||||||
<div {...provided.droppableProps} ref={provided.innerRef} style={{ ...style }}>
|
<div {...provided.droppableProps} ref={provided.innerRef} style={{ ...style }}>
|
||||||
{list.map((item, index) => (
|
{list.map((item, index) => {
|
||||||
<Draggable key={`draggable_${item.id}_${index}`} draggableId={item.id} index={index} {...droppableProps}>
|
const id = item.id || item
|
||||||
{(provided) => (
|
return (
|
||||||
<div
|
<Draggable key={`draggable_${id}_${index}`} draggableId={id} index={index} {...droppableProps}>
|
||||||
ref={provided.innerRef}
|
{(provided) => (
|
||||||
{...provided.draggableProps}
|
<div
|
||||||
{...provided.dragHandleProps}
|
ref={provided.innerRef}
|
||||||
style={{ ...provided.draggableProps.style, marginBottom: 8, ...listStyle }}>
|
{...provided.draggableProps}
|
||||||
{children(item, index)}
|
{...provided.dragHandleProps}
|
||||||
</div>
|
style={{ ...provided.draggableProps.style, marginBottom: 8, ...listStyle }}>
|
||||||
)}
|
{children(item, index)}
|
||||||
</Draggable>
|
</div>
|
||||||
))}
|
)}
|
||||||
|
</Draggable>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { useBridge } from '@renderer/hooks/useBridge'
|
|||||||
import store from '@renderer/store'
|
import store from '@renderer/store'
|
||||||
import { setMinappShow } from '@renderer/store/runtime'
|
import { setMinappShow } from '@renderer/store/runtime'
|
||||||
import { MinAppType } from '@renderer/types'
|
import { MinAppType } from '@renderer/types'
|
||||||
|
import { delay } from '@renderer/utils'
|
||||||
import { Avatar, Drawer } from 'antd'
|
import { Avatar, Drawer } from 'antd'
|
||||||
import { WebviewTag } from 'electron'
|
import { WebviewTag } from 'electron'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
@ -28,9 +29,10 @@ const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
|
|||||||
|
|
||||||
const canOpenExternalLink = app.url.startsWith('http://') || app.url.startsWith('https://')
|
const canOpenExternalLink = app.url.startsWith('http://') || app.url.startsWith('https://')
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = async (_delay = 0.3) => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
setTimeout(() => resolve({}), 300)
|
await delay(_delay)
|
||||||
|
resolve({})
|
||||||
}
|
}
|
||||||
|
|
||||||
MinApp.onClose = onClose
|
MinApp.onClose = onClose
|
||||||
@ -58,7 +60,7 @@ const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
|
|||||||
<ExportOutlined />
|
<ExportOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button onClick={onClose}>
|
<Button onClick={() => onClose()}>
|
||||||
<CloseOutlined />
|
<CloseOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonsGroup>
|
</ButtonsGroup>
|
||||||
@ -99,7 +101,7 @@ const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
|
|||||||
<Drawer
|
<Drawer
|
||||||
title={<Title />}
|
title={<Title />}
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
onClose={onClose}
|
onClose={() => onClose()}
|
||||||
open={open}
|
open={open}
|
||||||
mask={true}
|
mask={true}
|
||||||
rootClassName="minapp-drawer"
|
rootClassName="minapp-drawer"
|
||||||
@ -202,40 +204,39 @@ const EmptyView = styled.div`
|
|||||||
export default class MinApp {
|
export default class MinApp {
|
||||||
static topviewId = 0
|
static topviewId = 0
|
||||||
static onClose = () => {}
|
static onClose = () => {}
|
||||||
static isOpening = false
|
static app: MinAppType | null = null
|
||||||
|
|
||||||
static async start(app: MinAppType) {
|
static async start(app: MinAppType) {
|
||||||
if (this.isOpening) return
|
if (MinApp.app?.id === app.id) {
|
||||||
this.isOpening = true
|
return
|
||||||
|
|
||||||
try {
|
|
||||||
// 先关闭现有的小程序
|
|
||||||
await this.close()
|
|
||||||
|
|
||||||
// 确保 webview 完全卸载
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 100))
|
|
||||||
|
|
||||||
store.dispatch(setMinappShow(true))
|
|
||||||
return new Promise<any>((resolve) => {
|
|
||||||
TopView.show(
|
|
||||||
<PopupContainer
|
|
||||||
app={app}
|
|
||||||
resolve={(v) => {
|
|
||||||
resolve(v)
|
|
||||||
this.close()
|
|
||||||
}}
|
|
||||||
/>,
|
|
||||||
'MinApp'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
this.isOpening = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MinApp.app) {
|
||||||
|
// @ts-ignore delay params
|
||||||
|
await MinApp.onClose(0)
|
||||||
|
await delay(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
MinApp.app = app
|
||||||
|
store.dispatch(setMinappShow(true))
|
||||||
|
|
||||||
|
return new Promise<any>((resolve) => {
|
||||||
|
TopView.show(
|
||||||
|
<PopupContainer
|
||||||
|
app={app}
|
||||||
|
resolve={(v) => {
|
||||||
|
resolve(v)
|
||||||
|
this.close()
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
'MinApp'
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
static close() {
|
static close() {
|
||||||
if (!this.isOpening) return
|
|
||||||
TopView.hide('MinApp')
|
TopView.hide('MinApp')
|
||||||
store.dispatch(setMinappShow(false))
|
store.dispatch(setMinappShow(false))
|
||||||
|
MinApp.app = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
import { FileSearchOutlined, FolderOutlined, PictureOutlined, TranslationOutlined } from '@ant-design/icons'
|
import { FileSearchOutlined, FolderOutlined, PictureOutlined, TranslationOutlined } from '@ant-design/icons'
|
||||||
import { isMac } from '@renderer/config/constant'
|
import { isMac } from '@renderer/config/constant'
|
||||||
import { isLocalAi, UserAvatar } from '@renderer/config/env'
|
import { isLocalAi, UserAvatar } from '@renderer/config/env'
|
||||||
import { getAllMinApps } from '@renderer/config/minapps'
|
|
||||||
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 { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime'
|
import { modelGenerating, useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import type { MenuProps } from 'antd'
|
||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
import { Avatar } from 'antd'
|
import { Avatar } from 'antd'
|
||||||
|
import { Dropdown } from 'antd'
|
||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
import DragableList from '../DragableList'
|
||||||
import MinApp from '../MinApp'
|
import MinApp from '../MinApp'
|
||||||
import UserPopup from '../Popups/UserPopup'
|
import UserPopup from '../Popups/UserPopup'
|
||||||
|
|
||||||
@ -22,79 +25,22 @@ const Sidebar: FC = () => {
|
|||||||
const { minappShow } = useRuntime()
|
const { minappShow } = useRuntime()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { windowStyle, sidebarIcons, miniAppIcons } = useSettings()
|
const { windowStyle, sidebarIcons } = useSettings()
|
||||||
const { theme, toggleTheme } = useTheme()
|
const { theme, toggleTheme } = useTheme()
|
||||||
const allApps = getAllMinApps()
|
const { pinned } = useMinapps()
|
||||||
|
|
||||||
const isRoute = (path: string): string => (pathname === path ? 'active' : '')
|
|
||||||
const isRoutes = (path: string): string => (pathname.startsWith(path) ? 'active' : '')
|
|
||||||
|
|
||||||
const onEditUser = () => UserPopup.show()
|
const onEditUser = () => UserPopup.show()
|
||||||
|
|
||||||
const macTransparentWindow = isMac && windowStyle === 'transparent'
|
const macTransparentWindow = isMac && windowStyle === 'transparent'
|
||||||
const sidebarBgColor = macTransparentWindow ? 'transparent' : 'var(--navbar-background)'
|
const sidebarBgColor = macTransparentWindow ? 'transparent' : 'var(--navbar-background)'
|
||||||
|
|
||||||
|
const showPinnedApps = pinned.length > 0 && sidebarIcons.visible.includes('minapp')
|
||||||
|
|
||||||
const to = async (path: string) => {
|
const to = async (path: string) => {
|
||||||
await modelGenerating()
|
await modelGenerating()
|
||||||
navigate(path)
|
navigate(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderMainMenus = () => {
|
|
||||||
return sidebarIcons.visible.map((icon) => {
|
|
||||||
const iconMap = {
|
|
||||||
assistants: <i className="iconfont icon-chat" />,
|
|
||||||
agents: <i className="iconfont icon-business-smart-assistant" />,
|
|
||||||
paintings: <PictureOutlined style={{ fontSize: 16 }} />,
|
|
||||||
translate: <TranslationOutlined />,
|
|
||||||
minapp: <i className="iconfont icon-appstore" />,
|
|
||||||
knowledge: <FileSearchOutlined />,
|
|
||||||
files: <FolderOutlined />
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathMap = {
|
|
||||||
assistants: '/',
|
|
||||||
agents: '/agents',
|
|
||||||
paintings: '/paintings',
|
|
||||||
translate: '/translate',
|
|
||||||
minapp: '/apps',
|
|
||||||
knowledge: '/knowledge',
|
|
||||||
files: '/files'
|
|
||||||
}
|
|
||||||
|
|
||||||
const path = pathMap[icon]
|
|
||||||
const isActive = path === '/' ? isRoute(path) : isRoutes(path)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip key={icon} title={t(`${icon}.title`)} mouseEnterDelay={0.8} placement="right">
|
|
||||||
<StyledLink onClick={() => to(path)}>
|
|
||||||
<Icon className={isActive}>{iconMap[icon]}</Icon>
|
|
||||||
</StyledLink>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderPinnedApps = () => {
|
|
||||||
if (!miniAppIcons?.pinned) return null
|
|
||||||
const pinnedApps = allApps.filter((app) => miniAppIcons.pinned.includes(app.id))
|
|
||||||
return pinnedApps.map((app) => (
|
|
||||||
<Tooltip key={app.id} title={app.name} mouseEnterDelay={0.8} placement="right">
|
|
||||||
<StyledLink>
|
|
||||||
<Icon onClick={() => MinApp.start(app)}>
|
|
||||||
<AppIcon
|
|
||||||
src={app.logo}
|
|
||||||
style={{
|
|
||||||
width: '20px',
|
|
||||||
height: '20px',
|
|
||||||
border: app.bodered ? '0.5px solid var(--color-border)' : 'none'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Icon>
|
|
||||||
</StyledLink>
|
|
||||||
</Tooltip>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
id="app-sidebar"
|
id="app-sidebar"
|
||||||
@ -103,14 +49,19 @@ const Sidebar: FC = () => {
|
|||||||
zIndex: minappShow ? 10000 : 'initial'
|
zIndex: minappShow ? 10000 : 'initial'
|
||||||
}}>
|
}}>
|
||||||
<AvatarImg src={avatar || UserAvatar} draggable={false} className="nodrag" onClick={onEditUser} />
|
<AvatarImg src={avatar || UserAvatar} draggable={false} className="nodrag" onClick={onEditUser} />
|
||||||
<MainMenus>
|
<MainMenusContainer>
|
||||||
<ScrollContainer>
|
<Menus onClick={MinApp.onClose}>
|
||||||
<Menus onClick={MinApp.onClose}>
|
<MainMenus />
|
||||||
{renderMainMenus()}
|
</Menus>
|
||||||
{renderPinnedApps()}
|
{showPinnedApps && (
|
||||||
</Menus>
|
<AppsContainer>
|
||||||
</ScrollContainer>
|
<Divider />
|
||||||
</MainMenus>
|
<Menus>
|
||||||
|
<PinnedApps />
|
||||||
|
</Menus>
|
||||||
|
</AppsContainer>
|
||||||
|
)}
|
||||||
|
</MainMenusContainer>
|
||||||
<Menus onClick={MinApp.onClose}>
|
<Menus onClick={MinApp.onClose}>
|
||||||
<Tooltip title={t('settings.theme.title')} mouseEnterDelay={0.8} placement="right">
|
<Tooltip title={t('settings.theme.title')} mouseEnterDelay={0.8} placement="right">
|
||||||
<Icon onClick={() => toggleTheme()}>
|
<Icon onClick={() => toggleTheme()}>
|
||||||
@ -133,6 +84,89 @@ const Sidebar: FC = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MainMenus: FC = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { pathname } = useLocation()
|
||||||
|
const { sidebarIcons } = useSettings()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const isRoute = (path: string): string => (pathname === path ? 'active' : '')
|
||||||
|
const isRoutes = (path: string): string => (pathname.startsWith(path) ? 'active' : '')
|
||||||
|
|
||||||
|
const iconMap = {
|
||||||
|
assistants: <i className="iconfont icon-chat" />,
|
||||||
|
agents: <i className="iconfont icon-business-smart-assistant" />,
|
||||||
|
paintings: <PictureOutlined style={{ fontSize: 16 }} />,
|
||||||
|
translate: <TranslationOutlined />,
|
||||||
|
minapp: <i className="iconfont icon-appstore" />,
|
||||||
|
knowledge: <FileSearchOutlined />,
|
||||||
|
files: <FolderOutlined />
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathMap = {
|
||||||
|
assistants: '/',
|
||||||
|
agents: '/agents',
|
||||||
|
paintings: '/paintings',
|
||||||
|
translate: '/translate',
|
||||||
|
minapp: '/apps',
|
||||||
|
knowledge: '/knowledge',
|
||||||
|
files: '/files'
|
||||||
|
}
|
||||||
|
|
||||||
|
return sidebarIcons.visible.map((icon) => {
|
||||||
|
const path = pathMap[icon]
|
||||||
|
const isActive = path === '/' ? isRoute(path) : isRoutes(path)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip key={icon} title={t(`${icon}.title`)} mouseEnterDelay={0.8} placement="right">
|
||||||
|
<StyledLink onClick={() => navigate(path)}>
|
||||||
|
<Icon className={isActive}>{iconMap[icon]}</Icon>
|
||||||
|
</StyledLink>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const PinnedApps: FC = () => {
|
||||||
|
const { pinned, updatePinnedMinapps } = useMinapps()
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DragableList list={pinned} onUpdate={updatePinnedMinapps}>
|
||||||
|
{(app) => {
|
||||||
|
const menuItems: MenuProps['items'] = [
|
||||||
|
{
|
||||||
|
key: 'togglePin',
|
||||||
|
label: t('minapp.sidebar.remove.title'),
|
||||||
|
onClick: () => {
|
||||||
|
const newPinned = pinned.filter((item) => item.id !== app.id)
|
||||||
|
updatePinnedMinapps(newPinned)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<Tooltip key={app.id} title={app.name} mouseEnterDelay={0.8} placement="right">
|
||||||
|
<StyledLink>
|
||||||
|
<Dropdown menu={{ items: menuItems }} trigger={['contextMenu']}>
|
||||||
|
<Icon onClick={() => MinApp.start(app)}>
|
||||||
|
<AppIcon
|
||||||
|
src={app.logo}
|
||||||
|
style={{
|
||||||
|
width: '20px',
|
||||||
|
height: '20px',
|
||||||
|
border: app.bodered ? '0.5px solid var(--color-border)' : 'none'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Icon>
|
||||||
|
</Dropdown>
|
||||||
|
</StyledLink>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</DragableList>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -154,9 +188,10 @@ const AvatarImg = styled(Avatar)`
|
|||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
`
|
`
|
||||||
const MainMenus = styled.div`
|
const MainMenusContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -164,6 +199,7 @@ const Menus = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const Icon = styled.div`
|
const Icon = styled.div`
|
||||||
@ -173,7 +209,6 @@ const Icon = styled.div`
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-bottom: 5px;
|
|
||||||
-webkit-app-region: none;
|
-webkit-app-region: none;
|
||||||
border: 0.5px solid transparent;
|
border: 0.5px solid transparent;
|
||||||
.iconfont,
|
.iconfont,
|
||||||
@ -215,27 +250,23 @@ const AppIcon = styled.img`
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ScrollContainer = styled.div`
|
const AppsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
height: 100%;
|
margin-bottom: 10px;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 0px;
|
display: none;
|
||||||
}
|
|
||||||
|
|
||||||
&:hover::-webkit-scrollbar {
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: var(--color-border);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const Divider = styled.div`
|
||||||
|
width: 50%;
|
||||||
|
margin: 8px 0;
|
||||||
|
border-bottom: 0.5px solid var(--color-border);
|
||||||
|
`
|
||||||
|
|
||||||
export default Sidebar
|
export default Sidebar
|
||||||
|
|||||||
23
src/renderer/src/hooks/useMinapps.ts
Normal file
23
src/renderer/src/hooks/useMinapps.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { RootState, useAppDispatch, useAppSelector } from '@renderer/store'
|
||||||
|
import { setDisabledMinApps, setMinApps, setPinnedMinApps } from '@renderer/store/minapps'
|
||||||
|
import { MinAppType } from '@renderer/types'
|
||||||
|
|
||||||
|
export const useMinapps = () => {
|
||||||
|
const { enabled, disabled, pinned } = useAppSelector((state: RootState) => state.minapps)
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
return {
|
||||||
|
minapps: enabled,
|
||||||
|
disabled,
|
||||||
|
pinned,
|
||||||
|
updateMinapps: (minapps: MinAppType[]) => {
|
||||||
|
dispatch(setMinApps(minapps))
|
||||||
|
},
|
||||||
|
updateDisabledMinapps: (minapps: MinAppType[]) => {
|
||||||
|
dispatch(setDisabledMinApps(minapps))
|
||||||
|
},
|
||||||
|
updatePinnedMinapps: (minapps: MinAppType[]) => {
|
||||||
|
dispatch(setPinnedMinApps(minapps))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,13 +2,14 @@ import store, { useAppDispatch, useAppSelector } from '@renderer/store'
|
|||||||
import {
|
import {
|
||||||
SendMessageShortcut,
|
SendMessageShortcut,
|
||||||
setSendMessageShortcut as _setSendMessageShortcut,
|
setSendMessageShortcut as _setSendMessageShortcut,
|
||||||
|
setSidebarIcons,
|
||||||
setTheme,
|
setTheme,
|
||||||
SettingsState,
|
SettingsState,
|
||||||
setTopicPosition,
|
setTopicPosition,
|
||||||
setTray,
|
setTray,
|
||||||
setWindowStyle
|
setWindowStyle
|
||||||
} from '@renderer/store/settings'
|
} from '@renderer/store/settings'
|
||||||
import { ThemeMode } from '@renderer/types'
|
import { SidebarIcon, ThemeMode } from '@renderer/types'
|
||||||
|
|
||||||
export function useSettings() {
|
export function useSettings() {
|
||||||
const settings = useAppSelector((state) => state.settings)
|
const settings = useAppSelector((state) => state.settings)
|
||||||
@ -30,6 +31,15 @@ export function useSettings() {
|
|||||||
},
|
},
|
||||||
setTopicPosition(topicPosition: 'left' | 'right') {
|
setTopicPosition(topicPosition: 'left' | 'right') {
|
||||||
dispatch(setTopicPosition(topicPosition))
|
dispatch(setTopicPosition(topicPosition))
|
||||||
|
},
|
||||||
|
updateSidebarIcons(icons: { visible: SidebarIcon[]; disabled: SidebarIcon[] }) {
|
||||||
|
dispatch(setSidebarIcons(icons))
|
||||||
|
},
|
||||||
|
updateSidebarVisibleIcons(icons: SidebarIcon[]) {
|
||||||
|
dispatch(setSidebarIcons({ visible: icons }))
|
||||||
|
},
|
||||||
|
updateSidebarDisabledIcons(icons: SidebarIcon[]) {
|
||||||
|
dispatch(setSidebarIcons({ disabled: icons }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -265,8 +265,8 @@
|
|||||||
},
|
},
|
||||||
"minapp": {
|
"minapp": {
|
||||||
"title": "MinApp",
|
"title": "MinApp",
|
||||||
"sidebar.add.title": "Add minAPP to sidebar",
|
"sidebar.add.title": "Add to sidebar",
|
||||||
"sidebar.remove.title": "Remove minAPP from sidebar"
|
"sidebar.remove.title": "Remove from sidebar"
|
||||||
},
|
},
|
||||||
"ollama": {
|
"ollama": {
|
||||||
"keep_alive_time.description": "The time in minutes to keep the connection alive, default is 5 minutes.",
|
"keep_alive_time.description": "The time in minutes to keep the connection alive, default is 5 minutes.",
|
||||||
@ -403,15 +403,15 @@
|
|||||||
"display.sidebar.knowledge.icon": "Show Knowledge icon",
|
"display.sidebar.knowledge.icon": "Show Knowledge icon",
|
||||||
"display.sidebar.files.icon": "Show Files icon",
|
"display.sidebar.files.icon": "Show Files icon",
|
||||||
"display.sidebar.title": "Sidebar Settings",
|
"display.sidebar.title": "Sidebar Settings",
|
||||||
"display.sidebar.visible": "Show my sidebar icons",
|
"display.sidebar.visible": "Show icons",
|
||||||
"display.sidebar.disabled": "Hide my sidebar icons",
|
"display.sidebar.disabled": "Hide icons",
|
||||||
"display.sidebar.chat.hiddenMessage": "Assistants are basic functions, not supported for hiding",
|
"display.sidebar.chat.hiddenMessage": "Assistants are basic functions, not supported for hiding",
|
||||||
"display.sidebar.empty": "Drag the hidden feature from the left side here",
|
"display.sidebar.empty": "Drag the hidden feature from the left side here",
|
||||||
"display.minApp.title": "MinApp Settings",
|
"display.minApp.title": "MinApp Settings",
|
||||||
"display.minApp.visible": "Visible MinApp",
|
"display.minApp.visible": "Visible MinApp",
|
||||||
"display.minApp.disabled": "Hidden MinApp",
|
"display.minApp.disabled": "Hidden MinApp",
|
||||||
"display.minApp.empty": "Drag minApp from the left to hide them here",
|
"display.minApp.empty": "Drag minApp from the left to hide them here",
|
||||||
"display.minApp.pinnedError": "MinApp that have been added to the sidebar do not support hiding. If you want to hide them, please remove them from the sidebar first.",
|
"": "MinApp that have been added to the sidebar do not support hiding. If you want to hide them, please remove them from the sidebar first.",
|
||||||
"display.topic.title": "Topic Settings",
|
"display.topic.title": "Topic Settings",
|
||||||
"display.custom.css": "Custom CSS",
|
"display.custom.css": "Custom CSS",
|
||||||
"display.custom.css.placeholder": "/* Put custom CSS here */",
|
"display.custom.css.placeholder": "/* Put custom CSS here */",
|
||||||
|
|||||||
@ -263,8 +263,8 @@
|
|||||||
},
|
},
|
||||||
"minapp": {
|
"minapp": {
|
||||||
"title": "ミニアプリ",
|
"title": "ミニアプリ",
|
||||||
"sidebar.add.title": "ミニプログラムをサイドバーに追加",
|
"sidebar.add.title": "サイドバーに追加",
|
||||||
"sidebar.remove.title": "サイドバーからアプレットを削除する"
|
"sidebar.remove.title": "サイドバーから削除"
|
||||||
},
|
},
|
||||||
"ollama": {
|
"ollama": {
|
||||||
"keep_alive_time.description": "モデルがメモリに保持される時間(デフォルト:5分)",
|
"keep_alive_time.description": "モデルがメモリに保持される時間(デフォルト:5分)",
|
||||||
@ -401,8 +401,8 @@
|
|||||||
"display.sidebar.knowledge.icon": "ナレッジのアイコンを表示",
|
"display.sidebar.knowledge.icon": "ナレッジのアイコンを表示",
|
||||||
"display.sidebar.files.icon": "ファイルのアイコンを表示",
|
"display.sidebar.files.icon": "ファイルのアイコンを表示",
|
||||||
"display.sidebar.title": "サイドバー設定",
|
"display.sidebar.title": "サイドバー設定",
|
||||||
"display.sidebar.visible": "サイドバーのアイコンを表示する",
|
"display.sidebar.visible": "アイコンを表示",
|
||||||
"display.sidebar.disabled": "サイドバーのアイコンを非表示にする",
|
"display.sidebar.disabled": "アイコンを非表示",
|
||||||
"display.sidebar.chat.hiddenMessage": "アシスタントは基本的な機能であり、非表示はサポートされていません",
|
"display.sidebar.chat.hiddenMessage": "アシスタントは基本的な機能であり、非表示はサポートされていません",
|
||||||
"display.sidebar.empty": "非表示にする機能を左側からここにドラッグ",
|
"display.sidebar.empty": "非表示にする機能を左側からここにドラッグ",
|
||||||
"display.topic.title": "トピック設定",
|
"display.topic.title": "トピック設定",
|
||||||
@ -412,7 +412,6 @@
|
|||||||
"display.minApp.visible": "表示中ミニプログラム",
|
"display.minApp.visible": "表示中ミニプログラム",
|
||||||
"display.minApp.disabled": "非表示ミニプログラム",
|
"display.minApp.disabled": "非表示ミニプログラム",
|
||||||
"display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします",
|
"display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします",
|
||||||
"display.minApp.pinnedError": "サイドバーに追加されたミニ プログラムは非表示をサポートしていません。非表示にしたい場合は、まずサイドバーから削除してください",
|
|
||||||
"input.auto_translate_with_space": "スペースを3回押して翻訳",
|
"input.auto_translate_with_space": "スペースを3回押して翻訳",
|
||||||
"messages.divider": "メッセージ間に区切り線を表示",
|
"messages.divider": "メッセージ間に区切り線を表示",
|
||||||
"messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け",
|
"messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け",
|
||||||
|
|||||||
@ -265,8 +265,8 @@
|
|||||||
},
|
},
|
||||||
"minapp": {
|
"minapp": {
|
||||||
"title": "Встроенные приложения",
|
"title": "Встроенные приложения",
|
||||||
"sidebar.add.title": "Добавить мини-программу на боковую панель",
|
"sidebar.add.title": "Добавить в боковую панель",
|
||||||
"sidebar.remove.title": "Удалить апплет из боковой панели"
|
"sidebar.remove.title": "Удалить из боковой панели"
|
||||||
},
|
},
|
||||||
"ollama": {
|
"ollama": {
|
||||||
"keep_alive_time.description": "Время в минутах, в течение которого модель остается активной, по умолчанию 5 минут.",
|
"keep_alive_time.description": "Время в минутах, в течение которого модель остается активной, по умолчанию 5 минут.",
|
||||||
@ -403,15 +403,14 @@
|
|||||||
"display.sidebar.knowledge.icon": "Показывать иконку знаний",
|
"display.sidebar.knowledge.icon": "Показывать иконку знаний",
|
||||||
"display.sidebar.files.icon": "Показывать иконку файлов",
|
"display.sidebar.files.icon": "Показывать иконку файлов",
|
||||||
"display.sidebar.title": "Настройки боковой панели",
|
"display.sidebar.title": "Настройки боковой панели",
|
||||||
"display.sidebar.visible": "Показать мои значки на боковой панели",
|
"display.sidebar.visible": "Показывать иконки",
|
||||||
"display.sidebar.disabled": "Скрыть значок на боковой панели",
|
"display.sidebar.disabled": "Скрыть иконки",
|
||||||
"display.sidebar.chat.hiddenMessage": "Помощник является базовой функцией и не поддерживает скрытие",
|
"display.sidebar.chat.hiddenMessage": "Помощник является базовой функцией и не поддерживает скрытие",
|
||||||
"display.sidebar.empty": "Перетащите скрываемую функцию с левой стороны сюда",
|
"display.sidebar.empty": "Перетащите скрываемую функцию с левой стороны сюда",
|
||||||
"display.minApp.title": "Настройки отображения мини программы",
|
"display.minApp.title": "Настройки отображения мини программы",
|
||||||
"display.minApp.visible": "Отображаемый апплет",
|
"display.minApp.visible": "Отображаемый апплет",
|
||||||
"display.minApp.disabled": "скрытый апплет",
|
"display.minApp.disabled": "скрытый апплет",
|
||||||
"display.minApp.empty": "Перетащите апплет, который хотите скрыть, слева сюда",
|
"display.minApp.empty": "Перетащите апплет, который хотите скрыть, слева сюда",
|
||||||
"display.minApp.pinnedError": "Мини-программы, добавленные на боковую панель, не поддерживают скрытие. Если вы хотите скрыть их, сначала удалите их с боковой панели",
|
|
||||||
"display.topic.title": "Настройки топиков",
|
"display.topic.title": "Настройки топиков",
|
||||||
"display.custom.css": "Пользовательский CSS",
|
"display.custom.css": "Пользовательский CSS",
|
||||||
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
|
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
|
||||||
|
|||||||
@ -266,8 +266,8 @@
|
|||||||
},
|
},
|
||||||
"minapp": {
|
"minapp": {
|
||||||
"title": "小程序",
|
"title": "小程序",
|
||||||
"sidebar.add.title": "添加小程序到侧边栏",
|
"sidebar.add.title": "添加到侧边栏",
|
||||||
"sidebar.remove.title": "从侧边栏移除小程序"
|
"sidebar.remove.title": "从侧边栏移除"
|
||||||
},
|
},
|
||||||
"ollama": {
|
"ollama": {
|
||||||
"keep_alive_time.description": "对话后模型在内存中保持的时间(默认:5分钟)",
|
"keep_alive_time.description": "对话后模型在内存中保持的时间(默认:5分钟)",
|
||||||
@ -404,15 +404,14 @@
|
|||||||
"display.sidebar.knowledge.icon": "显示知识图标",
|
"display.sidebar.knowledge.icon": "显示知识图标",
|
||||||
"display.sidebar.files.icon": "显示文件图标",
|
"display.sidebar.files.icon": "显示文件图标",
|
||||||
"display.sidebar.title": "侧边栏设置",
|
"display.sidebar.title": "侧边栏设置",
|
||||||
"display.sidebar.visible": "显示我的侧边栏图标",
|
"display.sidebar.visible": "显示的图标",
|
||||||
"display.sidebar.disabled": "隐藏我的侧边栏图标",
|
"display.sidebar.disabled": "隐藏的图标",
|
||||||
"display.sidebar.chat.hiddenMessage": "助手是基础功能,不支持隐藏",
|
"display.sidebar.chat.hiddenMessage": "助手是基础功能,不支持隐藏",
|
||||||
"display.sidebar.empty": "把要隐藏的功能从左侧拖拽到这里",
|
"display.sidebar.empty": "把要隐藏的功能从左侧拖拽到这里",
|
||||||
"display.minApp.title": "小程序显示设置",
|
"display.minApp.title": "小程序显示设置",
|
||||||
"display.minApp.visible": "显示的小程序",
|
"display.minApp.visible": "显示的小程序",
|
||||||
"display.minApp.disabled": "隐藏的小程序",
|
"display.minApp.disabled": "隐藏的小程序",
|
||||||
"display.minApp.empty": "把要隐藏的小程序从左侧拖拽到这里",
|
"display.minApp.empty": "把要隐藏的小程序从左侧拖拽到这里",
|
||||||
"display.minApp.pinnedError": "已经添加到侧边栏的小程序,不支持隐藏,如需隐藏请先从侧边栏移除",
|
|
||||||
"display.topic.title": "话题设置",
|
"display.topic.title": "话题设置",
|
||||||
"display.custom.css": "自定义 CSS",
|
"display.custom.css": "自定义 CSS",
|
||||||
"display.custom.css.placeholder": "/* 这里写自定义CSS */",
|
"display.custom.css.placeholder": "/* 这里写自定义CSS */",
|
||||||
|
|||||||
@ -265,8 +265,8 @@
|
|||||||
},
|
},
|
||||||
"minapp": {
|
"minapp": {
|
||||||
"title": "小程序",
|
"title": "小程序",
|
||||||
"sidebar.add.title": "新增小程式到側邊欄",
|
"sidebar.add.title": "添加到側邊欄",
|
||||||
"sidebar.remove.title": "從側邊欄移除小程式"
|
"sidebar.remove.title": "從側邊欄移除"
|
||||||
},
|
},
|
||||||
"ollama": {
|
"ollama": {
|
||||||
"keep_alive_time.description": "對話後模型在記憶體中保持的時間(預設為 5 分鐘)。",
|
"keep_alive_time.description": "對話後模型在記憶體中保持的時間(預設為 5 分鐘)。",
|
||||||
@ -406,13 +406,12 @@
|
|||||||
"display.topic.title": "話題設定",
|
"display.topic.title": "話題設定",
|
||||||
"display.sidebar.chat.hiddenMessage": "助手是基礎功能,不支援隱藏",
|
"display.sidebar.chat.hiddenMessage": "助手是基礎功能,不支援隱藏",
|
||||||
"display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡",
|
"display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡",
|
||||||
"display.sidebar.visible": "顯示我的側邊欄圖標",
|
"display.sidebar.visible": "顯示的圖標",
|
||||||
"display.sidebar.disabled": "隱藏我的側邊欄圖標",
|
"display.sidebar.disabled": "隱藏的圖標",
|
||||||
"display.minApp.title": "小程序顯示設定",
|
"display.minApp.title": "小程序顯示設定",
|
||||||
"display.minApp.visible": "顯示的小程序",
|
"display.minApp.visible": "顯示的小程序",
|
||||||
"display.minApp.disabled": "隱藏的小程序",
|
"display.minApp.disabled": "隱藏的小程序",
|
||||||
"display.minApp.empty": "把要隱藏的小程序從左側拖拽到這裡",
|
"display.minApp.empty": "把要隱藏的小程序從左側拖拽到這裡",
|
||||||
"display.minApp.pinnedError": "已新增至側邊欄的小程序,不支援隱藏,如需隱藏請先從側邊欄移除",
|
|
||||||
"display.custom.css": "自定義 CSS",
|
"display.custom.css": "自定義 CSS",
|
||||||
"display.custom.css.placeholder": "/* 這裡寫自定義 CSS */",
|
"display.custom.css.placeholder": "/* 這裡寫自定義 CSS */",
|
||||||
"input.auto_translate_with_space": "快速敲擊3次空格翻譯",
|
"input.auto_translate_with_space": "快速敲擊3次空格翻譯",
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import MinApp from '@renderer/components/MinApp'
|
import MinApp from '@renderer/components/MinApp'
|
||||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { setMiniAppIcons } from '@renderer/store/settings'
|
|
||||||
import { MinAppType } from '@renderer/types'
|
import { MinAppType } from '@renderer/types'
|
||||||
import type { MenuProps } from 'antd'
|
import type { MenuProps } from 'antd'
|
||||||
import { Dropdown } from 'antd'
|
import { Dropdown } from 'antd'
|
||||||
@ -16,10 +15,9 @@ interface Props {
|
|||||||
|
|
||||||
const App: FC<Props> = ({ app, onClick, size = 60 }) => {
|
const App: FC<Props> = ({ app, onClick, size = 60 }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const dispatch = useAppDispatch()
|
const { minapps, pinned, updatePinnedMinapps } = useMinapps()
|
||||||
const { miniAppIcons } = useAppSelector((state) => state.settings)
|
const isPinned = pinned.some((p) => p.id === app.id)
|
||||||
const isPinned = miniAppIcons?.pinned.includes(app.id)
|
const isVisible = minapps.some((m) => m.id === app.id)
|
||||||
const isVisible = miniAppIcons?.visible.includes(app.id)
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
MinApp.start(app)
|
MinApp.start(app)
|
||||||
@ -31,17 +29,8 @@ const App: FC<Props> = ({ app, onClick, size = 60 }) => {
|
|||||||
key: 'togglePin',
|
key: 'togglePin',
|
||||||
label: isPinned ? t('minapp.sidebar.remove.title') : t('minapp.sidebar.add.title'),
|
label: isPinned ? t('minapp.sidebar.remove.title') : t('minapp.sidebar.add.title'),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const newPinned = isPinned
|
const newPinned = isPinned ? pinned.filter((item) => item.id !== app.id) : [...(pinned || []), app]
|
||||||
? miniAppIcons.pinned.filter((id) => id !== app.id)
|
updatePinnedMinapps(newPinned)
|
||||||
: [...(miniAppIcons.pinned || []), app.id]
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
setMiniAppIcons({
|
|
||||||
...miniAppIcons,
|
|
||||||
pinned: newPinned,
|
|
||||||
visible: isPinned ? miniAppIcons.visible : [...new Set([...miniAppIcons.visible, app.id])]
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import { SearchOutlined } from '@ant-design/icons'
|
import { SearchOutlined } from '@ant-design/icons'
|
||||||
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||||
import { Center } from '@renderer/components/Layout'
|
import { Center } from '@renderer/components/Layout'
|
||||||
import { getAllMinApps } from '@renderer/config/minapps'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
|
||||||
import { Empty, Input } from 'antd'
|
import { Empty, Input } from 'antd'
|
||||||
import { isEmpty } from 'lodash'
|
import { isEmpty } from 'lodash'
|
||||||
import React, { FC, useMemo, useState } from 'react'
|
import React, { FC, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -14,24 +13,15 @@ import App from './App'
|
|||||||
const AppsPage: FC = () => {
|
const AppsPage: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
const { miniAppIcons } = useSettings()
|
const { minapps } = useMinapps()
|
||||||
const allApps = useMemo(() => getAllMinApps(), [])
|
|
||||||
|
|
||||||
// 只显示可见的小程序,但包括所有固定的小程序
|
console.debug('minapps', minapps)
|
||||||
const visibleApps = useMemo(() => {
|
|
||||||
if (!miniAppIcons?.visible) return allApps
|
|
||||||
const visibleIds = new Set([
|
|
||||||
...miniAppIcons.visible,
|
|
||||||
...(miniAppIcons.pinned || []) // 确保固定的小程序总是可见
|
|
||||||
])
|
|
||||||
return allApps.filter((app) => visibleIds.has(app.id))
|
|
||||||
}, [allApps, miniAppIcons?.visible, miniAppIcons?.pinned])
|
|
||||||
|
|
||||||
const filteredApps = search
|
const filteredApps = search
|
||||||
? visibleApps.filter(
|
? minapps.filter(
|
||||||
(app) => app.name.toLowerCase().includes(search.toLowerCase()) || app.url.includes(search.toLowerCase())
|
(app) => app.name.toLowerCase().includes(search.toLowerCase()) || app.url.includes(search.toLowerCase())
|
||||||
)
|
)
|
||||||
: visibleApps
|
: minapps
|
||||||
|
|
||||||
// Calculate the required number of lines
|
// Calculate the required number of lines
|
||||||
const itemsPerRow = Math.floor(930 / 115) // Maximum width divided by the width of each item (including spacing)
|
const itemsPerRow = Math.floor(930 / 115) // Maximum width divided by the width of each item (including spacing)
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { isMac } from '@renderer/config/constant'
|
import { isMac } from '@renderer/config/constant'
|
||||||
|
import { getAllMinApps } from '@renderer/config/minapps'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import {
|
import {
|
||||||
DEFAULT_MINIAPP_ICONS,
|
|
||||||
DEFAULT_SIDEBAR_ICONS,
|
DEFAULT_SIDEBAR_ICONS,
|
||||||
setClickAssistantToShowTopic,
|
setClickAssistantToShowTopic,
|
||||||
setCustomCss,
|
setCustomCss,
|
||||||
setMiniAppIcons,
|
|
||||||
setShowTopicTime,
|
setShowTopicTime,
|
||||||
setSidebarIcons
|
setSidebarIcons
|
||||||
} from '@renderer/store/settings'
|
} from '@renderer/store/settings'
|
||||||
@ -32,17 +32,17 @@ const DisplaySettings: FC = () => {
|
|||||||
clickAssistantToShowTopic,
|
clickAssistantToShowTopic,
|
||||||
showTopicTime,
|
showTopicTime,
|
||||||
customCss,
|
customCss,
|
||||||
sidebarIcons,
|
sidebarIcons
|
||||||
miniAppIcons
|
|
||||||
} = useSettings()
|
} = useSettings()
|
||||||
|
const { minapps, disabled, updateMinapps, updateDisabledMinapps } = useMinapps()
|
||||||
const { theme: themeMode } = useTheme()
|
const { theme: themeMode } = useTheme()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const [visibleIcons, setVisibleIcons] = useState(sidebarIcons?.visible || DEFAULT_SIDEBAR_ICONS)
|
const [visibleIcons, setVisibleIcons] = useState(sidebarIcons?.visible || DEFAULT_SIDEBAR_ICONS)
|
||||||
const [disabledIcons, setDisabledIcons] = useState(sidebarIcons?.disabled || [])
|
const [disabledIcons, setDisabledIcons] = useState(sidebarIcons?.disabled || [])
|
||||||
const [visibleMiniApps, setVisibleMiniApps] = useState(miniAppIcons?.visible || DEFAULT_MINIAPP_ICONS)
|
const [visibleMiniApps, setVisibleMiniApps] = useState(minapps)
|
||||||
const [disabledMiniApps, setDisabledMiniApps] = useState(miniAppIcons?.disabled || [])
|
const [disabledMiniApps, setDisabledMiniApps] = useState(disabled || [])
|
||||||
|
|
||||||
// 使用useCallback优化回调函数
|
// 使用useCallback优化回调函数
|
||||||
const handleWindowStyleChange = useCallback(
|
const handleWindowStyleChange = useCallback(
|
||||||
@ -59,16 +59,11 @@ const DisplaySettings: FC = () => {
|
|||||||
}, [dispatch])
|
}, [dispatch])
|
||||||
|
|
||||||
const handleResetMinApps = useCallback(() => {
|
const handleResetMinApps = useCallback(() => {
|
||||||
setVisibleMiniApps(DEFAULT_MINIAPP_ICONS)
|
setVisibleMiniApps(getAllMinApps())
|
||||||
setDisabledMiniApps([])
|
setDisabledMiniApps([])
|
||||||
dispatch(
|
updateMinapps(getAllMinApps())
|
||||||
setMiniAppIcons({
|
updateDisabledMinapps([])
|
||||||
visible: DEFAULT_MINIAPP_ICONS,
|
}, [updateDisabledMinapps, updateMinapps])
|
||||||
disabled: [],
|
|
||||||
pinned: miniAppIcons?.pinned || []
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}, [dispatch, miniAppIcons?.pinned])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingContainer theme={themeMode}>
|
<SettingContainer theme={themeMode}>
|
||||||
|
|||||||
@ -8,39 +8,33 @@ import {
|
|||||||
DropResult
|
DropResult
|
||||||
} from '@hello-pangea/dnd'
|
} from '@hello-pangea/dnd'
|
||||||
import { getAllMinApps } from '@renderer/config/minapps'
|
import { getAllMinApps } from '@renderer/config/minapps'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { MinAppType } from '@renderer/types'
|
||||||
import { MinAppIcon, setMiniAppIcons } from '@renderer/store/settings'
|
|
||||||
import { FC, useCallback, useMemo } from 'react'
|
import { 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'
|
||||||
|
|
||||||
interface MiniAppManagerProps {
|
interface MiniAppManagerProps {
|
||||||
visibleMiniApps: MinAppIcon[]
|
visibleMiniApps: MinAppType[]
|
||||||
disabledMiniApps: MinAppIcon[]
|
disabledMiniApps: MinAppType[]
|
||||||
setVisibleMiniApps: (programs: MinAppIcon[]) => void
|
setVisibleMiniApps: (programs: MinAppType[]) => void
|
||||||
setDisabledMiniApps: (programs: MinAppIcon[]) => void
|
setDisabledMiniApps: (programs: MinAppType[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将可复用的类型和常量提取出来
|
|
||||||
type ListType = 'visible' | 'disabled'
|
type ListType = 'visible' | 'disabled'
|
||||||
interface AppInfo {
|
|
||||||
name: string
|
|
||||||
logo?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加 reorderLists 函数的接口定义
|
// 添加 reorderLists 函数的接口定义
|
||||||
interface ReorderListsParams {
|
interface ReorderListsParams {
|
||||||
sourceList: MinAppIcon[]
|
sourceList: MinAppType[]
|
||||||
destList: MinAppIcon[]
|
destList: MinAppType[]
|
||||||
sourceIndex: number
|
sourceIndex: number
|
||||||
destIndex: number
|
destIndex: number
|
||||||
isSameList: boolean
|
isSameList: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReorderListsResult {
|
interface ReorderListsResult {
|
||||||
sourceList: MinAppIcon[]
|
sourceList: MinAppType[]
|
||||||
destList: MinAppIcon[]
|
destList: MinAppType[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加 reorderLists 函数
|
// 添加 reorderLists 函数
|
||||||
@ -80,43 +74,18 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
setDisabledMiniApps
|
setDisabledMiniApps
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const dispatch = useAppDispatch()
|
|
||||||
const { miniAppIcons } = useSettings()
|
|
||||||
const allApps = useMemo(() => getAllMinApps(), [])
|
const allApps = useMemo(() => getAllMinApps(), [])
|
||||||
|
const { pinned, updateMinapps, updateDisabledMinapps, updatePinnedMinapps } = useMinapps()
|
||||||
// 创建 app 信息的 Map 缓存
|
|
||||||
const appInfoMap = useMemo(() => {
|
|
||||||
return allApps.reduce(
|
|
||||||
(acc, app) => {
|
|
||||||
acc[String(app.id)] = { name: app.name, logo: app.logo }
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
{} as Record<string, AppInfo>
|
|
||||||
)
|
|
||||||
}, [allApps])
|
|
||||||
|
|
||||||
const getAppInfo = useCallback(
|
|
||||||
(id: MinAppIcon) => {
|
|
||||||
return appInfoMap[String(id)] || { name: id, logo: '' }
|
|
||||||
},
|
|
||||||
[appInfoMap]
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleListUpdate = useCallback(
|
const handleListUpdate = useCallback(
|
||||||
(newVisible: MinAppIcon[], newDisabled: MinAppIcon[]) => {
|
(newVisible: MinAppType[], newDisabled: MinAppType[]) => {
|
||||||
setVisibleMiniApps(newVisible)
|
setVisibleMiniApps(newVisible)
|
||||||
setDisabledMiniApps(newDisabled)
|
setDisabledMiniApps(newDisabled)
|
||||||
|
updateMinapps(newVisible)
|
||||||
// 保持 pinned 状态不变
|
updateDisabledMinapps(newDisabled)
|
||||||
dispatch(
|
updatePinnedMinapps(pinned.filter((p) => !newDisabled.some((d) => d.id === p.id)))
|
||||||
setMiniAppIcons({
|
|
||||||
visible: newVisible,
|
|
||||||
disabled: newDisabled,
|
|
||||||
pinned: miniAppIcons.pinned // 保持原有的 pinned 状态
|
|
||||||
})
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
[dispatch, setVisibleMiniApps, setDisabledMiniApps, miniAppIcons.pinned]
|
[pinned, setDisabledMiniApps, setVisibleMiniApps, updateDisabledMinapps, updateMinapps, updatePinnedMinapps]
|
||||||
)
|
)
|
||||||
|
|
||||||
const onDragEnd = useCallback(
|
const onDragEnd = useCallback(
|
||||||
@ -127,15 +96,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
const sourceList = source.droppableId as ListType
|
const sourceList = source.droppableId as ListType
|
||||||
const destList = destination.droppableId as ListType
|
const destList = destination.droppableId as ListType
|
||||||
|
|
||||||
// 如果是 pinned 的小程序,不允许拖到 disabled
|
if (source.droppableId === destination.droppableId) return
|
||||||
if (destList === 'disabled') {
|
|
||||||
const draggedApp = sourceList === 'visible' ? visibleMiniApps[source.index] : disabledMiniApps[source.index]
|
|
||||||
|
|
||||||
if (miniAppIcons.pinned.includes(draggedApp)) {
|
|
||||||
window.message.error(t('settings.display.minApp.pinnedError'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newLists = reorderLists({
|
const newLists = reorderLists({
|
||||||
sourceList: sourceList === 'visible' ? visibleMiniApps : disabledMiniApps,
|
sourceList: sourceList === 'visible' ? visibleMiniApps : disabledMiniApps,
|
||||||
@ -150,32 +111,26 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
sourceList === 'visible' ? newLists.destList : newLists.sourceList
|
sourceList === 'visible' ? newLists.destList : newLists.sourceList
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
[visibleMiniApps, disabledMiniApps, handleListUpdate, miniAppIcons.pinned, t]
|
[disabledMiniApps, handleListUpdate, visibleMiniApps]
|
||||||
)
|
)
|
||||||
|
|
||||||
const onMoveMiniApp = useCallback(
|
const onMoveMiniApp = useCallback(
|
||||||
(program: MinAppIcon, fromList: ListType) => {
|
(program: MinAppType, fromList: ListType) => {
|
||||||
// 如果是从可见列表移动到隐藏列表,且程序是 pinned 状态,则阻止移动
|
|
||||||
if (fromList === 'visible' && miniAppIcons.pinned.includes(program)) {
|
|
||||||
window.message.error(t('settings.display.minApp.pinnedError'))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const isMovingToVisible = fromList === 'disabled'
|
const isMovingToVisible = fromList === 'disabled'
|
||||||
const newVisible = isMovingToVisible
|
const newVisible = isMovingToVisible
|
||||||
? [...visibleMiniApps, program]
|
? [...visibleMiniApps, program]
|
||||||
: visibleMiniApps.filter((p) => p !== program)
|
: visibleMiniApps.filter((p) => p.id !== program.id)
|
||||||
const newDisabled = isMovingToVisible
|
const newDisabled = isMovingToVisible
|
||||||
? disabledMiniApps.filter((p) => p !== program)
|
? disabledMiniApps.filter((p) => p.id !== program.id)
|
||||||
: [...disabledMiniApps, program]
|
: [...disabledMiniApps, program]
|
||||||
|
|
||||||
handleListUpdate(newVisible, newDisabled)
|
handleListUpdate(newVisible, newDisabled)
|
||||||
},
|
},
|
||||||
[visibleMiniApps, disabledMiniApps, handleListUpdate, miniAppIcons.pinned, t]
|
[visibleMiniApps, disabledMiniApps, handleListUpdate]
|
||||||
)
|
)
|
||||||
|
|
||||||
const renderProgramItem = (program: MinAppIcon, provided: DraggableProvided, listType: ListType) => {
|
const renderProgramItem = (program: MinAppType, provided: DraggableProvided, listType: ListType) => {
|
||||||
const { name, logo } = getAppInfo(program)
|
const { name, logo } = allApps.find((app) => app.id === program.id) || { name: program.name, logo: '' }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProgramItem ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
<ProgramItem ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
||||||
@ -201,7 +156,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
|
|||||||
<ProgramList ref={provided.innerRef} {...provided.droppableProps}>
|
<ProgramList ref={provided.innerRef} {...provided.droppableProps}>
|
||||||
<ScrollContainer>
|
<ScrollContainer>
|
||||||
{(listType === 'visible' ? visibleMiniApps : disabledMiniApps).map((program, index) => (
|
{(listType === 'visible' ? visibleMiniApps : disabledMiniApps).map((program, index) => (
|
||||||
<Draggable key={program} draggableId={String(program)} index={index}>
|
<Draggable key={program.id} draggableId={String(program.id)} index={index}>
|
||||||
{(provided: DraggableProvided) => renderProgramItem(program, provided, listType)}
|
{(provided: DraggableProvided) => renderProgramItem(program, provided, listType)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
))}
|
))}
|
||||||
@ -230,6 +185,7 @@ const AppLogo = styled.img`
|
|||||||
const ScrollContainer = styled.div`
|
const ScrollContainer = styled.div`
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
padding-right: 5px;
|
||||||
`
|
`
|
||||||
|
|
||||||
const ProgramSection = styled.div`
|
const ProgramSection = styled.div`
|
||||||
@ -253,6 +209,7 @@ const ProgramList = styled.div`
|
|||||||
height: 365px;
|
height: 365px;
|
||||||
min-height: 365px;
|
min-height: 365px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
padding-right: 5px;
|
||||||
background: var(--color-background-soft);
|
background: var(--color-background-soft);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import assistants from './assistants'
|
|||||||
import knowledge from './knowledge'
|
import knowledge from './knowledge'
|
||||||
import llm from './llm'
|
import llm from './llm'
|
||||||
import migrate from './migrate'
|
import migrate from './migrate'
|
||||||
|
import minapps from './minapps'
|
||||||
import paintings from './paintings'
|
import paintings from './paintings'
|
||||||
import runtime from './runtime'
|
import runtime from './runtime'
|
||||||
import settings from './settings'
|
import settings from './settings'
|
||||||
@ -21,7 +22,8 @@ const rootReducer = combineReducers({
|
|||||||
settings,
|
settings,
|
||||||
runtime,
|
runtime,
|
||||||
shortcuts,
|
shortcuts,
|
||||||
knowledge
|
knowledge,
|
||||||
|
minapps
|
||||||
})
|
})
|
||||||
|
|
||||||
const persistedReducer = persistReducer(
|
const persistedReducer = persistReducer(
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import { isEmpty } from 'lodash'
|
|||||||
import { createMigrate } from 'redux-persist'
|
import { createMigrate } from 'redux-persist'
|
||||||
|
|
||||||
import { RootState } from '.'
|
import { RootState } from '.'
|
||||||
import { DEFAULT_MINIAPP_ICONS, DEFAULT_SIDEBAR_ICONS } from './settings'
|
|
||||||
|
|
||||||
const migrateConfig = {
|
const migrateConfig = {
|
||||||
'2': (state: RootState) => {
|
'2': (state: RootState) => {
|
||||||
@ -785,15 +784,6 @@ const migrateConfig = {
|
|||||||
system: false
|
system: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
state.settings.sidebarIcons = {
|
|
||||||
visible: DEFAULT_SIDEBAR_ICONS,
|
|
||||||
disabled: []
|
|
||||||
}
|
|
||||||
state.settings.miniAppIcons = {
|
|
||||||
visible: DEFAULT_MINIAPP_ICONS,
|
|
||||||
disabled: [],
|
|
||||||
pinned: []
|
|
||||||
}
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
src/renderer/src/store/minapps.ts
Normal file
48
src/renderer/src/store/minapps.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
|
import { getAllMinApps } from '@renderer/config/minapps'
|
||||||
|
import { MinAppType, SidebarIcon } from '@renderer/types'
|
||||||
|
|
||||||
|
export const DEFAULT_SIDEBAR_ICONS: SidebarIcon[] = [
|
||||||
|
'assistants',
|
||||||
|
'agents',
|
||||||
|
'paintings',
|
||||||
|
'translate',
|
||||||
|
'minapp',
|
||||||
|
'knowledge',
|
||||||
|
'files'
|
||||||
|
]
|
||||||
|
|
||||||
|
export interface MinAppsState {
|
||||||
|
enabled: MinAppType[]
|
||||||
|
disabled: MinAppType[]
|
||||||
|
pinned: MinAppType[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: MinAppsState = {
|
||||||
|
enabled: getAllMinApps(),
|
||||||
|
disabled: [],
|
||||||
|
pinned: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const minAppsSlice = createSlice({
|
||||||
|
name: 'minApps',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setMinApps: (state, action: PayloadAction<MinAppType[]>) => {
|
||||||
|
state.enabled = action.payload
|
||||||
|
},
|
||||||
|
addMinApp: (state, action: PayloadAction<MinAppType>) => {
|
||||||
|
state.enabled.push(action.payload)
|
||||||
|
},
|
||||||
|
setDisabledMinApps: (state, action: PayloadAction<MinAppType[]>) => {
|
||||||
|
state.disabled = action.payload
|
||||||
|
},
|
||||||
|
setPinnedMinApps: (state, action: PayloadAction<MinAppType[]>) => {
|
||||||
|
state.pinned = action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const { setMinApps, addMinApp, setDisabledMinApps, setPinnedMinApps } = minAppsSlice.actions
|
||||||
|
|
||||||
|
export default minAppsSlice.reducer
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import { getAllMinApps } from '@renderer/config/minapps'
|
|
||||||
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
|
import { TRANSLATE_PROMPT } from '@renderer/config/prompts'
|
||||||
import { CodeStyleVarious, LanguageVarious, ThemeMode } from '@renderer/types'
|
import { CodeStyleVarious, LanguageVarious, ThemeMode } from '@renderer/types'
|
||||||
|
|
||||||
@ -16,11 +15,6 @@ export const DEFAULT_SIDEBAR_ICONS: SidebarIcon[] = [
|
|||||||
'knowledge',
|
'knowledge',
|
||||||
'files'
|
'files'
|
||||||
]
|
]
|
||||||
const [minApps] = await Promise.all([getAllMinApps()])
|
|
||||||
|
|
||||||
export type MinAppIcon = (typeof minApps)[number]['id'] // 假设每个小程序对象有 type 字段
|
|
||||||
|
|
||||||
export const DEFAULT_MINIAPP_ICONS: MinAppIcon[] = minApps.map((app) => app.id)
|
|
||||||
|
|
||||||
export interface SettingsState {
|
export interface SettingsState {
|
||||||
showAssistants: boolean
|
showAssistants: boolean
|
||||||
@ -67,11 +61,6 @@ export interface SettingsState {
|
|||||||
disabled: SidebarIcon[]
|
disabled: SidebarIcon[]
|
||||||
}
|
}
|
||||||
narrowMode: boolean
|
narrowMode: boolean
|
||||||
miniAppIcons: {
|
|
||||||
visible: MinAppIcon[]
|
|
||||||
disabled: MinAppIcon[]
|
|
||||||
pinned: MinAppIcon[]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: SettingsState = {
|
const initialState: SettingsState = {
|
||||||
@ -116,12 +105,7 @@ const initialState: SettingsState = {
|
|||||||
visible: DEFAULT_SIDEBAR_ICONS,
|
visible: DEFAULT_SIDEBAR_ICONS,
|
||||||
disabled: []
|
disabled: []
|
||||||
},
|
},
|
||||||
narrowMode: false,
|
narrowMode: false
|
||||||
miniAppIcons: {
|
|
||||||
visible: DEFAULT_MINIAPP_ICONS,
|
|
||||||
disabled: [],
|
|
||||||
pinned: []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsSlice = createSlice({
|
const settingsSlice = createSlice({
|
||||||
@ -246,17 +230,16 @@ const settingsSlice = createSlice({
|
|||||||
setTopicNamingPrompt: (state, action: PayloadAction<string>) => {
|
setTopicNamingPrompt: (state, action: PayloadAction<string>) => {
|
||||||
state.topicNamingPrompt = action.payload
|
state.topicNamingPrompt = action.payload
|
||||||
},
|
},
|
||||||
setSidebarIcons: (state, action: PayloadAction<{ visible: SidebarIcon[]; disabled: SidebarIcon[] }>) => {
|
setSidebarIcons: (state, action: PayloadAction<{ visible?: SidebarIcon[]; disabled?: SidebarIcon[] }>) => {
|
||||||
state.sidebarIcons = action.payload
|
if (action.payload.visible) {
|
||||||
|
state.sidebarIcons.visible = action.payload.visible
|
||||||
|
}
|
||||||
|
if (action.payload.disabled) {
|
||||||
|
state.sidebarIcons.disabled = action.payload.disabled
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setNarrowMode: (state, action: PayloadAction<boolean>) => {
|
setNarrowMode: (state, action: PayloadAction<boolean>) => {
|
||||||
state.narrowMode = action.payload
|
state.narrowMode = action.payload
|
||||||
},
|
|
||||||
setMiniAppIcons: (
|
|
||||||
state,
|
|
||||||
action: PayloadAction<{ visible: MinAppIcon[]; disabled: MinAppIcon[]; pinned: MinAppIcon[] }>
|
|
||||||
) => {
|
|
||||||
state.miniAppIcons = action.payload
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -302,8 +285,7 @@ export const {
|
|||||||
setCustomCss,
|
setCustomCss,
|
||||||
setTopicNamingPrompt,
|
setTopicNamingPrompt,
|
||||||
setSidebarIcons,
|
setSidebarIcons,
|
||||||
setNarrowMode,
|
setNarrowMode
|
||||||
setMiniAppIcons
|
|
||||||
} = settingsSlice.actions
|
} = settingsSlice.actions
|
||||||
|
|
||||||
export default settingsSlice.reducer
|
export default settingsSlice.reducer
|
||||||
|
|||||||
@ -163,7 +163,9 @@ export enum ThemeMode {
|
|||||||
dark = 'dark',
|
dark = 'dark',
|
||||||
auto = 'auto'
|
auto = 'auto'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LanguageVarious = 'zh-CN' | 'zh-TW' | 'en-US' | 'ru-RU' | 'ja-JP'
|
export type LanguageVarious = 'zh-CN' | 'zh-TW' | 'en-US' | 'ru-RU' | 'ja-JP'
|
||||||
|
|
||||||
export type CodeStyleVarious = BuiltinTheme | 'auto'
|
export type CodeStyleVarious = BuiltinTheme | 'auto'
|
||||||
|
|
||||||
export type WebDavConfig = {
|
export type WebDavConfig = {
|
||||||
@ -241,3 +243,5 @@ export type GenerateImageParams = {
|
|||||||
signal?: AbortSignal
|
signal?: AbortSignal
|
||||||
promptEnhancement?: boolean
|
promptEnhancement?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SidebarIcon = 'assistants' | 'agents' | 'paintings' | 'translate' | 'minapp' | 'knowledge' | 'files'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user