From 7e5f279284cb8bdd75a28b5f68b5ceec81b3e898 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 25 May 2026 03:47:49 +0200 Subject: [PATCH] refactor(frontend): drop CustomStatistic wrapper, move overrides to theme tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete `` (a pass-through wrapper over ) and its unscoped global `.ant-statistic-*` CSS overrides; consumers (IndexPage, ClientsPage, InboundsPage, NodesPage) now import AntD `` directly. - Add Statistic component tokens to ConfigProvider so the title (11px) and content (17px) font sizes still apply, without `!important` global selectors. - Move dark / ultra-dark card border colours from `body.dark .ant-card` + `html[data-theme='ultra-dark'] .ant-card` selectors into Card `colorBorderSecondary` tokens; page-cards.css now only carries the custom radius/shadow/transition that has no token equivalent. - Simplify XrayStatusCard badge: remove the custom `xray-pulse` dot keyframe and per-state ring-colour overrides; AntD `` already pulses the ring in the same colour, no extra CSS needed. --- frontend/src/components/CustomStatistic.css | 52 ------- frontend/src/components/CustomStatistic.tsx | 14 -- frontend/src/hooks/useTheme.tsx | 19 ++- frontend/src/pages/clients/ClientsPage.tsx | 14 +- frontend/src/pages/inbounds/InboundsPage.tsx | 8 +- frontend/src/pages/index/IndexPage.css | 151 ------------------- frontend/src/pages/index/IndexPage.tsx | 26 ++-- frontend/src/pages/index/XrayStatusCard.css | 30 ---- frontend/src/pages/index/XrayStatusCard.tsx | 21 +-- frontend/src/pages/nodes/NodesPage.tsx | 11 +- frontend/src/styles/page-cards.css | 87 ----------- 11 files changed, 49 insertions(+), 384 deletions(-) delete mode 100644 frontend/src/components/CustomStatistic.css delete mode 100644 frontend/src/components/CustomStatistic.tsx diff --git a/frontend/src/components/CustomStatistic.css b/frontend/src/components/CustomStatistic.css deleted file mode 100644 index 9cb3e065..00000000 --- a/frontend/src/components/CustomStatistic.css +++ /dev/null @@ -1,52 +0,0 @@ -.ant-statistic-content { - font-size: 17px !important; - line-height: 1.4 !important; - font-weight: 600; -} - -.ant-statistic-content-value, -.ant-statistic-content-prefix, -.ant-statistic-content-suffix { - font-size: 17px !important; -} - -.ant-statistic-content-prefix { - margin-inline-end: 8px !important; - opacity: 0.7; -} - -.ant-statistic-content-prefix .anticon { - font-size: 17px !important; -} - -.ant-statistic-content-suffix { - font-size: 12px !important; - opacity: 0.55; - margin-inline-start: 4px; - font-weight: 500; -} - -.ant-statistic-title { - font-size: 11px !important; - margin-bottom: 6px !important; - letter-spacing: 0.6px; - text-transform: uppercase; - color: rgba(0, 0, 0, 0.55); - font-weight: 500; -} - -body.dark .ant-statistic-content { - color: rgba(255, 255, 255, 0.92); -} - -body.dark .ant-statistic-title { - color: rgba(255, 255, 255, 0.72); -} - -html[data-theme='ultra-dark'] .ant-statistic-content { - color: rgba(255, 255, 255, 0.95); -} - -html[data-theme='ultra-dark'] .ant-statistic-title { - color: rgba(255, 255, 255, 0.70); -} diff --git a/frontend/src/components/CustomStatistic.tsx b/frontend/src/components/CustomStatistic.tsx deleted file mode 100644 index 6089637f..00000000 --- a/frontend/src/components/CustomStatistic.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { ReactNode } from 'react'; -import { Statistic } from 'antd'; -import './CustomStatistic.css'; - -interface CustomStatisticProps { - title?: string; - value?: string | number; - prefix?: ReactNode; - suffix?: ReactNode; -} - -export default function CustomStatistic({ title = '', value = '', prefix, suffix }: CustomStatisticProps) { - return ; -} diff --git a/frontend/src/hooks/useTheme.tsx b/frontend/src/hooks/useTheme.tsx index 12c33252..665e46f1 100644 --- a/frontend/src/hooks/useTheme.tsx +++ b/frontend/src/hooks/useTheme.tsx @@ -68,10 +68,25 @@ const ULTRA_DARK_MENU_TOKENS = { darkSubMenuItemBg: '#000', darkPopupBg: '#101013', }; +const DARK_CARD_TOKENS = { + colorBorderSecondary: 'rgba(255, 255, 255, 0.06)', +}; +const ULTRA_DARK_CARD_TOKENS = { + colorBorderSecondary: 'rgba(255, 255, 255, 0.04)', +}; +const STATISTIC_TOKENS = { + contentFontSize: 17, + titleFontSize: 11, +}; export function buildAntdThemeConfig(isDark: boolean, isUltra: boolean): ThemeConfig { if (!isDark) { - return { algorithm: antdTheme.defaultAlgorithm }; + return { + algorithm: antdTheme.defaultAlgorithm, + components: { + Statistic: STATISTIC_TOKENS, + }, + }; } return { algorithm: antdTheme.darkAlgorithm, @@ -79,6 +94,8 @@ export function buildAntdThemeConfig(isDark: boolean, isUltra: boolean): ThemeCo components: { Layout: isUltra ? ULTRA_DARK_LAYOUT_TOKENS : DARK_LAYOUT_TOKENS, Menu: isUltra ? ULTRA_DARK_MENU_TOKENS : DARK_MENU_TOKENS, + Card: isUltra ? ULTRA_DARK_CARD_TOKENS : DARK_CARD_TOKENS, + Statistic: STATISTIC_TOKENS, }, }; } diff --git a/frontend/src/pages/clients/ClientsPage.tsx b/frontend/src/pages/clients/ClientsPage.tsx index 0a024536..2e4f3315 100644 --- a/frontend/src/pages/clients/ClientsPage.tsx +++ b/frontend/src/pages/clients/ClientsPage.tsx @@ -18,6 +18,7 @@ import { Select, Space, Spin, + Statistic, Switch, Table, Tag, @@ -49,7 +50,6 @@ import { useClients } from '@/hooks/useClients'; import { useDatepicker } from '@/hooks/useDatepicker'; import type { ClientRecord, InboundOption } from '@/hooks/useClients'; import AppSidebar from '@/components/AppSidebar'; -import CustomStatistic from '@/components/CustomStatistic'; import { IntlUtil, SizeFormatter } from '@/utils'; import { setMessageInstance } from '@/utils/messageBus'; import LazyMount from '@/components/LazyMount'; @@ -624,7 +624,7 @@ export default function ClientsPage() { - } /> + } /> {summary.online.map((e) =>
{e}
)}} > - } /> + } />
@@ -641,7 +641,7 @@ export default function ClientsPage() { open={summary.depleted.length ? undefined : false} content={
{summary.depleted.map((e) =>
{e}
)}
} > - } /> + } /> @@ -650,7 +650,7 @@ export default function ClientsPage() { open={summary.expiring.length ? undefined : false} content={
{summary.expiring.map((e) =>
{e}
)}
} > - } /> + } /> @@ -659,11 +659,11 @@ export default function ClientsPage() { open={summary.deactive.length ? undefined : false} content={
{summary.deactive.map((e) =>
{e}
)}
} > - } /> + } /> - } /> + } />
diff --git a/frontend/src/pages/inbounds/InboundsPage.tsx b/frontend/src/pages/inbounds/InboundsPage.tsx index 44a5e6e0..e67ac45b 100644 --- a/frontend/src/pages/inbounds/InboundsPage.tsx +++ b/frontend/src/pages/inbounds/InboundsPage.tsx @@ -8,6 +8,7 @@ import { Modal, Row, Spin, + Statistic, message, } from 'antd'; @@ -26,7 +27,6 @@ import { useMediaQuery } from '@/hooks/useMediaQuery'; import { useWebSocket } from '@/hooks/useWebSocket'; import { useNodesQuery } from '@/api/queries/useNodesQuery'; import AppSidebar from '@/components/AppSidebar'; -import CustomStatistic from '@/components/CustomStatistic'; const TextModal = lazy(() => import('@/components/TextModal')); const PromptModal = lazy(() => import('@/components/PromptModal')); @@ -463,21 +463,21 @@ export default function InboundsPage() { - } /> - } /> - } diff --git a/frontend/src/pages/index/IndexPage.css b/frontend/src/pages/index/IndexPage.css index 889ed959..f6d72e39 100644 --- a/frontend/src/pages/index/IndexPage.css +++ b/frontend/src/pages/index/IndexPage.css @@ -40,152 +40,11 @@ min-height: calc(100vh - 120px); } -.index-page .ant-card { - border-radius: 12px; - border: 1px solid rgba(0, 0, 0, 0.06); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); - transition: transform 0.2s ease, box-shadow 0.25s ease, border-color 0.2s ease; -} - -body.dark .index-page .ant-card { - border-color: rgba(255, 255, 255, 0.06); - box-shadow: - 0 1px 2px rgba(0, 0, 0, 0.4), - inset 0 1px 0 rgba(255, 255, 255, 0.03); -} - -html[data-theme='ultra-dark'] .index-page .ant-card { - border-color: rgba(255, 255, 255, 0.04); - box-shadow: - 0 1px 2px rgba(0, 0, 0, 0.6), - inset 0 1px 0 rgba(255, 255, 255, 0.025); -} - -.index-page .ant-card.ant-card-hoverable:hover { - transform: translateY(-2px); - border-color: rgba(0, 0, 0, 0.10); - box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08); -} - -body.dark .index-page .ant-card.ant-card-hoverable:hover { - border-color: rgba(255, 255, 255, 0.12); - box-shadow: - 0 8px 24px rgba(0, 0, 0, 0.5), - inset 0 1px 0 rgba(255, 255, 255, 0.04); -} - -html[data-theme='ultra-dark'] .index-page .ant-card.ant-card-hoverable:hover { - border-color: rgba(255, 255, 255, 0.08); - box-shadow: - 0 8px 24px rgba(0, 0, 0, 0.75), - inset 0 1px 0 rgba(255, 255, 255, 0.03); -} - -.index-page .ant-card .ant-card-head { - min-height: 44px; - padding-inline: 16px; -} - -.index-page .ant-card .ant-card-head-title { - font-size: 13px; - font-weight: 600; - letter-spacing: 0.5px; - text-transform: uppercase; - opacity: 0.75; -} - -.index-page .ant-card .ant-card-body { - padding: 18px 20px; -} - -.index-page .ant-card .ant-card-body > .ant-row > .ant-col { - position: relative; - padding: 4px 6px; -} - -@media (min-width: 769px) { - .index-page .ant-card .ant-card-body > .ant-row > .ant-col + .ant-col::before { - content: ''; - position: absolute; - left: 0; - top: 10%; - bottom: 10%; - width: 1px; - background: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.10), transparent); - pointer-events: none; - } -} - -body.dark .index-page .ant-card .ant-card-body > .ant-row > .ant-col + .ant-col::before { - background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.12), transparent); -} - -.index-page .ant-card .ant-card-head { - border-bottom-color: rgba(0, 0, 0, 0.06); -} - -.index-page .ant-card .ant-card-actions { - border-top-color: rgba(0, 0, 0, 0.06); - background: transparent; -} - -.index-page .ant-card .ant-card-actions > li { - border-inline-end-color: rgba(0, 0, 0, 0.06); -} - -body.dark .index-page .ant-card .ant-card-head { - border-bottom-color: rgba(255, 255, 255, 0.06); -} - -body.dark .index-page .ant-card .ant-card-actions { - border-top-color: rgba(255, 255, 255, 0.06); -} - -body.dark .index-page .ant-card .ant-card-actions > li { - border-inline-end-color: rgba(255, 255, 255, 0.06); -} - -html[data-theme='ultra-dark'] .index-page .ant-card .ant-card-head { - border-bottom-color: rgba(255, 255, 255, 0.04); -} - -html[data-theme='ultra-dark'] .index-page .ant-card .ant-card-actions { - border-top-color: rgba(255, 255, 255, 0.04); -} - -html[data-theme='ultra-dark'] .index-page .ant-card .ant-card-actions > li { - border-inline-end-color: rgba(255, 255, 255, 0.04); -} - .index-page .action { cursor: pointer; justify-content: center; max-width: 100%; - padding: 0 8px; flex-wrap: nowrap; - color: rgba(0, 0, 0, 0.78); - font-weight: 500; - transition: opacity 0.15s ease, transform 0.15s ease, color 0.2s ease; -} - -.index-page .action .anticon { - color: rgba(0, 0, 0, 0.72); -} - -body.dark .index-page .action { - color: rgba(255, 255, 255, 0.82); -} - -body.dark .index-page .action .anticon { - color: rgba(255, 255, 255, 0.75); -} - -html[data-theme='ultra-dark'] .index-page .action { - color: rgba(255, 255, 255, 0.86); -} - -html[data-theme='ultra-dark'] .index-page .action .anticon { - color: rgba(255, 255, 255, 0.78); } .index-page .action > span:not(.anticon):not(.tg-icon) { @@ -195,16 +54,6 @@ html[data-theme='ultra-dark'] .index-page .action .anticon { min-width: 0; } -.index-page .action:hover { - opacity: 0.75; - transform: translateY(-1px); -} - -.index-page .ant-card-actions > li { - margin: 8px 0; - min-width: 0; -} - .index-page .action-update { color: #fa8c16; font-weight: 600; diff --git a/frontend/src/pages/index/IndexPage.tsx b/frontend/src/pages/index/IndexPage.tsx index 21bfcb3a..c091153a 100644 --- a/frontend/src/pages/index/IndexPage.tsx +++ b/frontend/src/pages/index/IndexPage.tsx @@ -11,6 +11,7 @@ import { Row, Space, Spin, + Statistic, Tag, Tooltip, } from 'antd'; @@ -39,7 +40,6 @@ import { useTheme } from '@/hooks/useTheme'; import { useStatusQuery } from '@/api/queries/useStatusQuery'; import { useMediaQuery } from '@/hooks/useMediaQuery'; import AppSidebar from '@/components/AppSidebar'; -import CustomStatistic from '@/components/CustomStatistic'; import LazyMount from '@/components/LazyMount'; import { setMessageInstance } from '@/utils/messageBus'; import StatusCard from './StatusCard'; @@ -285,14 +285,14 @@ export default function IndexPage() { - } /> - } @@ -306,14 +306,14 @@ export default function IndexPage() { - } /> - } @@ -327,7 +327,7 @@ export default function IndexPage() { - } @@ -335,7 +335,7 @@ export default function IndexPage() { /> - } @@ -350,14 +350,14 @@ export default function IndexPage() { - } /> - } @@ -392,14 +392,14 @@ export default function IndexPage() { > - } /> - } @@ -413,14 +413,14 @@ export default function IndexPage() { - } /> - } diff --git a/frontend/src/pages/index/XrayStatusCard.css b/frontend/src/pages/index/XrayStatusCard.css index 1e9abd47..91683c8d 100644 --- a/frontend/src/pages/index/XrayStatusCard.css +++ b/frontend/src/pages/index/XrayStatusCard.css @@ -12,33 +12,3 @@ .cursor-pointer { cursor: pointer; } - -.xray-processing-animation .ant-badge-status-dot { - animation: xray-pulse 1.2s linear infinite; -} - -.xray-running-animation .ant-badge-status-processing::after { - border-color: #1677ff; -} - -.xray-stop-animation .ant-badge-status-processing::after { - border-color: #fa8c16; -} - -.xray-error-animation .ant-badge-status-processing::after { - border-color: #f5222d; -} - -@keyframes xray-pulse { - 0%, - 50%, - 100% { - transform: scale(1); - opacity: 1; - } - - 10% { - transform: scale(1.5); - opacity: 0.2; - } -} diff --git a/frontend/src/pages/index/XrayStatusCard.tsx b/frontend/src/pages/index/XrayStatusCard.tsx index acdac689..95c31ffb 100644 --- a/frontend/src/pages/index/XrayStatusCard.tsx +++ b/frontend/src/pages/index/XrayStatusCard.tsx @@ -28,13 +28,6 @@ const XRAY_STATE_KEYS: Record = { error: 'pages.index.xrayStatusError', }; -function badgeAnimationClass(color: string): string { - if (color === 'green') return 'xray-running-animation'; - if (color === 'orange') return 'xray-stop-animation'; - if (color === 'red') return 'xray-error-animation'; - return 'xray-processing-animation'; -} - export default function XrayStatusCard({ status, isMobile, @@ -65,12 +58,7 @@ export default function XrayStatusCard({ const extra = status.xray.state !== 'error' ? ( - + ) : ( } > - + ); diff --git a/frontend/src/pages/nodes/NodesPage.tsx b/frontend/src/pages/nodes/NodesPage.tsx index 2f5b7a79..453c1cf5 100644 --- a/frontend/src/pages/nodes/NodesPage.tsx +++ b/frontend/src/pages/nodes/NodesPage.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Card, Col, ConfigProvider, Layout, Modal, Row, Spin, message } from 'antd'; +import { Card, Col, ConfigProvider, Layout, Modal, Row, Spin, Statistic, message } from 'antd'; import { CheckCircleOutlined, CloseCircleOutlined, @@ -14,7 +14,6 @@ import { useNodesQuery } from '@/api/queries/useNodesQuery'; import type { NodeRecord } from '@/api/queries/useNodesQuery'; import { useNodeMutations } from '@/api/queries/useNodeMutations'; import AppSidebar from '@/components/AppSidebar'; -import CustomStatistic from '@/components/CustomStatistic'; import NodeList from './NodeList'; import NodeFormModal from './NodeFormModal'; import { setMessageInstance } from '@/utils/messageBus'; @@ -109,28 +108,28 @@ export default function NodesPage() { - } /> - } /> - } /> - 0 ? `${totals.avgLatency} ms` : '-'} prefix={} diff --git a/frontend/src/styles/page-cards.css b/frontend/src/styles/page-cards.css index 89b39263..b9e6eacc 100644 --- a/frontend/src/styles/page-cards.css +++ b/frontend/src/styles/page-cards.css @@ -6,7 +6,6 @@ .nodes-page .ant-card, .api-docs-page .ant-card { border-radius: 12px; - border: 1px solid rgba(0, 0, 0, 0.06); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); transition: transform 0.2s ease, box-shadow 0.25s ease, border-color 0.2s ease; } @@ -18,7 +17,6 @@ body.dark .xray-page .ant-card, body.dark .settings-page .ant-card, body.dark .nodes-page .ant-card, body.dark .api-docs-page .ant-card { - border-color: rgba(255, 255, 255, 0.06); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.03); @@ -31,7 +29,6 @@ html[data-theme='ultra-dark'] .xray-page .ant-card, html[data-theme='ultra-dark'] .settings-page .ant-card, html[data-theme='ultra-dark'] .nodes-page .ant-card, html[data-theme='ultra-dark'] .api-docs-page .ant-card { - border-color: rgba(255, 255, 255, 0.04); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.025); @@ -45,7 +42,6 @@ html[data-theme='ultra-dark'] .api-docs-page .ant-card { .nodes-page .ant-card.ant-card-hoverable:hover, .api-docs-page .ant-card.ant-card-hoverable:hover { transform: translateY(-2px); - border-color: rgba(0, 0, 0, 0.10); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08); } @@ -56,7 +52,6 @@ body.dark .xray-page .ant-card.ant-card-hoverable:hover, body.dark .settings-page .ant-card.ant-card-hoverable:hover, body.dark .nodes-page .ant-card.ant-card-hoverable:hover, body.dark .api-docs-page .ant-card.ant-card-hoverable:hover { - border-color: rgba(255, 255, 255, 0.12); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.04); @@ -69,22 +64,11 @@ html[data-theme='ultra-dark'] .xray-page .ant-card.ant-card-hoverable:hover, html[data-theme='ultra-dark'] .settings-page .ant-card.ant-card-hoverable:hover, html[data-theme='ultra-dark'] .nodes-page .ant-card.ant-card-hoverable:hover, html[data-theme='ultra-dark'] .api-docs-page .ant-card.ant-card-hoverable:hover { - border-color: rgba(255, 255, 255, 0.08); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.03); } -.index-page .ant-card .ant-card-head, -.clients-page .ant-card .ant-card-head, -.inbounds-page .ant-card .ant-card-head, -.xray-page .ant-card .ant-card-head, -.settings-page .ant-card .ant-card-head, -.nodes-page .ant-card .ant-card-head, -.api-docs-page .ant-card .ant-card-head { - border-bottom-color: rgba(0, 0, 0, 0.06); -} - .index-page .ant-card .ant-card-actions, .clients-page .ant-card .ant-card-actions, .inbounds-page .ant-card .ant-card-actions, @@ -92,76 +76,5 @@ html[data-theme='ultra-dark'] .api-docs-page .ant-card.ant-card-hoverable:hover .settings-page .ant-card .ant-card-actions, .nodes-page .ant-card .ant-card-actions, .api-docs-page .ant-card .ant-card-actions { - border-top-color: rgba(0, 0, 0, 0.06); background: transparent; } - -.index-page .ant-card .ant-card-actions > li, -.clients-page .ant-card .ant-card-actions > li, -.inbounds-page .ant-card .ant-card-actions > li, -.xray-page .ant-card .ant-card-actions > li, -.settings-page .ant-card .ant-card-actions > li, -.nodes-page .ant-card .ant-card-actions > li, -.api-docs-page .ant-card .ant-card-actions > li { - border-inline-end-color: rgba(0, 0, 0, 0.06); -} - -body.dark .index-page .ant-card .ant-card-head, -body.dark .clients-page .ant-card .ant-card-head, -body.dark .inbounds-page .ant-card .ant-card-head, -body.dark .xray-page .ant-card .ant-card-head, -body.dark .settings-page .ant-card .ant-card-head, -body.dark .nodes-page .ant-card .ant-card-head, -body.dark .api-docs-page .ant-card .ant-card-head { - border-bottom-color: rgba(255, 255, 255, 0.06); -} - -body.dark .index-page .ant-card .ant-card-actions, -body.dark .clients-page .ant-card .ant-card-actions, -body.dark .inbounds-page .ant-card .ant-card-actions, -body.dark .xray-page .ant-card .ant-card-actions, -body.dark .settings-page .ant-card .ant-card-actions, -body.dark .nodes-page .ant-card .ant-card-actions, -body.dark .api-docs-page .ant-card .ant-card-actions { - border-top-color: rgba(255, 255, 255, 0.06); -} - -body.dark .index-page .ant-card .ant-card-actions > li, -body.dark .clients-page .ant-card .ant-card-actions > li, -body.dark .inbounds-page .ant-card .ant-card-actions > li, -body.dark .xray-page .ant-card .ant-card-actions > li, -body.dark .settings-page .ant-card .ant-card-actions > li, -body.dark .nodes-page .ant-card .ant-card-actions > li, -body.dark .api-docs-page .ant-card .ant-card-actions > li { - border-inline-end-color: rgba(255, 255, 255, 0.06); -} - -html[data-theme='ultra-dark'] .index-page .ant-card .ant-card-head, -html[data-theme='ultra-dark'] .clients-page .ant-card .ant-card-head, -html[data-theme='ultra-dark'] .inbounds-page .ant-card .ant-card-head, -html[data-theme='ultra-dark'] .xray-page .ant-card .ant-card-head, -html[data-theme='ultra-dark'] .settings-page .ant-card .ant-card-head, -html[data-theme='ultra-dark'] .nodes-page .ant-card .ant-card-head, -html[data-theme='ultra-dark'] .api-docs-page .ant-card .ant-card-head { - border-bottom-color: rgba(255, 255, 255, 0.04); -} - -html[data-theme='ultra-dark'] .index-page .ant-card .ant-card-actions, -html[data-theme='ultra-dark'] .clients-page .ant-card .ant-card-actions, -html[data-theme='ultra-dark'] .inbounds-page .ant-card .ant-card-actions, -html[data-theme='ultra-dark'] .xray-page .ant-card .ant-card-actions, -html[data-theme='ultra-dark'] .settings-page .ant-card .ant-card-actions, -html[data-theme='ultra-dark'] .nodes-page .ant-card .ant-card-actions, -html[data-theme='ultra-dark'] .api-docs-page .ant-card .ant-card-actions { - border-top-color: rgba(255, 255, 255, 0.04); -} - -html[data-theme='ultra-dark'] .index-page .ant-card .ant-card-actions > li, -html[data-theme='ultra-dark'] .clients-page .ant-card .ant-card-actions > li, -html[data-theme='ultra-dark'] .inbounds-page .ant-card .ant-card-actions > li, -html[data-theme='ultra-dark'] .xray-page .ant-card .ant-card-actions > li, -html[data-theme='ultra-dark'] .settings-page .ant-card .ant-card-actions > li, -html[data-theme='ultra-dark'] .nodes-page .ant-card .ant-card-actions > li, -html[data-theme='ultra-dark'] .api-docs-page .ant-card .ant-card-actions > li { - border-inline-end-color: rgba(255, 255, 255, 0.04); -}