diff --git a/.env.example b/.env.example index bd8cb55..0fe4cbf 100644 --- a/.env.example +++ b/.env.example @@ -17,3 +17,12 @@ SMTP_PASS= WIKIDOT_BOT_USER= WIKIDOT_BOT_PASS= + +# 开发环境身份切换开关(/api/dev/login) +# 该接口能直接签发任意角色的 JWT,默认关闭。 +# 本地调试时设为 1,并先执行 node scripts/dev-seed.js 造账号。 +# 生产环境即使误设也不会生效(NODE_ENV=production 时无条件 404)。 +ENABLE_DEV_LOGIN= + +# dev-seed.js 写入的测试账号口令(可选,未设置时用内置默认值) +DEV_SEED_PASSWORD= diff --git a/README.md b/README.md index b73f474..328a93f 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,7 @@ WikitDB-Server/ - **白然** — WikitDB LOGO 设计师 - **Kakushi** - Wikit创始人,Wikit API运维 - **UMOU** - 贡献者 +- **OxygenNine** - ui-redesign - 每一位为 Wikidot 社区贡献原创内容的创作者 ## 许可证 diff --git a/components/AuthorActivityChart.js b/components/AuthorActivityChart.js index d599218..568f367 100644 --- a/components/AuthorActivityChart.js +++ b/components/AuthorActivityChart.js @@ -2,6 +2,34 @@ import React, { useEffect, useRef, useState } from 'react'; // 核心修复:直接使用 auto 全自动注册,彻底解决漏引组件导致的致命闪退 import Chart from 'chart.js/auto'; +const isDark = () => typeof document !== 'undefined' && document.documentElement.classList.contains('dark'); + +// canvas 无法读取 CSS 变量,按当前主题返回具体色值 +const getChartColors = () => { + if (isDark()) { + return { + bar: 'rgba(139, 92, 246, 0.85)', + barBorder: 'rgb(139, 92, 246)', + tooltipBg: 'rgba(24, 24, 27, 0.96)', + tooltipTitle: '#f4f4f5', + tooltipBody: '#a1a1aa', + tooltipBorder: 'rgba(63, 63, 70, 1)', + grid: 'rgba(255, 255, 255, 0.05)', + ticks: '#a1a1aa', + }; + } + return { + bar: 'rgba(139, 92, 246, 0.85)', + barBorder: 'rgb(139, 92, 246)', + tooltipBg: 'rgba(255, 255, 255, 0.96)', + tooltipTitle: '#18181b', + tooltipBody: '#52525b', + tooltipBorder: 'rgba(228, 228, 231, 1)', + grid: 'rgba(0, 0, 0, 0.06)', + ticks: '#52525b', + }; +}; + export default function AuthorActivityChart({ data = [] }) { const canvasRef = useRef(null); const chartInstance = useRef(null); @@ -55,6 +83,8 @@ export default function AuthorActivityChart({ data = [] }) { const ctx = canvasRef.current.getContext('2d'); + const colors = getChartColors(); + chartInstance.current = new Chart(ctx, { type: 'bar', data: { @@ -63,8 +93,8 @@ export default function AuthorActivityChart({ data = [] }) { { label: '发布页面数', data: pagesData, - backgroundColor: 'rgba(99, 102, 241, 0.85)', - borderColor: 'rgb(99, 102, 241)', + backgroundColor: colors.bar, + borderColor: colors.barBorder, borderWidth: 1, barPercentage: 0.9, categoryPercentage: 1.0, @@ -77,10 +107,10 @@ export default function AuthorActivityChart({ data = [] }) { plugins: { legend: { display: false }, tooltip: { - backgroundColor: 'rgba(23,23,23,0.96)', - titleColor: '#fff', - bodyColor: 'rgb(200,200,200)', - borderColor: 'rgba(255,255,255,0.1)', + backgroundColor: colors.tooltipBg, + titleColor: colors.tooltipTitle, + bodyColor: colors.tooltipBody, + borderColor: colors.tooltipBorder, borderWidth: 1, callbacks: { label: function(context) { @@ -98,16 +128,38 @@ export default function AuthorActivityChart({ data = [] }) { scales: { x: { grid: { display: false }, - ticks: { color: 'rgb(110, 118, 129)', maxRotation: 45 } + ticks: { color: colors.ticks, maxRotation: 45 } }, y: { beginAtZero: true, - grid: { color: 'rgba(255, 255, 255, 0.05)' }, - ticks: { color: 'rgb(110, 118, 129)', stepSize: 1 } + grid: { color: colors.grid }, + ticks: { color: colors.ticks, stepSize: 1 } } } } }); + + // 亮暗主题切换时重设 canvas 配色(canvas 不支持 CSS 变量,需 JS 侧感知) + const applyThemeColors = () => { + const chart = chartInstance.current; + if (!chart) return; + const c = getChartColors(); + chart.data.datasets[0].backgroundColor = c.bar; + chart.data.datasets[0].borderColor = c.barBorder; + chart.options.plugins.tooltip.backgroundColor = c.tooltipBg; + chart.options.plugins.tooltip.titleColor = c.tooltipTitle; + chart.options.plugins.tooltip.bodyColor = c.tooltipBody; + chart.options.plugins.tooltip.borderColor = c.tooltipBorder; + chart.options.scales.x.ticks.color = c.ticks; + chart.options.scales.y.ticks.color = c.ticks; + chart.options.scales.y.grid.color = c.grid; + chart.update('none'); + }; + + const themeObserver = new MutationObserver(applyThemeColors); + themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); + + return () => themeObserver.disconnect(); } catch (err) { console.error("图表引擎渲染异常:", err); setChartError(err.message); @@ -118,7 +170,7 @@ export default function AuthorActivityChart({ data = [] }) { return (
{this.state.message}
+{this.state.message}
diff --git a/components/Footer.js b/components/Footer.js index b38e646..4c7819a 100644 --- a/components/Footer.js +++ b/components/Footer.js @@ -9,7 +9,7 @@ const Footer = () => { return ( <> -