From 0f7091f3a8da9b6b54a7382a961b196e7ed8f26d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=8F=94=E5=8F=94?= <2692268@gmail.com> Date: Tue, 29 Jul 2025 19:42:52 +0800 Subject: [PATCH] fix: resolve issue of top navigation bar being obscured by miniapp (#8517) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复顶部导航栏被小程序遮挡的问题 * chore: 删除多余文件 * fix: remove redundant changes * style: modify padding * fix(TabContainer): 切换页面时隐藏小程序弹窗 * fix(WebviewContainer): 修正顶部导航栏存在时的webview高度计算 当顶部导航栏存在时,高度计算需要减去两个导航栏高度变量 * fix(TabContainer): 在添加新标签时隐藏minapp弹窗 * fix(MinappPopupContainer): 修复按钮组在顶部导航栏时的边距问题 根据导航栏位置动态调整按钮组的右边距,当导航栏在顶部时不添加额外边距 * feat(useAppInit): 根据导航栏位置调整窗口背景色 根据导航栏位置(isTopNavbar)动态调整窗口背景色,当导航栏在顶部时使用固定背景色,否则保持原有逻辑 * feat(miniapps): 优化顶部导航栏中固定应用标签的样式和交互 重构顶部导航栏中固定应用标签的布局,添加应用名称显示 调整悬停和激活状态的样式,提升用户体验 * fix: 修正顶部导航栏在有 pinned 应用时的背景色显示问题 当有 pinned 应用时,顶部导航栏应显示背景色,之前逻辑错误地要求至少两个应用才显示 * refactor(PinnedMinapps): 移除多余的Tooltip组件并优化结构 * style(PinnedMinapps): 优化顶部导航项的悬停和激活样式 调整悬停效果,移除圆形背景改为底部边框高亮 激活状态改为1px边框并移除冗余的圆角设置 --------- Co-authored-by: xinming wong Co-authored-by: icarus --- .../MinApp/MinappPopupContainer.tsx | 13 ++-- .../components/MinApp/WebviewContainer.tsx | 4 +- .../src/components/Tab/TabContainer.tsx | 14 +++- .../src/components/app/PinnedMinapps.tsx | 65 +++++++++++++------ src/renderer/src/hooks/useAppInit.ts | 13 ++-- 5 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/renderer/src/components/MinApp/MinappPopupContainer.tsx b/src/renderer/src/components/MinApp/MinappPopupContainer.tsx index 45cb25c488..4a5df7fd8c 100644 --- a/src/renderer/src/components/MinApp/MinappPopupContainer.tsx +++ b/src/renderer/src/components/MinApp/MinappPopupContainer.tsx @@ -143,7 +143,7 @@ const MinappPopupContainer: React.FC = () => { const { pinned, updatePinnedMinapps } = useMinapps() const { t } = useTranslation() const backgroundColor = useNavBackgroundColor() - const { isTopNavbar } = useNavbarPosition() + const { isLeftNavbar, isTopNavbar } = useNavbarPosition() const dispatch = useAppDispatch() /** control the drawer open or close */ @@ -165,8 +165,6 @@ const MinappPopupContainer: React.FC = () => { /** whether the minapps open link external is enabled */ const { minappsOpenLinkExternal } = useSettings() - const { isLeftNavbar } = useNavbarPosition() - const isInDevelopment = process.env.NODE_ENV === 'development' useBridge() @@ -405,7 +403,7 @@ const MinappPopupContainer: React.FC = () => { )} - + handleGoBack(appInfo.id)}> @@ -507,6 +505,7 @@ const MinappPopupContainer: React.FC = () => { closeIcon={null} style={{ marginLeft: isLeftNavbar ? 'var(--sidebar-width)' : 0, + marginTop: isTopNavbar ? 'var(--navbar-height)' : 0, backgroundColor: window.root.style.background }}> {/* 在所有小程序中显示GoogleLoginTip */} @@ -541,7 +540,7 @@ const TitleContainer = styled.div` padding-left: ${isMac ? '20px' : '10px'}; } [navbar-position='top'] & { - padding-left: ${isMac ? '80px' : '10px'}; + padding-left: ${isMac ? '20px' : '10px'}; border-bottom: 0.5px solid var(--color-border); } ` @@ -563,14 +562,14 @@ const TitleTextTooltip = styled.span` } ` -const ButtonsGroup = styled.div` +const ButtonsGroup = styled.div<{ isTopNavBar: boolean }>` display: flex; flex-direction: row; align-items: center; gap: 5px; -webkit-app-region: no-drag; &.windows { - margin-right: ${isWin ? '130px' : isLinux ? '100px' : 0}; + margin-right: ${(props) => (props.isTopNavBar ? 0 : isWin ? '130px' : isLinux ? '100px' : 0)}; background-color: var(--color-background-mute); border-radius: 50px; padding: 0 3px; diff --git a/src/renderer/src/components/MinApp/WebviewContainer.tsx b/src/renderer/src/components/MinApp/WebviewContainer.tsx index 361bd39696..2d63e805be 100644 --- a/src/renderer/src/components/MinApp/WebviewContainer.tsx +++ b/src/renderer/src/components/MinApp/WebviewContainer.tsx @@ -23,7 +23,7 @@ const WebviewContainer = memo( }) => { const webviewRef = useRef(null) const { enableSpellCheck } = useSettings() - const { isLeftNavbar } = useNavbarPosition() + const { isLeftNavbar, isTopNavbar } = useNavbarPosition() const setRef = (appid: string) => { onSetRefCallback(appid, null) @@ -74,7 +74,7 @@ const WebviewContainer = memo( const WebviewStyle: React.CSSProperties = { width: isLeftNavbar ? 'calc(100vw - var(--sidebar-width))' : '100vw', - height: 'calc(100vh - var(--navbar-height))', + height: isTopNavbar ? 'calc(100vh - var(--navbar-height) - var(--navbar-height))' : '100vh', backgroundColor: 'var(--color-background)', display: 'inline-flex' } diff --git a/src/renderer/src/components/Tab/TabContainer.tsx b/src/renderer/src/components/Tab/TabContainer.tsx index 7abcb6bdf1..37c6b74cfb 100644 --- a/src/renderer/src/components/Tab/TabContainer.tsx +++ b/src/renderer/src/components/Tab/TabContainer.tsx @@ -2,6 +2,7 @@ import { PlusOutlined } from '@ant-design/icons' import { isLinux, isMac, isWin } from '@renderer/config/constant' import { useTheme } from '@renderer/context/ThemeProvider' import { useFullscreen } from '@renderer/hooks/useFullscreen' +import { useMinappPopup } from '@renderer/hooks/useMinappPopup' import { getTitleLabel } from '@renderer/i18n/label' import tabsService from '@renderer/services/TabsService' import { useAppDispatch, useAppSelector } from '@renderer/store' @@ -69,6 +70,7 @@ const TabsContainer: React.FC = ({ children }) => { const activeTabId = useAppSelector((state) => state.tabs.activeTabId) const isFullscreen = useFullscreen() const { theme, setTheme } = useTheme() + const { hideMinappPopup } = useMinappPopup() const getTabId = (path: string): string => { if (path === '/') return 'home' @@ -116,10 +118,12 @@ const TabsContainer: React.FC = ({ children }) => { } const handleAddTab = () => { + hideMinappPopup() navigate('/launchpad') } const handleSettingsClick = () => { + hideMinappPopup() navigate(lastSettingsPath) } @@ -130,7 +134,15 @@ const TabsContainer: React.FC = ({ children }) => { .filter((tab) => !specialTabs.includes(tab.id)) .map((tab) => { return ( - navigate(tab.path)}> + { + hideMinappPopup() + // 我不确定这个还需不需要,从Siderbar那边复制过来的 + // await modelGenerating() + navigate(tab.path) + }}> {tab.id && {getTabIcon(tab.id)}} {getTitleLabel(tab.id)} diff --git a/src/renderer/src/components/app/PinnedMinapps.tsx b/src/renderer/src/components/app/PinnedMinapps.tsx index 2d7e30f76f..8102bd3772 100644 --- a/src/renderer/src/components/app/PinnedMinapps.tsx +++ b/src/renderer/src/components/app/PinnedMinapps.tsx @@ -3,6 +3,7 @@ import { useMinappPopup } from '@renderer/hooks/useMinappPopup' import { useMinapps } from '@renderer/hooks/useMinapps' import { useRuntime } from '@renderer/hooks/useRuntime' import { useNavbarPosition, useSettings } from '@renderer/hooks/useSettings' +import { MinAppType } from '@renderer/types' import type { MenuProps } from 'antd' import { Dropdown, Tooltip } from 'antd' import { FC, useEffect, useState } from 'react' @@ -26,7 +27,7 @@ export const TopNavbarOpenedMinappTabs: FC = () => { return () => clearTimeout(timer) }, [openedKeepAliveMinapps]) - const handleOnClick = (app) => { + const handleOnClick = (app: MinAppType) => { if (minappShow && currentMinappId === app.id) { hideMinappPopup() } else { @@ -42,7 +43,7 @@ export const TopNavbarOpenedMinappTabs: FC = () => { return ( 1 ? 'var(--color-list-item)' : 'transparent' }}> + style={{ backgroundColor: keepAliveMinapps.length > 0 ? 'var(--color-list-item)' : 'transparent' }}> {keepAliveMinapps.map((app) => { const menuItems: MenuProps['items'] = [ @@ -64,18 +65,19 @@ export const TopNavbarOpenedMinappTabs: FC = () => { const isActive = minappShow && currentMinappId === app.id return ( - - - - handleOnClick(app)} - className={`${isActive ? 'opened-active' : ''}`}> + + + handleOnClick(app)} + theme={theme}> + - - - + {app.name} + + + ) })} @@ -327,7 +329,7 @@ const TabsWrapper = styled.div` const TopNavContainer = styled.div` display: flex; align-items: center; - padding: 4px 2px; + padding: 2px; gap: 6px; background-color: var(--color-list-item); border-radius: 20px; @@ -351,16 +353,39 @@ const TopNavIcon = styled(Icon)` height: 22px; } - &:hover { - background-color: ${({ theme }) => (theme === 'dark' ? 'var(--color-black)' : 'var(--color-white)')}; - opacity: 0.8; - border-radius: 50%; - } - &.opened-active { background-color: ${({ theme }) => (theme === 'dark' ? 'var(--color-black)' : 'var(--color-white)')}; border: 0.5px solid var(--color-border); - border-radius: 50%; + border-radius: 25%; + .icon { + color: var(--color-primary); + } + } +` + +const TopNavLabel = styled.div` + display: flex; + align-items: center; + justify-content: center; + padding: 0 4px; +` + +const TopNavItemContainer = styled.div` + display: flex; + padding: 4px 2px; + transition: border 0.2s ease; + border-radius: 18px; + /* 避免布局偏移 */ + border: 1px solid transparent; + + &:hover { + border-bottom: 2px solid var(--color-primary); + opacity: 0.8; + cursor: pointer; + } + + &.opened-active { + border: 1px solid var(--color-primary); .icon { color: var(--color-primary); } diff --git a/src/renderer/src/hooks/useAppInit.ts b/src/renderer/src/hooks/useAppInit.ts index 60b8ce448d..af7f44cb01 100644 --- a/src/renderer/src/hooks/useAppInit.ts +++ b/src/renderer/src/hooks/useAppInit.ts @@ -18,7 +18,7 @@ import { useEffect } from 'react' import { useDefaultModel } from './useAssistant' import useFullScreenNotice from './useFullScreenNotice' import { useRuntime } from './useRuntime' -import { useSettings } from './useSettings' +import { useNavbarPosition, useSettings } from './useSettings' import useUpdateHandler from './useUpdateHandler' const logger = loggerService.withContext('useAppInit') @@ -31,6 +31,7 @@ export function useAppInit() { const avatar = useLiveQuery(() => db.settings.get('image://avatar')) const { theme } = useTheme() const memoryConfig = useAppSelector(selectMemoryConfig) + const { isTopNavbar } = useNavbarPosition() useEffect(() => { document.getElementById('spinner')?.remove() @@ -85,13 +86,17 @@ export function useAppInit() { const transparentWindow = windowStyle === 'transparent' && isMac && !minappShow if (minappShow) { - window.root.style.background = - windowStyle === 'transparent' && isMac ? 'var(--color-background)' : 'var(--navbar-background)' + if (isTopNavbar) { + window.root.style.background = 'var(--navbar-background)' + } else { + window.root.style.background = + windowStyle === 'transparent' && isMac ? 'var(--color-background)' : 'var(--navbar-background)' + } return } window.root.style.background = transparentWindow ? 'var(--navbar-background-mac)' : 'var(--navbar-background)' - }, [windowStyle, minappShow, theme]) + }, [windowStyle, minappShow, theme, isTopNavbar]) useEffect(() => { if (isLocalAi) {