refactor(settings): 重构小程序设置 (#4092)

This commit is contained in:
George·Dong 2025-03-30 08:48:23 +08:00 committed by GitHub
parent be39c5f40c
commit 22b0bd54b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 342 additions and 68 deletions

View File

@ -173,6 +173,7 @@ const MainMenus: FC = () => {
const SidebarOpenedMinappTabs: FC = () => { const SidebarOpenedMinappTabs: FC = () => {
const { minappShow, openedKeepAliveMinapps, currentMinappId } = useRuntime() const { minappShow, openedKeepAliveMinapps, currentMinappId } = useRuntime()
const { openMinappKeepAlive, hideMinappPopup, closeMinapp, closeAllMinapps } = useMinappPopup() const { openMinappKeepAlive, hideMinappPopup, closeMinapp, closeAllMinapps } = useMinappPopup()
const { showOpenedMinappsInSidebar } = useSettings() // 获取控制显示的设置
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation() const { t } = useTranslation()
@ -208,7 +209,10 @@ const SidebarOpenedMinappTabs: FC = () => {
container.style.setProperty('--indicator-right', `${indicatorRight}px`) container.style.setProperty('--indicator-right', `${indicatorRight}px`)
}, [currentMinappId, openedKeepAliveMinapps, minappShow]) }, [currentMinappId, openedKeepAliveMinapps, minappShow])
const isShowOpened = openedKeepAliveMinapps.length > 0 // 检查是否需要显示已打开小程序组件
const isShowOpened = showOpenedMinappsInSidebar && openedKeepAliveMinapps.length > 0
// 如果不需要显示,返回空容器保持动画效果但不显示内容
if (!isShowOpened) return <TabsContainer className="TabsContainer" /> if (!isShowOpened) return <TabsContainer className="TabsContainer" />
return ( return (

View File

@ -1,4 +1,5 @@
import { useRuntime } from '@renderer/hooks/useRuntime' import { useRuntime } from '@renderer/hooks/useRuntime'
import { useSettings } from '@renderer/hooks/useSettings' // 使用设置中的值
import { useAppDispatch } from '@renderer/store' import { useAppDispatch } from '@renderer/store'
import { import {
setCurrentMinappId, setCurrentMinappId,
@ -8,9 +9,6 @@ import {
} from '@renderer/store/runtime' } from '@renderer/store/runtime'
import { MinAppType } from '@renderer/types' import { MinAppType } from '@renderer/types'
/** The max number of keep alive minapps */
const MINAPP_MAX_KEEPALIVE = 3
/** /**
* Usage: * Usage:
* *
@ -26,27 +24,26 @@ const MINAPP_MAX_KEEPALIVE = 3
* const { openedKeepAliveMinapps, openedOneOffMinapp, minappShow } = useRuntime() * const { openedKeepAliveMinapps, openedOneOffMinapp, minappShow } = useRuntime()
*/ */
export const useMinappPopup = () => { export const useMinappPopup = () => {
const { openedKeepAliveMinapps, openedOneOffMinapp, minappShow } = useRuntime()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { openedKeepAliveMinapps, openedOneOffMinapp, minappShow } = useRuntime()
const { maxKeepAliveMinapps } = useSettings() // 使用设置中的值
/** Open a minapp (popup shows and minapp loaded) */ /** Open a minapp (popup shows and minapp loaded) */
const openMinapp = (app: MinAppType, keepAlive: boolean = false) => { const openMinapp = (app: MinAppType, keepAlive: boolean = false) => {
if (keepAlive) { if (keepAlive) {
//if the minapp is already opened, do nothing // 如果小程序已经打开,只切换显示
if (openedKeepAliveMinapps.some((item) => item.id === app.id)) { if (openedKeepAliveMinapps.some((item) => item.id === app.id)) {
dispatch(setCurrentMinappId(app.id)) dispatch(setCurrentMinappId(app.id))
dispatch(setMinappShow(true)) dispatch(setMinappShow(true))
return return
} }
//if the minapp is not opened, open it // 如果缓存数量未达上限,添加到缓存列表
//check if the keep alive minapps meet the max limit if (openedKeepAliveMinapps.length < maxKeepAliveMinapps) {
if (openedKeepAliveMinapps.length < MINAPP_MAX_KEEPALIVE) {
//always put new minapp at the first
dispatch(setOpenedKeepAliveMinapps([app, ...openedKeepAliveMinapps])) dispatch(setOpenedKeepAliveMinapps([app, ...openedKeepAliveMinapps]))
} else { } else {
//pop the last one // 缓存数量达到上限,移除最后一个,添加新的
dispatch(setOpenedKeepAliveMinapps([app, ...openedKeepAliveMinapps.slice(0, MINAPP_MAX_KEEPALIVE - 1)])) dispatch(setOpenedKeepAliveMinapps([app, ...openedKeepAliveMinapps.slice(0, maxKeepAliveMinapps - 1)]))
} }
dispatch(setOpenedOneOffMinapp(null)) dispatch(setOpenedOneOffMinapp(null))

View File

@ -919,10 +919,6 @@
"display.custom.css": "Custom CSS", "display.custom.css": "Custom CSS",
"display.custom.css.cherrycss": "Get from cherrycss.com", "display.custom.css.cherrycss": "Get from cherrycss.com",
"display.custom.css.placeholder": "/* Put custom CSS here */", "display.custom.css.placeholder": "/* Put custom CSS here */",
"display.minApp.disabled": "Hidden MinApp",
"display.minApp.empty": "Drag minApp from the left to hide them here",
"display.minApp.title": "MinApp Settings",
"display.minApp.visible": "Visible MinApp",
"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.disabled": "Hide icons", "display.sidebar.disabled": "Hide icons",
"display.sidebar.empty": "Drag the hidden feature from the left side here", "display.sidebar.empty": "Drag the hidden feature from the left side here",
@ -935,6 +931,20 @@
"display.sidebar.visible": "Show icons", "display.sidebar.visible": "Show icons",
"display.title": "Display Settings", "display.title": "Display Settings",
"display.topic.title": "Topic Settings", "display.topic.title": "Topic Settings",
"miniapps": {
"title": "Mini Apps Settings",
"disabled": "Hidden Mini Apps",
"empty": "Drag mini apps from the left to hide them",
"visible": "Visible Mini Apps",
"cache_settings": "Cache Settings",
"cache_title": "Mini App Cache Limit",
"cache_description": "Set the maximum number of active mini apps to keep in memory",
"reset_tooltip": "Reset to default",
"display_title": "Mini App Display Settings",
"sidebar_title": "Sidebar Active Mini Apps Display",
"sidebar_description": "Show active mini apps in the sidebar",
"cache_change_notice": "Changes will take effect when the number of open mini apps reaches the set value"
},
"font_size.title": "Message font size", "font_size.title": "Message font size",
"general": "General Settings", "general": "General Settings",
"general.avatar.reset": "Reset Avatar", "general.avatar.reset": "Reset Avatar",

View File

@ -919,10 +919,6 @@
"display.custom.css": "カスタムCSS", "display.custom.css": "カスタムCSS",
"display.custom.css.cherrycss": "cherrycss.comから取得", "display.custom.css.cherrycss": "cherrycss.comから取得",
"display.custom.css.placeholder": "/* ここにカスタムCSSを入力 */", "display.custom.css.placeholder": "/* ここにカスタムCSSを入力 */",
"display.minApp.disabled": "非表示ミニプログラム",
"display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします",
"display.minApp.title": "ミニプログラム表示設定",
"display.minApp.visible": "表示中ミニプログラム",
"display.sidebar.chat.hiddenMessage": "アシスタントは基本的な機能であり、非表示はサポートされていません", "display.sidebar.chat.hiddenMessage": "アシスタントは基本的な機能であり、非表示はサポートされていません",
"display.sidebar.disabled": "アイコンを非表示", "display.sidebar.disabled": "アイコンを非表示",
"display.sidebar.empty": "非表示にする機能を左側からここにドラッグ", "display.sidebar.empty": "非表示にする機能を左側からここにドラッグ",
@ -935,6 +931,20 @@
"display.sidebar.visible": "アイコンを表示", "display.sidebar.visible": "アイコンを表示",
"display.title": "表示設定", "display.title": "表示設定",
"display.topic.title": "トピック設定", "display.topic.title": "トピック設定",
"miniapps": {
"title": "ミニアプリ設定",
"disabled": "非表示のミニアプリ",
"empty": "非表示にするミニアプリを左側からここにドラッグしてください",
"visible": "表示するミニアプリ",
"cache_settings": "キャッシュ設定",
"cache_title": "ミニアプリのキャッシュ数",
"cache_description": "メモリに保持するアクティブなミニアプリの最大数を設定します",
"reset_tooltip": "デフォルト値にリセット",
"display_title": "ミニアプリ表示設定",
"sidebar_title": "サイドバーのアクティブなミニアプリ表示",
"sidebar_description": "サイドバーにアクティブなミニアプリを表示するかどうかを設定します",
"cache_change_notice": "設定値に達するまでミニアプリの開閉が行われた後に変更が適用されます"
},
"font_size.title": "メッセージのフォントサイズ", "font_size.title": "メッセージのフォントサイズ",
"general": "一般設定", "general": "一般設定",
"general.avatar.reset": "アバターをリセット", "general.avatar.reset": "アバターをリセット",

View File

@ -919,10 +919,6 @@
"display.custom.css": "Пользовательский CSS", "display.custom.css": "Пользовательский CSS",
"display.custom.css.cherrycss": "Получить из cherrycss.com", "display.custom.css.cherrycss": "Получить из cherrycss.com",
"display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */", "display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */",
"display.minApp.disabled": "скрытый апплет",
"display.minApp.empty": "Перетащите апплет, который хотите скрыть, слева сюда",
"display.minApp.title": "Настройки отображения мини программы",
"display.minApp.visible": "Отображаемый апплет",
"display.sidebar.chat.hiddenMessage": "Помощник является базовой функцией и не поддерживает скрытие", "display.sidebar.chat.hiddenMessage": "Помощник является базовой функцией и не поддерживает скрытие",
"display.sidebar.disabled": "Скрыть иконки", "display.sidebar.disabled": "Скрыть иконки",
"display.sidebar.empty": "Перетащите скрываемую функцию с левой стороны сюда", "display.sidebar.empty": "Перетащите скрываемую функцию с левой стороны сюда",
@ -935,6 +931,20 @@
"display.sidebar.visible": "Показывать иконки", "display.sidebar.visible": "Показывать иконки",
"display.title": "Настройки отображения", "display.title": "Настройки отображения",
"display.topic.title": "Настройки топиков", "display.topic.title": "Настройки топиков",
"miniapps": {
"title": "Настройки мини-приложений",
"disabled": "Скрытые мини-приложения",
"empty": "Перетащите мини-приложения слева, чтобы скрыть их",
"visible": "Отображаемые мини-приложения",
"cache_settings": "Настройки кэша",
"cache_title": "Количество кэшируемых мини-приложений",
"cache_description": "Установить максимальное количество активных мини-приложений в памяти",
"reset_tooltip": "Сбросить до значения по умолчанию",
"display_title": "Настройки отображения мини-приложений",
"sidebar_title": "Отображение активных мини-приложений в боковой панели",
"sidebar_description": "Настройка отображения активных мини-приложений в боковой панели",
"cache_change_notice": "Изменения вступят в силу, когда количество открытых мини-приложений достигнет установленного значения"
},
"font_size.title": "Размер шрифта сообщений", "font_size.title": "Размер шрифта сообщений",
"general": "Общие настройки", "general": "Общие настройки",
"general.avatar.reset": "Сброс аватара", "general.avatar.reset": "Сброс аватара",

View File

@ -919,10 +919,6 @@
"display.custom.css": "自定义 CSS", "display.custom.css": "自定义 CSS",
"display.custom.css.cherrycss": "从 cherrycss.com 获取", "display.custom.css.cherrycss": "从 cherrycss.com 获取",
"display.custom.css.placeholder": "/* 这里写自定义CSS */", "display.custom.css.placeholder": "/* 这里写自定义CSS */",
"display.minApp.disabled": "隐藏的小程序",
"display.minApp.empty": "把要隐藏的小程序从左侧拖拽到这里",
"display.minApp.title": "小程序显示设置",
"display.minApp.visible": "显示的小程序",
"display.sidebar.chat.hiddenMessage": "助手是基础功能,不支持隐藏", "display.sidebar.chat.hiddenMessage": "助手是基础功能,不支持隐藏",
"display.sidebar.disabled": "隐藏的图标", "display.sidebar.disabled": "隐藏的图标",
"display.sidebar.empty": "把要隐藏的功能从左侧拖拽到这里", "display.sidebar.empty": "把要隐藏的功能从左侧拖拽到这里",
@ -935,6 +931,20 @@
"display.sidebar.visible": "显示的图标", "display.sidebar.visible": "显示的图标",
"display.title": "显示设置", "display.title": "显示设置",
"display.topic.title": "话题设置", "display.topic.title": "话题设置",
"miniapps": {
"title": "小程序设置",
"disabled": "隐藏的小程序",
"empty": "把要隐藏的小程序从左侧拖拽到这里",
"visible": "显示的小程序",
"cache_settings": "缓存设置",
"cache_title": "小程序缓存数量",
"cache_description": "设置同时保持活跃状态的小程序最大数量",
"reset_tooltip": "重置为默认值",
"display_title": "小程序显示设置",
"sidebar_title": "侧边栏活跃小程序显示设置",
"sidebar_description": "设置侧边栏是否显示活跃的小程序",
"cache_change_notice": "更改将在打开的小程序增减至设定值后生效"
},
"font_size.title": "消息字体大小", "font_size.title": "消息字体大小",
"general": "常规设置", "general": "常规设置",
"general.avatar.reset": "重置头像", "general.avatar.reset": "重置头像",

View File

@ -919,10 +919,6 @@
"display.custom.css": "自訂 CSS", "display.custom.css": "自訂 CSS",
"display.custom.css.cherrycss": "從 cherrycss.com 取得", "display.custom.css.cherrycss": "從 cherrycss.com 取得",
"display.custom.css.placeholder": "/* 這裡寫自訂 CSS */", "display.custom.css.placeholder": "/* 這裡寫自訂 CSS */",
"display.minApp.disabled": "隱藏的小工具",
"display.minApp.empty": "把要隱藏的小工具從左側拖拽到這裡",
"display.minApp.title": "小工具顯示設定",
"display.minApp.visible": "顯示的小工具",
"display.sidebar.chat.hiddenMessage": "助手是基礎功能,不支援隱藏", "display.sidebar.chat.hiddenMessage": "助手是基礎功能,不支援隱藏",
"display.sidebar.disabled": "隱藏的圖示", "display.sidebar.disabled": "隱藏的圖示",
"display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡", "display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡",
@ -935,6 +931,20 @@
"display.sidebar.visible": "顯示的圖示", "display.sidebar.visible": "顯示的圖示",
"display.title": "顯示設定", "display.title": "顯示設定",
"display.topic.title": "話題設定", "display.topic.title": "話題設定",
"miniapps": {
"title": "小程式設置",
"disabled": "隱藏的小程式",
"empty": "把要隱藏的小程式從左側拖拽到這裡",
"visible": "顯示的小程式",
"cache_settings": "緩存設置",
"cache_title": "小程式緩存數量",
"cache_description": "設置同時保持活躍狀態的小程式最大數量",
"reset_tooltip": "重置為預設值",
"display_title": "小程式顯示設置",
"sidebar_title": "側邊欄活躍小程式顯示設置",
"sidebar_description": "設置側邊欄是否顯示活躍的小程式",
"cache_change_notice": "更改將在打開的小程式增減至設定值後生效"
},
"font_size.title": "訊息字型大小", "font_size.title": "訊息字型大小",
"general": "一般設定", "general": "一般設定",
"general.avatar.reset": "重設頭像", "general.avatar.reset": "重設頭像",

View File

@ -1,8 +1,6 @@
import { SyncOutlined } from '@ant-design/icons' import { SyncOutlined } from '@ant-design/icons'
import { isMac } from '@renderer/config/constant' import { isMac } from '@renderer/config/constant'
import { DEFAULT_MIN_APPS } 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 {
@ -19,7 +17,6 @@ import { useTranslation } from 'react-i18next'
import styled from 'styled-components' import styled from 'styled-components'
import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..' import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingRowTitle, SettingTitle } from '..'
import MiniAppIconsManager from './MiniAppIconsManager'
import SidebarIconsManager from './SidebarIconsManager' import SidebarIconsManager from './SidebarIconsManager'
const DisplaySettings: FC = () => { const DisplaySettings: FC = () => {
@ -37,17 +34,13 @@ const DisplaySettings: FC = () => {
showAssistantIcon, showAssistantIcon,
setShowAssistantIcon setShowAssistantIcon
} = 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(minapps)
const [disabledMiniApps, setDisabledMiniApps] = useState(disabled || [])
// 使用useCallback优化回调函数
const handleWindowStyleChange = useCallback( const handleWindowStyleChange = useCallback(
(checked: boolean) => { (checked: boolean) => {
setWindowStyle(checked ? 'transparent' : 'opaque') setWindowStyle(checked ? 'transparent' : 'opaque')
@ -61,13 +54,6 @@ const DisplaySettings: FC = () => {
dispatch(setSidebarIcons({ visible: DEFAULT_SIDEBAR_ICONS, disabled: [] })) dispatch(setSidebarIcons({ visible: DEFAULT_SIDEBAR_ICONS, disabled: [] }))
}, [dispatch]) }, [dispatch])
const handleResetMinApps = useCallback(() => {
setVisibleMiniApps(DEFAULT_MIN_APPS)
setDisabledMiniApps([])
updateMinapps(DEFAULT_MIN_APPS)
updateDisabledMinapps([])
}, [updateDisabledMinapps, updateMinapps])
const themeOptions = useMemo( const themeOptions = useMemo(
() => [ () => [
{ {
@ -177,22 +163,6 @@ const DisplaySettings: FC = () => {
setDisabledIcons={setDisabledIcons} setDisabledIcons={setDisabledIcons}
/> />
</SettingGroup> </SettingGroup>
<SettingGroup theme={theme}>
<SettingTitle
style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
<span>{t('settings.display.minApp.title')}</span>
<ResetButtonWrapper>
<Button onClick={handleResetMinApps}>{t('common.reset')}</Button>
</ResetButtonWrapper>
</SettingTitle>
<SettingDivider />
<MiniAppIconsManager
visibleMiniApps={visibleMiniApps}
disabledMiniApps={disabledMiniApps}
setVisibleMiniApps={setVisibleMiniApps}
setDisabledMiniApps={setDisabledMiniApps}
/>
</SettingGroup>
<SettingGroup theme={theme}> <SettingGroup theme={theme}>
<SettingTitle> <SettingTitle>
{t('settings.display.custom.css')} {t('settings.display.custom.css')}

View File

@ -115,7 +115,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
<ProgramSection> <ProgramSection>
{(['visible', 'disabled'] as const).map((listType) => ( {(['visible', 'disabled'] as const).map((listType) => (
<ProgramColumn key={listType}> <ProgramColumn key={listType}>
<h4>{t(`settings.display.minApp.${listType}`)}</h4> <h4>{t(`settings.miniapps.${listType}`)}</h4>
<Droppable droppableId={listType}> <Droppable droppableId={listType}>
{(provided: DroppableProvided) => ( {(provided: DroppableProvided) => (
<ProgramList ref={provided.innerRef} {...provided.droppableProps}> <ProgramList ref={provided.innerRef} {...provided.droppableProps}>
@ -125,7 +125,7 @@ const MiniAppIconsManager: FC<MiniAppManagerProps> = ({
</Draggable> </Draggable>
))} ))}
{disabledMiniApps.length === 0 && listType === 'disabled' && ( {disabledMiniApps.length === 0 && listType === 'disabled' && (
<EmptyPlaceholder>{t('settings.display.minApp.empty')}</EmptyPlaceholder> <EmptyPlaceholder>{t('settings.miniapps.empty')}</EmptyPlaceholder>
)} )}
{provided.placeholder} {provided.placeholder}
</ProgramList> </ProgramList>

View File

@ -0,0 +1,226 @@
import { UndoOutlined } from '@ant-design/icons' // 导入重置图标
import { DEFAULT_MIN_APPS } from '@renderer/config/minapps'
import { useTheme } from '@renderer/context/ThemeProvider'
import { useMinapps } from '@renderer/hooks/useMinapps'
import { useSettings } from '@renderer/hooks/useSettings'
import { useAppDispatch } from '@renderer/store'
import { setMaxKeepAliveMinapps, setShowOpenedMinappsInSidebar } from '@renderer/store/settings'
import { Button, message, Slider, Switch, Tooltip } from 'antd'
import { FC, useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { SettingContainer, SettingDescription, SettingDivider, SettingGroup, SettingRowTitle, SettingTitle } from '..'
import MiniAppIconsManager from './MiniAppIconsManager'
// 默认小程序缓存数量
const DEFAULT_MAX_KEEPALIVE = 3
const MiniAppSettings: FC = () => {
const { t } = useTranslation()
const { theme } = useTheme()
const dispatch = useAppDispatch()
const { maxKeepAliveMinapps, showOpenedMinappsInSidebar } = useSettings()
const { minapps, disabled, updateMinapps, updateDisabledMinapps } = useMinapps()
const [visibleMiniApps, setVisibleMiniApps] = useState(minapps)
const [disabledMiniApps, setDisabledMiniApps] = useState(disabled || [])
const [messageApi, contextHolder] = message.useMessage()
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null)
const handleResetMinApps = useCallback(() => {
setVisibleMiniApps(DEFAULT_MIN_APPS)
setDisabledMiniApps([])
updateMinapps(DEFAULT_MIN_APPS)
updateDisabledMinapps([])
}, [updateDisabledMinapps, updateMinapps])
// 恢复默认缓存数量
const handleResetCacheLimit = useCallback(() => {
dispatch(setMaxKeepAliveMinapps(DEFAULT_MAX_KEEPALIVE))
messageApi.info(t('settings.miniapps.cache_change_notice'))
}, [dispatch, messageApi, t])
// 处理缓存数量变更
const handleCacheChange = useCallback(
(value: number) => {
dispatch(setMaxKeepAliveMinapps(value))
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current)
}
debounceTimerRef.current = setTimeout(() => {
messageApi.info(t('settings.miniapps.cache_change_notice'))
debounceTimerRef.current = null
}, 500)
},
[dispatch, messageApi, t]
)
// 组件卸载时清除定时器
useEffect(() => {
return () => {
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current)
}
}
}, [])
return (
<SettingContainer theme={theme}>
{contextHolder} {/* 添加消息上下文 */}
<SettingGroup theme={theme}>
<SettingTitle>{t('settings.miniapps.title')}</SettingTitle>
<SettingDivider />
<SettingTitle
style={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
<span>{t('settings.miniapps.display_title')}</span>
<ResetButtonWrapper>
<Button onClick={handleResetMinApps}>{t('common.reset')}</Button>
</ResetButtonWrapper>
</SettingTitle>
<BorderedContainer>
<MiniAppIconsManager
visibleMiniApps={visibleMiniApps}
disabledMiniApps={disabledMiniApps}
setVisibleMiniApps={setVisibleMiniApps}
setDisabledMiniApps={setDisabledMiniApps}
/>
</BorderedContainer>
<SettingDivider />
{/* 缓存小程序数量设置 */}
<CacheSettingRow>
<SettingLabelGroup>
<SettingRowTitle>{t('settings.miniapps.cache_title')}</SettingRowTitle>
<SettingDescription>{t('settings.miniapps.cache_description')}</SettingDescription>
</SettingLabelGroup>
<CacheSettingControls>
<SliderWithResetContainer>
<Tooltip title={t('settings.miniapps.reset_tooltip')} placement="top">
<ResetButton onClick={handleResetCacheLimit}>
<UndoOutlined />
</ResetButton>
</Tooltip>
<Slider
min={1}
max={5}
value={maxKeepAliveMinapps}
onChange={handleCacheChange}
marks={{
1: '1',
3: '3',
5: '5'
}}
tooltip={{ formatter: (value) => `${value}` }}
/>
</SliderWithResetContainer>
</CacheSettingControls>
</CacheSettingRow>
<SettingDivider />
<SidebarSettingRow>
<SettingLabelGroup>
<SettingRowTitle>{t('settings.miniapps.sidebar_title')}</SettingRowTitle>
<SettingDescription>{t('settings.miniapps.sidebar_description')}</SettingDescription>
</SettingLabelGroup>
<Switch
checked={showOpenedMinappsInSidebar}
onChange={(checked) => dispatch(setShowOpenedMinappsInSidebar(checked))}
/>
</SidebarSettingRow>
</SettingGroup>
</SettingContainer>
)
}
// 修改和新增样式
const CacheSettingRow = styled.div`
display: flex;
align-items: flex-start;
justify-content: space-between;
margin: 0;
gap: 20px;
`
const SettingLabelGroup = styled.div`
flex: 1;
`
// 新增控件容器,包含滑块和恢复默认按钮
const CacheSettingControls = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
width: 240px;
`
const SliderWithResetContainer = styled.div`
display: flex;
align-items: center;
gap: 10px;
width: 100%;
.ant-slider {
flex: 1;
}
.ant-slider-track {
background-color: var(--color-primary);
}
.ant-slider-handle {
border-color: var(--color-primary);
}
`
// 重置按钮样式
const ResetButton = styled.button`
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
min-width: 28px; /* 确保不会被压缩 */
border-radius: 4px;
border: 1px solid var(--color-border);
background-color: var(--color-bg-1);
cursor: pointer;
transition: all 0.2s;
padding: 0;
color: var(--color-text);
&:hover {
border-color: var(--color-primary);
color: var(--color-primary);
}
&:active {
background-color: var(--color-bg-2);
}
`
const ResetButtonWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
`
// 新增侧边栏设置行样式
const SidebarSettingRow = styled.div`
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
`
// 新增: 带边框的容器组件
const BorderedContainer = styled.div`
border: 1px solid var(--color-border);
border-radius: 8px;
padding: 8px;
margin: 8px 0 8px;
background-color: var(--color-bg-1);
`
export default MiniAppSettings

View File

@ -1,4 +1,5 @@
import { import {
AppstoreOutlined,
CloudOutlined, CloudOutlined,
CodeOutlined, CodeOutlined,
GlobalOutlined, GlobalOutlined,
@ -11,7 +12,9 @@ import {
} from '@ant-design/icons' } from '@ant-design/icons'
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
import { isLocalAi } from '@renderer/config/env' import { isLocalAi } from '@renderer/config/env'
import { useSidebarIconShow } from '@renderer/hooks/useSidebarIcon'
import ModelSettings from '@renderer/pages/settings/ModelSettings/ModelSettings' import ModelSettings from '@renderer/pages/settings/ModelSettings/ModelSettings'
// 导入useAppSelector
import { FC } from 'react' import { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Link, Route, Routes, useLocation } from 'react-router-dom' import { Link, Route, Routes, useLocation } from 'react-router-dom'
@ -23,6 +26,7 @@ import DisplaySettings from './DisplaySettings/DisplaySettings'
import GeneralSettings from './GeneralSettings' import GeneralSettings from './GeneralSettings'
import MCPSettings from './MCPSettings' import MCPSettings from './MCPSettings'
import { McpSettingsNavbar } from './MCPSettings/McpSettingsNavbar' import { McpSettingsNavbar } from './MCPSettings/McpSettingsNavbar'
import MiniAppSettings from './MiniappSettings/MiniAppSettings'
import ProvidersList from './ProviderSettings' import ProvidersList from './ProviderSettings'
import QuickAssistantSettings from './QuickAssistantSettings' import QuickAssistantSettings from './QuickAssistantSettings'
import ShortcutSettings from './ShortcutSettings' import ShortcutSettings from './ShortcutSettings'
@ -32,6 +36,8 @@ const SettingsPage: FC = () => {
const { pathname } = useLocation() const { pathname } = useLocation()
const { t } = useTranslation() const { t } = useTranslation()
const showMiniAppSettings = useSidebarIconShow('minapp')
const isRoute = (path: string): string => (pathname.startsWith(path) ? 'active' : '') const isRoute = (path: string): string => (pathname.startsWith(path) ? 'active' : '')
return ( return (
@ -82,6 +88,14 @@ const SettingsPage: FC = () => {
{t('settings.display.title')} {t('settings.display.title')}
</MenuItem> </MenuItem>
</MenuItemLink> </MenuItemLink>
{showMiniAppSettings && (
<MenuItemLink to="/settings/miniapps">
<MenuItem className={isRoute('/settings/miniapps')}>
<AppstoreOutlined />
{t('settings.miniapps.title')}
</MenuItem>
</MenuItemLink>
)}
<MenuItemLink to="/settings/shortcut"> <MenuItemLink to="/settings/shortcut">
<MenuItem className={isRoute('/settings/shortcut')}> <MenuItem className={isRoute('/settings/shortcut')}>
<MacCommandOutlined /> <MacCommandOutlined />
@ -115,9 +129,10 @@ const SettingsPage: FC = () => {
<Route path="mcp" element={<MCPSettings />} /> <Route path="mcp" element={<MCPSettings />} />
<Route path="general/*" element={<GeneralSettings />} /> <Route path="general/*" element={<GeneralSettings />} />
<Route path="display" element={<DisplaySettings />} /> <Route path="display" element={<DisplaySettings />} />
<Route path="data/*" element={<DataSettings />} /> {showMiniAppSettings && <Route path="miniapps" element={<MiniAppSettings />} />}
<Route path="quickAssistant" element={<QuickAssistantSettings />} />
<Route path="shortcut" element={<ShortcutSettings />} /> <Route path="shortcut" element={<ShortcutSettings />} />
<Route path="quickAssistant" element={<QuickAssistantSettings />} />
<Route path="data/*" element={<DataSettings />} />
<Route path="about" element={<AboutSettings />} /> <Route path="about" element={<AboutSettings />} />
</Routes> </Routes>
</SettingContent> </SettingContent>

View File

@ -99,6 +99,8 @@ export interface SettingsState {
siyuanToken: string | null siyuanToken: string | null
siyuanBoxId: string | null siyuanBoxId: string | null
siyuanRootPath: string | null siyuanRootPath: string | null
maxKeepAliveMinapps: number
showOpenedMinappsInSidebar: boolean
} }
export type MultiModelMessageStyle = 'horizontal' | 'vertical' | 'fold' | 'grid' export type MultiModelMessageStyle = 'horizontal' | 'vertical' | 'fold' | 'grid'
@ -178,7 +180,9 @@ const initialState: SettingsState = {
siyuanApiUrl: null, siyuanApiUrl: null,
siyuanToken: null, siyuanToken: null,
siyuanBoxId: null, siyuanBoxId: null,
siyuanRootPath: null siyuanRootPath: null,
maxKeepAliveMinapps: 3,
showOpenedMinappsInSidebar: true
} }
const settingsSlice = createSlice({ const settingsSlice = createSlice({
@ -409,6 +413,12 @@ const settingsSlice = createSlice({
}, },
setDefaultObsidianVault: (state, action: PayloadAction<string>) => { setDefaultObsidianVault: (state, action: PayloadAction<string>) => {
state.defaultObsidianVault = action.payload state.defaultObsidianVault = action.payload
},
setMaxKeepAliveMinapps: (state, action: PayloadAction<number>) => {
state.maxKeepAliveMinapps = action.payload
},
setShowOpenedMinappsInSidebar: (state, action: PayloadAction<boolean>) => {
state.showOpenedMinappsInSidebar = action.payload
} }
} }
}) })
@ -486,7 +496,9 @@ export const {
setSiyuanApiUrl, setSiyuanApiUrl,
setSiyuanToken, setSiyuanToken,
setSiyuanBoxId, setSiyuanBoxId,
setSiyuanRootPath setSiyuanRootPath,
setMaxKeepAliveMinapps,
setShowOpenedMinappsInSidebar
} = settingsSlice.actions } = settingsSlice.actions
export default settingsSlice.reducer export default settingsSlice.reducer