refactor(theme): 重构主题配置和管理后台样式

- 将 Ant Design 主题配置提取到独立的 getAntThemeConfig 函数
- 移除 AGENTS.md 中关于状态管理和样式的冗余说明
- 删除 globals.css 中的 admin 相关样式和颜色变量
- 更新管理后台布局使用新的主题配置和样式常量
- 调整代码编辑器样式使用 Ant Design 的 CSS 变量
- 优化管理后台整体视觉风格为中性色调
This commit is contained in:
HouYunFei
2026-05-21 11:04:59 +08:00
parent 330f06bb05
commit dce6ab2282
7 changed files with 118 additions and 302 deletions
+4
View File
@@ -34,6 +34,7 @@
- 前端使用 Next.js App Router、React、TypeScript、Ant Design、Tailwind、Zustand。
- API 请求统一放在 `web/src/services/api/`
- 全局或跨页面状态优先放在 `web/src/stores/`
- 已经放在全局 store 或全局 hook 中的状态/动作,组件需要时直接使用对应 store/hook,不要为了“纯组件”层层透传 props;避免一个组件传递过多参数。
- 画布相关状态和组件放在 `web/src/app/(user)/canvas/` 内部。
- 页面里只有一个主业务组件时直接写在 `page.tsx`,不要单独拆 `Manager` 组件再传一堆 props。
- 管理后台页面私有组件放到各自页面目录的 `components/` 下,例如 `admin/assets/components/``admin/prompts/components/`;不要为了单页面使用放到 `admin/components/` 共享目录。
@@ -42,6 +43,9 @@
- UI 图标优先使用 `lucide-react` 或项目已经使用的 Ant Design 图标。
- 页面文案保持中文。
- 不要在组件里堆太多无关逻辑;复杂逻辑优先抽成同目录工具函数或小组件。
- 样式优先由组件自己管理;组件私有样式优先使用 Tailwind className 或少量内联 style,不要为单个组件新增大量全局 CSS。
- 全局 CSS 只放基础变量、全局重置、跨页面通用样式和少量第三方组件必要覆盖;不要在 `globals.css` 堆页面私有样式。
- 代码尽量短小直接,少拆不必要组件,少做多层 props 传递,避免为了抽象堆出更多代码。
- 前端业务数据需要浏览器本地持久化时,默认使用 `localforage``localStorage` 只用于极小的简单配置,不要用来保存业务列表、生成记录、图片、base64 或大 JSON。
## 画布 UI 规范
+1
View File
@@ -6,3 +6,4 @@
- 后端应自动维护 `settings` 表,并支持公开读取 public 配置、管理员读取和保存 public/private 两行 JSON 配置。
- 管理后台系统设置页面应按公开/私有两个 Tab 区分配置,并支持可视化编辑和手动编辑 JSON,且可保存 public/private 配置。
- 管理后台私有配置中的模型渠道应以列表展示、通过抽屉新增编辑,并支持填写权重、远程获取模型列表、模型清单测试和批量测试。
- 管理后台亮色和暗色主题应使用接近 shadcn 的黑白中性色,侧栏、顶部栏、卡片、表格、弹窗和 JSON 编辑器不应再出现偏棕色或默认蓝色主色。
+40 -38
View File
@@ -1,7 +1,7 @@
"use client";
import { FileTextOutlined, HomeOutlined, LogoutOutlined, PictureOutlined, SettingOutlined } from "@ant-design/icons";
import { Button, Flex, Layout, Menu, Typography } from "antd";
import { Button, Flex, Layout, Menu, Typography, theme } from "antd";
import { LogOut } from "lucide-react";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
@@ -9,10 +9,12 @@ import type { ReactNode } from "react";
import { useEffect } from "react";
import { UserStatusActions } from "@/components/user-status-actions";
import { adminLayoutStyle } from "@/lib/app-theme";
import { useThemeStore } from "@/stores/use-theme-store";
import { useUserStore } from "@/stores/use-user-store";
export default function AdminLayout({ children }: { children: ReactNode }) {
const { token: antToken } = theme.useToken();
const router = useRouter();
const pathname = usePathname();
const token = useUserStore((state) => state.token);
@@ -38,50 +40,50 @@ export default function AdminLayout({ children }: { children: ReactNode }) {
if (!isReady || !token || user?.role !== "admin") {
return (
<div style={{ display: "flex", minHeight: "100vh", alignItems: "center", justifyContent: "center", background: "var(--background)" }}>
<div style={{ display: "flex", minHeight: "100vh", alignItems: "center", justifyContent: "center", background: antToken.colorBgLayout }}>
<span />
</div>
);
}
return (
<Layout className="admin-layout" hasSider style={{ height: "100vh", overflow: "hidden" }}>
<Layout.Sider width={232} style={{ height: "100vh", overflow: "hidden" }}>
<Flex className="admin-brand" align="center" gap={12} style={{ height: 56, padding: "0 20px" }}>
<span className="admin-logo" aria-hidden />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
<Layout hasSider style={{ height: "100vh", overflow: "hidden", background: antToken.colorBgLayout }}>
<Layout.Sider width={adminLayoutStyle.siderWidth} style={{ height: "100vh", overflow: "hidden", background: antToken.colorBgContainer, borderRight: `1px solid ${antToken.colorBorder}` }}>
<Flex align="center" gap={12} style={{ height: adminLayoutStyle.brandHeight, padding: "0 20px", borderBottom: `1px solid ${antToken.colorBorderSecondary}` }}>
<span aria-hidden style={{ display: "inline-block", width: 30, height: 30, background: antToken.colorText, WebkitMask: "url(/logo.svg) center / contain no-repeat", mask: "url(/logo.svg) center / contain no-repeat" }} />
<Typography.Text strong style={{ fontSize: 18, letterSpacing: 0 }}></Typography.Text>
</Flex>
<Menu
mode="inline"
selectedKeys={[activeKey]}
style={adminLayoutStyle.menu}
items={[
{ key: "/admin/prompts", icon: <FileTextOutlined />, label: <Link href="/admin/prompts" style={{ color: "inherit" }}></Link>, style: adminLayoutStyle.menuItem },
{ key: "/admin/assets", icon: <PictureOutlined />, label: <Link href="/admin/assets" style={{ color: "inherit" }}></Link>, style: adminLayoutStyle.menuItem },
{ key: "/admin/settings", icon: <SettingOutlined />, label: <Link href="/admin/settings" style={{ color: "inherit" }}></Link>, style: adminLayoutStyle.menuItem },
]}
/>
<Flex vertical gap={8} style={{ position: "absolute", bottom: 0, insetInline: 0, padding: 12, borderTop: `1px solid ${antToken.colorBorder}`, background: antToken.colorBgContainer }}>
<Button block icon={<HomeOutlined />} href="/canvas" target="_blank" rel="noreferrer"></Button>
<Button block icon={<LogoutOutlined />} onClick={logout}>退</Button>
</Flex>
</Layout.Sider>
<Layout style={{ background: antToken.colorBgLayout }}>
<Layout.Header style={{ display: "flex", alignItems: "center", justifyContent: "space-between", height: adminLayoutStyle.headerHeight, padding: "0 24px", background: antToken.colorBgContainer, borderBottom: `1px solid ${antToken.colorBorder}` }}>
<Typography.Title level={5} style={{ margin: 0 }}>{pageTitle}</Typography.Title>
<Flex align="center" gap={4}>
<UserStatusActions
version={appVersion}
theme={colorTheme}
onThemeChange={setTheme}
showConfig={false}
userName={user.username}
menuItems={[{ key: "logout", icon: <LogOut className="size-4" />, label: "退出登录", onClick: logout }]}
/>
</Flex>
<Menu
mode="inline"
selectedKeys={[activeKey]}
style={{ borderInlineEnd: 0, padding: "12px 8px" }}
items={[
{ key: "/admin/prompts", icon: <FileTextOutlined />, label: <Link href="/admin/prompts" style={{ color: "inherit" }}></Link> },
{ key: "/admin/assets", icon: <PictureOutlined />, label: <Link href="/admin/assets" style={{ color: "inherit" }}></Link> },
{ key: "/admin/settings", icon: <SettingOutlined />, label: <Link href="/admin/settings" style={{ color: "inherit" }}></Link> },
]}
/>
<Flex vertical gap={8} style={{ position: "absolute", bottom: 0, insetInline: 0, padding: 12 }}>
<Button block icon={<HomeOutlined />} href="/canvas" target="_blank" rel="noreferrer"></Button>
<Button block icon={<LogoutOutlined />} onClick={logout}>退</Button>
</Flex>
</Layout.Sider>
<Layout>
<Layout.Header style={{ display: "flex", alignItems: "center", justifyContent: "space-between", height: 56, padding: "0 24px" }}>
<Typography.Title level={5} style={{ margin: 0 }}>{pageTitle}</Typography.Title>
<Flex align="center" gap={4}>
<UserStatusActions
version={appVersion}
theme={colorTheme}
onThemeChange={setTheme}
showConfig={false}
userName={user.username}
menuItems={[{ key: "logout", icon: <LogOut className="size-4" />, label: "退出登录", onClick: logout }]}
/>
</Flex>
</Layout.Header>
<Layout.Content style={{ minHeight: 0, overflow: "auto" }}>{children}</Layout.Content>
</Layout>
</Layout.Header>
<Layout.Content style={{ minHeight: 0, overflow: "auto" }}>{children}</Layout.Content>
</Layout>
</Layout>
);
}
+11 -25
View File
@@ -1,9 +1,7 @@
"use client";
import { CheckCircleOutlined, DeleteOutlined, FormatPainterOutlined, PlusOutlined, ReloadOutlined, SaveOutlined } from "@ant-design/icons";
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
import { json } from "@codemirror/lang-json";
import { tags } from "@lezer/highlight";
import { App, Button, Card, Col, Drawer, Flex, Form, Input, InputNumber, Modal, Row, Segmented, Select, Space, Switch, Table, Tabs, Tag, Typography } from "antd";
import dynamic from "next/dynamic";
import { useEffect, useState } from "react";
@@ -14,27 +12,17 @@ import { useUserStore } from "@/stores/use-user-store";
const CodeMirror = dynamic(() => import("@uiw/react-codemirror"), { ssr: false });
const jsonEditorTheme = EditorView.theme({
"&": { backgroundColor: "var(--card)", color: "var(--foreground)" },
".cm-content": { caretColor: "var(--foreground)", padding: "12px 0" },
"&": { backgroundColor: "var(--ant-color-bg-container)", color: "var(--ant-color-text)" },
".cm-content": { caretColor: "var(--ant-color-text)", padding: "12px 0" },
".cm-line": { padding: "0 18px" },
".cm-gutters": { backgroundColor: "color-mix(in srgb, var(--card) 94%, var(--foreground))", borderRight: "1px solid var(--border)", color: "var(--muted-foreground)" },
".cm-activeLine": { backgroundColor: "color-mix(in srgb, var(--primary) 9%, transparent)" },
".cm-activeLineGutter": { backgroundColor: "color-mix(in srgb, var(--primary) 10%, transparent)", color: "var(--foreground)" },
".cm-cursor": { borderLeftColor: "var(--foreground)" },
".cm-selectionBackground, &.cm-focused .cm-selectionBackground": { backgroundColor: "color-mix(in srgb, var(--primary) 25%, transparent)" },
".cm-foldPlaceholder": { backgroundColor: "var(--muted)", border: "1px solid var(--border)", color: "var(--muted-foreground)" },
".cm-gutters": { backgroundColor: "var(--ant-color-fill-quaternary)", borderRight: "1px solid var(--ant-color-border)", color: "var(--ant-color-text-tertiary)" },
".cm-activeLine": { backgroundColor: "var(--ant-color-fill-quaternary)" },
".cm-activeLineGutter": { backgroundColor: "var(--ant-color-fill-quaternary)", color: "var(--ant-color-text)" },
".cm-cursor": { borderLeftColor: "var(--ant-color-text)" },
".cm-selectionBackground, &.cm-focused .cm-selectionBackground": { backgroundColor: "var(--ant-control-item-bg-active)" },
".cm-foldPlaceholder": { backgroundColor: "var(--ant-color-fill-quaternary)", border: "1px solid var(--ant-color-border)", color: "var(--ant-color-text-tertiary)" },
"&.cm-focused": { outline: "none" },
}, { dark: true });
const jsonHighlightStyle = HighlightStyle.define([
{ tag: tags.propertyName, color: "#f2a7a7" },
{ tag: tags.string, color: "#d6c6a8" },
{ tag: tags.number, color: "#ddb27d" },
{ tag: tags.bool, color: "#c5b3ff" },
{ tag: tags.null, color: "#c5b3ff" },
{ tag: tags.punctuation, color: "rgba(250, 250, 249, 0.62)" },
{ tag: tags.squareBracket, color: "rgba(250, 250, 249, 0.62)" },
{ tag: tags.brace, color: "rgba(250, 250, 249, 0.62)" },
]);
});
const emptySettings: AdminSettings = {
public: {
@@ -291,11 +279,10 @@ export default function AdminSettingsPage() {
<CodeMirror
value={activeJsonText}
height="520px"
extensions={[json(), jsonEditorTheme, syntaxHighlighting(jsonHighlightStyle)]}
extensions={[json(), jsonEditorTheme]}
basicSetup={{ foldGutter: true, lineNumbers: true, highlightActiveLine: true, highlightActiveLineGutter: true }}
theme="none"
onChange={(value) => setJsonText((current) => ({ ...current, public: value }))}
className="admin-json-editor"
style={{ fontSize: 13 }}
/>
</div>
@@ -341,11 +328,10 @@ export default function AdminSettingsPage() {
<CodeMirror
value={activeJsonText}
height="520px"
extensions={[json(), jsonEditorTheme, syntaxHighlighting(jsonHighlightStyle)]}
extensions={[json(), jsonEditorTheme]}
basicSetup={{ foldGutter: true, lineNumbers: true, highlightActiveLine: true, highlightActiveLineGutter: true }}
theme="none"
onChange={(value) => setJsonText((current) => ({ ...current, private: value }))}
className="admin-json-editor"
style={{ fontSize: 13 }}
/>
</div>
-68
View File
@@ -80,7 +80,6 @@
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--admin-card-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}
.dark {
@@ -115,7 +114,6 @@
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
--admin-card-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06);
}
@layer base {
@@ -370,72 +368,6 @@
top: 21px;
}
.admin-layout .ant-layout-sider {
border-right: 1px solid var(--border);
}
.admin-layout .ant-layout-header {
border-bottom: 1px solid var(--border);
}
.admin-layout .ant-layout-sider-children > .ant-flex:first-child {
border-bottom: 1px solid var(--border);
}
.admin-logo {
background: currentColor;
display: inline-block;
height: 32px;
mask: url(/logo.svg) center / contain no-repeat;
width: 32px;
-webkit-mask: url(/logo.svg) center / contain no-repeat;
}
.admin-layout .ant-layout-sider-children > .ant-flex:last-child {
border-top: 1px solid var(--border);
background: var(--card);
}
.admin-layout .ant-card,
.admin-layout .ant-pro-card {
box-shadow: var(--admin-card-shadow);
}
.admin-layout .ant-table-cell .ant-btn-icon-only.ant-btn-sm {
height: 26px;
width: 26px;
}
.admin-json-editor .cm-editor {
background: var(--card);
color: var(--foreground);
font-family: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.admin-json-editor .cm-scroller {
font-family: inherit;
}
.admin-json-editor .cm-gutters {
background: color-mix(in srgb, var(--card) 92%, var(--foreground));
border-right: 1px solid var(--border);
color: var(--muted-foreground);
}
.admin-json-editor .cm-activeLine,
.admin-json-editor .cm-activeLineGutter {
background: color-mix(in srgb, var(--primary) 12%, transparent);
}
.admin-json-editor .cm-cursor {
border-left-color: var(--foreground);
}
.admin-json-editor .cm-selectionBackground,
.admin-json-editor .cm-focused .cm-selectionBackground {
background: color-mix(in srgb, var(--primary) 28%, transparent);
}
@keyframes canvas-batch-child-in {
from {
opacity: 0;
+3 -171
View File
@@ -2,188 +2,20 @@
import type { ReactNode } from "react";
import { ProConfigProvider } from "@ant-design/pro-components";
import { App, ConfigProvider, theme as antdTheme } from "antd";
import { App, ConfigProvider } from "antd";
import zhCN from "antd/locale/zh_CN";
import { getAntThemeConfig } from "@/lib/app-theme";
import { useThemeStore } from "@/stores/use-theme-store";
export function AntThemeProvider({ children }: { children: ReactNode }) {
const theme = useThemeStore((state) => state.theme);
const dark = theme === "dark";
const colors = dark
? {
bg: "#1f1d1a",
layout: "#181715",
panel: "#24211e",
elevated: "#292524",
fill: "#322e29",
fillHover: "#3a3631",
border: "#44403c",
borderSoft: "rgba(214, 211, 209, 0.18)",
text: "#f5f5f4",
textSecondary: "#d6d3d1",
textTertiary: "#a8a29e",
primary: "#f5f5f4",
primaryText: "#1c1917",
menuSelected: "#3a3631",
tableHeader: "#2b2521",
}
: {
bg: "#fbfaf7",
layout: "#f4f2ed",
panel: "#ffffff",
elevated: "#ffffff",
fill: "#f5f5f4",
fillHover: "#e7e5df",
border: "#d6d3ca",
borderSoft: "rgba(87, 83, 78, 0.18)",
text: "#292524",
textSecondary: "#57534e",
textTertiary: "#78716c",
primary: "#111111",
primaryText: "#ffffff",
menuSelected: "#f5f5f4",
tableHeader: "#f8fafc",
};
return (
<ConfigProvider
locale={zhCN}
theme={{
algorithm: dark ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
token: {
colorPrimary: colors.primary,
colorPrimaryHover: dark ? "#ffffff" : "#2a2a2a",
colorPrimaryActive: dark ? "#e7e5e4" : "#000000",
colorInfo: colors.primary,
colorBgBase: colors.bg,
colorBgLayout: colors.layout,
colorBgContainer: colors.panel,
colorBgElevated: colors.elevated,
colorFill: colors.fill,
colorFillSecondary: colors.fill,
colorFillTertiary: colors.fillHover,
colorFillQuaternary: dark ? "rgba(245, 245, 244, 0.08)" : "rgba(28, 25, 23, 0.04)",
colorBorder: colors.border,
colorBorderSecondary: colors.borderSoft,
colorSplit: colors.borderSoft,
colorText: colors.text,
colorTextBase: colors.text,
colorTextSecondary: colors.textSecondary,
colorTextTertiary: colors.textTertiary,
colorTextQuaternary: dark ? "#78716c" : "#a8a29e",
colorIcon: colors.textSecondary,
colorIconHover: colors.text,
colorLink: colors.text,
colorLinkHover: colors.text,
colorBgSpotlight: dark ? "#f5f5f4" : "#1c1917",
colorTextLightSolid: dark ? "#1c1917" : "#ffffff",
colorError: "#ff4d4f",
colorErrorHover: "#ff7875",
colorErrorActive: "#d9363e",
colorWarning: "#faad14",
colorBgMask: dark ? "rgba(0, 0, 0, 0.62)" : "rgba(28, 25, 23, 0.35)",
borderRadius: 8,
borderRadiusLG: 12,
boxShadow: dark ? "0 18px 48px rgba(0, 0, 0, 0.46)" : "0 18px 48px rgba(41, 37, 36, 0.16)",
boxShadowSecondary: dark ? "0 0 0 1px rgba(255,255,255,.06)" : "0 1px 2px rgba(15,23,42,.04)",
fontFamily: '"SF Pro Text","PingFang SC","Microsoft YaHei","Helvetica Neue",sans-serif',
},
components: {
Button: {
primaryColor: colors.primaryText,
defaultColor: colors.text,
defaultBg: dark ? "#1f1d1a" : "#ffffff",
defaultBorderColor: colors.border,
defaultHoverColor: colors.text,
defaultHoverBg: colors.fillHover,
defaultHoverBorderColor: dark ? "#78716c" : "#a8a29e",
dangerColor: "#ffffff",
primaryShadow: "none",
defaultShadow: "none",
dangerShadow: "none",
},
Modal: {
contentBg: colors.elevated,
headerBg: colors.elevated,
footerBg: colors.elevated,
titleColor: colors.text,
},
Menu: {
popupBg: colors.elevated,
itemBg: colors.panel,
itemColor: colors.textSecondary,
itemHoverBg: colors.fillHover,
itemHoverColor: colors.text,
itemActiveBg: colors.menuSelected,
itemSelectedBg: colors.menuSelected,
itemSelectedColor: dark ? "#ffffff" : colors.text,
darkItemBg: colors.panel,
darkItemColor: colors.textSecondary,
darkItemHoverBg: colors.fillHover,
darkItemHoverColor: colors.text,
darkItemSelectedBg: colors.menuSelected,
darkItemSelectedColor: "#ffffff",
},
Layout: {
bodyBg: colors.layout,
headerBg: colors.panel,
headerColor: colors.text,
lightSiderBg: colors.panel,
siderBg: colors.panel,
},
Card: {
bodyPadding: 24,
headerBg: colors.panel,
headerHeight: 56,
},
Table: {
borderColor: colors.borderSoft,
cellPaddingBlockMD: 14,
headerBg: colors.tableHeader,
headerColor: colors.text,
rowHoverBg: colors.fill,
},
Segmented: {
trackBg: colors.fill,
itemSelectedBg: colors.primary,
itemSelectedColor: colors.primaryText,
},
Select: {
selectorBg: dark ? "#1f1d1a" : "#ffffff",
optionActiveBg: colors.fillHover,
optionSelectedBg: dark ? "#3f3a35" : "#f5f5f4",
optionSelectedColor: colors.text,
activeBorderColor: dark ? "#78716c" : "#a8a29e",
hoverBorderColor: dark ? "#57534e" : "#a8a29e",
activeOutlineColor: "transparent",
},
Input: {
activeBg: dark ? "#1f1d1a" : "#ffffff",
hoverBg: dark ? "#1f1d1a" : "#ffffff",
activeBorderColor: dark ? "#78716c" : "#a8a29e",
hoverBorderColor: dark ? "#57534e" : "#a8a29e",
activeShadow: "none",
},
InputNumber: {
activeBg: dark ? "#1f1d1a" : "#ffffff",
hoverBg: dark ? "#1f1d1a" : "#ffffff",
activeBorderColor: dark ? "#78716c" : "#a8a29e",
hoverBorderColor: dark ? "#57534e" : "#a8a29e",
activeShadow: "none",
},
Tabs: {
itemColor: colors.textSecondary,
itemSelectedColor: colors.text,
itemHoverColor: colors.text,
inkBarColor: colors.text,
},
Checkbox: {
colorPrimary: colors.primary,
colorPrimaryHover: colors.primary,
},
},
}}
theme={getAntThemeConfig(dark)}
>
<ProConfigProvider dark={dark}>
<App>{children}</App>
+59
View File
@@ -0,0 +1,59 @@
import type { CSSProperties } from "react";
import type { ThemeConfig } from "antd";
import { theme as antdTheme } from "antd";
const neutral = {
light: {
primary: "#171717",
primaryHover: "#000000",
primaryText: "#ffffff",
menuBg: "#f5f5f5",
menuText: "#171717",
},
dark: {
primary: "#fafafa",
primaryHover: "#ffffff",
primaryText: "#171717",
menuBg: "#262626",
menuText: "#fafafa",
},
};
export const adminLayoutStyle = {
siderWidth: 232,
headerHeight: 56,
brandHeight: 64,
menu: { borderInlineEnd: 0, padding: "18px 12px", fontSize: 15 } satisfies CSSProperties,
menuItem: { height: 44, lineHeight: "44px", marginBlock: 4, borderRadius: 8 } satisfies CSSProperties,
};
export function getAntThemeConfig(dark: boolean): ThemeConfig {
const color = dark ? neutral.dark : neutral.light;
return {
algorithm: dark ? antdTheme.darkAlgorithm : antdTheme.defaultAlgorithm,
cssVar: true,
token: {
colorPrimary: color.primary,
colorInfo: color.primary,
colorLink: color.primary,
colorLinkHover: color.primaryHover,
colorLinkActive: color.primary,
colorTextLightSolid: color.primaryText,
},
components: {
Button: {
primaryShadow: "none",
},
Menu: {
itemActiveBg: color.menuBg,
itemHoverBg: color.menuBg,
itemSelectedBg: color.menuBg,
itemSelectedColor: color.menuText,
darkItemHoverBg: neutral.dark.menuBg,
darkItemSelectedBg: neutral.dark.menuBg,
darkItemSelectedColor: neutral.dark.menuText,
},
},
};
}