瀏覽代碼

fix(admin): restore readable component contrast

AI-Co-Authored-By: Codex
chendeben 1 月之前
父節點
當前提交
d2b30113cf
共有 3 個文件被更改,包括 116 次插入 和 2 次删除
  1. 46 1
      admin-web/src/global.less
  2. 1 1
      admin-web/src/layouts/AdminLayout.tsx
  3. 69 0
      admin-web/tests/e2e/admin.spec.ts

+ 46 - 1
admin-web/src/global.less

@@ -590,10 +590,55 @@ a:focus-visible,
 .ant-tag {
   margin-inline-end: 6px;
   padding-inline: 7px;
+  color: #405469;
+  background: #f1f5f8;
+  border-color: #d5e0e8;
   border-radius: 6px;
   line-height: 22px;
 }
 
+.ant-tag.ant-tag-success,
+.ant-tag.ant-tag-green {
+  color: #09613e;
+  background: #effaf5;
+  border-color: #bfe8d4;
+}
+
+.ant-tag.ant-tag-error,
+.ant-tag.ant-tag-red {
+  color: #8c3030;
+  background: #fff2f1;
+  border-color: #f3c5c2;
+}
+
+.ant-tag.ant-tag-warning,
+.ant-tag.ant-tag-gold,
+.ant-tag.ant-tag-orange {
+  color: #76510a;
+  background: #fff8e8;
+  border-color: #f0d9a7;
+}
+
+.ant-tag.ant-tag-processing,
+.ant-tag.ant-tag-blue,
+.ant-tag.ant-tag-cyan {
+  color: #075e87;
+  background: #edf9fe;
+  border-color: #bce5f6;
+}
+
+.ant-tag.ant-tag-purple {
+  color: #5b21b6;
+  background: #f5f3ff;
+  border-color: #ddd6fe;
+}
+
+.ant-tag.ant-tag-volcano {
+  color: #9a3412;
+  background: #fff7ed;
+  border-color: #fed7aa;
+}
+
 .ant-descriptions-bordered .ant-descriptions-view {
   overflow: hidden;
   border-radius: 10px;
@@ -624,7 +669,7 @@ a:focus-visible,
   box-shadow: 18px 0 54px rgba(7, 25, 40, 0.13);
 }
 
-.admin-shell .ant-menu-dark {
+.admin-shell .ant-menu {
   background: transparent !important;
 }
 

+ 1 - 1
admin-web/src/layouts/AdminLayout.tsx

@@ -191,7 +191,7 @@ export default function AdminLayout() {
         location={{ pathname: location.pathname }}
         menu={{ request: async () => visibleMenuItems }}
         layout="mix"
-        navTheme="realDark"
+        navTheme="light"
         fixedHeader
         fixSiderbar
         siderWidth={224}

+ 69 - 0
admin-web/tests/e2e/admin.spec.ts

@@ -70,6 +70,44 @@ function envelope(data: unknown) {
   return JSON.stringify({ data });
 }
 
+function luminance(color: string) {
+  const channels = color.match(/[\d.]+/g)?.slice(0, 3).map(Number) || [];
+  if (channels.length !== 3) throw new Error(`无法解析颜色:${color}`);
+  const linear = channels.map((value) => {
+    const normalized = value / 255;
+    return normalized <= 0.04045
+      ? normalized / 12.92
+      : ((normalized + 0.055) / 1.055) ** 2.4;
+  });
+  return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
+}
+
+function contrastRatio(foreground: string, background: string) {
+  const lighter = Math.max(luminance(foreground), luminance(background));
+  const darker = Math.min(luminance(foreground), luminance(background));
+  return (lighter + 0.05) / (darker + 0.05);
+}
+
+async function expectReadablePair(
+  page: Page,
+  foregroundSelector: string,
+  backgroundSelector: string,
+  minimum = 4.5,
+) {
+  const colors = await page.locator(foregroundSelector).first().evaluate(
+    (foreground, selector) => {
+      const background = document.querySelector(selector);
+      if (!background) throw new Error(`找不到背景元素:${selector}`);
+      return {
+        foreground: getComputedStyle(foreground).color,
+        background: getComputedStyle(background).backgroundColor,
+      };
+    },
+    backgroundSelector,
+  );
+  expect(contrastRatio(colors.foreground, colors.background)).toBeGreaterThanOrEqual(minimum);
+}
+
 async function selectChatWorkspace(page: Page, name: string) {
   if ((page.viewportSize()?.width || 0) <= 575) {
     await page.evaluate(() => window.scrollTo(0, 0));
@@ -480,3 +518,34 @@ test('登录与主要管理视图在不同视口无页面级横向滚动', async
     expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(1);
   }
 });
+
+test('深色导航不污染下拉、状态标签与业务弹层的浅色可读性', async ({ page }) => {
+  await page.goto('/admin/chats');
+  await expect(page.getByRole('heading', { name: '群组管理' })).toBeVisible();
+
+  await page.locator('.bot-selector .ant-select-selector').click();
+  await expect(page.locator('.ant-select-dropdown')).toBeVisible();
+  await expect(page.locator('.ant-select-dropdown')).toHaveCSS('background-color', 'rgb(255, 255, 255)');
+  await expectReadablePair(
+    page,
+    '.ant-select-dropdown .ant-select-item-option-content',
+    '.ant-select-dropdown',
+  );
+
+  await page.keyboard.press('Escape');
+  await expect(page.locator('.ant-table-tbody .ant-tag')).toHaveCSS('background-color', 'rgb(239, 250, 245)');
+  await expectReadablePair(page, '.ant-table-tbody .ant-tag', '.ant-table-tbody .ant-tag');
+
+  await page.goto('/admin/giveaways');
+  await page.getByRole('button', { name: '创建抽奖' }).click();
+  await expect(page.locator('.ant-modal-content')).toHaveCSS('background-color', 'rgb(255, 255, 255)');
+  await expectReadablePair(page, '.ant-modal-title', '.ant-modal-content');
+  await expectReadablePair(page, '.ant-modal .ant-form-item-label label', '.ant-modal-content');
+  await page.locator('.ant-modal-close').click();
+
+  await page.goto('/admin/points');
+  await page.getByRole('button', { name: '手工调整' }).click();
+  await expect(page.locator('.ant-modal-content')).toHaveCSS('background-color', 'rgb(255, 255, 255)');
+  await expectReadablePair(page, '.ant-modal-title', '.ant-modal-content');
+  await expectReadablePair(page, '.ant-modal .ant-form-item-label label', '.ant-modal-content');
+});