Просмотр исходного кода

feat(ui): add shared MailHub indigo theme tokens

AI-Co-Authored-By: Grok
chendeben 1 месяц назад
Родитель
Сommit
735d9fa221
5 измененных файлов с 115 добавлено и 51 удалено
  1. 2 19
      src/frontend/App.tsx
  2. 2 15
      src/frontend/auth/main.tsx
  3. 36 17
      src/frontend/styles.css
  4. 60 0
      src/frontend/theme.ts
  5. 15 0
      test/frontend-theme.test.js

+ 2 - 19
src/frontend/App.tsx

@@ -17,6 +17,7 @@ import { I18nProvider, useI18n } from './i18n/react';
 import { buildDnsApplyFeedback } from './domain-model.js';
 import { buildDnsApplyFeedback } from './domain-model.js';
 import { api } from './services/api';
 import { api } from './services/api';
 import './styles.css';
 import './styles.css';
+import { mailhubTheme } from './theme';
 import type {
 import type {
   AddDomainPayload,
   AddDomainPayload,
   ApiToken,
   ApiToken,
@@ -62,25 +63,7 @@ const viewTitleKeys: Record<ViewKey, string> = {
 
 
 export default function App() {
 export default function App() {
   return (
   return (
-    <ConfigProvider
-      theme={{
-        token: {
-          colorPrimary: '#1677ff',
-          borderRadius: 10,
-          colorBgLayout: '#f5f7fb',
-          colorBorderSecondary: '#e5eaf2'
-        },
-        components: {
-          Card: {
-            borderRadiusLG: 12
-          },
-          Table: {
-            cellPaddingBlock: 14,
-            cellPaddingInline: 14
-          }
-        }
-      }}
-    >
+    <ConfigProvider theme={mailhubTheme}>
       <AntApp>
       <AntApp>
         <I18nProvider>
         <I18nProvider>
           <MailHubConsole />
           <MailHubConsole />

+ 2 - 15
src/frontend/auth/main.tsx

@@ -3,24 +3,11 @@ import { App as AntApp, ConfigProvider } from 'antd';
 
 
 import { I18nProvider } from '../i18n/react';
 import { I18nProvider } from '../i18n/react';
 import '../styles.css';
 import '../styles.css';
+import { mailhubTheme } from '../theme';
 import { AuthApp } from './AuthApp';
 import { AuthApp } from './AuthApp';
 
 
 createRoot(document.getElementById('auth-root')!).render(
 createRoot(document.getElementById('auth-root')!).render(
-  <ConfigProvider
-    theme={{
-      token: {
-        colorPrimary: '#1677ff',
-        borderRadius: 10,
-        colorBgLayout: '#f5f7fb',
-        colorBorderSecondary: '#e5eaf2'
-      },
-      components: {
-        Card: {
-          borderRadiusLG: 12
-        }
-      }
-    }}
-  >
+  <ConfigProvider theme={mailhubTheme}>
     <AntApp>
     <AntApp>
       <I18nProvider>
       <I18nProvider>
         <AuthApp />
         <AuthApp />

+ 36 - 17
src/frontend/styles.css

@@ -1,3 +1,21 @@
+:root {
+  --mh-primary: #4f46e5;
+  --mh-primary-hover: #4338ca;
+  --mh-primary-soft: #eef2ff;
+  --mh-ink: #0f172a;
+  --mh-text-secondary: #64748b;
+  --mh-text-muted: #94a3b8;
+  --mh-canvas: #f4f6fb;
+  --mh-surface: #ffffff;
+  --mh-border: #e2e8f0;
+  --mh-success: #16a34a;
+  --mh-warning: #d97706;
+  --mh-danger: #dc2626;
+  --mh-radius-control: 10px;
+  --mh-radius-card: 14px;
+  --mh-shadow-card: 0 1px 2px rgba(15, 23, 42, 0.04), 0 8px 24px rgba(15, 23, 42, 0.04);
+}
+
 html,
 html,
 body,
 body,
 #root {
 #root {
@@ -6,8 +24,9 @@ body,
 
 
 body {
 body {
   margin: 0;
   margin: 0;
-  background: #f5f7fb;
-  color: #172033;
+  background: var(--mh-canvas);
+  color: var(--mh-ink);
+  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
 }
 }
 
 
 .full-width {
 .full-width {
@@ -19,7 +38,7 @@ body {
 }
 }
 
 
 .admin-sider {
 .admin-sider {
-  background: #111827 !important;
+  background: var(--mh-ink) !important;
   border-right: 1px solid rgba(255, 255, 255, 0.06);
   border-right: 1px solid rgba(255, 255, 255, 0.06);
   height: 100vh;
   height: 100vh;
   max-height: 100vh;
   max-height: 100vh;
@@ -39,9 +58,9 @@ body {
 
 
 .brand-logo {
 .brand-logo {
   align-items: center;
   align-items: center;
-  background: #ffffff;
-  border-radius: 10px;
-  color: #1677ff;
+  background: var(--mh-surface);
+  border-radius: var(--mh-radius-control);
+  color: var(--mh-primary);
   display: inline-flex;
   display: inline-flex;
   font-weight: 800;
   font-weight: 800;
   height: 36px;
   height: 36px;
@@ -62,8 +81,8 @@ body {
 
 
 .admin-header {
 .admin-header {
   align-items: center;
   align-items: center;
-  background: #ffffff;
-  border-bottom: 1px solid #e5eaf2;
+  background: var(--mh-surface);
+  border-bottom: 1px solid var(--mh-border);
   display: flex;
   display: flex;
   height: auto;
   height: auto;
   justify-content: space-between;
   justify-content: space-between;
@@ -88,13 +107,13 @@ body {
 }
 }
 
 
 .admin-content {
 .admin-content {
-  background: #f5f7fb;
+  background: var(--mh-canvas);
   padding: 24px;
   padding: 24px;
 }
 }
 
 
 .ant-card {
 .ant-card {
-  border-color: #e5eaf2;
-  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03);
+  border-color: var(--mh-border);
+  box-shadow: var(--mh-shadow-card);
 }
 }
 
 
 .metric-value {
 .metric-value {
@@ -159,7 +178,7 @@ body {
 }
 }
 
 
 .trend-bar-fill {
 .trend-bar-fill {
-  background: #1677ff;
+  background: var(--mh-primary);
   border-radius: 8px 8px 0 0;
   border-radius: 8px 8px 0 0;
   width: 100%;
   width: 100%;
 }
 }
@@ -226,7 +245,7 @@ body {
 
 
 .domain-action-panel {
 .domain-action-panel {
   background: #f8fafc;
   background: #f8fafc;
-  border: 1px solid #e5eaf2;
+  border: 1px solid var(--mh-border);
   border-radius: 12px;
   border-radius: 12px;
   display: grid;
   display: grid;
   gap: 12px;
   gap: 12px;
@@ -320,15 +339,15 @@ body {
 
 
 .auth-page {
 .auth-page {
   background:
   background:
-    radial-gradient(circle at 8% 8%, rgba(22, 119, 255, 0.12), transparent 28%),
-    linear-gradient(135deg, #f5f7fb 0%, #eef4ff 48%, #f8fafc 100%);
+    radial-gradient(circle at 8% 8%, rgba(79, 70, 229, 0.12), transparent 28%),
+    linear-gradient(135deg, var(--mh-canvas) 0%, var(--mh-primary-soft) 48%, #f8fafc 100%);
   display: grid;
   display: grid;
   grid-template-columns: minmax(360px, 0.95fr) minmax(420px, 1.05fr);
   grid-template-columns: minmax(360px, 0.95fr) minmax(420px, 1.05fr);
   min-height: 100vh;
   min-height: 100vh;
 }
 }
 
 
 .auth-brand-panel {
 .auth-brand-panel {
-  background: #111827;
+  background: var(--mh-ink);
   color: #fff;
   color: #fff;
   display: grid;
   display: grid;
   gap: 32px;
   gap: 32px;
@@ -432,7 +451,7 @@ body {
 }
 }
 
 
 .auth-eyebrow {
 .auth-eyebrow {
-  color: #1677ff;
+  color: var(--mh-primary);
   font-size: 12px;
   font-size: 12px;
   font-weight: 700;
   font-weight: 700;
   letter-spacing: 0.08em;
   letter-spacing: 0.08em;

+ 60 - 0
src/frontend/theme.ts

@@ -0,0 +1,60 @@
+import type { ThemeConfig } from 'antd';
+
+export const brandColors = {
+  primary: '#4F46E5',
+  primaryHover: '#4338CA',
+  primarySoft: '#EEF2FF',
+  ink: '#0F172A',
+  textSecondary: '#64748B',
+  textMuted: '#94A3B8',
+  canvas: '#F4F6FB',
+  surface: '#FFFFFF',
+  border: '#E2E8F0',
+  success: '#16A34A',
+  warning: '#D97706',
+  danger: '#DC2626',
+  chartPrimary: '#4F46E5',
+  chartSuccess: '#16A34A',
+  chartDanger: '#DC2626',
+  chartWarning: '#D97706',
+  chartTrack: '#DBEAFE'
+} as const;
+
+export const mailhubTheme: ThemeConfig = {
+  token: {
+    colorPrimary: brandColors.primary,
+    colorSuccess: brandColors.success,
+    colorWarning: brandColors.warning,
+    colorError: brandColors.danger,
+    colorBgLayout: brandColors.canvas,
+    colorBgContainer: brandColors.surface,
+    colorBorderSecondary: brandColors.border,
+    colorText: brandColors.ink,
+    colorTextSecondary: brandColors.textSecondary,
+    borderRadius: 10,
+    borderRadiusLG: 14,
+    fontFamily:
+      'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
+  },
+  components: {
+    Card: {
+      borderRadiusLG: 14
+    },
+    Table: {
+      cellPaddingBlock: 14,
+      cellPaddingInline: 16
+    },
+    Button: {
+      controlHeight: 36,
+      borderRadius: 10
+    },
+    Menu: {
+      darkItemBg: brandColors.ink,
+      darkSubMenuItemBg: brandColors.ink,
+      darkItemSelectedBg: 'rgba(79, 70, 229, 0.22)',
+      darkItemSelectedColor: '#E0E7FF',
+      darkItemHoverBg: 'rgba(255, 255, 255, 0.06)',
+      itemBorderRadius: 10
+    }
+  }
+};

+ 15 - 0
test/frontend-theme.test.js

@@ -0,0 +1,15 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { mailhubTheme, brandColors } from '../src/frontend/theme.ts';
+
+test('brand primary is indigo, not Ant Design default blue', () => {
+  assert.equal(brandColors.primary, '#4F46E5');
+  assert.notEqual(brandColors.primary.toLowerCase(), '#1677ff');
+  assert.equal(mailhubTheme.token.colorPrimary, brandColors.primary);
+});
+
+test('layout canvas and ink tokens match redesign spec', () => {
+  assert.equal(brandColors.canvas, '#F4F6FB');
+  assert.equal(brandColors.ink, '#0F172A');
+  assert.equal(mailhubTheme.token.colorBgLayout, brandColors.canvas);
+});