mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/* 图片预览样式 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -89,8 +89,7 @@
|
||||
"newUsername": "Новое имя пользователя (опционально)",
|
||||
"passwordHint": "Пароль должен быть не менее 8 символов",
|
||||
"confirmPasswordHint": "Введите новый пароль еще раз",
|
||||
"usernameHint": "Оставьте пустым, если не хотите менять имя пользователя",
|
||||
"defaultCredentials": "Логин и пароль по умолчанию: astrbot"
|
||||
"usernameHint": "Оставьте пустым, если не хотите менять имя пользователя"
|
||||
},
|
||||
"validation": {
|
||||
"passwordRequired": "Введите пароль",
|
||||
|
||||
@@ -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": "Автосинхронизация с системной темой"
|
||||
}
|
||||
|
||||
@@ -90,8 +90,7 @@
|
||||
"newUsername": "新用户名 (可选)",
|
||||
"passwordHint": "密码长度至少 8 位",
|
||||
"confirmPasswordHint": "请再次输入新密码以确认",
|
||||
"usernameHint": "留空表示不修改用户名",
|
||||
"defaultCredentials": "初始用户名:astrbot,请使用 `astrbot conf admin` 设置密码"
|
||||
"usernameHint": "留空表示不修改用户名"
|
||||
},
|
||||
"validation": {
|
||||
"passwordRequired": "请输入密码",
|
||||
|
||||
@@ -23,5 +23,9 @@
|
||||
"save": "保存并刷新",
|
||||
"cancel": "取消",
|
||||
"tooltip": "服务器配置"
|
||||
}
|
||||
},
|
||||
"presetName": "预设名称",
|
||||
"presetUrl": "预设地址",
|
||||
"addPreset": "添加预设",
|
||||
"autoTheme": "自动跟随系统主题"
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user