diff --git a/.github/workflows/delete-branch.yml b/.github/workflows/delete-branch.yml new file mode 100644 index 0000000000..fae32c7477 --- /dev/null +++ b/.github/workflows/delete-branch.yml @@ -0,0 +1,22 @@ +name: Delete merged branch +on: + pull_request: + types: + - closed + +jobs: + delete-branch: + runs-on: ubuntu-latest + permissions: + contents: write + if: github.event.pull_request.merged == true && github.event.pull_request.head.repo.full_name == github.repository + steps: + - name: Delete merged branch + uses: actions/github-script@v7 + with: + script: | + github.rest.git.deleteRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `heads/${context.payload.pull_request.head.ref}`, + }) diff --git a/electron-builder.yml b/electron-builder.yml index d53473bd22..1803a37865 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -128,16 +128,13 @@ afterSign: scripts/notarize.js artifactBuildCompleted: scripts/artifact-build-completed.js releaseInfo: releaseNotes: | - ✨ 新功能: - - 新增 CherryIN 服务商 - - 新增 AiOnly AI 服务商 - - 更新 MCP 服务器卡片布局和样式,改为列表视图 + 🎨 界面优化: + - 优化了多个组件的布局和间距,提升视觉体验 + - 改进了导航栏和标签栏的样式显示 + - MCP 服务器卡片宽度调整为 100%,提高响应式布局效果 + - 优化了笔记侧边栏的滚动行为 🐛 问题修复: - - 修复 QwenMT 模型的翻译内容处理逻辑 - - 修复无法将外部笔记添加到知识库的问题 - - 🚀 性能优化: - - 提升输入框响应速度 - - 优化模型切换性能 - - 改进翻译功能的引用和邮件格式处理 + - 修复了小应用打开功能无法正常工作的问题 + - 修复了助手更新时 ID 丢失导致更新失败的问题 + - 确保助手更新时 ID 字段为必填项,防止数据错误 diff --git a/packages/ui/src/components/interactive/Sortable/ItemRenderer.tsx b/packages/ui/src/components/interactive/Sortable/ItemRenderer.tsx index dfec065eaa..e9e048fd6a 100644 --- a/packages/ui/src/components/interactive/Sortable/ItemRenderer.tsx +++ b/packages/ui/src/components/interactive/Sortable/ItemRenderer.tsx @@ -18,6 +18,7 @@ interface ItemRendererProps { transform?: Transform | null transition?: string | null listeners?: DraggableSyntheticListeners + itemStyle?: React.CSSProperties } export function ItemRenderer({ @@ -31,6 +32,7 @@ export function ItemRenderer({ transform, transition, listeners, + itemStyle, ...props }: ItemRendererProps) { useEffect(() => { @@ -45,13 +47,17 @@ export function ItemRenderer({ } }, [dragOverlay]) - const wrapperStyle = { + const style = { transition, transform: CSS.Transform.toString(transform ?? null) } as React.CSSProperties return ( - + { className?: string /** Item list style */ listStyle?: React.CSSProperties + /** Item style */ + itemStyle?: React.CSSProperties /** Item gap */ gap?: number | string /** Restrictions, shortcuts for some modifiers */ @@ -91,6 +93,7 @@ function Sortable({ showGhost = false, className, listStyle, + itemStyle, gap, restrictions, modifiers: customModifiers @@ -199,19 +202,19 @@ function Sortable({ renderItem={renderItem} useDragOverlay={useDragOverlay} showGhost={showGhost} + itemStyle={itemStyle} /> ))} - {useDragOverlay - ? createPortal( - - {activeItem ? : null} - , - document.body - ) - : null} + {useDragOverlay && + createPortal( + + {activeItem && } + , + document.body + )} ) } diff --git a/packages/ui/src/components/interactive/Sortable/SortableItem.tsx b/packages/ui/src/components/interactive/Sortable/SortableItem.tsx index 97b0e3a3d0..2b8d2ee905 100644 --- a/packages/ui/src/components/interactive/Sortable/SortableItem.tsx +++ b/packages/ui/src/components/interactive/Sortable/SortableItem.tsx @@ -10,6 +10,7 @@ interface SortableItemProps { renderItem: RenderItemType useDragOverlay?: boolean showGhost?: boolean + itemStyle?: React.CSSProperties } export function SortableItem({ @@ -18,7 +19,8 @@ export function SortableItem({ index, renderItem, useDragOverlay = true, - showGhost = true + showGhost = true, + itemStyle }: SortableItemProps) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id @@ -36,6 +38,7 @@ export function SortableItem({ transform={transform} transition={transition} listeners={listeners} + itemStyle={itemStyle} {...attributes} /> ) diff --git a/src/renderer/src/aiCore/legacy/clients/ApiClientFactory.ts b/src/renderer/src/aiCore/legacy/clients/ApiClientFactory.ts index beefcf6c3b..b01bc1eaba 100644 --- a/src/renderer/src/aiCore/legacy/clients/ApiClientFactory.ts +++ b/src/renderer/src/aiCore/legacy/clients/ApiClientFactory.ts @@ -1,4 +1,5 @@ import { loggerService } from '@logger' +import { isNewApiProvider } from '@renderer/config/providers' import type { Provider } from '@renderer/types' import { AihubmixAPIClient } from './aihubmix/AihubmixAPIClient' @@ -45,7 +46,7 @@ export class ApiClientFactory { return instance } - if (provider.id === 'new-api') { + if (isNewApiProvider(provider)) { logger.debug(`Creating NewAPIClient for provider: ${provider.id}`) instance = new NewAPIClient(provider) as BaseApiClient return instance diff --git a/src/renderer/src/aiCore/legacy/clients/__tests__/ApiClientFactory.test.ts b/src/renderer/src/aiCore/legacy/clients/__tests__/ApiClientFactory.test.ts index 8bbddd09f5..c3edeb2adb 100644 --- a/src/renderer/src/aiCore/legacy/clients/__tests__/ApiClientFactory.test.ts +++ b/src/renderer/src/aiCore/legacy/clients/__tests__/ApiClientFactory.test.ts @@ -67,7 +67,9 @@ vi.mock('@renderer/config/models', () => ({ silicon: [], defaultModel: [] }, - isOpenAIModel: vi.fn(() => false) + isOpenAIModel: vi.fn(() => false), + glm45FlashModel: {}, + qwen38bModel: {} })) describe('ApiClientFactory', () => { diff --git a/src/renderer/src/aiCore/legacy/clients/__tests__/index.clientCompatibilityTypes.test.ts b/src/renderer/src/aiCore/legacy/clients/__tests__/index.clientCompatibilityTypes.test.ts index 80ae983443..3157e4b63a 100644 --- a/src/renderer/src/aiCore/legacy/clients/__tests__/index.clientCompatibilityTypes.test.ts +++ b/src/renderer/src/aiCore/legacy/clients/__tests__/index.clientCompatibilityTypes.test.ts @@ -35,18 +35,8 @@ vi.mock('@renderer/config/models', () => ({ findTokenLimit: vi.fn().mockReturnValue(4096), isFunctionCallingModel: vi.fn().mockReturnValue(false), DEFAULT_MAX_TOKENS: 4096, - qwen38bModel: { - id: 'Qwen/Qwen3-8B', - name: 'Qwen3-8B', - provider: 'cherryai', - group: 'Qwen' - }, - glm45FlashModel: { - id: 'glm-4.5-flash', - name: 'GLM-4.5-Flash', - provider: 'cherryai', - group: 'GLM-4.5' - } + qwen38bModel: {}, + glm45FlashModel: {} })) vi.mock('@renderer/services/AssistantService', () => ({ diff --git a/src/renderer/src/aiCore/provider/providerConfig.ts b/src/renderer/src/aiCore/provider/providerConfig.ts index eaaef15211..b91dad9cf7 100644 --- a/src/renderer/src/aiCore/provider/providerConfig.ts +++ b/src/renderer/src/aiCore/provider/providerConfig.ts @@ -6,6 +6,7 @@ import { type ProviderSettingsMap } from '@cherrystudio/ai-core/provider' import { isOpenAIChatCompletionOnlyModel } from '@renderer/config/models' +import { isNewApiProvider } from '@renderer/config/providers' import { getAwsBedrockAccessKeyId, getAwsBedrockRegion, @@ -65,7 +66,7 @@ function handleSpecialProviders(model: Model, provider: Provider): Provider { if (provider.id === 'aihubmix') { return aihubmixProviderCreator(model, provider) } - if (provider.id === 'new-api') { + if (isNewApiProvider(provider)) { return newApiResolverCreator(model, provider) } if (provider.id === 'vertexai') { diff --git a/src/renderer/src/aiCore/utils/reasoning.ts b/src/renderer/src/aiCore/utils/reasoning.ts index d708ab26d9..c78deaa19f 100644 --- a/src/renderer/src/aiCore/utils/reasoning.ts +++ b/src/renderer/src/aiCore/utils/reasoning.ts @@ -113,6 +113,8 @@ export function getReasoningEffort(assistant: Assistant, model: Model): Reasonin return { enable_thinking: true } + case SystemProviderIds.hunyuan: + case SystemProviderIds['tencent-cloud-ti']: case SystemProviderIds.doubao: return { thinking: { diff --git a/src/renderer/src/components/Icons/MinAppIcon.tsx b/src/renderer/src/components/Icons/MinAppIcon.tsx index 4431ea738d..58da46a723 100644 --- a/src/renderer/src/components/Icons/MinAppIcon.tsx +++ b/src/renderer/src/components/Icons/MinAppIcon.tsx @@ -1,7 +1,6 @@ import { DEFAULT_MIN_APPS } from '@renderer/config/minapps' import type { MinAppType } from '@renderer/types' import type { FC } from 'react' -import styled from 'styled-components' interface Props { app: MinAppType @@ -11,31 +10,52 @@ interface Props { } const MinAppIcon: FC = ({ app, size = 48, style, sidebar = false }) => { + // First try to find in DEFAULT_MIN_APPS for predefined styling const _app = DEFAULT_MIN_APPS.find((item) => item.id === app.id) - if (!_app) { - return null + // If found in DEFAULT_MIN_APPS, use predefined styling + if (_app) { + return ( + {app.name + ) } - return ( - - ) + // If not found in DEFAULT_MIN_APPS but app has logo, use it (for temporary apps) + if (app.logo) { + return ( + {app.name + ) + } + + return null } -const Container = styled.img` - border-radius: 16px; - user-select: none; - -webkit-user-drag: none; -` - export default MinAppIcon diff --git a/src/renderer/src/components/Icons/__tests__/__snapshots__/MinAppIcon.test.tsx.snap b/src/renderer/src/components/Icons/__tests__/__snapshots__/MinAppIcon.test.tsx.snap index e41515fed6..3395e366f4 100644 --- a/src/renderer/src/components/Icons/__tests__/__snapshots__/MinAppIcon.test.tsx.snap +++ b/src/renderer/src/components/Icons/__tests__/__snapshots__/MinAppIcon.test.tsx.snap @@ -1,15 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`MinAppIcon > should render correctly with various props 1`] = ` -.c0 { - border-radius: 16px; - user-select: none; - -webkit-user-drag: none; -} - Test App `; diff --git a/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx b/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx index 9b2b48460e..c9c6abd532 100644 --- a/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx +++ b/src/renderer/src/components/Popups/SelectModelPopup/popup.tsx @@ -181,7 +181,7 @@ const PopupContainer: React.FC = ({ model, filter: baseFilter, showTagFil key: `provider-${p.id}`, type: 'group', name: getFancyProviderName(p), - actions: ( + actions: p.id !== 'cherryai' && ( { +const logger = loggerService.withContext('TabContainer') + +const getTabIcon = ( + tabId: string, + minapps: MinAppType[], + minAppsCache?: LRUCache +): React.ReactNode | undefined => { // Check if it's a minapp tab (format: apps:appId) if (tabId.startsWith('apps:')) { const appId = tabId.replace('apps:', '') - const app = [...DEFAULT_MIN_APPS, ...minapps].find((app) => app.id === appId) + let app = [...DEFAULT_MIN_APPS, ...minapps].find((app) => app.id === appId) + + // If not found in permanent apps, search in temporary apps cache + // The cache stores apps opened via openSmartMinapp() for top navbar mode + // These are temporary MinApps that were opened but not yet saved to user's config + // The cache is LRU (Least Recently Used) with max size from settings + // Cache validity: Apps in cache are currently active/recently used, not outdated + if (!app && minAppsCache) { + app = minAppsCache.get(appId) + + // Defensive programming: If app not found in cache but tab exists, + // the cache entry may have been evicted due to LRU policy + // Log warning for debugging potential sync issues + if (!app) { + logger.warn(`MinApp ${appId} not found in cache, using fallback icon`) + } + } + if (app) { return } + + // Fallback: If no app found (cache evicted), show default icon + return } switch (tabId) { @@ -94,7 +123,7 @@ const TabsContainer: React.FC = ({ children }) => { const activeTabId = useAppSelector((state) => state.tabs.activeTabId) const isFullscreen = useFullscreen() const { settedTheme, toggleTheme } = useTheme() - const { hideMinappPopup } = useMinappPopup() + const { hideMinappPopup, minAppsCache } = useMinappPopup() const { minapps } = useMinapps() const { t } = useTranslation() @@ -112,8 +141,23 @@ const TabsContainer: React.FC = ({ children }) => { // Check if it's a minapp tab if (tabId.startsWith('apps:')) { const appId = tabId.replace('apps:', '') - const app = [...DEFAULT_MIN_APPS, ...minapps].find((app) => app.id === appId) - return app ? app.name : 'MinApp' + let app = [...DEFAULT_MIN_APPS, ...minapps].find((app) => app.id === appId) + + // If not found in permanent apps, search in temporary apps cache + // This ensures temporary MinApps display proper titles while being used + // The LRU cache automatically manages app lifecycle and prevents memory leaks + if (!app && minAppsCache) { + app = minAppsCache.get(appId) + + // Defensive programming: If app not found in cache but tab exists, + // the cache entry may have been evicted due to LRU policy + if (!app) { + logger.warn(`MinApp ${appId} not found in cache, using fallback title`) + } + } + + // Return app name if found, otherwise use fallback with appId + return app ? app.name : `MinApp-${appId}` } return getTitleLabel(tabId) } @@ -196,7 +240,7 @@ const TabsContainer: React.FC = ({ children }) => { renderItem={(tab) => ( handleTabClick(tab)}> - {tab.id && {getTabIcon(tab.id, minapps)}} + {tab.id && {getTabIcon(tab.id, minapps, minAppsCache)}} {getTabTitle(tab.id)} {tab.id !== 'home' && ( @@ -259,7 +303,7 @@ const TabsBar = styled.div<{ $isFullscreen: boolean }>` flex-direction: row; align-items: center; gap: 5px; - padding-left: ${({ $isFullscreen }) => (!$isFullscreen && isMac ? 'env(titlebar-area-x)' : '15px')}; + padding-left: ${({ $isFullscreen }) => (!$isFullscreen && isMac ? 'calc(env(titlebar-area-x) + 4px)' : '15px')}; padding-right: ${({ $isFullscreen }) => ($isFullscreen ? '12px' : '0')}; height: var(--navbar-height); min-height: ${({ $isFullscreen }) => (!$isFullscreen && isMac ? 'env(titlebar-area-height)' : '')}; diff --git a/src/renderer/src/components/app/Navbar.tsx b/src/renderer/src/components/app/Navbar.tsx index 330e2dab9b..0a1d2db69d 100644 --- a/src/renderer/src/components/app/Navbar.tsx +++ b/src/renderer/src/components/app/Navbar.tsx @@ -88,6 +88,7 @@ const NavbarCenterContainer = styled.div` display: flex; align-items: center; padding: 0 ${isMac ? '20px' : 0}; + padding-left: 10px; font-weight: bold; color: var(--color-text-1); position: relative; @@ -108,7 +109,8 @@ const NavbarMainContainer = styled.div<{ $isFullscreen: boolean }>` flex-direction: row; align-items: center; justify-content: space-between; - padding: 0 ${isMac ? '20px' : 0}; + padding-right: ${isMac ? '20px' : 0}; + padding-left: 10px; font-weight: bold; color: var(--color-text-1); padding-right: ${({ $isFullscreen }) => ($isFullscreen ? '12px' : isWin ? '140px' : isLinux ? '120px' : '12px')}; diff --git a/src/renderer/src/config/models/reasoning.ts b/src/renderer/src/config/models/reasoning.ts index 51e633fac5..5d9f39a6da 100644 --- a/src/renderer/src/config/models/reasoning.ts +++ b/src/renderer/src/config/models/reasoning.ts @@ -93,7 +93,17 @@ export function isSupportedThinkingTokenModel(model?: Model): boolean { // Specifically for DeepSeek V3.1. White list for now if (isDeepSeekHybridInferenceModel(model)) { return ( - ['openrouter', 'dashscope', 'modelscope', 'doubao', 'silicon', 'nvidia', 'ppio'] satisfies SystemProviderId[] + [ + 'openrouter', + 'dashscope', + 'modelscope', + 'doubao', + 'silicon', + 'nvidia', + 'ppio', + 'hunyuan', + 'tencent-cloud-ti' + ] satisfies SystemProviderId[] ).some((id) => id === model.provider) } diff --git a/src/renderer/src/config/providers.ts b/src/renderer/src/config/providers.ts index 18325aabda..a525dbd423 100644 --- a/src/renderer/src/config/providers.ts +++ b/src/renderer/src/config/providers.ts @@ -131,16 +131,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = isSystem: true, enabled: false }, - ppio: { - id: 'ppio', - name: 'PPIO', - type: 'openai', - apiKey: '', - apiHost: 'https://api.ppinfra.com/v3/openai/', - models: SYSTEM_MODELS.ppio, - isSystem: true, - enabled: false - }, alayanew: { id: 'alayanew', name: 'AlayaNew', @@ -151,16 +141,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = isSystem: true, enabled: false }, - qiniu: { - id: 'qiniu', - name: 'Qiniu', - type: 'openai', - apiKey: '', - apiHost: 'https://api.qnaigc.com', - models: SYSTEM_MODELS.qiniu, - isSystem: true, - enabled: false - }, dmxapi: { id: 'dmxapi', name: 'DMXAPI', @@ -171,6 +151,16 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = isSystem: true, enabled: false }, + aionly: { + id: 'aionly', + name: 'AIOnly', + type: 'openai', + apiKey: '', + apiHost: 'https://api.aiionly.com', + models: SYSTEM_MODELS.aionly, + isSystem: true, + enabled: false + }, burncloud: { id: 'burncloud', name: 'BurnCloud', @@ -231,6 +221,26 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = isSystem: true, enabled: false }, + ppio: { + id: 'ppio', + name: 'PPIO', + type: 'openai', + apiKey: '', + apiHost: 'https://api.ppinfra.com/v3/openai/', + models: SYSTEM_MODELS.ppio, + isSystem: true, + enabled: false + }, + qiniu: { + id: 'qiniu', + name: 'Qiniu', + type: 'openai', + apiKey: '', + apiHost: 'https://api.qnaigc.com', + models: SYSTEM_MODELS.qiniu, + isSystem: true, + enabled: false + }, openrouter: { id: 'openrouter', name: 'OpenRouter', @@ -605,16 +615,6 @@ export const SYSTEM_PROVIDERS_CONFIG: Record = models: SYSTEM_MODELS['poe'], isSystem: true, enabled: false - }, - aionly: { - id: 'aionly', - name: 'AIOnly', - type: 'openai', - apiKey: '', - apiHost: 'https://api.aiionly.com', - models: SYSTEM_MODELS.aionly, - isSystem: true, - enabled: false } } as const @@ -1368,3 +1368,7 @@ const SUPPORT_GEMINI_NATIVE_WEB_SEARCH_PROVIDERS = ['gemini', 'vertexai'] as con export const isGeminiWebSearchProvider = (provider: Provider) => { return SUPPORT_GEMINI_NATIVE_WEB_SEARCH_PROVIDERS.some((id) => id === provider.id) } + +export const isNewApiProvider = (provider: Provider) => { + return ['new-api', 'cherryin'].includes(provider.id) +} diff --git a/src/renderer/src/hooks/useMinappPopup.ts b/src/renderer/src/hooks/useMinappPopup.ts index 99eba81464..f08924bd0a 100644 --- a/src/renderer/src/hooks/useMinappPopup.ts +++ b/src/renderer/src/hooks/useMinappPopup.ts @@ -1,12 +1,15 @@ import { usePreference } from '@data/hooks/usePreference' import { DEFAULT_MIN_APPS } from '@renderer/config/minapps' import { useMinapps } from '@renderer/hooks/useMinapps' +import NavigationService from '@renderer/services/NavigationService' import TabsService from '@renderer/services/TabsService' import type { MinAppType } from '@renderer/types' import { clearWebviewState } from '@renderer/utils/webviewStateManager' import { LRUCache } from 'lru-cache' import { useCallback } from 'react' +import { useNavbarPosition } from './useNavbar' + let minAppsCache: LRUCache /** @@ -34,6 +37,7 @@ export const useMinappPopup = () => { setMinappShow } = useMinapps() const [maxKeepAliveMinapps] = usePreference('feature.minapp.max_keep_alive') + const { isTopNavbar } = useNavbarPosition() const createLRUCache = useCallback(() => { return new LRUCache({ @@ -165,6 +169,33 @@ export const useMinappPopup = () => { setMinappShow(false) }, [minappShow, openedOneOffMinapp, setOpenedOneOffMinapp, setCurrentMinappId, setMinappShow]) + /** Smart open minapp that adapts to navbar position */ + const openSmartMinapp = useCallback( + (config: MinAppType, keepAlive: boolean = false) => { + if (isTopNavbar) { + // For top navbar mode, need to add to cache first for temporary apps + const cacheApp = minAppsCache.get(config.id) + if (!cacheApp) { + // Add temporary app to cache so MinAppPage can find it + minAppsCache.set(config.id, config) + } + + // Set current minapp and show state + setCurrentMinappId(config.id) + setMinappShow(true) + + // Then navigate to the app tab using NavigationService + if (NavigationService.navigate) { + NavigationService.navigate(`/apps/${config.id}`) + } + } else { + // For side navbar, use the traditional popup system + openMinapp(config, keepAlive) + } + }, + [isTopNavbar, openMinapp, setCurrentMinappId, setMinappShow] + ) + return { openMinapp, openMinappKeepAlive, @@ -172,6 +203,7 @@ export const useMinappPopup = () => { closeMinapp, hideMinappPopup, closeAllMinapps, + openSmartMinapp, // Expose cache instance for TabsService integration minAppsCache } diff --git a/src/renderer/src/pages/home/Navbar.tsx b/src/renderer/src/pages/home/Navbar.tsx index 76710145fb..6b1809abab 100644 --- a/src/renderer/src/pages/home/Navbar.tsx +++ b/src/renderer/src/pages/home/Navbar.tsx @@ -2,7 +2,7 @@ import { RowFlex } from '@cherrystudio/ui' import { usePreference } from '@data/hooks/usePreference' import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar' import SearchPopup from '@renderer/components/Popups/SearchPopup' -import { isLinux, isWin } from '@renderer/config/constant' +import { isLinux, isMac, isWin } from '@renderer/config/constant' import { useAssistant } from '@renderer/hooks/useAssistant' import { modelGenerating } from '@renderer/hooks/useModel' import { useShortcut } from '@renderer/hooks/useShortcuts' @@ -84,7 +84,14 @@ const HeaderNavbar: FC = ({ activeAssistant, setActiveAssistant, activeTo )} {!showAssistants && ( - + toggleShowAssistants()}> @@ -104,7 +111,7 @@ const HeaderNavbar: FC = ({ activeAssistant, setActiveAssistant, activeTo )} - + = ({ activeAssistant, setActiveAssistant, activeTo justifyContent: 'flex-end', flex: 1, position: 'relative', - paddingRight: isWin || isLinux ? '144px' : '6px' + paddingRight: isWin || isLinux ? '144px' : '15px' }} className="home-navbar-right"> diff --git a/src/renderer/src/pages/home/Tabs/SettingsTab.tsx b/src/renderer/src/pages/home/Tabs/SettingsTab.tsx index 4ab2d06eb8..5a54a852b1 100644 --- a/src/renderer/src/pages/home/Tabs/SettingsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/SettingsTab.tsx @@ -394,7 +394,7 @@ const SettingsTab: FC = (props) => { - + {/* {t('settings.math.engine.label')} */} @@ -421,7 +421,7 @@ const SettingsTab: FC = (props) => { - + {/* {t('message.message.code_style')} */} @@ -551,7 +551,7 @@ const SettingsTab: FC = (props) => { - + {t('settings.messages.input.show_estimated_tokens')} diff --git a/src/renderer/src/pages/minapps/MinAppPage.tsx b/src/renderer/src/pages/minapps/MinAppPage.tsx index 326eddc61e..a3b9eeac45 100644 --- a/src/renderer/src/pages/minapps/MinAppPage.tsx +++ b/src/renderer/src/pages/minapps/MinAppPage.tsx @@ -45,11 +45,20 @@ const MinAppPage: FC = () => { } }, [isTopNavbar]) - // Find the app from all available apps + // Find the app from all available apps (including cached ones) const app = useMemo(() => { if (!appId) return null - return [...DEFAULT_MIN_APPS, ...minapps].find((app) => app.id === appId) - }, [appId, minapps]) + + // First try to find in default and custom mini-apps + let foundApp = [...DEFAULT_MIN_APPS, ...minapps].find((app) => app.id === appId) + + // If not found and we have cache, try to find in cache (for temporary apps) + if (!foundApp && minAppsCache) { + foundApp = minAppsCache.get(appId) + } + + return foundApp + }, [appId, minapps, minAppsCache]) useEffect(() => { // If app not found, redirect to apps list diff --git a/src/renderer/src/pages/notes/NotesSidebar.tsx b/src/renderer/src/pages/notes/NotesSidebar.tsx index 7c8e7597d0..40a5a658d8 100644 --- a/src/renderer/src/pages/notes/NotesSidebar.tsx +++ b/src/renderer/src/pages/notes/NotesSidebar.tsx @@ -113,7 +113,7 @@ const NotesSidebar: FC = ({ const targetScrollTop = elementOffsetTop - (containerHeight - elementHeight) / 2 scrollContainer.scrollTo({ top: Math.max(0, targetScrollTop), - behavior: 'smooth' + behavior: 'instant' }) } } diff --git a/src/renderer/src/pages/paintings/ZhipuPage.tsx b/src/renderer/src/pages/paintings/ZhipuPage.tsx index 9489434822..7ac16a6eb8 100644 --- a/src/renderer/src/pages/paintings/ZhipuPage.tsx +++ b/src/renderer/src/pages/paintings/ZhipuPage.tsx @@ -305,7 +305,7 @@ const ZhipuPage: FC<{ Options: string[] }> = ({ Options }) => { } } - const createNewPainting = () => { + const handleAddPainting = () => { if (generating) return const newPainting = getNewPainting() const addedPainting = addPainting('zhipu_paintings', newPainting) @@ -340,12 +340,12 @@ const ZhipuPage: FC<{ Options: string[] }> = ({ Options }) => { return ( - - {t('title.paintings')} - + {t('paintings.title')} {isMac && ( - - )} @@ -480,7 +480,7 @@ const ZhipuPage: FC<{ Options: string[] }> = ({ Options }) => { selectedPainting={painting} onSelectPainting={onSelectPainting} onDeletePainting={onDeletePainting} - onNewPainting={createNewPainting} + onNewPainting={handleAddPainting} /> @@ -554,12 +554,6 @@ const ToolbarMenu = styled.div` gap: 8px; ` -const Title = styled.h1` - margin: 0; - font-size: 18px; - font-weight: 600; -` - const ProviderTitleContainer = styled.div` display: flex; justify-content: space-between; diff --git a/src/renderer/src/pages/settings/AboutSettings.tsx b/src/renderer/src/pages/settings/AboutSettings.tsx index 2dfb7ddeb0..e288bf84f6 100644 --- a/src/renderer/src/pages/settings/AboutSettings.tsx +++ b/src/renderer/src/pages/settings/AboutSettings.tsx @@ -16,7 +16,7 @@ import { UpgradeChannel } from '@shared/data/preference/preferenceTypes' import { ThemeMode } from '@shared/data/preference/preferenceTypes' import { Avatar, Button, Progress, Radio, Row, Tag, Tooltip } from 'antd' import { debounce } from 'lodash' -import { Bug, FileCheck, Github, Globe, Mail, Rss } from 'lucide-react' +import { Bug, FileCheck, Globe, Mail, Rss } from 'lucide-react' import { BadgeQuestionMark } from 'lucide-react' import type { FC } from 'react' import { useEffect, useState } from 'react' @@ -38,7 +38,7 @@ const AboutSettings: FC = () => { const { theme } = useTheme() // const dispatch = useAppDispatch() // const { update } = useRuntime() - const { openMinapp } = useMinappPopup() + const { openSmartMinapp } = useMinappPopup() const { appUpdateState, updateAppUpdateState } = useAppUpdateState() @@ -87,7 +87,7 @@ const AboutSettings: FC = () => { const showLicense = async () => { const { appPath } = await window.api.getAppInfo() - openMinapp({ + openSmartMinapp({ id: 'cherrystudio-license', name: t('settings.about.license.title'), url: `file://${appPath}/resources/cherry-studio/license.html`, @@ -97,7 +97,7 @@ const AboutSettings: FC = () => { const showReleases = async () => { const { appPath } = await window.api.getAppInfo() - openMinapp({ + openSmartMinapp({ id: 'cherrystudio-releases', name: t('settings.about.releases.title'), url: `file://${appPath}/resources/cherry-studio/releases.html?theme=${theme === ThemeMode.dark ? 'dark' : 'light'}`, @@ -313,7 +313,7 @@ const AboutSettings: FC = () => { - + {t('settings.about.feedback.title')}