This commit is contained in:
Baobhan Sith
2025-04-17 22:32:24 +08:00
parent 6a4f3d7a00
commit f8e4c14fa8
6 changed files with 854 additions and 310 deletions
+45 -13
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router';
import { RouterLink, RouterView, useRoute } from 'vue-router';
import { ref, onMounted, watch, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAuthStore } from './stores/auth.store';
import { useSettingsStore } from './stores/settings.store';
@@ -20,6 +21,35 @@ const { isAuthenticated } = storeToRefs(authStore);
const { showPopupFileEditorBoolean } = storeToRefs(settingsStore);
const { isStyleCustomizerVisible } = storeToRefs(appearanceStore); // 从外观 store 获取可见性状态
const route = useRoute();
const navRef = ref<HTMLElement | null>(null);
const underlineRef = ref<HTMLElement | null>(null);
const updateUnderline = async () => {
await nextTick(); // 等待 DOM 更新
if (navRef.value && underlineRef.value) {
const activeLink = navRef.value.querySelector('.router-link-exact-active') as HTMLElement;
if (activeLink) {
underlineRef.value.style.left = `${activeLink.offsetLeft}px`;
underlineRef.value.style.width = `${activeLink.offsetWidth}px`;
underlineRef.value.style.opacity = '1'; // Make it visible
} else {
underlineRef.value.style.opacity = '0'; // Hide if no active link (e.g., on login page if not a nav link)
}
}
};
onMounted(() => {
// Initial position update
// Use setTimeout to ensure styles are applied and elements have dimensions
setTimeout(updateUnderline, 100);
});
watch(route, () => {
updateUnderline();
});
const handleLogout = () => {
authStore.logout();
};
@@ -38,7 +68,7 @@ const closeStyleCustomizer = () => {
<template>
<div id="app-container">
<header>
<nav>
<nav ref="navRef">
<div class="nav-left"> <!-- Group left-aligned links -->
<RouterLink to="/">{{ t('nav.dashboard') }}</RouterLink>
<RouterLink to="/connections">{{ t('nav.connections') }}</RouterLink>
@@ -53,6 +83,8 @@ const closeStyleCustomizer = () => {
<RouterLink v-if="!isAuthenticated" to="/login">{{ t('nav.login') }}</RouterLink>
<a href="#" v-if="isAuthenticated" @click.prevent="handleLogout">{{ t('nav.logout') }}</a>
</div>
<!-- Sliding underline element -->
<div ref="underlineRef" class="nav-underline"></div>
</nav>
</header>
@@ -133,19 +165,19 @@ nav a.router-link-exact-active {
font-weight: 500; /* Medium weight */
color: var(--link-active-color); /* Use active link color */
background-color: transparent; /* Remove background for active link */
/* Add a bottom border for active state */
/* The underline is now handled by a separate element */
}
/* Add a pseudo-element for the active indicator */
nav a.router-link-exact-active::after {
content: '';
position: absolute;
bottom: -1px; /* Position slightly below the text, aligning with header border */
left: 10%; /* Start slightly indented */
right: 10%; /* End slightly indented */
height: 2px; /* Thickness of the indicator */
background-color: var(--link-active-color); /* Color of the indicator */
border-radius: 1px;
/* Style for the sliding underline */
.nav-underline {
position: absolute;
bottom: 0px; /* Position at the very bottom of the nav */
height: 2px; /* Thickness of the indicator */
background-color: var(--link-active-color); /* Color of the indicator */
border-radius: 1px;
transition: left 0.3s ease-in-out, width 0.3s ease-in-out; /* Smooth transition for sliding */
opacity: 0; /* Initially hidden */
pointer-events: none; /* Prevent interaction */
}
@@ -458,15 +458,161 @@ const handleTestNotification = async () => {
<style scoped>
.notification-setting-form {
padding: 1.5rem;
background-color: #fff;
border-radius: 0.3rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
padding: var(--base-padding);
background-color: var(--app-bg-color); /* Use app background */
border: 1px solid var(--border-color); /* Add border consistent with theme */
border-radius: 4px;
color: var(--text-color);
/* Removed box-shadow for a flatter look, can be added back if desired */
}
h3 {
color: var(--text-color);
margin-bottom: calc(var(--base-margin) * 2);
padding-bottom: var(--base-margin);
border-bottom: 1px solid var(--border-color);
font-size: 1.25rem; /* Slightly larger heading */
}
.mb-3 { /* Bootstrap margin bottom class */
margin-bottom: calc(var(--base-margin) * 1.5) !important; /* Use variable, increase slightly */
}
.form-label {
display: block;
margin-bottom: calc(var(--base-margin) / 2);
color: var(--text-color);
font-weight: bold;
}
.form-control, .form-select, .form-check-input {
background-color: var(--app-bg-color);
color: var(--text-color);
border: 1px solid var(--border-color);
padding: 0.5rem 0.75rem;
border-radius: 4px;
width: 100%; /* Ensure inputs take full width */
box-sizing: border-box; /* Include padding and border in element's total width */
}
.form-control:focus, .form-select:focus {
border-color: var(--link-active-color); /* Highlight focus */
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); /* Optional focus shadow */
}
textarea.form-control {
min-height: 80px; /* Give textareas more space */
}
.form-check {
display: flex; /* Align checkbox and label */
align-items: center;
padding-left: 0; /* Reset Bootstrap padding */
}
.form-check-input {
width: auto; /* Don't force checkbox to full width */
margin-right: 0.5rem; /* Space between checkbox and label */
margin-top: 0; /* Align vertically */
border: 1px solid var(--border-color); /* Ensure border is visible */
}
.form-check-label {
margin-bottom: 0; /* Reset label margin */
font-weight: normal; /* Normal weight for checkbox labels */
}
.text-muted {
color: var(--text-color-secondary);
font-size: 0.85em;
display: block; /* Ensure it takes its own line */
margin-top: calc(var(--base-margin) / 2);
}
.text-danger {
color: #dc3545; /* Keep specific danger color */
}
.text-success {
color: #198754; /* Keep specific success color */
}
.channel-config {
border: 1px solid var(--border-color);
border-radius: 4px;
padding: var(--base-padding);
margin-top: var(--base-margin);
background-color: var(--header-bg-color); /* Slightly different background */
}
.channel-config h4 {
font-size: 1rem;
font-weight: bold;
margin-bottom: 1rem;
margin-bottom: var(--base-margin);
color: var(--text-color);
padding-bottom: calc(var(--base-margin) / 2);
border-bottom: 1px dashed var(--border-color); /* Dashed separator */
}
/* Button styling (reuse from NotificationSettings or define globally) */
.btn {
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
font-weight: bold;
}
.btn-primary {
background-color: var(--button-bg-color);
border: 1px solid var(--button-bg-color);
color: var(--button-text-color);
}
.btn-primary:hover {
background-color: var(--button-hover-bg-color);
border-color: var(--button-hover-bg-color);
color: var(--button-text-color);
}
.btn-primary:disabled {
opacity: 0.65;
cursor: not-allowed;
}
.btn-secondary {
background-color: var(--text-color-secondary);
border: 1px solid var(--text-color-secondary);
color: var(--app-bg-color);
}
.btn-secondary:hover {
background-color: var(--text-color);
border-color: var(--text-color);
color: var(--app-bg-color);
}
.btn-outline-secondary {
color: var(--text-color-secondary);
border: 1px solid var(--border-color);
background-color: transparent;
}
.btn-outline-secondary:hover {
background-color: var(--header-bg-color);
color: var(--text-color);
border-color: var(--border-color);
}
.btn-sm {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}
.spinner-border-sm {
width: 1rem;
height: 1rem;
border-width: 0.2em;
vertical-align: -0.125em; /* Align spinner better with text */
}
.alert { /* General alert styling */
padding: var(--base-padding);
margin-top: var(--base-margin);
border: 1px solid transparent;
border-radius: 4px;
}
.alert-danger {
color: #842029;
background-color: #f8d7da;
border-color: #f5c2c7;
}
/* Add more specific styling if needed */
</style>
@@ -118,66 +118,133 @@ const handleSave = (savedSetting: NotificationSetting) => {
<style scoped>
.notification-settings {
padding: var(--base-padding, 1rem); /* 使用变量 */
/* Inherits text color and background from parent */
}
.loading-indicator, .error-message {
margin-top: var(--base-margin, 1rem); /* 使用变量 */
color: var(--text-color-secondary); /* 使用次要文本颜色 */
}
.error-message {
color: var(--bs-danger); /* 保留 Bootstrap 变量或特定错误颜色 */
padding: var(--base-padding);
/* Inherits text color and background from parent (NotificationsView) */
}
/* Apply variables to list items if needed (assuming Bootstrap classes handle most styling) */
.list-group-item {
background-color: var(--app-bg-color);
border-color: var(--border-color);
color: var(--text-color);
h2 {
color: var(--text-color);
margin-bottom: calc(var(--base-margin) * 2);
padding-bottom: var(--base-margin);
border-bottom: 1px solid var(--border-color);
}
.list-group-item .text-muted {
color: var(--text-color-secondary);
.loading-indicator, .error-message, .alert-info {
margin-top: var(--base-margin);
padding: var(--base-padding);
border-radius: 4px;
color: var(--text-color-secondary);
background-color: var(--header-bg-color); /* Use header bg for subtle background */
border: 1px solid var(--border-color);
}
/* Apply variables to buttons if not handled by global styles or Bootstrap */
.error-message {
color: #dc3545; /* Keep specific error color */
border-color: #dc3545;
background-color: #f8d7da; /* Light red background for errors */
}
.alert-info {
color: var(--text-color); /* Use primary text color for info */
}
.btn { /* General button styling */
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
margin: var(--base-margin) 0; /* Add some default margin */
}
.btn-primary {
background-color: var(--button-bg-color);
border-color: var(--button-bg-color);
border: 1px solid var(--button-bg-color);
color: var(--button-text-color);
}
.btn-primary:hover {
background-color: var(--button-hover-bg-color);
border-color: var(--button-hover-bg-color);
color: var(--button-text-color);
}
.btn-outline-secondary {
color: var(--text-color-secondary);
border-color: var(--border-color);
border: 1px solid var(--border-color);
background-color: transparent;
}
.btn-outline-secondary:hover {
background-color: var(--header-bg-color); /* Example hover */
background-color: var(--header-bg-color);
color: var(--text-color);
border-color: var(--border-color);
}
.btn-outline-danger {
color: var(--bs-danger); /* Keep specific color */
border-color: var(--bs-danger);
color: #dc3545; /* Keep specific danger color */
border: 1px solid #dc3545;
background-color: transparent;
}
.btn-outline-danger:hover {
background-color: var(--bs-danger);
background-color: #dc3545;
color: var(--button-text-color);
border-color: #dc3545;
}
/* Apply variables to badges if needed */
.list-group {
list-style: none;
padding: 0;
margin-top: var(--base-margin);
}
.list-group-item {
background-color: var(--app-bg-color);
border: 1px solid var(--border-color);
color: var(--text-color);
padding: var(--base-padding);
margin-bottom: var(--base-margin); /* Space between items */
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.list-group-item:last-child {
margin-bottom: 0;
}
.list-group-item strong {
color: var(--text-color);
}
.list-group-item .text-muted {
color: var(--text-color-secondary);
font-size: 0.9em;
margin-top: calc(var(--base-margin) / 2);
}
.badge {
padding: 0.3em 0.6em;
font-size: 0.8em;
border-radius: 0.25rem;
font-weight: bold;
}
.badge.bg-secondary {
background-color: var(--text-color-secondary);
color: var(--button-text-color); /* Assuming high contrast needed */
color: var(--app-bg-color); /* Use app background for contrast */
}
.badge.bg-success {
background-color: #198754; /* Keep specific success color */
color: #fff;
}
.badge.bg-warning {
background-color: #ffc107; /* Keep specific warning color */
color: #000; /* Black text for better contrast on yellow */
}
/* Keep success/warning colors for status or define specific variables later */
/* .badge.bg-success {} */
/* .badge.bg-warning {} */
.modal-placeholder {
margin-top: calc(var(--base-margin, 1rem) * 2); /* 使用变量 */
padding: var(--base-padding, 1rem); /* 使用变量 */
border: 1px dashed var(--border-color, #ccc); /* 使用变量 */
background-color: var(--header-bg-color, #f8f9fa); /* 使用变量 */
margin-top: calc(var(--base-margin) * 3);
padding: var(--base-padding);
border: 1px solid var(--border-color);
background-color: var(--header-bg-color);
border-radius: 4px;
}
</style>
@@ -517,77 +517,87 @@ const formatXtermLabel = (key: keyof ITheme): string => {
<style scoped>
.style-customizer-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
inset: 0; /* top, right, bottom, left = 0 */
background-color: rgba(0, 0, 0, 0.6); /* 更深的遮罩 */
display: flex;
justify-content: center;
align-items: center;
z-index: 1000; /* 确保在顶层 */
z-index: 1000;
}
.style-customizer-panel {
background-color: var(--app-bg-color, #fff);
color: var(--text-color, #333);
background-color: var(--app-bg-color);
color: var(--text-color);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
width: 80%;
max-width: 700px; /* 最大宽度 */
max-height: 80vh; /* 最大高度 */
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
width: 90%;
max-width: 800px; /* 增加最大宽度 */
height: 85vh; /* 使用视口高度 */
max-height: 700px; /* 限制最大高度 */
display: flex;
flex-direction: column;
overflow: hidden; /* 防止内容溢出 */
overflow: hidden;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--base-padding, 1rem);
border-bottom: 1px solid var(--border-color, #ccc);
background-color: var(--header-bg-color, #f0f0f0); /* 使用头部背景色 */
padding: calc(var(--base-padding) * 0.8) var(--base-padding); /* 调整内边距 */
border-bottom: 1px solid var(--border-color);
background-color: var(--header-bg-color);
flex-shrink: 0; /* 防止头部被压缩 */
}
.panel-header h2 {
margin: 0;
font-size: 1.2rem;
font-size: 1.25rem; /* 稍大标题 */
color: var(--text-color);
}
.close-button {
background: none;
border: none;
font-size: 1.5rem;
font-size: 1.8rem; /* 增大关闭按钮 */
line-height: 1;
cursor: pointer;
color: var(--text-color-secondary, #666);
color: var(--text-color-secondary);
padding: 0.2rem 0.5rem;
border-radius: 4px;
}
.close-button:hover {
color: var(--text-color);
background-color: rgba(0,0,0,0.1);
}
.panel-content {
display: flex;
flex-grow: 1;
overflow-y: auto; /* 内部滚动 */
overflow: hidden; /* 防止内部滚动条影响布局 */
}
.panel-nav {
width: 150px; /* 固定导航宽度 */
border-right: 1px solid var(--border-color, #ccc);
padding: var(--base-padding, 1rem);
background-color: var(--header-bg-color, #f0f0f0); /* 轻微区分背景 */
flex-shrink: 0; /* 防止导航栏被压缩 */
width: 180px; /* 增加导航宽度 */
border-right: 1px solid var(--border-color);
padding: var(--base-padding);
background-color: var(--header-bg-color);
flex-shrink: 0;
overflow-y: auto; /* 导航内部滚动 */
}
.panel-nav button {
display: block;
width: 100%;
padding: 0.5rem;
margin-bottom: 0.5rem;
padding: 0.7rem 0.8rem; /* 增加导航按钮内边距 */
margin-bottom: var(--base-margin);
text-align: left;
background: none;
border: 1px solid transparent;
border-radius: 4px;
cursor: pointer;
color: var(--text-color, #333);
color: var(--text-color);
font-size: 0.95rem;
transition: background-color 0.2s ease, color 0.2s ease;
}
.panel-nav button:hover {
@@ -595,222 +605,328 @@ const formatXtermLabel = (key: keyof ITheme): string => {
}
.panel-nav button.active {
background-color: var(--link-active-color, #007bff);
color: var(--button-text-color, #fff);
background-color: var(--button-bg-color); /* 使用按钮背景色 */
color: var(--button-text-color);
font-weight: bold;
}
.panel-nav button:disabled {
opacity: 0.6;
opacity: 0.5;
cursor: not-allowed;
background-color: transparent !important; /* 确保禁用时背景透明 */
color: var(--text-color-secondary, #999); /* 禁用时文字颜色变灰 */
background-color: transparent !important;
color: var(--text-color-secondary);
}
.panel-main {
flex-grow: 1;
padding: var(--base-padding, 1rem);
padding: var(--base-padding) calc(var(--base-padding) * 1.5); /* 增加左右内边距 */
overflow-y: auto; /* 主要内容区域滚动 */
}
.panel-main h3 {
margin-top: 0;
border-bottom: 1px solid var(--border-color, #ccc);
padding-bottom: 0.5rem;
margin-bottom: 1rem;
border-bottom: 1px solid var(--border-color);
padding-bottom: var(--base-margin);
margin-bottom: calc(var(--base-margin) * 2);
font-size: 1.15rem;
color: var(--text-color);
}
.panel-main h4 {
margin-top: 1.5rem;
margin-bottom: 0.8rem;
margin-top: calc(var(--base-margin) * 2.5);
margin-bottom: var(--base-margin);
color: var(--text-color);
font-size: 1.05rem;
}
.panel-main p {
.panel-main p:not(.error-message):not(.setting-description) {
color: var(--text-color-secondary);
font-size: 0.9rem;
margin-bottom: 1.5rem;
line-height: 1.6;
margin-bottom: calc(var(--base-margin) * 1.5);
}
.setting-description {
font-size: 0.85rem;
color: var(--text-color-secondary);
margin-top: -0.5rem; /* 减少与上方元素的间距 */
margin-bottom: 1rem;
margin-top: calc(var(--base-margin) / -2); /* 减少与上方元素的间距 */
margin-bottom: var(--base-margin);
}
.form-group {
margin-bottom: 1rem;
display: flex; /* 使用 flex 布局 */
align-items: center; /* 垂直居中对齐 */
flex-wrap: wrap; /* 允许换行 */
margin-bottom: calc(var(--base-margin) * 1.5);
display: grid;
/* Define grid columns: Auto label, flexible control, auto button */
grid-template-columns: auto minmax(0, 1fr) auto; /* Let label width adjust */
align-items: center; /* Vertically center items in the row */
gap: calc(var(--base-margin) * 1.5); /* Increase gap slightly for better spacing */
}
/* Adjust grid for rows without a third element (like inline buttons) */
.form-group > *:nth-child(2):last-child {
grid-column: 2 / 4; /* Let the second element span if it's the last */
}
/* Specific adjustments for theme editor rows if needed */
section[v-if*="isEditingTheme"] .form-group {
/* Keep 2 columns for editor: auto label + flexible input */
grid-template-columns: auto 1fr;
margin-bottom: var(--base-margin);
gap: var(--base-margin); /* Keep editor gap smaller */
}
.form-group label {
/* display: inline-block; */
min-width: 150px; /* 调整标签最小宽度以适应更长的文本 */
margin-right: 0.5rem;
/* vertical-align: middle; */
text-align: right; /* 标签右对齐 */
padding-right: 5px; /* 标签和输入框间距 */
flex-shrink: 0; /* 防止标签被压缩 */
grid-column: 1 / 2;
text-align: left; /* Keep text aligned to the left */
/* justify-self: start; Removed */
padding-right: 0; /* Ensure no right padding interferes */
padding-left: 0; /* Ensure no left padding interferes */
color: var(--text-color);
font-size: 0.9rem;
margin-bottom: 0;
/* white-space: nowrap; Removed in case it affects alignment */
overflow: hidden;
text-overflow: ellipsis;
font-weight: 500; /* 稍微加粗标签 */
/* Ensure it behaves predictably within the grid cell */
display: block; /* Or inline-block if needed, but block is usually fine */
width: 100%; /* Occupy the auto-calculated width */
}
.form-group input[type="color"] {
/* vertical-align: middle; */
border: 1px solid var(--border-color);
padding: 2px;
cursor: pointer;
width: 150px; /* 统一输入框宽度 */
height: 30px; /* 增加高度 */
}
.form-group input[type="text"].text-input {
/* vertical-align: middle; */
border: 1px solid var(--border-color);
padding: 4px 6px;
border-radius: 3px;
width: 150px; /* 统一文本输入框宽度 */
flex-grow: 1; /* 允许输入框扩展 */
min-width: 100px; /* 最小宽度 */
}
.form-group input[type="text"].wide-input {
/* width: calc(100% - 200px); */ /* 调整宽度以适应按钮 */
/* min-width: 200px; */
flex-grow: 1; /* 占据更多空间 */
}
/* 输入控件 */
.form-group input[type="color"],
.form-group input[type="text"].text-input,
.form-group select {
padding: 4px 6px;
grid-column: 2 / 3;
border: 1px solid var(--border-color);
border-radius: 3px;
flex-grow: 1;
min-width: 150px;
padding: 0.5rem 0.7rem;
border-radius: 4px;
font-size: 0.9rem;
background-color: var(--app-bg-color);
color: var(--text-color);
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s ease, box-shadow 0.2s ease; /* 添加过渡效果 */
}
.form-group input[type="range"] {
flex-grow: 1;
margin: 0 10px;
.form-group input[type="color"] {
padding: 2px;
height: 34px;
min-width: 50px;
max-width: 70px;
justify-self: start;
border-radius: 4px; /* 保持圆角一致 */
}
.form-group input:focus, .form-group select:focus {
border-color: var(--link-active-color);
outline: 0;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.15); /* 调整聚焦阴影 */
}
/* Input controls (text, color, select) */
.form-group input[type="color"],
.form-group input[type="text"].text-input,
.form-group select {
grid-column: 2 / 3; /* Place in the second column */
/* Existing styles below... */
border: 1px solid var(--border-color);
padding: 0.5rem 0.7rem;
border-radius: 4px;
font-size: 0.9rem;
background-color: var(--app-bg-color);
color: var(--text-color);
width: 100%;
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; /* 保持圆角一致 */
}
.form-group input:focus, .form-group select:focus {
border-color: var(--link-active-color);
outline: 0;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.15); /* 调整聚焦阴影 */
}
.panel-footer {
display: flex;
justify-content: flex-end;
padding: var(--base-padding, 1rem);
border-top: 1px solid var(--border-color, #ccc);
background-color: var(--footer-bg-color, #f0f0f0); /* 使用底部背景色 */
/* Inline buttons within form-group */
.form-group .button-inline,
.form-group .button-danger {
grid-column: 3 / 4; /* Place in the third column */
margin-left: 0; /* Reset margin if needed */
padding: 0.4rem 0.8rem;
font-size: 0.9rem;
border: 1px solid var(--border-color);
white-space: nowrap;
justify-self: start;
border-radius: 4px; /* 统一圆角 */
transition: background-color 0.2s ease, border-color 0.2s ease; /* 添加过渡 */
}
.panel-footer button {
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
margin-left: 0.5rem;
border: 1px solid transparent;
}
.button-primary {
background-color: var(--button-bg-color, #007bff);
color: var(--button-text-color, #fff);
border-color: var(--button-bg-color, #007bff);
}
.button-primary:hover {
background-color: var(--button-hover-bg-color, #0056b3);
border-color: var(--button-hover-bg-color, #0056b3);
}
.button-secondary {
background-color: #6c757d; /* 暂时硬编码,后续可改为变量 */
color: #fff;
border-color: #6c757d;
}
.button-secondary:hover {
background-color: #5a6268;
border-color: #545b62;
}
.button-inline {
margin-left: 10px;
padding: 4px 8px;
/* vertical-align: middle; */
flex-shrink: 0; /* 防止按钮被压缩 */
background-color: var(--header-bg-color); /* Default inline button style */
color: var(--text-color);
}
.form-group .button-inline:hover:not(:disabled) {
background-color: var(--border-color);
border-color: var(--text-color-secondary);
}
/* Danger button specific styles remain */
.form-group .button-danger {
background-color: #f8d7da;
color: #842029;
border-color: #f5c2c7;
}
.form-group .button-danger:hover:not(:disabled) {
background-color: #f1aeb5;
border-color: #ec8a98;
}
.form-group .button-danger:disabled,
.form-group .button-inline:disabled {
opacity: 0.6;
cursor: not-allowed;
}
hr {
border: none;
border-top: 1px solid var(--border-color, #eee);
margin: 1.5rem 0;
border-top: 1px solid var(--border-color);
margin: calc(var(--base-padding) * 2) 0;
}
/* Theme Management Styles */
.theme-management-buttons {
margin-top: 1rem;
margin-bottom: 1rem;
margin-top: var(--base-padding);
margin-bottom: calc(var(--base-padding) * 1.5);
display: flex;
gap: 10px; /* 按钮间距 */
flex-wrap: wrap; /* 允许换行 */
gap: var(--base-margin);
flex-wrap: wrap;
padding-bottom: var(--base-padding);
border-bottom: 1px dashed var(--border-color);
}
/* Apply unified styles to theme management buttons - matching button-inline */
.theme-management-buttons button {
padding: 0.5rem 1rem;
padding: 0.4rem 0.8rem; /* Match button-inline */
font-size: 0.9rem; /* Match button-inline */
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--header-bg-color); /* Match button-inline */
color: var(--text-color);
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease;
white-space: nowrap; /* Match button-inline */
}
.theme-management-buttons button:hover:not(:disabled) {
background-color: var(--border-color); /* Match button-inline hover */
border-color: var(--text-color-secondary);
}
.theme-management-buttons button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.theme-list {
list-style: none;
padding: 0;
margin-top: 1rem;
max-height: 200px; /* 限制列表高度并滚动 */
margin-top: 0;
max-height: 280px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--app-bg-color);
}
.theme-list li {
display: flex;
justify-content: space-between;
display: grid; /* 使用 Grid 布局列表项 */
grid-template-columns: 1fr auto; /* 名称弹性,按钮固定 */
align-items: center;
padding: 0.5rem 1rem;
padding: 0.7rem 1rem;
border-bottom: 1px solid var(--border-color);
font-size: 0.95rem;
transition: background-color 0.2s ease;
gap: var(--base-margin); /* 列间距 */
}
.theme-list li:hover {
background-color: var(--header-bg-color);
}
.theme-list li:last-child {
border-bottom: none;
}
.theme-list li span { /* 主题名称 */
grid-column: 1 / 2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.theme-list li.preset-theme span {
font-style: italic;
color: var(--text-color-secondary);
}
.theme-actions {
flex-shrink: 0; /* 防止按钮组被压缩 */
grid-column: 2 / 3; /* 按钮组在第二列 */
flex-shrink: 0;
display: flex;
gap: 0.5rem;
}
/* Apply unified styles to theme action buttons - matching button-inline */
.theme-actions button {
margin-left: 0.5rem;
padding: 2px 6px;
font-size: 0.8rem;
margin-left: 0;
padding: 0.4rem 0.8rem; /* Corrected padding to match button-inline */
font-size: 0.9rem; /* Corrected font size to match button-inline */
border: 1px solid var(--border-color);
border-radius: 4px; /* Match border-radius */
background-color: var(--header-bg-color); /* Default style */
color: var(--text-color);
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease;
white-space: nowrap;
}
.button-danger {
background-color: #dc3545;
color: white;
border-color: #dc3545;
.theme-actions button:hover:not(:disabled) {
background-color: var(--border-color);
border-color: var(--text-color-secondary);
}
.button-danger:hover {
background-color: #c82333;
border-color: #bd2130;
/* Specific style for danger button within theme actions */
/* Specific style for danger button within theme actions */
.theme-actions button.button-danger {
/* Danger colors override default */
background-color: #f8d7da;
color: #842029;
border-color: #f5c2c7;
/* Size and padding are inherited from the base .theme-actions button rule */
}
.button-danger:disabled {
opacity: 0.5;
.theme-actions button.button-danger:hover:not(:disabled) {
/* Danger hover overrides default hover */
background-color: #f1aeb5;
border-color: #ec8a98;
}
.theme-actions button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.editor-footer {
margin-top: 1.5rem;
margin-top: var(--base-padding);
display: flex;
justify-content: flex-end;
gap: 10px;
gap: var(--base-margin);
padding-top: var(--base-padding);
border-top: 1px solid var(--border-color);
}
.editor-footer button { /* 确保页脚按钮样式统一 */
padding: 0.6rem 1.2rem;
border-radius: 4px;
font-weight: bold;
}
/* Background Styles */
.background-preview {
width: 100%;
height: 100px;
height: 150px;
border: 1px dashed var(--border-color);
margin-bottom: 10px;
margin-bottom: var(--base-margin);
display: flex;
justify-content: center;
align-items: center;
@@ -818,21 +934,115 @@ hr {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
border-radius: 4px;
background-color: var(--header-bg-color);
position: relative;
overflow: hidden; /* 防止背景图溢出圆角 */
}
.background-preview span {
background-color: rgba(255, 255, 255, 0.8); /* 增加背景不透明度 */
padding: 0.4rem 0.8rem; /* 增加内边距 */
border-radius: 3px;
font-size: 0.9rem;
font-weight: 500;
color: var(--text-color); /* 使用主文本颜色 */
box-shadow: 0 1px 2px rgba(0,0,0,0.1); /* 添加轻微阴影 */
}
.background-controls {
display: flex;
gap: 10px;
margin-bottom: 1rem;
gap: var(--base-margin);
margin-bottom: var(--base-padding);
flex-wrap: wrap;
align-items: center;
}
.background-controls button {
padding: 0.5rem 1rem;
/* Style default buttons in background-controls - matching button-inline */
.background-controls button:not(.button-danger) {
padding: 0.4rem 0.8rem; /* Match button-inline */
font-size: 0.9rem; /* Match button-inline */
border: 1px solid var(--border-color);
border-radius: 4px;
background-color: var(--header-bg-color); /* Match button-inline */
color: var(--text-color);
cursor: pointer;
transition: background-color 0.2s ease, border-color 0.2s ease;
white-space: nowrap; /* Match button-inline */
}
.background-controls button:not(.button-danger):hover:not(:disabled) {
background-color: var(--border-color); /* Match button-inline hover */
border-color: var(--text-color-secondary);
}
/* Ensure danger button styles override default if necessary */
.background-controls button.button-danger {
/* Keep specific danger styles */
padding: 0.4rem 0.8rem; /* Match padding */
font-size: 0.9rem; /* Match font size */
border-radius: 4px; /* Match border radius */
white-space: nowrap; /* Match button-inline */
background-color: #f8d7da; /* 淡红色背景 */
color: #842029; /* 深红色文字 */
border-color: #f5c2c7; /* 边框颜色 */
}
.background-controls button.button-danger:hover:not(:disabled) {
background-color: #f1aeb5;
border-color: #ec8a98;
}
.background-controls button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.error-message {
color: red;
font-size: 0.9rem;
margin-top: 5px;
width: 100%; /* 确保错误消息占满宽度 */
color: #842029;
background-color: #f8d7da;
border: 1px solid #f5c2c7;
padding: calc(var(--base-padding) * 0.75);
border-radius: 4px;
margin-top: var(--base-margin);
font-size: 0.9rem;
width: 100%;
box-sizing: border-box;
grid-column: 1 / -1; /* 错误消息横跨所有列 */
}
.panel-footer {
display: flex;
justify-content: flex-end;
padding: var(--base-padding);
border-top: 1px solid var(--border-color);
background-color: var(--footer-bg-color);
flex-shrink: 0;
}
.panel-footer button {
padding: 0.6rem 1.2rem;
border-radius: 4px;
cursor: pointer;
margin-left: var(--base-margin);
border: 1px solid transparent;
font-weight: bold;
}
.panel-footer .button-primary {
background-color: var(--button-bg-color);
color: var(--button-text-color);
border-color: var(--button-bg-color);
}
.panel-footer .button-primary:hover:not(:disabled) {
background-color: var(--button-hover-bg-color);
border-color: var(--button-hover-bg-color);
}
.panel-footer .button-secondary {
background-color: var(--header-bg-color);
color: var(--text-color);
border-color: var(--border-color);
}
.panel-footer .button-secondary:hover:not(:disabled) {
background-color: var(--border-color);
}
.panel-footer button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>
+185 -97
View File
@@ -574,200 +574,288 @@ onMounted(async () => {
<style scoped>
.settings-view {
padding: var(--base-padding, 20px); /* 使用变量,保留默认值 */
padding: var(--base-padding);
color: var(--text-color);
background-color: var(--app-bg-color);
}
.settings-section {
margin-bottom: calc(var(--base-margin, 0.5rem) * 3); /* 调整间距 */
padding: var(--base-padding, 20px); /* 使用变量 */
border: 1px solid var(--border-color, #ccc); /* 使用变量 */
border-radius: 5px;
background-color: var(--app-bg-color); /* 确保背景色一致 */
h1 {
margin-bottom: calc(var(--base-margin) * 3);
padding-bottom: var(--base-margin);
border-bottom: 1px solid var(--border-color);
}
.settings-section {
margin-bottom: calc(var(--base-margin) * 4); /* 增加区域间距 */
padding: calc(var(--base-padding) * 1.5); /* 增加区域内边距 */
border: 1px solid var(--border-color);
border-radius: 6px; /* 稍圆润的边角 */
background-color: var(--app-bg-color);
/* box-shadow: 0 1px 3px rgba(0,0,0,0.05); */ /* 可选:添加轻微阴影 */
}
.settings-section h2 {
font-size: 1.3rem;
color: var(--text-color);
margin-top: 0;
margin-bottom: calc(var(--base-margin) * 2);
padding-bottom: var(--base-margin);
border-bottom: 1px dashed var(--border-color); /* 虚线分隔 */
}
.settings-section p:not([class*="-message"]) { /* 普通段落样式 */
color: var(--text-color-secondary);
line-height: 1.6;
margin-bottom: var(--base-margin);
}
.setting-description { /* 特定描述文本 */
font-size: 0.9em;
color: var(--text-color-secondary);
margin-bottom: var(--base-margin);
}
.form-group {
margin-bottom: 15px;
margin-bottom: calc(var(--base-margin) * 1.5);
}
label {
display: block;
margin-bottom: 5px;
margin-bottom: calc(var(--base-margin) / 2);
font-weight: bold;
color: var(--text-color);
}
input[type="password"],
input[type="text"],
input[type="number"], /* 添加 number 类型 */
textarea,
select { /* Add select style */
select {
width: 100%;
padding: 8px; /* 保持特定内边距 */
padding: 0.6rem 0.8rem; /* 调整内边距 */
box-sizing: border-box;
border: 1px solid var(--border-color, #ccc); /* 使用变量 */
border: 1px solid var(--border-color);
border-radius: 4px;
font-family: var(--font-family-sans-serif, sans-serif); /* 使用变量 */
font-size: inherit;
color: var(--text-color); /* 确保输入文本颜色 */
background-color: var(--app-bg-color); /* 确保输入背景色 */
font-family: var(--font-family-sans-serif);
font-size: 1rem;
color: var(--text-color);
background-color: var(--app-bg-color);
transition: border-color 0.2s ease;
}
input:focus, textarea:focus, select:focus {
border-color: var(--link-active-color); /* 聚焦时高亮边框 */
outline: 0;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.15); /* 细微的聚焦阴影 */
}
textarea {
resize: vertical;
min-height: 80px;
min-height: 100px;
}
small {
display: block;
margin-top: 5px;
margin-top: calc(var(--base-margin) / 2);
font-size: 0.85em;
color: var(--text-color-secondary, #666); /* 使用变量 */
color: var(--text-color-secondary);
}
button {
padding: 10px 15px;
button, .btn { /* 统一按钮样式 */
padding: 0.6rem 1.2rem; /* 调整按钮内边距 */
cursor: pointer;
background-color: var(--button-bg-color, #007bff); /* 使用变量 */
color: var(--button-text-color, #ffffff); /* 使用变量 */
border: none; /* 移除默认边框 */
background-color: var(--button-bg-color);
color: var(--button-text-color);
border: 1px solid var(--button-bg-color); /* 添加边框 */
border-radius: 4px;
font-weight: bold;
transition: background-color 0.2s ease, border-color 0.2s ease;
margin-right: var(--base-margin); /* 按钮间距 */
}
button:last-of-type, .btn:last-of-type {
margin-right: 0;
}
button:hover:not(:disabled) {
background-color: var(--button-hover-bg-color, #0056b3); /* 使用变量 */
button:hover:not(:disabled), .btn:hover:not(:disabled) {
background-color: var(--button-hover-bg-color);
border-color: var(--button-hover-bg-color);
}
button:disabled {
button:disabled, .btn:disabled {
cursor: not-allowed;
opacity: 0.6;
}
/* 次要按钮样式 (例如取消按钮) */
button[type="button"], .btn-secondary {
background-color: var(--header-bg-color);
color: var(--text-color);
border-color: var(--border-color);
}
button[type="button"]:hover:not(:disabled), .btn-secondary:hover:not(:disabled) {
background-color: var(--border-color);
border-color: var(--border-color);
}
hr {
border: none;
border-top: 1px solid var(--border-color, #eee); /* 使用变量 */
margin: 30px 0;
border-top: 1px solid var(--border-color);
margin: calc(var(--base-margin) * 4) 0; /* 增加分隔线间距 */
}
code {
background-color: var(--header-bg-color, #f1f1f1); /* 使用变量 */
padding: 2px 4px;
background-color: var(--header-bg-color);
padding: 0.2em 0.4em;
border-radius: 3px;
color: var(--text-color); /* 确保代码文本颜色 */
color: var(--text-color);
font-family: monospace;
font-size: 0.9em;
}
img {
display: block;
margin: 10px 0;
margin: var(--base-margin) auto; /* 居中显示 */
max-width: 200px;
border: 1px solid var(--border-color);
padding: 5px;
background-color: white; /* 确保二维码背景是白色 */
}
.success-message {
color: green;
margin-top: 10px;
color: #198754; /* Bootstrap success color */
background-color: #d1e7dd; /* Light green background */
border: 1px solid #a3cfbb;
padding: var(--base-padding);
border-radius: 4px;
margin-top: var(--base-margin);
}
.error-message {
color: red;
margin-top: 10px;
color: #842029; /* Bootstrap danger color */
background-color: #f8d7da; /* Light red background */
border: 1px solid #f5c2c7;
padding: var(--base-padding);
border-radius: 4px;
margin-top: var(--base-margin);
}
.loading-message {
margin-top: var(--base-margin);
color: var(--text-color-secondary);
font-style: italic;
}
/* Blacklist Table Styles */
.blacklist-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
margin-top: var(--base-padding);
font-size: 0.95rem;
}
.blacklist-table th,
.blacklist-table td {
border: 1px solid var(--border-color, #ddd); /* 使用变量 */
padding: 8px;
border: 1px solid var(--border-color);
padding: 0.75rem; /* 调整单元格内边距 */
text-align: left;
vertical-align: middle;
}
.blacklist-table th {
background-color: var(--header-bg-color);
font-weight: bold;
color: var(--text-color);
}
.blacklist-table tr:nth-child(even) {
background-color: var(--header-bg-color); /* 斑马纹 */
}
.blacklist-table .btn-danger {
background-color: #dc3545;
color: var(--button-text-color);
border: none;
padding: 0.3rem 0.6rem; /* 调整小按钮内边距 */
border-radius: 4px;
cursor: pointer;
font-size: 0.9em;
}
.blacklist-table .btn-danger:disabled {
background-color: #f8d7da;
cursor: not-allowed;
opacity: 0.7;
}
/* 复选框组样式 */
.form-group-checkbox {
display: flex;
align-items: center;
margin-bottom: var(--base-margin); /* 确保与其他组间距一致 */
}
.form-group-checkbox input[type="checkbox"] {
width: auto; /* 不要占满宽度 */
margin-right: 10px;
width: auto;
margin-right: 0.6rem; /* 调整复选框和标签间距 */
flex-shrink: 0; /* 防止复选框被压缩 */
appearance: none; /* 自定义样式 */
background-color: var(--app-bg-color);
border: 1px solid var(--border-color);
width: 1.1em;
height: 1.1em;
border-radius: 3px;
cursor: pointer;
position: relative;
top: 2px; /* 微调垂直对齐 */
}
.form-group-checkbox input[type="checkbox"]:checked {
background-color: var(--button-bg-color);
border-color: var(--button-bg-color);
}
/* 添加勾选标记 */
.form-group-checkbox input[type="checkbox"]:checked::after {
content: '✔';
position: absolute;
color: var(--button-text-color);
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 0.8em;
}
.form-group-checkbox label {
display: inline-block; /* 让标签和复选框在同一行 */
margin-bottom: 0; /* 移除默认的块级标签下边距 */
display: inline-block;
margin-bottom: 0;
cursor: pointer;
font-weight: normal; /* 普通标签字体重量 */
}
.blacklist-table th {
background-color: var(--header-bg-color, #f2f2f2); /* 使用变量 */
font-weight: bold;
color: var(--text-color); /* 确保表头文本颜色 */
}
.blacklist-table .btn-danger {
background-color: #dc3545; /* 保留危险色 */
color: var(--button-text-color, white); /* 使用变量 */
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
.blacklist-table .btn-danger:disabled {
background-color: #f8d7da;
cursor: not-allowed;
}
.loading-message {
margin-top: 15px;
color: var(--text-color-secondary, #666); /* 使用变量 */
}
/* Pagination Styles (Optional) */
.pagination {
margin-top: 15px;
display: flex;
justify-content: center;
align-items: center;
}
.pagination button {
margin: 0 5px;
}
.pagination span {
margin: 0 10px;
}
/* Blacklist Settings Form Styles */
.blacklist-settings-form {
margin-top: 15px;
margin-top: var(--base-padding);
padding-top: var(--base-padding);
border-top: 1px dashed var(--border-color);
}
.blacklist-settings-form .inline-group {
display: inline-block;
margin-right: 20px;
margin-bottom: 10px;
display: inline-flex; /* 使用 flex 布局 */
align-items: center; /* 垂直居中 */
margin-right: calc(var(--base-margin) * 2);
margin-bottom: var(--base-margin);
}
.blacklist-settings-form .inline-group label {
display: inline-block;
margin-right: 5px;
width: auto;
margin-bottom: 0;
margin-right: var(--base-margin);
margin-bottom: 0; /* 移除 label 下边距 */
white-space: nowrap; /* 防止标签换行 */
}
.blacklist-settings-form .inline-group input[type="number"] {
width: 80px;
display: inline-block;
padding: 6px;
width: 80px; /* 固定宽度 */
padding: 0.5rem; /* 调整内边距 */
}
.blacklist-settings-form button {
vertical-align: bottom;
vertical-align: middle; /* 尝试对齐按钮 */
}
.blacklist-settings-form p {
margin-top: 10px;
margin-top: var(--base-margin);
}
</style>