From 191962b8543f3d9711771b952d021c5b1220cc77 Mon Sep 17 00:00:00 2001 From: yinjianm Date: Wed, 25 Mar 2026 05:10:01 +0800 Subject: [PATCH] feat(frontend): redesign connections and workspace ui refresh the connections view into a control center card layout with summary stats, bulk actions, and faster access to test and connect filtered SSH entries polish workspace chrome with glass panel containers and update the terminal tab bar styling and scrolling behavior fix the top nav underline so it only tracks active nav links and stays aligned after window resizing --- .helloagents/CHANGELOG.md | 1 + packages/frontend/src/App.vue | 13 +- .../src/components/TerminalTabBar.vue | 46 +- .../frontend/src/views/ConnectionsView.vue | 904 ++++++++++-------- packages/frontend/src/views/WorkspaceView.vue | 121 ++- 5 files changed, 617 insertions(+), 468 deletions(-) diff --git a/.helloagents/CHANGELOG.md b/.helloagents/CHANGELOG.md index 98a28f4..9dedf32 100644 --- a/.helloagents/CHANGELOG.md +++ b/.helloagents/CHANGELOG.md @@ -7,3 +7,4 @@ - 2026-03-25:`/workspace` 默认布局改为“左侧 Workbench + 中央终端 + 右侧状态监控”,并在状态监控中新增开机累计上/下行流量展示。 - 2026-03-25:继续微调 `/workspace` Workbench,新增默认“快捷指令”标签、调整三栏宽度到更接近 xterminal 参考图,并修复终端区域鼠标悬停时指针异常消失的问题。 - 2026-03-25:前端主站视觉语言统一升级为 `Slate Control Center`,新增公共页面壳层与认证壳层,并重做 Dashboard、Settings、Login、Setup、Notifications、Proxies、Audit Logs、Workbench、StatusMonitor 的现代化 UI 表达。 +- 2026-03-25:收口前端控制中心细节,修复顶部 `app-nav` 激活下划线误命中品牌链接的问题,并将 `ConnectionsView` 重做为控制中心卡片列表,同时升级 `/workspace` 外层容器与 `TerminalTabBar` 的玻璃面板视觉。 diff --git a/packages/frontend/src/App.vue b/packages/frontend/src/App.vue index 379a18c..280a31b 100644 --- a/packages/frontend/src/App.vue +++ b/packages/frontend/src/App.vue @@ -49,7 +49,7 @@ const altShortcutKey = ref(null); const updateUnderline = async () => { await nextTick(); if (navRef.value && underlineRef.value) { - const activeLink = navRef.value.querySelector('.router-link-exact-active') as HTMLElement; + const activeLink = navRef.value.querySelector('.app-nav__link.is-active, .app-nav__link.router-link-exact-active') as HTMLElement | null; if (activeLink) { underlineRef.value.style.left = `${activeLink.offsetLeft}px`; underlineRef.value.style.width = `${activeLink.offsetWidth}px`; @@ -65,6 +65,7 @@ onMounted(() => { window.addEventListener('keydown', handleAltKeyDown); window.addEventListener('keyup', handleGlobalKeyUp); + window.addEventListener('resize', updateUnderline); window.addEventListener('beforeinstallprompt', () => { console.log('[App.vue] beforeinstallprompt event fired. Browser will handle install prompt.'); @@ -90,6 +91,7 @@ watch( onUnmounted(() => { window.removeEventListener('keydown', handleAltKeyDown); window.removeEventListener('keyup', handleGlobalKeyUp); + window.removeEventListener('resize', updateUnderline); }); const isWorkspaceRoute = computed(() => route.path === '/workspace'); @@ -368,9 +370,18 @@ const handleGlobalKeyUp = async (event: KeyboardEvent) => { display: flex; align-items: center; gap: 0.35rem; + min-width: 0; + max-width: 100%; padding: 0.35rem; border-radius: 18px; background: rgba(241, 245, 251, 0.9); + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; +} + +.app-nav::-webkit-scrollbar { + display: none; } .app-nav__link { diff --git a/packages/frontend/src/components/TerminalTabBar.vue b/packages/frontend/src/components/TerminalTabBar.vue index 457601b..dd476e4 100644 --- a/packages/frontend/src/components/TerminalTabBar.vue +++ b/packages/frontend/src/components/TerminalTabBar.vue @@ -63,6 +63,7 @@ const sessionStore = useSessionStore(); // Session store 保持不变 const showConnectionListPopup = ref(false); // 连接列表弹出状态 const draggableSessions = ref([]); // + Local state for draggable const showTransferProgressModal = ref(false); // 控制传输进度模态框的显示状态 +const tabScrollerRef = ref(null); // + Watch prop changes to update local state watch(() => props.sessions, (newSessions) => { @@ -393,7 +394,7 @@ const handleWheel: EventListener = (event: Event) => { // 在组件挂载时添加滚轮事件监听 onMounted(() => { - const tabContainer = document.querySelector('.overflow-x-auto'); + const tabContainer = tabScrollerRef.value; if (tabContainer) { tabContainer.addEventListener('wheel', handleWheel as EventListener, { passive: false }); } @@ -401,7 +402,7 @@ onMounted(() => { // 在组件卸载时移除滚轮事件监听 onBeforeUnmount(() => { - const tabContainer = document.querySelector('.overflow-x-auto'); + const tabContainer = tabScrollerRef.value; if (tabContainer) { tabContainer.removeEventListener('wheel', handleWheel as EventListener); } @@ -411,11 +412,13 @@ onBeforeUnmount(() => { + + diff --git a/packages/frontend/src/views/ConnectionsView.vue b/packages/frontend/src/views/ConnectionsView.vue index 119da4d..349d0ee 100644 --- a/packages/frontend/src/views/ConnectionsView.vue +++ b/packages/frontend/src/views/ConnectionsView.vue @@ -1,21 +1,19 @@ diff --git a/packages/frontend/src/views/WorkspaceView.vue b/packages/frontend/src/views/WorkspaceView.vue index 45add48..81ac8ff 100644 --- a/packages/frontend/src/views/WorkspaceView.vue +++ b/packages/frontend/src/views/WorkspaceView.vue @@ -824,14 +824,32 @@ const closeFileManagerModal = () => {