update
This commit is contained in:
@@ -252,17 +252,17 @@ const isElementVisibleAndFocusable = (element: HTMLElement): boolean => {
|
||||
<!-- Left navigation links with Tailwind classes using theme variables -->
|
||||
<div class="flex items-center space-x-1">
|
||||
<!-- <RouterLink to="/">{{ t('nav.dashboard') }}</RouterLink> --> <!-- 隐藏仪表盘链接 -->
|
||||
<RouterLink to="/workspace" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-link-active-bg">{{ t('nav.terminal') }}</RouterLink>
|
||||
<RouterLink to="/proxies" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-link-active-bg">{{ t('nav.proxies') }}</RouterLink>
|
||||
<RouterLink to="/notifications" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-link-active-bg">{{ t('nav.notifications') }}</RouterLink>
|
||||
<RouterLink to="/audit-logs" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-link-active-bg">{{ t('nav.auditLogs') }}</RouterLink>
|
||||
<RouterLink to="/settings" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-link-active-bg">{{ t('nav.settings') }}</RouterLink>
|
||||
<RouterLink to="/workspace" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-nav-active-bg">{{ t('nav.terminal') }}</RouterLink>
|
||||
<RouterLink to="/proxies" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-nav-active-bg">{{ t('nav.proxies') }}</RouterLink>
|
||||
<RouterLink to="/notifications" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-nav-active-bg">{{ t('nav.notifications') }}</RouterLink>
|
||||
<RouterLink to="/audit-logs" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-nav-active-bg">{{ t('nav.auditLogs') }}</RouterLink>
|
||||
<RouterLink to="/settings" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap" active-class="text-link-active bg-nav-active-bg">{{ t('nav.settings') }}</RouterLink>
|
||||
</div>
|
||||
<!-- Right navigation links with Tailwind classes using theme variables -->
|
||||
<div class="flex items-center space-x-1">
|
||||
<a href="#" @click.prevent="openStyleCustomizer" :title="t('nav.customizeStyle')" class="px-2 py-2 rounded-md text-lg text-icon hover:text-icon-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out">🎨</a>
|
||||
<RouterLink v-if="!isAuthenticated" to="/login" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap">{{ t('nav.login') }}</RouterLink>
|
||||
<a href="#" v-if="isAuthenticated" @click.prevent="handleLogout" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-link-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap">{{ t('nav.logout') }}</a>
|
||||
<a href="#" @click.prevent="openStyleCustomizer" :title="t('nav.customizeStyle')" class="px-2 py-2 rounded-md text-lg text-icon hover:text-icon-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out">🎨</a>
|
||||
<RouterLink v-if="!isAuthenticated" to="/login" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap">{{ t('nav.login') }}</RouterLink>
|
||||
<a href="#" v-if="isAuthenticated" @click.prevent="handleLogout" class="px-3 py-2 rounded-md text-sm font-medium text-secondary hover:text-link-hover hover:bg-nav-active-bg hover:no-underline transition duration-150 ease-in-out whitespace-nowrap">{{ t('nav.logout') }}</a>
|
||||
</div>
|
||||
<!-- Sliding underline element with Tailwind classes using theme variables (JS still controls positioning) -->
|
||||
<div ref="underlineRef" class="absolute bottom-0 h-0.5 bg-link-active rounded transition-all duration-300 ease-in-out pointer-events-none opacity-0"></div> <!-- Added opacity-0 -->
|
||||
|
||||
@@ -766,6 +766,14 @@ watch(() => editingTheme.value?.themeData, (newThemeData) => {
|
||||
}
|
||||
}, { deep: true }); // 需要 deep watch 来监听 themeData 内部的变化
|
||||
|
||||
// Helper function to safely select text in an input on focus
|
||||
const handleFocusAndSelect = (event: FocusEvent) => {
|
||||
const target = event.target;
|
||||
if (target instanceof HTMLInputElement) {
|
||||
target.select();
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -798,21 +806,34 @@ watch(() => editingTheme.value?.themeData, (newThemeData) => {
|
||||
<!-- 动态生成 UI 样式编辑控件 -->
|
||||
<div v-for="(value, key) in editableUiTheme" :key="key" class="form-group">
|
||||
<label :for="`ui-${key}`">{{ formatLabel(key) }}:</label>
|
||||
<!-- 简单判断是否为颜色值,显示颜色选择器 -->
|
||||
<input
|
||||
v-if="typeof value === 'string' && (value.startsWith('#') || value.startsWith('rgb') || value.startsWith('hsl'))"
|
||||
type="color"
|
||||
:id="`ui-${key}`"
|
||||
v-model="editableUiTheme[key]"
|
||||
/>
|
||||
<!-- 否则显示文本输入框 -->
|
||||
<input
|
||||
v-else
|
||||
type="text"
|
||||
:id="`ui-${key}`"
|
||||
v-model="editableUiTheme[key]"
|
||||
class="text-input"
|
||||
/>
|
||||
<!-- Container for color picker and text display -->
|
||||
<div class="color-input-group">
|
||||
<!-- Color Picker -->
|
||||
<input
|
||||
v-if="typeof value === 'string' && (value.startsWith('#') || value.startsWith('rgb') || value.startsWith('hsl'))"
|
||||
type="color"
|
||||
:id="`ui-${key}`"
|
||||
v-model="editableUiTheme[key]"
|
||||
class="color-picker-input"
|
||||
/>
|
||||
<!-- Readonly text input to display and copy color value -->
|
||||
<input
|
||||
v-if="typeof value === 'string' && (value.startsWith('#') || value.startsWith('rgb') || value.startsWith('hsl'))"
|
||||
type="text"
|
||||
:value="editableUiTheme[key]"
|
||||
readonly
|
||||
class="color-text-input text-input"
|
||||
@focus="handleFocusAndSelect"
|
||||
/>
|
||||
<!-- Fallback for non-color values -->
|
||||
<input
|
||||
v-else
|
||||
type="text"
|
||||
:id="`ui-${key}`"
|
||||
v-model="editableUiTheme[key]"
|
||||
class="text-input full-span-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- UI Theme Textarea -->
|
||||
<hr style="margin-top: calc(var(--base-padding) * 2); margin-bottom: calc(var(--base-padding) * 2);">
|
||||
@@ -920,21 +941,34 @@ watch(() => editingTheme.value?.themeData, (newThemeData) => {
|
||||
<!-- 动态生成终端样式编辑控件 -->
|
||||
<div v-for="(value, key) in editingTheme.themeData" :key="key" class="form-group">
|
||||
<label :for="`xterm-${key}`">{{ formatXtermLabel(key as keyof ITheme) }}:</label>
|
||||
<!-- 简单判断是否为颜色值 -->
|
||||
<input
|
||||
v-if="typeof value === 'string' && value.startsWith('#')"
|
||||
type="color"
|
||||
:id="`xterm-${key}`"
|
||||
v-model="(editingTheme.themeData as any)[key]"
|
||||
/>
|
||||
<!-- 其他类型(如数字、布尔值)可以添加相应控件,这里简化为文本 -->
|
||||
<input
|
||||
v-else
|
||||
type="text"
|
||||
:id="`xterm-${key}`"
|
||||
v-model="(editingTheme.themeData as any)[key]"
|
||||
class="text-input"
|
||||
/>
|
||||
<!-- Container for color picker and text display -->
|
||||
<div class="color-input-group">
|
||||
<!-- Color Picker -->
|
||||
<input
|
||||
v-if="typeof value === 'string' && value.startsWith('#')"
|
||||
type="color"
|
||||
:id="`xterm-${key}`"
|
||||
v-model="(editingTheme.themeData as any)[key]"
|
||||
class="color-picker-input"
|
||||
/>
|
||||
<!-- Readonly text input to display and copy color value -->
|
||||
<input
|
||||
v-if="typeof value === 'string' && value.startsWith('#')"
|
||||
type="text"
|
||||
:value="(editingTheme.themeData as any)[key]"
|
||||
readonly
|
||||
class="color-text-input text-input"
|
||||
@focus="handleFocusAndSelect"
|
||||
/>
|
||||
<!-- Fallback for non-color values -->
|
||||
<input
|
||||
v-else
|
||||
type="text"
|
||||
:id="`xterm-${key}`"
|
||||
v-model="(editingTheme.themeData as any)[key]"
|
||||
class="text-input full-span-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 显示解析错误(如果颜色选择器下方也需要的话) -->
|
||||
<!-- <p v-if="terminalThemeParseError" class="error-message full-width-group">{{ terminalThemeParseError }}</p> --> <!-- 错误消息统一显示在 Textarea 下方 -->
|
||||
@@ -1218,14 +1252,32 @@ section[v-if*="isEditingTheme"] .form-group {
|
||||
box-sizing: border-box;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease; /* 添加过渡效果 */
|
||||
}
|
||||
.form-group input[type="color"] {
|
||||
padding: 2px;
|
||||
height: 34px;
|
||||
min-width: 50px;
|
||||
max-width: 70px;
|
||||
justify-self: start;
|
||||
border-radius: 4px; /* 保持圆角一致 */
|
||||
.color-input-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem; /* Space between color picker and text input */
|
||||
grid-column: 2 / 3; /* Ensure the group stays in the second column */
|
||||
width: 100%; /* Take full width of the column */
|
||||
}
|
||||
.color-picker-input {
|
||||
padding: 2px !important; /* Override general padding */
|
||||
height: 34px !important; /* Match text input height */
|
||||
min-width: 40px !important; /* Slightly smaller */
|
||||
max-width: 50px !important;
|
||||
border-radius: 4px !important;
|
||||
border: 1px solid var(--border-color) !important; /* Add border */
|
||||
flex-shrink: 0; /* Prevent shrinking */
|
||||
}
|
||||
.color-text-input {
|
||||
flex-grow: 1; /* Allow text input to take remaining space */
|
||||
min-width: 80px; /* Minimum width for text */
|
||||
background-color: var(--header-bg-color) !important; /* Indicate readonly */
|
||||
cursor: text; /* Allow text selection cursor */
|
||||
}
|
||||
.full-span-input {
|
||||
grid-column: 1 / -1; /* Make non-color inputs span the whole group width */
|
||||
}
|
||||
|
||||
.form-group input:focus, .form-group select:focus {
|
||||
border-color: var(--link-active-color);
|
||||
outline: 0;
|
||||
|
||||
@@ -35,6 +35,8 @@ export const defaultUiTheme: Record<string, string> = {
|
||||
'--link-color': '#333',
|
||||
'--link-hover-color': '#0056b3',
|
||||
'--link-active-color': '#007bff',
|
||||
'--link-active-bg-color': '#e0e0ff', /* Added */
|
||||
'--nav-item-active-bg-color': 'var(--link-active-bg-color)', /* Added */
|
||||
'--header-bg-color': '#f0f0f0',
|
||||
'--footer-bg-color': '#f0f0f0',
|
||||
'--button-bg-color': '#007bff',
|
||||
@@ -47,6 +49,8 @@ export const defaultUiTheme: Record<string, string> = {
|
||||
'--split-line-hover-color': 'var(--border-color)', /* 分割线悬停颜色 */
|
||||
'--input-focus-border-color': 'var(--link-active-color)', /* 输入框聚焦边框颜色 */
|
||||
'--input-focus-glow': 'var(--link-active-color)', /* 输入框聚焦光晕值 */
|
||||
'--ssh-tab-active': 'transparent', /* Added SSH Tab Active */
|
||||
'--ssh-tab-background': 'transparent', /* Added SSH Tab Background */
|
||||
// End added variables
|
||||
'--font-family-sans-serif': 'sans-serif',
|
||||
'--base-padding': '1rem',
|
||||
|
||||
@@ -3,15 +3,19 @@
|
||||
/* Tailwind Theme Variables Mapping */
|
||||
@theme inline {
|
||||
/* Base Colors */
|
||||
--color-app: var(--app-bg-color);
|
||||
--color-text-default: var(--text-color);
|
||||
--color-background: var(--app-bg-color); /* More generic name */
|
||||
--color-foreground: var(--text-color); /* More generic name */
|
||||
--color-app: var(--app-bg-color); /* Keep specific if needed */
|
||||
--color-text-default: var(--text-color); /* Keep specific if needed */
|
||||
--color-text-secondary: var(--text-color-secondary);
|
||||
--color-border-default: var(--border-color);
|
||||
--color-border: var(--border-color); /* Simplified name */
|
||||
--color-border-default: var(--border-color); /* Keep specific if needed */
|
||||
--color-link: var(--link-color);
|
||||
--color-link-hover: var(--link-hover-color);
|
||||
--color-link-active: var(--link-active-color); /* Also used as primary/theme color */
|
||||
--color-primary: var(--link-active-color); /* Map primary to active link color */
|
||||
--color-link-active-bg: var(--link-active-bg-color); /* Map active link background */
|
||||
--color-nav-active-bg: var(--nav-item-active-bg-color); /* Map specific nav active background */
|
||||
|
||||
/* Component Colors */
|
||||
--color-header: var(--header-bg-color);
|
||||
@@ -40,6 +44,7 @@
|
||||
--link-hover-color: #0056b3; /* 链接悬停颜色 */
|
||||
--link-active-color: #007bff; /* 激活链接/主题色 */
|
||||
--link-active-bg-color: #e0e0ff; /* 激活链接背景色 (类似 indigo-50) */
|
||||
--nav-item-active-bg-color: var(--link-active-bg-color); /* 导航选中项背景色, 默认同激活链接背景 */
|
||||
|
||||
/* 组件颜色 */
|
||||
--header-bg-color: #f0f0f0; /* 头部背景色 */
|
||||
@@ -53,8 +58,8 @@
|
||||
--split-line-hover-color: var(--border-color); /* 分割线悬停颜色 */
|
||||
--input-focus-border-color: var(--link-active-color); /* 输入框聚焦边框颜色 */
|
||||
--input-focus-glow: var(--link-active-color); /* 输入框聚焦光晕值 */
|
||||
--ssh-tab-active: none;/* ssh标签激活状态颜色 */
|
||||
--ssh-tab-background: none;/* ssh标签背景颜色 */
|
||||
--ssh-tab-active: transparent; /* Corrected value */
|
||||
--ssh-tab-background: transparent; /* Corrected value */
|
||||
|
||||
/* 字体 */
|
||||
--font-family-sans-serif: sans-serif; /* 默认字体 */
|
||||
|
||||
Reference in New Issue
Block a user