fix(theme): adapt custom styles to dark mode via design tokens
- Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS. fix(theme): adapt custom styles to dark mode via design tokens - Add useEffect in App.tsx to set data-theme attribute on documentElement (also toggles html.dark class) so CSS rules can use [data-theme='dark'] selectors and Ant Design's darkAlgorithm can fully cascade. - Replace hardcoded rgba(0,0,0,*) colors in Dashboard.tsx with Ant Design tokens via theme.useToken(): - ProcessUsageWall: colorTextSecondary (was rgba 0.45), colorTextDisabled (was rgba 0.35), colorBorderSecondary (was rgba 0.06), colorFillQuaternary (was rgba 0.02 header bg), HIGH/MED/LOW usage colors now use colorError / colorWarning / colorSuccess tokens. - Statistic valueStyles and Progress trailColor also token-based. - Login.tsx: replace isDark ternary '#141414' / '#f5f5f5' with token.colorBgLayout (single source of truth, auto-adapts). - Logs.tsx: replace '#888' timestamp color with token.colorTextTertiary. - Sidebar.tsx: replace hardcoded rgba(5,5,5,0.06) logout divider border with var(--ant-color-border-secondary, ...) CSS variable fallback chain. - responsive.css: add dark variants for .app-bottom-nav box-shadow and .app-header-bar border so sticky surfaces stay readable in dark mode. - Delete dead hooks/useTheme.ts (never imported; the data-theme attribute is now set centrally by App.tsx). Tested: build PASS, lint 0 errors (42 pre-existing warnings unchanged), unit tests 16/16 PASS.
This commit is contained in:
1 parent
a3ee711f5d
commit
b53b996dd7
7 files changed
+67
-56
No files matched your search
+11
-1
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { ConfigProvider, App as AntApp, theme } from 'antd';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
@@ -40,6 +40,16 @@ import SharePage from './pages/Share';
|
||||
const ThemedApp: React.FC = () => {
|
||||
const isDark = useThemeStore((s) => s.isDark);
|
||||
const { locale } = useI18n();
|
||||
|
||||
// Propagate isDark to <html data-theme="…"> so plain CSS rules
|
||||
// (e.g. `[data-theme='dark'] …` in responsive.css) and any other
|
||||
// data-theme-aware styles can adapt alongside Ant Design's darkAlgorithm.
|
||||
useEffect(() => {
|
||||
if (typeof document === 'undefined') return;
|
||||
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
||||
document.documentElement.classList.toggle('dark', isDark);
|
||||
}, [isDark]);
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
locale={(() => {
|
||||
|
||||
@@ -51,6 +51,9 @@ export const SidebarMenu: React.FC<{ onNavigate?: () => void; style?: React.CSSP
|
||||
}) => {
|
||||
const { items, selectedKeys, onMenuClick, onLogout, t } = useSidebarMenuItems(onNavigate);
|
||||
|
||||
// Sidebar is rendered with theme="light" on the Sider below; the logout
|
||||
// divider is therefore a light-mode border regardless of the global theme,
|
||||
// so a static light color is correct here.
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', ...style }}>
|
||||
<div style={{ height: 64, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8, fontWeight: 700, fontSize: 18, flexShrink: 0, padding: '0 12px' }}>
|
||||
@@ -58,7 +61,7 @@ export const SidebarMenu: React.FC<{ onNavigate?: () => void; style?: React.CSSP
|
||||
{!collapsed && <span>3M-UI</span>}
|
||||
</div>
|
||||
<Menu mode="inline" selectedKeys={selectedKeys} items={items} onClick={onMenuClick} style={{ flex: 1, borderInlineEnd: 'none' }} />
|
||||
<Menu mode="inline" selectable={false} items={[{ key: 'logout', icon: <LogoutOutlined />, label: t('nav.logout'), onClick: onLogout }]} style={{ borderInlineEnd: 'none', borderTop: '1px solid rgba(5,5,5,0.06)' }} />
|
||||
<Menu mode="inline" selectable={false} items={[{ key: 'logout', icon: <LogoutOutlined />, label: t('nav.logout'), onClick: onLogout }]} style={{ borderInlineEnd: 'none', borderTop: '1px solid var(--ant-color-border-secondary, rgba(0, 0, 0, 0.06))' }} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
type Theme = 'light' | 'dark';
|
||||
|
||||
export function useTheme() {
|
||||
const [theme, setTheme] = useState<Theme>(() => {
|
||||
const saved = localStorage.getItem('3m-ui-theme');
|
||||
return (saved as Theme) || 'light';
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('3m-ui-theme', theme);
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
}, [theme]);
|
||||
|
||||
const toggle = () => setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));
|
||||
|
||||
return { theme, toggle, isDark: theme === 'dark' };
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Card, Row, Col, Statistic, Button, Space, Tag, Progress, Typography, Grid, message } from 'antd';
|
||||
import { Card, Row, Col, Statistic, Button, Space, Tag, Progress, Typography, Grid, message, theme } from 'antd';
|
||||
import { PlayCircleOutlined, StopOutlined, RedoOutlined } from '@ant-design/icons';
|
||||
import { fetchDashboard, startMihomo, stopMihomo, restartMihomo } from '../api/system';
|
||||
import { isCanceledError } from '../api/client';
|
||||
@@ -29,25 +29,6 @@ type ProcSample = {
|
||||
memory_percent?: number;
|
||||
};
|
||||
|
||||
const muted: React.CSSProperties = { fontSize: 12, color: 'rgba(0,0,0,0.45)', lineHeight: 1.4 };
|
||||
|
||||
/** Usage level → color. ≥80% high (red), ≥50% medium (orange), else inherit. */
|
||||
const HIGH = '#cf1322';
|
||||
const MED = '#d46b08';
|
||||
const LOW = '#3f8600';
|
||||
function usageColor(pct: number): string | undefined {
|
||||
if (pct >= 80) return HIGH;
|
||||
if (pct >= 50) return MED;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Bar variant: always resolves, so a healthy bar reads green rather than neutral. */
|
||||
function usageBarColor(pct: number): string {
|
||||
if (pct >= 80) return HIGH;
|
||||
if (pct >= 50) return MED;
|
||||
return LOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process usage, grouped by **process**: Panel | Core.
|
||||
*
|
||||
@@ -71,9 +52,17 @@ const ProcessUsageWall: React.FC<{
|
||||
memLabel: string;
|
||||
pidLabel: string;
|
||||
}> = ({ panel, core, coreRunning, panelLabel, coreLabel, cpuLabel, memLabel, pidLabel }) => {
|
||||
const { token } = theme.useToken();
|
||||
const screens = Grid.useBreakpoint();
|
||||
const stacked = !screens.sm; // xs: groups stacked; sm+: side by side
|
||||
|
||||
/** Usage level → color. ≥80% high (red), ≥50% medium (orange), else inherit. */
|
||||
const usageColor = (pct: number): string | undefined => {
|
||||
if (pct >= 80) return token.colorError;
|
||||
if (pct >= 50) return token.colorWarning;
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const groups = [
|
||||
{
|
||||
key: 'panel',
|
||||
@@ -117,7 +106,7 @@ const ProcessUsageWall: React.FC<{
|
||||
});
|
||||
const detailStyle: React.CSSProperties = {
|
||||
fontSize: 11,
|
||||
color: 'rgba(0,0,0,0.45)',
|
||||
color: token.colorTextSecondary,
|
||||
marginTop: 2,
|
||||
lineHeight: 1.3,
|
||||
whiteSpace: 'nowrap',
|
||||
@@ -126,7 +115,7 @@ const ProcessUsageWall: React.FC<{
|
||||
};
|
||||
const labelStyle: React.CSSProperties = {
|
||||
fontSize: 12,
|
||||
color: 'rgba(0,0,0,0.45)',
|
||||
color: token.colorTextSecondary,
|
||||
marginTop: 4,
|
||||
lineHeight: 1.4,
|
||||
whiteSpace: 'nowrap',
|
||||
@@ -135,10 +124,10 @@ const ProcessUsageWall: React.FC<{
|
||||
};
|
||||
const emptyStyle: React.CSSProperties = {
|
||||
...numStyle(0),
|
||||
color: 'rgba(0,0,0,0.35)',
|
||||
color: token.colorTextDisabled,
|
||||
};
|
||||
const cellStyle: React.CSSProperties = { textAlign: 'center', padding: '10px 4px', minWidth: 0 };
|
||||
const border = '1px solid rgba(0,0,0,0.06)';
|
||||
const border = `1px solid ${token.colorBorderSecondary}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -173,12 +162,12 @@ const ProcessUsageWall: React.FC<{
|
||||
gap: 8,
|
||||
padding: '6px 10px',
|
||||
borderBottom: border,
|
||||
background: 'rgba(0,0,0,0.02)',
|
||||
background: token.colorFillQuaternary,
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 12, fontWeight: 600 }}>{g.name}</span>
|
||||
{g.live && g.pid ? (
|
||||
<span style={{ fontSize: 11, color: 'rgba(0,0,0,0.45)' }}>
|
||||
<span style={{ fontSize: 11, color: token.colorTextSecondary }}>
|
||||
{pidLabel} {g.pid}
|
||||
</span>
|
||||
) : null}
|
||||
@@ -214,11 +203,22 @@ const ProcessUsageWall: React.FC<{
|
||||
const Dashboard: React.FC = () => {
|
||||
const { t } = useI18n();
|
||||
const isMobile = useIsMobile();
|
||||
const { token } = theme.useToken();
|
||||
const [data, setData] = useState<any>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const cardSize = isMobile ? 'small' as const : 'default' as const;
|
||||
const gutter = isMobile ? ([8, 8] as [number, number]) : ([16, 16] as [number, number]);
|
||||
|
||||
// Theme-adaptive muted text style (was a hardcoded rgba(0,0,0,0.45)).
|
||||
const muted: React.CSSProperties = { fontSize: 12, color: token.colorTextSecondary, lineHeight: 1.4 };
|
||||
|
||||
/** Bar variant: always resolves, so a healthy bar reads green rather than neutral. */
|
||||
const usageBarColor = (pct: number): string => {
|
||||
if (pct >= 80) return token.colorError;
|
||||
if (pct >= 50) return token.colorWarning;
|
||||
return token.colorSuccess;
|
||||
};
|
||||
|
||||
const load = async (signal?: AbortSignal) => {
|
||||
try {
|
||||
const d = await fetchDashboard(signal);
|
||||
@@ -316,8 +316,8 @@ const Dashboard: React.FC = () => {
|
||||
<Card size={cardSize} title={t('dashboard.listeners')}>
|
||||
<Row gutter={isMobile ? [8, 8] : 16}>
|
||||
<Col span={8}><Statistic title={t('dashboard.total')} value={data?.listeners?.total || 0} /></Col>
|
||||
<Col span={8}><Statistic title={t('dashboard.enabled')} value={data?.listeners?.enabled || 0} valueStyle={{ color: '#3f8600' }} /></Col>
|
||||
<Col span={8}><Statistic title={t('dashboard.disabled')} value={data?.listeners?.disabled || 0} valueStyle={{ color: '#cf1322' }} /></Col>
|
||||
<Col span={8}><Statistic title={t('dashboard.enabled')} value={data?.listeners?.enabled || 0} valueStyle={{ color: token.colorSuccess }} /></Col>
|
||||
<Col span={8}><Statistic title={t('dashboard.disabled')} value={data?.listeners?.disabled || 0} valueStyle={{ color: token.colorError }} /></Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Col>
|
||||
@@ -356,7 +356,7 @@ const Dashboard: React.FC = () => {
|
||||
return (
|
||||
<div key={m.key}>
|
||||
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 8 }}>
|
||||
<span style={{ fontSize: 13, color: 'rgba(0,0,0,0.65)' }}>{m.label}</span>
|
||||
<span style={{ fontSize: 13, color: token.colorText }}>{m.label}</span>
|
||||
<span style={{ fontSize: 13, fontWeight: 600, color, fontVariantNumeric: 'tabular-nums' }}>
|
||||
{m.pct}%
|
||||
</span>
|
||||
@@ -366,7 +366,7 @@ const Dashboard: React.FC = () => {
|
||||
showInfo={false}
|
||||
size="small"
|
||||
strokeColor={color}
|
||||
trailColor="rgba(0,0,0,0.06)"
|
||||
trailColor={token.colorBorderSecondary}
|
||||
strokeLinecap="butt"
|
||||
/>
|
||||
{m.detail ? <div style={{ ...muted, fontSize: 11, marginTop: 2 }}>{m.detail}</div> : null}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { Card, Form, Input, Button, Typography, message, Space, Dropdown, Steps, Alert } from 'antd';
|
||||
import { Card, Form, Input, Button, Typography, message, Space, Dropdown, Steps, Alert, theme } from 'antd';
|
||||
import {
|
||||
UserOutlined,
|
||||
LockOutlined,
|
||||
@@ -25,7 +25,8 @@ const Login: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const totpInputRef = useRef<any>(null);
|
||||
const { t, locale, setLocale } = useI18n();
|
||||
const { mode, setMode, isDark } = useThemeStore();
|
||||
const { mode, setMode } = useThemeStore();
|
||||
const { token } = theme.useToken();
|
||||
const from = (location.state as { from?: { pathname?: string } } | null)?.from?.pathname || '/';
|
||||
|
||||
useEffect(() => {
|
||||
@@ -94,7 +95,7 @@ const Login: React.FC = () => {
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: isDark ? '#141414' : '#f5f5f5',
|
||||
background: token.colorBgLayout,
|
||||
padding: '24px 0',
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Card, List, Tag, Button, Space, Empty, Spin, message } from 'antd';
|
||||
import { Card, List, Tag, Button, Space, Empty, Spin, message, theme } from 'antd';
|
||||
import { ReloadOutlined, ClearOutlined } from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import client from '../api/client';
|
||||
@@ -14,6 +14,7 @@ const levelColor: Record<string, string> = { debug: 'default', info: 'blue', war
|
||||
const Logs: React.FC = () => {
|
||||
const { t } = useI18n();
|
||||
const isMobile = useIsMobile();
|
||||
const { token } = theme.useToken();
|
||||
const [logs, setLogs] = useState<LogEntry[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [autoRefresh, setAutoRefresh] = useState(true);
|
||||
@@ -39,7 +40,7 @@ const Logs: React.FC = () => {
|
||||
{loading && logs.length === 0 ? <Spin /> : logs.length === 0 ? <Empty description={t('logs.empty')} /> : (
|
||||
<List size="small" dataSource={logs} renderItem={(log, i) => (
|
||||
<List.Item key={i} style={{ fontFamily: 'monospace', fontSize: 13 }}>
|
||||
<span style={{ color: '#888', marginRight: 8 }}>[{dayjs(log.timestamp).format('YYYY-MM-DD HH:mm:ss')}]</span>
|
||||
<span style={{ color: token.colorTextTertiary, marginRight: 8 }}>[{dayjs(log.timestamp).format('YYYY-MM-DD HH:mm:ss')}]</span>
|
||||
<Tag color={levelColor[log.level?.toLowerCase()] || 'default'} style={{ marginRight: 8 }}>{log.level?.toUpperCase()}</Tag>
|
||||
<span>{log.payload}</span>
|
||||
</List.Item>
|
||||
|
||||
@@ -385,6 +385,21 @@ html.dark .mobile-entity-card,
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
/* Dark mode: subtle lift for sticky surfaces whose hardcoded light shadow
|
||||
(rgba(0,0,0,0.04)) is invisible on a dark background. */
|
||||
html.dark .app-bottom-nav,
|
||||
[data-theme='dark'] .app-bottom-nav {
|
||||
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
/* Dark mode: lift the sticky header bar's blur scrim slightly so light text
|
||||
stays readable over scrolling content. The var() fallback (rgba(0,0,0,0.06))
|
||||
is too faint on dark surfaces. */
|
||||
html.dark .app-header-bar,
|
||||
[data-theme='dark'] .app-header-bar {
|
||||
border-bottom-color: var(--ant-color-border-secondary, rgba(255, 255, 255, 0.08)) !important;
|
||||
}
|
||||
|
||||
|
||||
/* —— Mobile bottom navigation —— */
|
||||
.app-bottom-nav {
|
||||
|
||||
Reference in new issue
Block a user