fix(dashboard): ReactorBg eased scope, CSS comments, theme types, and chat text color

- ReactorBg.vue: fix eased variable scoping bug (moved to outer loop scope)
- WelcomePage.vue: fix CSS // comments (not valid in SCSS)
- DiamondBg.vue: fix CSS // comment in style block
- ThemeType.ts: add missing MD3 hyphenated color properties
- AddNewPlatform.vue: add optional chaining and emits declaration
- FullLayout.vue: console.error -> console.warn for backend timeout
- ConsoleDisplayer.vue: add content-type based log line coloring
- VerticalHeader.vue + i18n: remove deprecated defaultCredentials hint
- MessageList.vue: fix user/bot bubble text color for dark mode
This commit is contained in:
LIghtJUNction
2026-03-29 21:24:39 +08:00
parent 0c021494aa
commit 7fc1a13519
14 changed files with 138 additions and 55 deletions

View File

@@ -6,7 +6,11 @@
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
import { onMounted, onUnmounted, ref, computed } from "vue";
import { useCustomizerStore } from "@/stores/customizer";
const customizer = useCustomizerStore();
const isDark = computed(() => customizer.isDarkTheme);
const bgEl = ref<HTMLElement | null>(null);
const canvasEl = ref<HTMLCanvasElement | null>(null);
@@ -44,9 +48,10 @@ function draw() {
const W = width;
const H = height;
const dark = isDark.value;
// clear
ctx.fillStyle = "#0A0A0C";
ctx.fillStyle = dark ? "#0A0A0C" : "#FFFFFF";
ctx.fillRect(0, 0, W, H);
const cols = Math.ceil(W / GRID) + 1;
@@ -56,7 +61,7 @@ function draw() {
const my = smoothY.value;
// draw static base grid (very faint)
ctx.strokeStyle = "rgba(255, 255, 255, 0.03)";
ctx.strokeStyle = dark ? "rgba(255, 255, 255, 0.03)" : "rgba(0, 49, 83, 0.03)";
ctx.lineWidth = 0.5;
for (let x = 0; x <= W; x += GRID) {
ctx.beginPath();
@@ -95,11 +100,12 @@ function draw() {
if (dist < ENERGY_RADIUS) {
const t = 1 - dist / ENERGY_RADIUS;
// eased
const eased = t * t * (3 - 2 * t);
crossAlpha = 0.05 + eased * 0.35;
crossAlpha = dark
? 0.05 + eased * 0.35
: 0.04 + eased * 0.4;
crossScale = 1.0 - eased * SINK_DEPTH;
crossBlue = Math.floor(eased * 180);
crossBlue = dark ? Math.floor(eased * 180) : 0;
}
if (crossAlpha < 0.01) continue;
@@ -107,7 +113,9 @@ function draw() {
const halfLen = CROSS_SIZE * crossScale;
const strokeColor = crossBlue > 0
? `rgba(${crossBlue * 0.3}, ${crossBlue * 0.8}, ${crossBlue}, ${crossAlpha})`
: `rgba(255, 255, 255, ${crossAlpha})`;
: dark
? `rgba(255, 255, 255, ${crossAlpha})`
: `rgba(26, 46, 60, ${crossAlpha})`;
ctx.strokeStyle = strokeColor;
ctx.lineWidth = 0.4;
@@ -120,13 +128,21 @@ function draw() {
}
}
// core Cherenkov dot at exact mouse position
// core mouse dot at exact mouse position
if (mx > 0 && my > 0 && mx < W && my < H) {
const grad = ctx.createRadialGradient(mx, my, 0, mx, my, 6);
grad.addColorStop(0, "rgba(0, 242, 255, 0.95)");
grad.addColorStop(0.3, "rgba(0, 210, 255, 0.6)");
grad.addColorStop(1, "rgba(0, 180, 255, 0)");
ctx.fillStyle = grad;
if (dark) {
const grad = ctx.createRadialGradient(mx, my, 0, mx, my, 6);
grad.addColorStop(0, "rgba(0, 242, 255, 0.95)");
grad.addColorStop(0.3, "rgba(0, 210, 255, 0.6)");
grad.addColorStop(1, "rgba(0, 180, 255, 0)");
ctx.fillStyle = grad;
} else {
const grad = ctx.createRadialGradient(mx, my, 0, mx, my, 6);
grad.addColorStop(0, "rgba(0, 49, 83, 0.4)");
grad.addColorStop(0.3, "rgba(0, 49, 83, 0.15)");
grad.addColorStop(1, "rgba(0, 49, 83, 0)");
ctx.fillStyle = grad;
}
ctx.beginPath();
ctx.arc(mx, my, 6, 0, Math.PI * 2);
ctx.fill();
@@ -173,6 +189,11 @@ onUnmounted(() => {
background: #0a0a0c;
}
/* Light mode: clean white */
.v-theme--bluebusinesstheme .bg {
background: #FFFFFF;
}
.bg-canvas {
position: absolute;
inset: 0;

View File

@@ -30,7 +30,7 @@
:class="{ 'has-audio': hasAudio(msg.content.message) }"
:style="{
backgroundColor: 'var(--v-theme-chatMessageBubble)',
color: 'rgba(228, 225, 230, 0.9) !important',
color: '#E2E2E7 !important',
}"
>
<!-- 遍历 message parts -->
@@ -55,11 +55,7 @@
<!-- 纯文本 -->
<pre
v-else-if="part.type === 'plain' && part.text"
style="
font-family: inherit;
white-space: pre-wrap;
word-wrap: break-word;
"
class="bubble-text"
>{{ part.text }}</pre
>
@@ -189,7 +185,7 @@
class="message-bubble bot-bubble"
:style="{
backgroundColor: 'var(--v-theme-chatAssistantBubble)',
color: 'rgba(228, 225, 230, 0.9) !important',
color: '#E2E2E7 !important',
}"
>
<!-- Loading state -->
@@ -1255,7 +1251,7 @@ export default {
.loading-text {
font-size: 14px;
color: var(--v-theme-secondaryText);
color: var(--v-theme-on-surface-variant);
animation: pulse 1.5s ease-in-out infinite;
}
@@ -1359,7 +1355,7 @@ export default {
.message-time {
font-size: 12px;
color: var(--v-theme-secondaryText);
color: var(--v-theme-on-surface-variant);
opacity: 0.7;
white-space: nowrap;
}
@@ -1367,7 +1363,7 @@ export default {
/* Agent Stats Info Icon */
.stats-info-icon {
margin-left: 6px;
color: var(--v-theme-secondaryText);
color: var(--v-theme-on-surface-variant);
opacity: 0.6;
cursor: pointer;
transition: opacity 0.2s ease;
@@ -1448,7 +1444,7 @@ export default {
.reply-quote-text {
font-size: 13px;
color: var(--v-theme-secondaryText);
color: var(--v-theme-on-surface-variant);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -1470,7 +1466,7 @@ export default {
}
.user-bubble {
color: var(--v-theme-primaryText);
color: var(--v-theme-on-surface);
padding: 12px 18px;
font-size: 15px;
max-width: 60%;
@@ -1479,7 +1475,7 @@ export default {
.bot-bubble {
border: 1px solid var(--v-theme-border);
color: var(--v-theme-primaryText);
color: var(--v-theme-on-surface);
font-size: 16px;
max-width: 100%;
padding-left: 12px;
@@ -1625,6 +1621,11 @@ export default {
line-height: 1.6;
}
/* Bubble text: hardcoded for debugging - #E2E2E7 = BlueBusinessDark primaryText */
.bubble-text {
color: #E2E2E7 !important;
}
/* Stats Menu 样式 */
.stats-menu-card {
border-radius: 8px !important;
@@ -1647,14 +1648,14 @@ export default {
.stats-menu-label {
font-size: 13px;
color: var(--v-theme-secondaryText);
color: var(--v-theme-on-surface-variant);
}
.stats-menu-value {
font-size: 13px;
font-weight: 600;
font-family: "Fira Code", "Consolas", monospace;
color: var(--v-theme-primaryText);
color: var(--v-theme-on-surface);
}
/* 图片预览样式 */

View File

@@ -208,7 +208,7 @@ export default {
}
},
parseAnsiLog(log: string): { text: string; color: string } {
parseAnsiLog(log: string): { text: string; color: string; borderColor?: string } {
// ANSI color code map
const ansiMap: Record<string, string> = {
"\u001b[1;34m": "#39C5BB",
@@ -219,6 +219,29 @@ export default {
"\u001b[0m": "inherit",
"\u001b[32m": "#69F0AE",
};
// Content-based color differentiation: system, private, group, platform
const lowerLog = log.toLowerCase();
if (lowerLog.includes("· astrbot") || lowerLog.includes("· reactor")) {
// System messages: cyan-teal
return { text: log, color: "#00F2FF", borderColor: "system" };
}
if (lowerLog.includes("[private")) {
// Private messages: warm green
return { text: log, color: "#69F0AE", borderColor: "private" };
}
if (lowerLog.includes("[group")) {
// Group messages: soft periwinkle blue
return { text: log, color: "#8fb6d2", borderColor: "group" };
}
if (lowerLog.includes("telegram") || lowerLog.includes("discord") || lowerLog.includes("qq ") || lowerLog.includes("onebot")) {
// Platform adapter messages: soft purple
return { text: log, color: "#B39DDB", borderColor: "platform" };
}
if (lowerLog.includes("error") || lowerLog.includes("failed") || lowerLog.includes("exception")) {
// Error indicators keep default treatment
}
let color = "rgba(255,255,255,0.75)";
for (const [code, c] of Object.entries(ansiMap)) {
if (log.startsWith(code)) {
@@ -234,7 +257,7 @@ export default {
const ele = document.getElementById("term");
if (!ele) return;
const { text, color } = this.parseAnsiLog(log);
const { text, color, borderColor } = this.parseAnsiLog(log);
const line = document.createElement("div");
line.classList.add("log-line");
@@ -242,6 +265,9 @@ export default {
if (level) {
line.classList.add(`log-line-${level.toLowerCase()}`);
}
if (borderColor) {
line.classList.add(`log-line-${borderColor}`);
}
line.innerText = text;
line.style.color = color;
@@ -431,6 +457,20 @@ export default {
box-shadow: inset 2px 0 0 rgba(0, 242, 255, 0.3);
}
/* Content-type left border indicators */
:deep(.log-line-system) {
box-shadow: inset 3px 0 0 #00F2FF !important;
}
:deep(.log-line-private) {
box-shadow: inset 3px 0 0 #69F0AE !important;
}
:deep(.log-line-group) {
box-shadow: inset 3px 0 0 #8fb6d2 !important;
}
:deep(.log-line-platform) {
box-shadow: inset 3px 0 0 #B39DDB !important;
}
/* New entry pulse animation */
:deep(.log-line) {
animation: entryPulse 0.25s ease-out;

View File

@@ -33,7 +33,7 @@ function draw() {
const isDark = customizer.isDarkTheme;
// Background
ctx.fillStyle = isDark ? "#050507" : "#F2F5F8";
ctx.fillStyle = isDark ? "#050507" : "#FFFFFF";
ctx.fillRect(0, 0, W, H);
const cols = Math.ceil(W / GRID) + 1;
@@ -42,10 +42,10 @@ function draw() {
const mx = smoothX;
const my = smoothY;
// Grid lines — dark mode: faint white, light mode: faint deep-blue
// Grid lines — dark mode: faint white, light mode: nearly invisible
ctx.strokeStyle = isDark
? "rgba(255, 255, 255, 0.025)"
: "rgba(26, 46, 60, 0.04)";
: "rgba(0, 49, 83, 0.03)";
ctx.lineWidth = 0.5;
for (let x = 0; x <= W; x += GRID) {
ctx.beginPath();

View File

@@ -90,8 +90,7 @@
"newUsername": "New Username (Optional)",
"passwordHint": "Password must be at least 8 characters",
"confirmPasswordHint": "Please enter new password again to confirm",
"usernameHint": "Leave blank to keep current username",
"defaultCredentials": "Default username: astrbot. Use `astrbot conf admin` to set your password"
"usernameHint": "Leave blank to keep current username"
},
"validation": {
"passwordRequired": "Please enter password",

View File

@@ -23,5 +23,9 @@
"save": "Save & Reload",
"cancel": "Cancel",
"tooltip": "Server Configuration"
}
},
"presetName": "Preset Name",
"presetUrl": "Preset URL",
"addPreset": "Add Preset",
"autoTheme": "Auto Sync with System Theme"
}

View File

@@ -89,8 +89,7 @@
"newUsername": "Новое имя пользователя (опционально)",
"passwordHint": "Пароль должен быть не менее 8 символов",
"confirmPasswordHint": "Введите новый пароль еще раз",
"usernameHint": "Оставьте пустым, если не хотите менять имя пользователя",
"defaultCredentials": "Логин и пароль по умолчанию: astrbot"
"usernameHint": "Оставьте пустым, если не хотите менять имя пользователя"
},
"validation": {
"passwordRequired": "Введите пароль",

View File

@@ -3,11 +3,29 @@
"username": "Имя пользователя",
"password": "Пароль",
"defaultHint": "Сначала выполните `astrbot conf admin` для настройки учётной записи администратора.",
"shareLink": "Поделиться ссылкой",
"linkCopied": "Ссылка скопирована в буфер обмена",
"linkCopyFailed": "Не удалось скопировать ссылку",
"logo": {
"title": "AstrBot Звёздная Панель"
},
"theme": {
"switchToDark": "Перейти на темную тему",
"switchToLight": "Перейти на светлую тему"
}
},
"serverConfig": {
"title": "Конфигурация сервера",
"description": "Если бэкенд находится не на том же источнике (хост/порт), укажите полный URL здесь.",
"label": "Базовый URL API",
"placeholder": "напр. http://localhost:6185",
"hint": "Пусто для значения по умолчанию (относительный путь)",
"presetLabel": "Быстрый выбор пресета",
"save": "Сохранить и перезагрузить",
"cancel": "Отмена",
"tooltip": "Конфигурация сервера"
},
"presetName": "Название пресета",
"presetUrl": "URL пресета",
"addPreset": "Добавить пресет",
"autoTheme": "Автосинхронизация с системной темой"
}

View File

@@ -90,8 +90,7 @@
"newUsername": "新用户名 (可选)",
"passwordHint": "密码长度至少 8 位",
"confirmPasswordHint": "请再次输入新密码以确认",
"usernameHint": "留空表示不修改用户名",
"defaultCredentials": "初始用户名astrbot请使用 `astrbot conf admin` 设置密码"
"usernameHint": "留空表示不修改用户名"
},
"validation": {
"passwordRequired": "请输入密码",

View File

@@ -23,5 +23,9 @@
"save": "保存并刷新",
"cancel": "取消",
"tooltip": "服务器配置"
}
},
"presetName": "预设名称",
"presetUrl": "预设地址",
"addPreset": "添加预设",
"autoTheme": "自动跟随系统主题"
}

View File

@@ -52,7 +52,7 @@ const checkMigration = async (): Promise<boolean> => {
return true;
}
} catch (error) {
console.error("Failed to check migration status:", error);
console.warn("Failed to check migration status (backend may not be running):", error);
}
return false;
};
@@ -78,7 +78,7 @@ const maybeShowFirstNotice = async () => {
localStorage.setItem(FIRST_NOTICE_SEEN_KEY, "1");
} catch (error) {
console.error("Failed to load first notice:", error);
console.warn("Failed to load first notice (backend may not be running):", error);
}
};

View File

@@ -1201,10 +1201,6 @@ const isChristmas = computed(() => {
class="mb-3"
/>
</v-form>
<div class="text-caption text-medium-emphasis mt-2">
{{ t("core.header.accountDialog.form.defaultCredentials") }}
</div>
</v-card-text>
<v-divider />

View File

@@ -5,6 +5,7 @@ export type ThemeTypes = {
colors: {
primary?: string;
secondary?: string;
tertiary?: string;
info?: string;
success?: string;
accent?: string;
@@ -23,6 +24,7 @@ export type ThemeTypes = {
border?: string;
inputBorder?: string;
containerBg?: string;
"on-surface-variant-bg"?: string;
surface?: string;
background?: string;
overlay?: string;
@@ -47,6 +49,7 @@ export type ThemeTypes = {
"on-surface"?: string;
"surface-variant"?: string;
surfaceTint?: string;
outline?: string;
"outline-variant"?: string;
"inverse-surface"?: string;
"inverse-on-surface"?: string;

View File

@@ -662,13 +662,12 @@ watch(showProviderDialog, async (visible, wasVisible) => {
font-family: "JetBrains Mono", "Fira Code", monospace !important;
font-size: clamp(1.8rem, 4vw, 3rem) !important;
font-weight: 700 !important;
/* Restrained precision — readable gray, not flashy neon */
color: rgba(228, 225, 230, 0.85) !important;
color: var(--v-theme-on-surface) !important;
letter-spacing: 0.5px;
position: relative;
padding-left: 16px;
animation: welcomeFadeIn 0.8s ease-out both;
/* 2px thin precision tick mark (not a glowing bar) */
/* Dark: cyan tick mark; Light: prussian blue tick mark */
&::before {
content: "";
position: absolute;
@@ -677,7 +676,7 @@ watch(showProviderDialog, async (visible, wasVisible) => {
transform: translateY(-50%);
width: 2px;
height: 55%;
background: rgba(0, 242, 255, 0.45);
background: rgba(var(--v-theme-primary), 0.45);
border-radius: 1px;
}
}
@@ -685,7 +684,7 @@ watch(showProviderDialog, async (visible, wasVisible) => {
.welcome-page .text-subtitle-1 {
font-family: "JetBrains Mono", monospace !important;
font-size: 0.9rem !important;
color: rgba(228, 225, 230, 0.4) !important;
color: var(--v-theme-on-surface-variant) !important;
animation: welcomeFadeIn 0.8s ease-out 0.3s both;
letter-spacing: 0.3px;
}
@@ -693,11 +692,11 @@ watch(showProviderDialog, async (visible, wasVisible) => {
.welcome-page .text-h3 {
font-family: "JetBrains Mono", monospace !important;
font-weight: 600 !important;
color: rgba(228, 225, 230, 0.75) !important;
color: var(--v-theme-on-surface) !important;
font-size: 1rem !important;
letter-spacing: 0.5px;
text-transform: uppercase;
border-left: 2px solid rgba(0, 242, 255, 0.3) !important;
border-left: 2px solid rgba(var(--v-theme-primary), 0.3) !important;
padding-left: 10px !important;
}