From 2e82f2b2d1c6c38c35f297949237393df9622b8a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 11:16:41 +0800 Subject: [PATCH] fix: plugin pages scroll entire viewport instead of content area only (#1788) * Initial plan * Fix scroll behavior in plugin pages - only content areas scroll now Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com> --- .../PluginInstalledComponent.tsx | 2 +- .../plugin-market/PluginMarketComponent.tsx | 199 ++++++++++-------- .../plugins/mcp-server/MCPServerComponent.tsx | 10 +- web/src/app/home/plugins/page.tsx | 19 +- 4 files changed, 125 insertions(+), 105 deletions(-) diff --git a/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx b/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx index 612151d9..ed711e71 100644 --- a/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx +++ b/web/src/app/home/plugins/components/plugin-installed/PluginInstalledComponent.tsx @@ -274,7 +274,7 @@ const PluginInstalledComponent = forwardRef( {pluginList.length === 0 ? ( -
+
(null); + const scrollContainerRef = useRef(null); // 排序选项 const sortOptions: SortOption[] = [ @@ -262,19 +263,21 @@ function MarketPageContent({ } }, [currentPage, isLoadingMore, hasMore, fetchPlugins, searchQuery]); - // 监听滚动事件 + // Listen to scroll events on the scroll container useEffect(() => { + const scrollContainer = scrollContainerRef.current; + if (!scrollContainer) return; + const handleScroll = () => { - if ( - window.innerHeight + document.documentElement.scrollTop >= - document.documentElement.offsetHeight - 100 - ) { + const { scrollTop, scrollHeight, clientHeight } = scrollContainer; + // Load more when scrolled to within 100px of the bottom + if (scrollTop + clientHeight >= scrollHeight - 100) { loadMore(); } }; - window.addEventListener('scroll', handleScroll); - return () => window.removeEventListener('scroll', handleScroll); + scrollContainer.addEventListener('scroll', handleScroll); + return () => scrollContainer.removeEventListener('scroll', handleScroll); }, [loadMore]); // 安装插件 @@ -283,99 +286,109 @@ function MarketPageContent({ // }; return ( -
- {/* 搜索框 */} -
-
- - handleSearchInputChange(e.target.value)} - onKeyPress={(e) => { - if (e.key === 'Enter') { - // 立即搜索,清除防抖定时器 - if (searchTimeoutRef.current) { - clearTimeout(searchTimeoutRef.current); +
+ {/* Fixed header with search and sort controls */} +
+ {/* Search box */} +
+
+ + handleSearchInputChange(e.target.value)} + onKeyPress={(e) => { + if (e.key === 'Enter') { + // Immediately search, clear debounce timer + if (searchTimeoutRef.current) { + clearTimeout(searchTimeoutRef.current); + } + handleSearch(searchQuery); } - handleSearch(searchQuery); - } - }} - className="pl-10 pr-4 text-sm sm:text-base" - /> -
-
- - {/* 排序下拉框 */} -
-
- - {t('market.sortBy')}: - - -
-
- - {/* 搜索结果统计 */} - {total > 0 && ( -
- {searchQuery - ? t('market.searchResults', { count: total }) - : t('market.totalPlugins', { count: total })} -
- )} - - {/* 插件列表 */} - {isLoading ? ( -
- - {t('market.loading')} -
- ) : plugins.length === 0 ? ( -
-
- {searchQuery ? t('market.noResults') : t('market.noPlugins')} + }} + className="pl-10 pr-4 text-sm sm:text-base" + />
- ) : ( -
- {plugins.map((plugin) => ( - - ))} -
- )} - {/* 加载更多指示器 */} - {isLoadingMore && ( -
- - {t('market.loadingMore')} + {/* Sort dropdown */} +
+
+ + {t('market.sortBy')}: + + +
- )} - {/* 没有更多数据提示 */} - {!hasMore && plugins.length > 0 && ( -
- {t('market.allLoaded')} -
- )} + {/* Search results stats */} + {total > 0 && ( +
+ {searchQuery + ? t('market.searchResults', { count: total }) + : t('market.totalPlugins', { count: total })} +
+ )} +
- {/* 插件详情对话框 */} + {/* Scrollable content area */} +
+ {isLoading ? ( +
+ + {t('market.loading')} +
+ ) : plugins.length === 0 ? ( +
+
+ {searchQuery ? t('market.noResults') : t('market.noPlugins')} +
+
+ ) : ( + <> +
+ {plugins.map((plugin) => ( + + ))} +
+ + {/* Loading more indicator */} + {isLoadingMore && ( +
+ + {t('market.loadingMore')} +
+ )} + + {/* No more data hint */} + {!hasMore && plugins.length > 0 && ( +
+ {t('market.allLoaded')} +
+ )} + + )} +
+ + {/* Plugin detail dialog */} - {/* 已安装的服务器列表 */} -
+ {/* Server list */} +
{loading ? ( -
+
{t('mcp.loading')}
) : installedServers.length === 0 ? ( -
+
{t('mcp.noServerInstalled')}
) : ( -
+
{installedServers.map((server, index) => (
- -
+ +
{t('plugins.installed')} @@ -522,10 +526,10 @@ export default function PluginConfigPage() {
- + - + { setInstallSource('marketplace'); @@ -539,7 +543,10 @@ export default function PluginConfigPage() { }} /> - + {