Revert "feat(frontend): redesign connections and workspace ui"
This reverts commit 191962b854.
This commit is contained in:
@@ -7,4 +7,3 @@
|
|||||||
- 2026-03-25:`/workspace` 默认布局改为“左侧 Workbench + 中央终端 + 右侧状态监控”,并在状态监控中新增开机累计上/下行流量展示。
|
- 2026-03-25:`/workspace` 默认布局改为“左侧 Workbench + 中央终端 + 右侧状态监控”,并在状态监控中新增开机累计上/下行流量展示。
|
||||||
- 2026-03-25:继续微调 `/workspace` Workbench,新增默认“快捷指令”标签、调整三栏宽度到更接近 xterminal 参考图,并修复终端区域鼠标悬停时指针异常消失的问题。
|
- 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:前端主站视觉语言统一升级为 `Slate Control Center`,新增公共页面壳层与认证壳层,并重做 Dashboard、Settings、Login、Setup、Notifications、Proxies、Audit Logs、Workbench、StatusMonitor 的现代化 UI 表达。
|
||||||
- 2026-03-25:收口前端控制中心细节,修复顶部 `app-nav` 激活下划线误命中品牌链接的问题,并将 `ConnectionsView` 重做为控制中心卡片列表,同时升级 `/workspace` 外层容器与 `TerminalTabBar` 的玻璃面板视觉。
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const altShortcutKey = ref<string | null>(null);
|
|||||||
const updateUnderline = async () => {
|
const updateUnderline = async () => {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
if (navRef.value && underlineRef.value) {
|
if (navRef.value && underlineRef.value) {
|
||||||
const activeLink = navRef.value.querySelector('.app-nav__link.is-active, .app-nav__link.router-link-exact-active') as HTMLElement | null;
|
const activeLink = navRef.value.querySelector('.router-link-exact-active') as HTMLElement;
|
||||||
if (activeLink) {
|
if (activeLink) {
|
||||||
underlineRef.value.style.left = `${activeLink.offsetLeft}px`;
|
underlineRef.value.style.left = `${activeLink.offsetLeft}px`;
|
||||||
underlineRef.value.style.width = `${activeLink.offsetWidth}px`;
|
underlineRef.value.style.width = `${activeLink.offsetWidth}px`;
|
||||||
@@ -65,7 +65,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
window.addEventListener('keydown', handleAltKeyDown);
|
window.addEventListener('keydown', handleAltKeyDown);
|
||||||
window.addEventListener('keyup', handleGlobalKeyUp);
|
window.addEventListener('keyup', handleGlobalKeyUp);
|
||||||
window.addEventListener('resize', updateUnderline);
|
|
||||||
|
|
||||||
window.addEventListener('beforeinstallprompt', () => {
|
window.addEventListener('beforeinstallprompt', () => {
|
||||||
console.log('[App.vue] beforeinstallprompt event fired. Browser will handle install prompt.');
|
console.log('[App.vue] beforeinstallprompt event fired. Browser will handle install prompt.');
|
||||||
@@ -91,7 +90,6 @@ watch(
|
|||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('keydown', handleAltKeyDown);
|
window.removeEventListener('keydown', handleAltKeyDown);
|
||||||
window.removeEventListener('keyup', handleGlobalKeyUp);
|
window.removeEventListener('keyup', handleGlobalKeyUp);
|
||||||
window.removeEventListener('resize', updateUnderline);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const isWorkspaceRoute = computed(() => route.path === '/workspace');
|
const isWorkspaceRoute = computed(() => route.path === '/workspace');
|
||||||
@@ -370,18 +368,9 @@ const handleGlobalKeyUp = async (event: KeyboardEvent) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.35rem;
|
gap: 0.35rem;
|
||||||
min-width: 0;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0.35rem;
|
padding: 0.35rem;
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
background: rgba(241, 245, 251, 0.9);
|
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 {
|
.app-nav__link {
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ const sessionStore = useSessionStore(); // Session store 保持不变
|
|||||||
const showConnectionListPopup = ref(false); // 连接列表弹出状态
|
const showConnectionListPopup = ref(false); // 连接列表弹出状态
|
||||||
const draggableSessions = ref<SessionTabInfoWithStatus[]>([]); // + Local state for draggable
|
const draggableSessions = ref<SessionTabInfoWithStatus[]>([]); // + Local state for draggable
|
||||||
const showTransferProgressModal = ref(false); // 控制传输进度模态框的显示状态
|
const showTransferProgressModal = ref(false); // 控制传输进度模态框的显示状态
|
||||||
const tabScrollerRef = ref<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
// + Watch prop changes to update local state
|
// + Watch prop changes to update local state
|
||||||
watch(() => props.sessions, (newSessions) => {
|
watch(() => props.sessions, (newSessions) => {
|
||||||
@@ -394,7 +393,7 @@ const handleWheel: EventListener = (event: Event) => {
|
|||||||
|
|
||||||
// 在组件挂载时添加滚轮事件监听
|
// 在组件挂载时添加滚轮事件监听
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const tabContainer = tabScrollerRef.value;
|
const tabContainer = document.querySelector('.overflow-x-auto');
|
||||||
if (tabContainer) {
|
if (tabContainer) {
|
||||||
tabContainer.addEventListener('wheel', handleWheel as EventListener, { passive: false });
|
tabContainer.addEventListener('wheel', handleWheel as EventListener, { passive: false });
|
||||||
}
|
}
|
||||||
@@ -402,7 +401,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 在组件卸载时移除滚轮事件监听
|
// 在组件卸载时移除滚轮事件监听
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
const tabContainer = tabScrollerRef.value;
|
const tabContainer = document.querySelector('.overflow-x-auto');
|
||||||
if (tabContainer) {
|
if (tabContainer) {
|
||||||
tabContainer.removeEventListener('wheel', handleWheel as EventListener);
|
tabContainer.removeEventListener('wheel', handleWheel as EventListener);
|
||||||
}
|
}
|
||||||
@@ -412,13 +411,11 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- +++ 使用 :class 绑定来条件化样式,包括高度 (修正 props 引用) +++ -->
|
<!-- +++ 使用 :class 绑定来条件化样式,包括高度 (修正 props 引用) +++ -->
|
||||||
<div
|
<div :class="['flex bg-header border border-border overflow-hidden',
|
||||||
:class="[
|
{ 'rounded-t-md mx-2 mt-2': !props.isMobile }, // Desktop margins/rounding - Use props.isMobile
|
||||||
'terminal-tab-shell flex overflow-hidden',
|
props.isMobile ? 'h-8' : 'h-10' // Mobile height h-8, Desktop h-10 - Use props.isMobile
|
||||||
props.isMobile ? 'terminal-tab-shell--mobile h-10' : 'terminal-tab-shell--desktop h-12',
|
]">
|
||||||
]"
|
<div class="flex items-center overflow-x-auto flex-shrink min-w-0 h-full"> <!-- Ensure inner div has h-full -->
|
||||||
>
|
|
||||||
<div ref="tabScrollerRef" class="terminal-tab-shell__scroller flex items-center overflow-x-auto flex-shrink min-w-0 h-full">
|
|
||||||
<draggable
|
<draggable
|
||||||
v-model="draggableSessions"
|
v-model="draggableSessions"
|
||||||
item-key="sessionId"
|
item-key="sessionId"
|
||||||
@@ -521,32 +518,3 @@ onBeforeUnmount(() => {
|
|||||||
<TransferProgressModal v-model:visible="showTransferProgressModal" />
|
<TransferProgressModal v-model:visible="showTransferProgressModal" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.terminal-tab-shell {
|
|
||||||
position: relative;
|
|
||||||
align-items: stretch;
|
|
||||||
border: 1px solid rgba(103, 124, 155, 0.18);
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.82), rgba(243, 247, 253, 0.74));
|
|
||||||
box-shadow: var(--shadow-card);
|
|
||||||
backdrop-filter: blur(18px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-tab-shell--desktop {
|
|
||||||
margin: 1rem 1rem 0;
|
|
||||||
border-radius: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-tab-shell--mobile {
|
|
||||||
margin: 0.75rem 0.75rem 0;
|
|
||||||
border-radius: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-tab-shell__scroller {
|
|
||||||
scrollbar-width: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.terminal-tab-shell__scroller::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -824,32 +824,14 @@ const closeFileManagerModal = () => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.workspace-view {
|
.workspace-view {
|
||||||
position: relative;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.85rem;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0 1rem 1rem;
|
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
flex-direction: column;
|
||||||
height: 100dvh; /* 使用动态视口高度 */
|
height: 100dvh; /* 使用动态视口高度 */
|
||||||
min-height: 0;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: height 0.3s ease; /* 可选:添加过渡效果 */
|
transition: height 0.3s ease; /* 可选:添加过渡效果 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-view::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: 0.9rem 1rem 1rem;
|
|
||||||
border-radius: 32px;
|
|
||||||
border: 1px solid rgba(103, 124, 155, 0.12);
|
|
||||||
background:
|
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.4), rgba(241, 246, 252, 0.18)),
|
|
||||||
radial-gradient(circle at top right, rgba(60, 105, 231, 0.1), transparent 28%);
|
|
||||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.72);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 当 Header 可见时,调整高度 */
|
/* 当 Header 可见时,调整高度 */
|
||||||
.workspace-view.with-header {
|
.workspace-view.with-header {
|
||||||
/* 假设 Header 高度为 55px (根据 App.vue CSS) */
|
/* 假设 Header 高度为 55px (根据 App.vue CSS) */
|
||||||
@@ -857,20 +839,14 @@ const closeFileManagerModal = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main-content-area {
|
.main-content-area {
|
||||||
position: relative;
|
display: flex;
|
||||||
z-index: 1;
|
flex: 1;
|
||||||
display: flex;
|
overflow: hidden; /* Keep overflow hidden */
|
||||||
flex: 1;
|
border: 1px solid var(--border-color, #ccc); /* Use variable for border */
|
||||||
min-height: 0;
|
border-top: none; /* Remove top border as it's handled by the tab bar */
|
||||||
overflow: hidden;
|
border-radius: 0 0 5px 5px; /* Top-left, Top-right, Bottom-right, Bottom-left */
|
||||||
border: 1px solid rgba(103, 124, 155, 0.18);
|
margin: var(--base-margin, 0.5rem); /* Add some margin around the content area */
|
||||||
border-radius: 30px;
|
margin-top: 0; /* Remove top margin if tab bar is directly above */
|
||||||
background:
|
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.84), rgba(242, 247, 253, 0.72)),
|
|
||||||
linear-gradient(135deg, rgba(60, 105, 231, 0.05), transparent);
|
|
||||||
box-shadow: var(--shadow-soft);
|
|
||||||
backdrop-filter: blur(22px);
|
|
||||||
padding: 0.85rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-renderer-wrapper {
|
.layout-renderer-wrapper {
|
||||||
@@ -878,81 +854,64 @@ const closeFileManagerModal = () => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 24px;
|
|
||||||
background: rgba(255, 255, 255, 0.46);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 面板占位符样式 (用于加载或错误状态) */
|
/* 面板占位符样式 (用于加载或错误状态) */
|
||||||
.pane-placeholder {
|
.pane-placeholder {
|
||||||
position: relative;
|
flex-grow: 1;
|
||||||
z-index: 1;
|
display: flex;
|
||||||
flex-grow: 1;
|
justify-content: center;
|
||||||
display: flex;
|
align-items: center;
|
||||||
justify-content: center;
|
text-align: center;
|
||||||
align-items: center;
|
color: var(--text-color-secondary); /* Use secondary text color variable */
|
||||||
text-align: center;
|
background-color: var(--header-bg-color); /* Use header background for slight contrast */
|
||||||
color: var(--text-color-secondary);
|
font-size: 0.9em;
|
||||||
background: rgba(248, 251, 255, 0.72);
|
padding: var(--base-padding); /* Use base padding variable */
|
||||||
border: 1px dashed rgba(103, 124, 155, 0.28);
|
|
||||||
border-radius: 24px;
|
|
||||||
font-size: 0.92em;
|
|
||||||
padding: var(--base-padding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --- Mobile Layout Styles --- */
|
/* --- Mobile Layout Styles --- */
|
||||||
.workspace-view.is-mobile {
|
.workspace-view.is-mobile {
|
||||||
padding: 0 0 0.85rem;
|
/* Ensure flex column layout */
|
||||||
|
display: flex; /* Uncommented */
|
||||||
|
flex-direction: column; /* Uncommented */
|
||||||
|
/* Height is already handled by .workspace-view and .with-header */
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-view.is-mobile .main-content-area {
|
.workspace-view.is-mobile .main-content-area {
|
||||||
|
/* Hide the desktop content area in mobile view */
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-content-area {
|
.mobile-content-area {
|
||||||
position: relative;
|
display: flex; /* Use flex for the terminal container */
|
||||||
z-index: 1;
|
flex-direction: column; /* Stack elements vertically if needed */
|
||||||
display: flex;
|
flex-grow: 1; /* Allow this area to take up remaining space */
|
||||||
flex-direction: column;
|
overflow: hidden; /* Prevent overflow */
|
||||||
flex-grow: 1;
|
position: relative; /* Needed for potential absolute positioning inside */
|
||||||
min-height: 0;
|
/* Remove desktop margins/borders */
|
||||||
overflow: hidden;
|
margin: 0;
|
||||||
margin: 0 0.75rem;
|
border: none;
|
||||||
border: 1px solid rgba(103, 124, 155, 0.18);
|
border-radius: 0;
|
||||||
border-radius: 26px;
|
|
||||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.84), rgba(242, 247, 253, 0.72));
|
|
||||||
box-shadow: var(--shadow-soft);
|
|
||||||
backdrop-filter: blur(22px);
|
|
||||||
padding: 0.75rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-terminal {
|
.mobile-terminal {
|
||||||
flex-grow: 1;
|
flex-grow: 1; /* Terminal takes all available space in mobile-content-area */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-command-bar {
|
.mobile-command-bar {
|
||||||
position: relative;
|
flex-shrink: 0; /* Prevent command bar from shrinking */
|
||||||
z-index: 1;
|
/* Add specific styles if needed, e.g., border-top */
|
||||||
flex-shrink: 0;
|
border-top: 1px solid var(--border-color, #ccc);
|
||||||
margin: 0.75rem 0.75rem 0;
|
|
||||||
border: 1px solid rgba(103, 124, 155, 0.18);
|
|
||||||
border-radius: 22px;
|
|
||||||
background: rgba(255, 255, 255, 0.82);
|
|
||||||
box-shadow: var(--shadow-card);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-virtual-keyboard {
|
.mobile-virtual-keyboard {
|
||||||
position: relative;
|
flex-shrink: 0; /* 防止虚拟键盘缩小 */
|
||||||
z-index: 1;
|
width: 100%; /* 确保宽度为 100% */
|
||||||
flex-shrink: 0;
|
box-sizing: border-box; /* 边框和内边距包含在宽度内 */
|
||||||
width: calc(100% - 1.5rem);
|
/* 可以添加更多样式,例如背景色、边框等 */
|
||||||
margin: 0.75rem auto 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 24px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user