From 1b73d68cbf1aec919902ab4d5d43d22e02fb1c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Fri, 20 Feb 2026 23:05:20 +0800 Subject: [PATCH] Refactor extension tabs layout and styles Remove the overflow wrapper around extension tabs and move max-w/full styling to the Tabs component. Simplify classNames (tabList, cursor) and clean up shrinking/truncation classes on tab items and plugin name to improve responsiveness and layout, while preserving the openInNewWindow click behavior. --- .../src/pages/dashboard/extension.tsx | 56 ++++++++++++++++--- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx b/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx index 902a3cb4..38dda072 100644 --- a/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx +++ b/packages/napcat-webui-frontend/src/pages/dashboard/extension.tsx @@ -1,7 +1,7 @@ import { Tab, Tabs } from '@heroui/tabs'; import { Button } from '@heroui/button'; import { Spinner } from '@heroui/spinner'; -import { useEffect, useState, useMemo } from 'react'; +import { useEffect, useState, useMemo, useRef, useCallback } from 'react'; import toast from 'react-hot-toast'; import { IoMdRefresh } from 'react-icons/io'; import { MdExtension } from 'react-icons/md'; @@ -93,14 +93,45 @@ export default function ExtensionPage () { window.open(url, '_blank'); }; + // 拖拽滚动支持(鼠标 + 触摸) + const scrollRef = useRef(null); + const isDragging = useRef(false); + const startX = useRef(0); + const scrollLeft = useRef(0); + + const handlePointerDown = useCallback((e: React.PointerEvent) => { + const el = scrollRef.current; + if (!el) return; + isDragging.current = true; + startX.current = e.clientX; + scrollLeft.current = el.scrollLeft; + el.setPointerCapture(e.pointerId); + el.style.cursor = 'grabbing'; + el.style.userSelect = 'none'; + }, []); + + const handlePointerMove = useCallback((e: React.PointerEvent) => { + if (!isDragging.current || !scrollRef.current) return; + const dx = e.clientX - startX.current; + scrollRef.current.scrollLeft = scrollLeft.current - dx; + }, []); + + const handlePointerUp = useCallback((e: React.PointerEvent) => { + if (!isDragging.current || !scrollRef.current) return; + isDragging.current = false; + scrollRef.current.releasePointerCapture(e.pointerId); + scrollRef.current.style.cursor = 'grab'; + scrollRef.current.style.userSelect = ''; + }, []); + return ( <> 扩展页面 - NapCat WebUI
-
-
+
+
插件扩展页面 @@ -115,10 +146,18 @@ export default function ExtensionPage () {
{extensionPages.length > 0 && ( -
+
setSelectedTab(key as string)} classNames={{ @@ -130,12 +169,11 @@ export default function ExtensionPage () { {tabs.map((tab) => ( +
{tab.icon && {tab.icon}} { e.stopPropagation(); @@ -144,7 +182,7 @@ export default function ExtensionPage () { > {tab.title} - ({tab.pluginName}) + ({tab.pluginName})
} />