From 25153dbd8484fb078c536738b57ecee1839908cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E5=AE=8F=E5=87=AF?= Date: Fri, 24 Jul 2026 14:12:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend-web/src/App.tsx | 2 +- frontend-web/src/components/page-sdebar.css | 15 ++ .../components/workspace/agent-icon-color.ts | 48 ++++- .../workspace/agents/agent-chat-sidebar.tsx | 3 +- .../workspace/agents/agent-module-sidebar.tsx | 7 +- .../workspace/appearance-controls.tsx | 3 +- .../workspace/general-qa-sidebar.tsx | 13 +- .../settings/appearance-settings-page.tsx | 42 +++- .../workspace/workspace-nav-chat-list.tsx | 6 +- frontend-web/src/contexts/ThemeContext.tsx | 39 +++- .../src/core/branding/brand-assets.ts | 5 +- frontend-web/src/core/i18n/locales/en-US.ts | 2 + frontend-web/src/core/i18n/locales/types.ts | 2 + frontend-web/src/core/i18n/locales/zh-CN.ts | 2 + frontend-web/src/core/system-settings/api.ts | 2 +- frontend-web/src/pages/LightAppIframeView.tsx | 4 +- frontend-web/src/pages/LightAppListPage.tsx | 11 ++ frontend-web/src/pages/LightAppNoteQAPage.tsx | 17 +- .../src/pages/NotebookAIWritingPage.tsx | 2 +- frontend-web/src/pages/ScheduledTasksPage.tsx | 4 +- .../src/pages/light-app-management.css | 52 +++++ frontend-web/src/pages/light-app-pages.css | 5 + .../pages/PositionRoundtablePage.tsx | 3 +- .../styles/roundtable-planning.css | 27 +++ .../src/strategy-components/Header.tsx | 34 ++-- .../task-components/css/strategy-data.css | 13 ++ .../src/strategy-components/lib/light-app.ts | 5 +- frontend-web/src/styles/globals.css | 187 ++++++++++++++++++ frontend-web/src/styles/tdesign-theme.css | 33 ++++ .../app/gateway/routers/system_settings.py | 6 +- .../deerflow/config/system_settings.py | 4 +- 31 files changed, 536 insertions(+), 62 deletions(-) diff --git a/frontend-web/src/App.tsx b/frontend-web/src/App.tsx index 13ac398c..34fe1658 100644 --- a/frontend-web/src/App.tsx +++ b/frontend-web/src/App.tsx @@ -93,7 +93,7 @@ function AppProviders({ children }: { children: React.ReactNode }) { attribute="class" storageKey="strategy-theme" defaultTheme="light" - themes={["light", "dark", "lightblue", "lightgreen", "iceblue"]} + themes={["light", "dark", "lightblue", "lightgreen", "iceblue", "lightyellow"]} enableSystem={false} disableTransitionOnChange forcedTheme={forcedTheme} diff --git a/frontend-web/src/components/page-sdebar.css b/frontend-web/src/components/page-sdebar.css index 8737cbe7..091df5fd 100644 --- a/frontend-web/src/components/page-sdebar.css +++ b/frontend-web/src/components/page-sdebar.css @@ -580,6 +580,21 @@ html.iceblue .light-topnav-item--active::after { background: #3d6e96; } +/* Pale yellow has the same light-banner contrast requirement as ice blue. */ +html.lightyellow .light-topnav-item { + color: rgba(48, 61, 35, 0.78); +} + +html.lightyellow .light-topnav-item:hover, +html.lightyellow .light-topnav-item--active, +html.lightyellow .light-topnav-item--active:hover { + color: #303d23; +} + +html.lightyellow .light-topnav-item--active::after { + background: #4c6330; +} + /* ── 侧边栏:二级图标卡片列(96px)+ 右侧三级列(展开时整体变宽,带过渡)──────── */ .light-sidebar { position: fixed; diff --git a/frontend-web/src/components/workspace/agent-icon-color.ts b/frontend-web/src/components/workspace/agent-icon-color.ts index 5f78c7e6..b035cda0 100644 --- a/frontend-web/src/components/workspace/agent-icon-color.ts +++ b/frontend-web/src/components/workspace/agent-icon-color.ts @@ -24,12 +24,52 @@ const AGENT_COLORS_DARK = [ { from: "#69B1FF", to: "#003EB3" }, // 浅蓝 → 主色按下 ] as const; -/** 按 agent id 稳定散列出一对渐变色(from → to)。`isDark` 切换深蓝/浅色调色板。 */ -export function agentColor(id: string, isDark: boolean) { +/** 按 agent id 稳定散列出一对渐变色,并根据当前主题返回可读的图标前景色。 */ +const AGENT_COLORS_ICEBLUE = [ + { from: "#eff8fd", to: "#b7dcf5" }, + { from: "#e3f2fb", to: "#9bcef1" }, + { from: "#ebf6fb", to: "#add8e9" }, + { from: "#edf2fc", to: "#b7cdef" }, + { from: "#e9f7f5", to: "#afe0dc" }, +] as const; + +const AGENT_COLORS_LIGHTYELLOW = [ + { from: "#fbfdef", to: "#e4efbf" }, + { from: "#f7fae9", to: "#F3FBD9" }, + { from: "#f9fbe8", to: "#dcebad" }, + { from: "#faf8e9", to: "#e7dfb9" }, + { from: "#f1f8e5", to: "#cce0af" }, +] as const; + +type AgentAvatarTheme = + | "dark" + | "iceblue" + | "lightyellow" + | "light" + | "lightblue" + | "lightgreen"; + +/** Returns a stable avatar gradient and readable icon color for each theme. */ +export function agentColor(id: string, theme: AgentAvatarTheme) { let hash = 0; for (let i = 0; i < id.length; i++) { hash = (hash * 31 + id.charCodeAt(i)) >>> 0; } - const palette = isDark ? AGENT_COLORS_DARK : AGENT_COLORS_LIGHT; - return palette[hash % palette.length]!; + const palette = + theme === "dark" + ? AGENT_COLORS_DARK + : theme === "iceblue" + ? AGENT_COLORS_ICEBLUE + : theme === "lightyellow" + ? AGENT_COLORS_LIGHTYELLOW + : AGENT_COLORS_LIGHT; + return { + ...palette[hash % palette.length]!, + foreground: + theme === "iceblue" + ? "#2d587a" + : theme === "lightyellow" + ? "#4c6330" + : "#ffffff", + }; } diff --git a/frontend-web/src/components/workspace/agents/agent-chat-sidebar.tsx b/frontend-web/src/components/workspace/agents/agent-chat-sidebar.tsx index b7452f1e..8f75052a 100644 --- a/frontend-web/src/components/workspace/agents/agent-chat-sidebar.tsx +++ b/frontend-web/src/components/workspace/agents/agent-chat-sidebar.tsx @@ -254,7 +254,7 @@ export function AgentChatSidebar({ activeAgentId }: { activeAgentId?: string }) {agents.map((agent) => { const href = `${routeBase}/agents/${agent.id}/chats/new`; const isActive = agent.id === activeAgentId; - const { from, to } = agentColor(agent.id, isDark); + const { from, to, foreground } = agentColor(agent.id, theme); return ( diff --git a/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx b/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx index c5cf8ae1..18951da6 100644 --- a/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx +++ b/frontend-web/src/components/workspace/agents/agent-module-sidebar.tsx @@ -206,7 +206,7 @@ export function AgentModuleSidebar({ const renderAgentCard = (agent: Agent, keyPrefix: string) => { const href = `${routeBase}/agents/${agent.id}/chats/new`; const isActive = agent.id === activeAgentId; - const { from, to } = agentColor(agent.id, isDark); + const { from, to, foreground } = agentColor(agent.id, theme); return ( diff --git a/frontend-web/src/components/workspace/appearance-controls.tsx b/frontend-web/src/components/workspace/appearance-controls.tsx index 192fc33c..decf3371 100644 --- a/frontend-web/src/components/workspace/appearance-controls.tsx +++ b/frontend-web/src/components/workspace/appearance-controls.tsx @@ -28,12 +28,13 @@ import { buildLightAppUrl } from "@/strategy-components/lib/light-app"; */ export type AppearanceControlTone = "banner-dark" | "banner-light" | "content"; -// 换肤色板:红色=红白主题(light),蓝色=浅蓝主题(lightblue),冰川蓝=柔和浅蓝主题(iceblue),深蓝色=深色主题(dark) +// 换肤色板:红色=红白主题(light),蓝色=浅蓝主题(lightblue),冰川蓝=柔和浅蓝主题(iceblue),浅黄色=柔和黄主题(lightyellow),深蓝色=深色主题(dark) export const THEME_SWATCHES: { id: ThemeType; label: string; color: string }[] = [ { id: "light", label: "红色", color: "#cf1322" }, { id: "lightgreen", label: "绿色", color: "#07c05f" }, { id: "lightblue", label: "蓝色", color: "#0062d9" }, { id: "iceblue", label: "冰川蓝", color: "#9BCEF1" }, + { id: "lightyellow", label: "浅黄色", color: "#F3FBD9" }, { id: "dark", label: "深蓝色", color: "#002466" }, ]; diff --git a/frontend-web/src/components/workspace/general-qa-sidebar.tsx b/frontend-web/src/components/workspace/general-qa-sidebar.tsx index 0d9ab511..23bdfbab 100644 --- a/frontend-web/src/components/workspace/general-qa-sidebar.tsx +++ b/frontend-web/src/components/workspace/general-qa-sidebar.tsx @@ -318,7 +318,7 @@ export function GeneralQaSidebar() { onClick={handleNewChatClick} style={{ borderColor: "var(--primary)", color: "var(--primary)" }} className={cn( - "flex h-10 min-w-0 flex-1 items-center justify-center gap-1.5 rounded-[5px] text-[14px] font-semibold transition-colors", + "gq-new-chat-button flex h-10 min-w-0 flex-1 items-center justify-center gap-1.5 rounded-[5px] text-[14px] font-semibold transition-colors", "border border-solid", "bg-[rgb(var(--legacy-primary-rgb)/14%)] hover:bg-[rgb(var(--legacy-primary-rgb)/24%)]", )} @@ -342,7 +342,7 @@ export function GeneralQaSidebar() {
{frequent.map((agent) => { const isActive = activeAgentId === agent.id; - const { from, to } = agentColor(agent.id, isDark); + const { from, to, foreground } = agentColor(agent.id, theme); return ( +

当前系统默认: {globalDefault === "light" @@ -607,7 +627,9 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) { ? "绿色" : globalDefault === "iceblue" ? "冰川蓝" - : "浅蓝"} + : globalDefault === "lightyellow" + ? "浅黄色" + : "浅蓝"}

@@ -1124,8 +1146,8 @@ function ThemePreviewCard({ label: string; description: string; active: boolean; - mode: "light" | "dark" | "lightblue" | "lightgreen" | "iceblue"; - onSelect: (mode: "light" | "dark" | "lightblue" | "lightgreen" | "iceblue") => void; + mode: "light" | "dark" | "lightblue" | "lightgreen" | "iceblue" | "lightyellow"; + onSelect: (mode: "light" | "dark" | "lightblue" | "lightgreen" | "iceblue" | "lightyellow") => void; }) { const previewMode = mode; return ( @@ -1161,7 +1183,9 @@ function ThemePreviewCard({ ? "border-emerald-200 bg-white text-emerald-950" : previewMode === "iceblue" ? "border-sky-200 bg-[#F7FBFE] text-[#18324A]" - : "border-slate-200 bg-white text-slate-900", + : previewMode === "lightyellow" + ? "border-lime-200 bg-[#FCFDF5] text-[#303D23]" + : "border-slate-200 bg-white text-slate-900", )} >
@@ -1176,7 +1200,9 @@ function ThemePreviewCard({ ? "bg-[#07c05f]" : previewMode === "iceblue" ? "bg-[#9BCEF1]" - : "bg-[#cf1322]", + : previewMode === "lightyellow" + ? "bg-[#F3FBD9]" + : "bg-[#cf1322]", )} />
diff --git a/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx b/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx index 58505ae7..1c93ecec 100644 --- a/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx +++ b/frontend-web/src/components/workspace/workspace-nav-chat-list.tsx @@ -23,19 +23,19 @@ import { cn } from "@/lib/utils"; // 普通导航项:默认中性色,激活态与「新对话」一致——主色浅底 + 主色文字/图标 const NAV_ITEM_CLASS = - "text-sidebar-foreground/80 hover:text-primary rounded-xl h-9 px-3 transition-colors hover:bg-primary/10 " + + "workspace-nav-item text-sidebar-foreground/80 hover:text-primary rounded-xl h-9 px-3 transition-colors hover:bg-primary/10 " + "data-[active=true]:bg-primary/15 data-[active=true]:text-primary data-[active=true]:shadow-none " + "dark:hover:bg-primary/15 dark:data-[active=true]:bg-primary/25 dark:data-[active=true]:text-primary-foreground"; // 「新对话」专属:默认仅主色文字/图标(显眼但不是选中态),命中 /chats/new 时才上主色底 const NEW_CHAT_CLASS = - "rounded-xl h-9 px-3 text-primary transition-colors hover:bg-primary/10 hover:text-primary " + + "workspace-nav-new-chat rounded-xl h-9 px-3 text-primary transition-colors hover:bg-primary/10 hover:text-primary " + "data-[active=true]:bg-primary/15 data-[active=true]:text-primary data-[active=true]:shadow-none " + "dark:text-primary-foreground dark:hover:bg-primary/15 dark:data-[active=true]:bg-primary/25"; // 紧凑模式(CM 参考图):白卡描边、居中、主色 + 图标 const NEW_CHAT_COMPACT_CLASS = - "h-9 justify-center gap-2 rounded-xl bg-card text-[13px] font-semibold text-foreground transition-colors " + + "workspace-compact-new-chat h-9 justify-center gap-2 rounded-xl bg-card text-[13px] font-semibold text-foreground transition-colors " + "border border-[rgb(var(--legacy-primary-rgb)/18%)] " + "hover:bg-[rgb(var(--legacy-primary-rgb)/4%)] hover:text-[var(--primary)] hover:border-[rgb(var(--legacy-primary-rgb)/32%)] " + "data-[active=true]:bg-card data-[active=true]:text-[var(--primary)] data-[active=true]:shadow-none"; diff --git a/frontend-web/src/contexts/ThemeContext.tsx b/frontend-web/src/contexts/ThemeContext.tsx index f44e7ad7..afc8eb83 100644 --- a/frontend-web/src/contexts/ThemeContext.tsx +++ b/frontend-web/src/contexts/ThemeContext.tsx @@ -11,7 +11,7 @@ import { useAppearanceSettings } from '@/core/system-settings/hooks'; import { isPositionRoundtableStandaloneMode } from '@/position-roundtable/demo/position-roundtable-demo-config'; // 主题类型 -export type ThemeType = 'dark' | 'light' | 'lightblue' | 'lightgreen' | 'iceblue'; +export type ThemeType = 'dark' | 'light' | 'lightblue' | 'lightgreen' | 'iceblue' | 'lightyellow'; // 主题配置 export interface ThemeConfig { @@ -151,6 +151,28 @@ const themes: Record = { overlay: 'slate-900/30', }, }, + lightyellow: { + type: 'lightyellow', + name: '浅黄色主题', + colors: { + background: 'lime-50', + backgroundSecondary: 'lime-100', + text: 'lime-950', + textSecondary: 'lime-800', + primary: 'lime-100', + primaryHover: 'lime-200', + border: 'lime-200', + accent: 'lime-100', + success: 'emerald-600', + warning: 'amber-600', + error: 'red-600', + card: 'white', + cardHover: 'lime-50', + input: 'white', + inputBorder: 'lime-200', + overlay: 'slate-900/30', + }, + }, }; const STORAGE_KEY = 'strategy-theme'; @@ -170,6 +192,7 @@ function readPersistedTheme(): ThemeType { if (saved === 'lightblue') return 'lightblue'; if (saved === 'lightgreen') return 'lightgreen'; if (saved === 'iceblue') return 'iceblue'; + if (saved === 'lightyellow') return 'lightyellow'; return 'light'; } @@ -232,7 +255,8 @@ export const ThemeProvider: React.FC = ({ children }) => { current !== 'dark' && current !== 'lightblue' && current !== 'lightgreen' && - current !== 'iceblue' + current !== 'iceblue' && + current !== 'lightyellow' ) { // Garbage value — wipe it so the boot-sync below can take over. localStorage.removeItem(STORAGE_KEY); @@ -273,7 +297,9 @@ export const ThemeProvider: React.FC = ({ children }) => { ? 'lightgreen' : effectiveTheme === 'iceblue' ? 'iceblue' - : 'light' + : effectiveTheme === 'lightyellow' + ? 'lightyellow' + : 'light' : readPersistedTheme(); useEffect(() => { @@ -291,7 +317,12 @@ export const ThemeProvider: React.FC = ({ children }) => { root.removeAttribute('theme-mode'); root.classList.remove('dark'); - if (theme === 'lightblue' || theme === 'lightgreen' || theme === 'iceblue') { + if ( + theme === 'lightblue' || + theme === 'lightgreen' || + theme === 'iceblue' || + theme === 'lightyellow' + ) { root.setAttribute('data-theme', theme); } else { root.removeAttribute('data-theme'); diff --git a/frontend-web/src/core/branding/brand-assets.ts b/frontend-web/src/core/branding/brand-assets.ts index 77182eba..f78779ce 100644 --- a/frontend-web/src/core/branding/brand-assets.ts +++ b/frontend-web/src/core/branding/brand-assets.ts @@ -3,13 +3,14 @@ import fallbackLogoLight from "@/assets/img/brand-logo-light.png"; import fallbackLogoLightblue from "@/assets/img/brand-logo-lightblue.png"; import { readRuntimeEnv } from "@/env"; -export type BrandTheme = "light" | "lightblue" | "lightgreen" | "iceblue" | "dark"; +export type BrandTheme = "light" | "lightblue" | "lightgreen" | "iceblue" | "lightyellow" | "dark"; const headerFallbackAssets: Record = { light: fallbackLogoLight, lightblue: fallbackLogoLightblue, lightgreen: fallbackLogoLight, iceblue: fallbackLogoLightblue, + lightyellow: fallbackLogoLight, dark: fallbackLogoDark, }; @@ -18,6 +19,7 @@ const headerRuntimeKeys: Record = { lightblue: "VITE_BRAND_LOGO_LIGHTBLUE_URL", lightgreen: "VITE_BRAND_LOGO_LIGHTGREEN_URL", iceblue: "VITE_BRAND_LOGO_ICEBLUE_URL", + lightyellow: "VITE_BRAND_LOGO_LIGHTYELLOW_URL", dark: "VITE_BRAND_LOGO_DARK_URL", }; @@ -26,6 +28,7 @@ const welcomeRuntimeKeys: Record = { lightblue: "VITE_BRAND_WELCOME_LIGHTBLUE_URL", lightgreen: "VITE_BRAND_WELCOME_LIGHTGREEN_URL", iceblue: "VITE_BRAND_WELCOME_ICEBLUE_URL", + lightyellow: "VITE_BRAND_WELCOME_LIGHTYELLOW_URL", dark: "VITE_BRAND_WELCOME_DARK_URL", }; diff --git a/frontend-web/src/core/i18n/locales/en-US.ts b/frontend-web/src/core/i18n/locales/en-US.ts index 396a828b..ebaae531 100644 --- a/frontend-web/src/core/i18n/locales/en-US.ts +++ b/frontend-web/src/core/i18n/locales/en-US.ts @@ -451,12 +451,14 @@ export const enUS: Translations = { lightblue: "Light Blue", lightgreen: "Green", iceblue: "Glacier Blue", + lightyellow: "Pale Yellow", systemDescription: "Match the operating system preference automatically.", lightDescription: "Bright palette with higher contrast for daytime.", darkDescription: "Dim palette that reduces glare for focus.", lightblueDescription: "A crisp light palette built around blue.", lightgreenDescription: "A crisp light palette built around WeKnora green.", iceblueDescription: "An airy palette built around #9BCEF1 with accessible blue actions.", + lightyellowDescription: "A soft palette built around #F3FBD9 with readable olive actions.", languageTitle: "Language", languageDescription: "Switch between languages.", }, diff --git a/frontend-web/src/core/i18n/locales/types.ts b/frontend-web/src/core/i18n/locales/types.ts index 64dc4f67..2dc0c0c6 100644 --- a/frontend-web/src/core/i18n/locales/types.ts +++ b/frontend-web/src/core/i18n/locales/types.ts @@ -386,12 +386,14 @@ export interface Translations { lightblue: string; lightgreen: string; iceblue: string; + lightyellow: string; systemDescription: string; lightDescription: string; darkDescription: string; lightblueDescription: string; lightgreenDescription: string; iceblueDescription: string; + lightyellowDescription: string; languageTitle: string; languageDescription: string; }; diff --git a/frontend-web/src/core/i18n/locales/zh-CN.ts b/frontend-web/src/core/i18n/locales/zh-CN.ts index 5f54be64..98ecbb27 100644 --- a/frontend-web/src/core/i18n/locales/zh-CN.ts +++ b/frontend-web/src/core/i18n/locales/zh-CN.ts @@ -432,12 +432,14 @@ export const zhCN: Translations = { lightblue: "浅蓝", lightgreen: "绿色", iceblue: "冰川蓝", + lightyellow: "浅黄色", systemDescription: "自动跟随系统主题。", lightDescription: "更明亮的配色,适合日间使用。", darkDescription: "更暗的配色,减少眩光方便专注。", lightblueDescription: "以蓝色为主色的清爽浅色配色。", lightgreenDescription: "采用 WeKnora 绿色的清爽浅色配色。", iceblueDescription: "以 #9BCEF1 为主色,搭配冰蓝留白与沉稳交互色。", + lightyellowDescription: "以 #F3FBD9 为主色,搭配柔和浅黄留白与深橄榄交互色。", languageTitle: "语言", languageDescription: "在不同语言之间切换。", }, diff --git a/frontend-web/src/core/system-settings/api.ts b/frontend-web/src/core/system-settings/api.ts index 0ae6d5fa..4d45a3e1 100644 --- a/frontend-web/src/core/system-settings/api.ts +++ b/frontend-web/src/core/system-settings/api.ts @@ -276,7 +276,7 @@ export async function updatePublishSquares( return data; } -export type ThemeMode = "light" | "dark" | "lightblue" | "lightgreen" | "iceblue"; +export type ThemeMode = "light" | "dark" | "lightblue" | "lightgreen" | "iceblue" | "lightyellow"; export type ViewMode = "card" | "list"; export type LayoutMode = "full" | "compact"; export type CompactShortcutParamType = "login" | "theme"; diff --git a/frontend-web/src/pages/LightAppIframeView.tsx b/frontend-web/src/pages/LightAppIframeView.tsx index 91aa1c28..28fbbd5f 100644 --- a/frontend-web/src/pages/LightAppIframeView.tsx +++ b/frontend-web/src/pages/LightAppIframeView.tsx @@ -29,7 +29,9 @@ export default function LightAppIframeView() { ? "blue" : theme === "iceblue" ? "iceblue" - : "red"; + : theme === "lightyellow" + ? "lightyellow" + : "red"; const src = useMemo( () => (app ? buildLightAppUrl(app, undefined, themeColor) : ""), [app, themeColor], diff --git a/frontend-web/src/pages/LightAppListPage.tsx b/frontend-web/src/pages/LightAppListPage.tsx index 1f6da0b0..5031a9f6 100644 --- a/frontend-web/src/pages/LightAppListPage.tsx +++ b/frontend-web/src/pages/LightAppListPage.tsx @@ -98,6 +98,17 @@ function getLightAccent(theme: ThemeType) { button: "bg-[#9BCEF1] text-[#18324A] shadow-[0_1px_3px_rgba(155,206,241,0.42)] hover:bg-[#B7DCF5]", }; } + if (theme === "lightyellow") { + return { + dot: "bg-[#F3FBD9]", + badge: "border-[#4C6330]/15 bg-[#EEF6D4] text-[#4C6330]", + focus: "focus:border-[#4C6330]/60 focus:ring-[#F3FBD9]/40", + text: "text-[#4C6330]", + hoverText: "group-hover:text-[#4C6330]", + link: "text-[#4C6330] hover:text-[#34451F]", + button: "bg-[#F3FBD9] text-[#303D23] shadow-[0_1px_3px_rgba(243,251,217,0.72)] hover:bg-[#E4EFBF]", + }; + } return { dot: "bg-[#CF1322]", badge: "border-[#CF1322]/15 bg-[#FFF1F0] text-[#CF1322]", diff --git a/frontend-web/src/pages/LightAppNoteQAPage.tsx b/frontend-web/src/pages/LightAppNoteQAPage.tsx index 1136b974..da1889f7 100644 --- a/frontend-web/src/pages/LightAppNoteQAPage.tsx +++ b/frontend-web/src/pages/LightAppNoteQAPage.tsx @@ -11,6 +11,7 @@ export default function LightAppNoteQAPage() { const isDark = theme === "dark"; const isLightBlue = theme === 'lightblue' || theme === 'iceblue'; const isLightGreen = theme === "lightgreen"; + const isLightYellow = theme === "lightyellow"; const [question, setQuestion] = useState(""); const handleSubmit = () => { @@ -31,7 +32,9 @@ export default function LightAppNoteQAPage() { style={{ background: isDark ? "radial-gradient(ellipse 60% 50% at 50% 46%, rgba(59,130,246,0.10) 0%, rgba(139,92,246,0.06) 50%, transparent 70%)" - : "radial-gradient(ellipse 60% 50% at 50% 46%, rgba(147,197,253,0.38) 0%, rgba(165,180,252,0.18) 50%, transparent 70%)", + : isLightYellow + ? "radial-gradient(ellipse 60% 50% at 50% 46%, rgba(243,251,217,0.7) 0%, rgba(220,235,173,0.26) 50%, transparent 70%)" + : "radial-gradient(ellipse 60% 50% at 50% 46%, rgba(147,197,253,0.38) 0%, rgba(165,180,252,0.18) 50%, transparent 70%)", }} /> @@ -43,7 +46,11 @@ export default function LightAppNoteQAPage() {
@@ -66,7 +73,9 @@ export default function LightAppNoteQAPage() { "flex items-center gap-1.5 rounded-full px-4 py-1 text-sm font-medium transition-colors", isDark ? "bg-sky-500/20 text-sky-300 hover:bg-sky-500/30" - : "bg-sky-100 text-sky-600 hover:bg-sky-200", + : isLightYellow + ? "bg-[#EEF6D4] text-[#4C6330] hover:bg-[#E4EFBF]" + : "bg-sky-100 text-sky-600 hover:bg-sky-200", )} > @@ -115,6 +124,8 @@ export default function LightAppNoteQAPage() { ? "bg-sky-500 text-white hover:bg-sky-400" : isLightGreen ? "bg-[#07C05F] text-white hover:bg-[#08DD6E]" + : isLightYellow + ? "bg-[#F3FBD9] text-[#303D23] hover:bg-[#E4EFBF]" : isLightBlue ? "bg-[#0062D9] text-white hover:bg-[#0079FE]" : "bg-[#F5222D] text-white hover:bg-[#CF1322]", diff --git a/frontend-web/src/pages/NotebookAIWritingPage.tsx b/frontend-web/src/pages/NotebookAIWritingPage.tsx index 9e719570..af811ab0 100644 --- a/frontend-web/src/pages/NotebookAIWritingPage.tsx +++ b/frontend-web/src/pages/NotebookAIWritingPage.tsx @@ -4,7 +4,7 @@ import AIWritingPage from '@/open-canvas/pages/AIWritingPage'; import { getNotebookApiBaseURL } from '@/core/config'; import { useTheme, type ThemeType } from '@/contexts/ThemeContext'; -const VALID_THEMES: ThemeType[] = ['dark', 'light', 'lightblue', 'lightgreen', 'iceblue']; +const VALID_THEMES: ThemeType[] = ['dark', 'light', 'lightblue', 'lightgreen', 'iceblue', 'lightyellow']; interface NotebookTokenData { doc_ids: number[]; diff --git a/frontend-web/src/pages/ScheduledTasksPage.tsx b/frontend-web/src/pages/ScheduledTasksPage.tsx index 00bb752b..ca50aefb 100644 --- a/frontend-web/src/pages/ScheduledTasksPage.tsx +++ b/frontend-web/src/pages/ScheduledTasksPage.tsx @@ -793,7 +793,7 @@ export default function ScheduledTasksPage({ @@ -323,7 +323,7 @@ const Header = ({ collapsed }: HeaderProps) => { onError={handleBrandLogoError} />
- + {desensitizeText("CM业务中心")}
@@ -344,7 +344,7 @@ const Header = ({ collapsed }: HeaderProps) => { "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg", isDark ? "bg-gradient-to-br from-blue-500 to-cyan-400" - : isIceBlue + : isPaleLightTheme ? "bg-white/55" : "bg-white/20", )} @@ -358,7 +358,7 @@ const Header = ({ collapsed }: HeaderProps) => { />
{!collapsed && ( - + {desensitizeText("CM业务中心")} )} diff --git a/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css b/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css index a6a06e42..516e428f 100644 --- a/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css +++ b/frontend-web/src/strategy-components/components/task-components/css/strategy-data.css @@ -44,6 +44,19 @@ --input-border: 204 50% 90%; } +/* Pale yellow follows the global #F3FBD9 primary and readable olive labels. */ +[data-theme="lightyellow"] .strategy-data { + --color-main: #F3FBD9; + --color-main-foreground: #303D23; + --bg-color: #EEF6D4; + --card-border: #DCEBAD; + --text-color: #303D23; + + --card-hover: 75 66% 95%; + --border-color: 75 47% 86%; + --input-border: 75 47% 86%; +} + /* ── CSS variables (dark) ────────────────────────────────────────────── */ .dark .strategy-data { --color-main: var(--color-primary); diff --git a/frontend-web/src/strategy-components/lib/light-app.ts b/frontend-web/src/strategy-components/lib/light-app.ts index e55463a0..f6662722 100644 --- a/frontend-web/src/strategy-components/lib/light-app.ts +++ b/frontend-web/src/strategy-components/lib/light-app.ts @@ -42,7 +42,7 @@ export const LOGIN_SOURCE_OPTIONS: { label: string; value: string }[] = [ * 我方主题色键。当前启用 red(浅色) / dark-blue(深色);blue 为后续将新增的主题。 * 主题参数的映射以这些键为左侧 key(如 `dark-blue=darkBlue`)。 */ -export type AppThemeColor = "red" | "green" | "blue" | "iceblue" | "dark-blue"; +export type AppThemeColor = "red" | "green" | "blue" | "iceblue" | "lightyellow" | "dark-blue"; /** 我方全部主题色(「应用管理」主题参数逐项配置目标值时遍历;dot 为配色小圆点)。 */ export const APP_THEME_COLORS: { key: AppThemeColor; label: string; dot: string }[] = [ @@ -50,6 +50,7 @@ export const APP_THEME_COLORS: { key: AppThemeColor; label: string; dot: string { key: "red", label: "红色", dot: "#F5222D" }, { key: "blue", label: "蓝色", dot: "#1677FF" }, { key: "iceblue", label: "冰川蓝", dot: "#9BCEF1" }, + { key: "lightyellow", label: "浅黄色", dot: "#F3FBD9" }, { key: "dark-blue", label: "深蓝色", dot: "#002B5C" }, ]; @@ -62,6 +63,7 @@ const THEME_KEY_ALIASES: Record = { green: ["green", "lightgreen"], blue: ["blue"], iceblue: ["iceblue", "ice-blue"], + lightyellow: ["lightyellow", "light-yellow", "yellow"], "dark-blue": ["dark-blue", "darkblue", "dark"], }; @@ -76,6 +78,7 @@ export function getCurrentTheme(): AppThemeColor { if (classList.contains("lightgreen")) return "green"; if (classList.contains("lightblue")) return "blue"; if (classList.contains("iceblue")) return "iceblue"; + if (classList.contains("lightyellow")) return "lightyellow"; } return "red"; } diff --git a/frontend-web/src/styles/globals.css b/frontend-web/src/styles/globals.css index 85531329..498bf0ee 100644 --- a/frontend-web/src/styles/globals.css +++ b/frontend-web/src/styles/globals.css @@ -525,6 +525,65 @@ --legacy-workspace-brand-rgb: 155 206 241; } +/* Pale yellow: #F3FBD9 is the signature hue. Dark olive foreground and + interaction tokens preserve contrast while the surfaces remain airy. */ +.lightyellow { + --workspace-brand: #F3FBD9; + --workspace-brand-foreground: #303d23; + --brand-200: #eef6d4; + --brand-900: #4c6330; + --brand-950: #34451f; + --background: #fcfdf5; + --foreground: #303d23; + --card: #ffffff; + --card-foreground: #303d23; + --popover: #ffffff; + --popover-foreground: #303d23; + --primary: #F3FBD9; + --primary-foreground: #303d23; + --secondary: #f7fae9; + --secondary-foreground: #4c6330; + --muted: #f6f8ea; + --muted-foreground: #68705a; + --accent: #eef6d4; + --accent-foreground: #4c6330; + --destructive: #cf4a4a; + --border: #dce8bc; + --input: #d2e1ad; + --ring: rgb(243 251 217 / 0.78); + --chart-1: #627b3d; + --chart-2: #56855e; + --chart-3: #85714b; + --chart-4: #bb8535; + --chart-5: #4f8f76; + --sidebar: #fdfef8; + --sidebar-foreground: #303d23; + --sidebar-primary: #F3FBD9; + --sidebar-primary-foreground: #303d23; + --sidebar-accent: #eef6d4; + --sidebar-accent-foreground: #4c6330; + --sidebar-border: #e4edcb; + --sidebar-ring: rgb(243 251 217 / 0.78); + --legacy-accent-rgb: 238 246 212; + --legacy-background-rgb: 252 253 245; + --legacy-border-rgb: 220 232 188; + --legacy-brand-200-rgb: 238 246 212; + --legacy-card-rgb: 255 255 255; + --legacy-destructive-rgb: 207 74 74; + --legacy-foreground-rgb: 48 61 35; + --legacy-input-rgb: 210 225 173; + --legacy-muted-rgb: 246 248 234; + --legacy-muted-foreground-rgb: 104 112 90; + --legacy-primary-rgb: 243 251 217; + --legacy-primary-foreground-rgb: 48 61 35; + --legacy-ring-rgb: 243 251 217; + --legacy-secondary-rgb: 247 250 233; + --legacy-sidebar-accent-rgb: 238 246 212; + --legacy-sidebar-border-rgb: 228 237 203; + --legacy-sidebar-foreground-rgb: 48 61 35; + --legacy-workspace-brand-rgb: 243 251 217; +} + @layer base { * { @apply border-border outline-ring/50; @@ -1471,6 +1530,43 @@ html.iceblue .tiptap-writing-editor .ProseMirror ::selection { background: rgb(155 206 241 / 0.5); } +html.lightyellow .strategy-app-header { + background-color: #F3FBD9; + background-image: linear-gradient(105deg, #71864c 0%, #F3FBD9 52%, #fbfeec 100%); +} + +html.lightyellow *::-webkit-scrollbar-thumb { + background: linear-gradient(180deg, rgb(228 239 191 / 0.88), rgb(76 99 48 / 0.9)) + padding-box; +} + +html.lightyellow .workspace-panel { + border: 1px solid #dce8bc; + box-shadow: + 0 32px 72px -46px rgb(78 99 47 / 0.28), + 0 12px 28px -22px rgb(153 178 101 / 0.2); +} + +html.lightyellow .workspace-user-bubble { + border: 1px solid rgb(255 255 255 / 0.22); + background: linear-gradient(135deg, #a9bd72 0%, #71864c 58%, #4c6330 100%); + box-shadow: + 0 22px 40px -28px rgb(76 99 48 / 0.5), + 0 10px 20px -16px rgb(52 69 31 / 0.34); +} + +html.lightyellow .workspace-assistant-card { + border: 1px solid #e3edc8; +} + +html.lightyellow .workspace-assistant-card::before { + background: linear-gradient(180deg, rgb(243 251 217 / 0.86), rgb(243 251 217 / 0.12)); +} + +html.lightyellow .tiptap-writing-editor .ProseMirror ::selection { + background: rgb(243 251 217 / 0.72); +} + /* ── 来源上传弹窗:A系统基因库的分段单选条(custom-radio) ─────────────── */ /* 外层容器,模拟 nz-radio-group */ .custom-radio-group { @@ -1583,6 +1679,85 @@ html.iceblue .tiptap-writing-editor .ProseMirror ::selection { border-color: rgb(61 110 150 / 0.5); } +.lightyellow .agent-avatar { + background-color: #eef6d4; + color: #4c6330; + box-shadow: inset 0 0 0 1px rgb(76 99 48 / 0.16); +} + +.lightyellow .agent-sidebar-card--active { + background-color: #eef6d4; + border-color: rgb(76 99 48 / 0.5); +} + +/* Compact workspace navigation: the pale primary needs an olive foreground + on selected items instead of inheriting #F3FBD9 as text. */ +html.lightyellow .workspace-compact-new-chat { + border-color: rgb(76 99 48 / 0.38) !important; + color: #4c6330 !important; +} + +html.lightyellow .workspace-compact-new-chat:hover, +html.lightyellow .workspace-compact-new-chat[data-active="true"] { + border-color: rgb(76 99 48 / 0.58) !important; + background-color: #eef6d4 !important; + color: #4c6330 !important; + box-shadow: inset 0 0 0 1px rgb(76 99 48 / 0.1); +} + +html.lightyellow .workspace-compact-new-chat :is(svg, span) { + color: #4c6330 !important; +} + +/* Full workspace sidebar: its original selected state uses `text-primary`. + The pale yellow brand color is intentionally unsuitable for text on white, + so only this theme gets an olive selected foreground and a visible marker. */ +html.lightyellow .workspace-nav-new-chat { + color: #4c6330 !important; +} + +html.lightyellow .workspace-nav-new-chat :is(svg, span), +html.lightyellow .workspace-nav-item:hover :is(svg, span), +html.lightyellow .workspace-nav-item[data-active="true"] :is(svg, span) { + color: #4c6330 !important; +} + +html.lightyellow .workspace-nav-new-chat:hover, +html.lightyellow .workspace-nav-new-chat[data-active="true"], +html.lightyellow .workspace-nav-item:hover, +html.lightyellow .workspace-nav-item[data-active="true"] { + background-color: #eef6d4 !important; + color: #4c6330 !important; + box-shadow: inset 3px 0 0 #4c6330; +} + +html.lightyellow .gq-new-chat-button { + border-color: #4c6330 !important; + background-color: #eef6d4 !important; + color: #4c6330 !important; +} + +html.lightyellow .gq-new-chat-button:hover { + background-color: #e4efbf !important; +} + +html.lightyellow .gq-sidebar .agent-sidebar-card--active, +html.lightyellow .gq-history-item--active { + border-color: rgb(76 99 48 / 0.54) !important; + background-color: #eef6d4 !important; + color: #4c6330 !important; +} + +html.lightyellow .gq-sidebar .agent-sidebar-card--active .text-primary, +html.lightyellow .gq-history-item--active :is(svg, span) { + color: #4c6330 !important; +} + +html.lightyellow .gq-sidebar .agent-sidebar-card--active .bg-primary, +html.lightyellow .gq-history-item--active .bg-primary { + background-color: #4c6330 !important; +} + @supports not (color: oklch(1 0 0)) { .bg-primary\/5 { background-color: rgba(190, 35, 35, 0.05); } .bg-primary\/8 { background-color: rgba(190, 35, 35, 0.08); } @@ -1657,4 +1832,16 @@ html.iceblue .tiptap-writing-editor .ProseMirror ::selection { .iceblue .bg-primary\/60 { background-color: rgba(155, 206, 241, 0.60); } .iceblue .bg-primary\/70 { background-color: rgba(155, 206, 241, 0.70); } .iceblue .bg-primary\/90 { background-color: rgba(155, 206, 241, 0.90); } + + .lightyellow .bg-primary\/5 { background-color: rgba(243, 251, 217, 0.05); } + .lightyellow .bg-primary\/8 { background-color: rgba(243, 251, 217, 0.08); } + .lightyellow .bg-primary\/10 { background-color: rgba(243, 251, 217, 0.10); } + .lightyellow .bg-primary\/14 { background-color: rgba(243, 251, 217, 0.14); } + .lightyellow .bg-primary\/15 { background-color: rgba(243, 251, 217, 0.15); } + .lightyellow .bg-primary\/20 { background-color: rgba(243, 251, 217, 0.20); } + .lightyellow .bg-primary\/25 { background-color: rgba(243, 251, 217, 0.25); } + .lightyellow .bg-primary\/30 { background-color: rgba(243, 251, 217, 0.30); } + .lightyellow .bg-primary\/60 { background-color: rgba(243, 251, 217, 0.60); } + .lightyellow .bg-primary\/70 { background-color: rgba(243, 251, 217, 0.70); } + .lightyellow .bg-primary\/90 { background-color: rgba(243, 251, 217, 0.90); } } diff --git a/frontend-web/src/styles/tdesign-theme.css b/frontend-web/src/styles/tdesign-theme.css index 23e73c62..4f970394 100644 --- a/frontend-web/src/styles/tdesign-theme.css +++ b/frontend-web/src/styles/tdesign-theme.css @@ -228,6 +228,39 @@ --td-bg-color-secondarycontainer-active: #cbe7f7; } +/* Pale yellow: #F3FBD9 stays the primary surface while dark olive supplies + readable links and text actions. */ +:root[data-theme="lightyellow"] { + --td-brand-color-1: #fcfdf5; + --td-brand-color-2: #f8fbe9; + --td-brand-color-3: #eef6d4; + --td-brand-color-4: #e4efbf; + --td-brand-color-5: #F3FBD9; + --td-brand-color-6: #F3FBD9; + --td-brand-color-7: #dcebad; + --td-brand-color-8: #b4c985; + --td-brand-color-9: #627b3d; + --td-brand-color-10: #34451f; + + --td-brand-color: #F3FBD9; + --td-brand-color-hover: #e4efbf; + --td-brand-color-focus: #eef6d4; + --td-brand-color-active: #dcebad; + --td-brand-color-disabled: #eef5d8; + --td-brand-color-light: #eef6d4; + --td-brand-color-light-hover: #e4efbf; + --td-text-color-primary: #303d23; + --td-text-color-secondary: #68705a; + --td-text-color-brand: #4c6330; + --td-text-color-link: #4c6330; + --td-text-color-anti: #303d23; + --td-bg-color-container-hover: #fcfdf5; + --td-bg-color-container-active: #eef6d4; + --td-bg-color-secondarycontainer: #f7fae9; + --td-bg-color-secondarycontainer-hover: #eef6d4; + --td-bg-color-secondarycontainer-active: #e4efbf; +} + /* WeKnora green: selected by ThemeContext through data-theme="lightgreen". */ :root[data-theme="lightgreen"] { --td-brand-color-1: #e9f8ec; diff --git a/offline-backend-20260512/backend/app/gateway/routers/system_settings.py b/offline-backend-20260512/backend/app/gateway/routers/system_settings.py index a9a5fe8c..2b1f27f5 100644 --- a/offline-backend-20260512/backend/app/gateway/routers/system_settings.py +++ b/offline-backend-20260512/backend/app/gateway/routers/system_settings.py @@ -536,8 +536,8 @@ async def update_publish_squares(body: PublishSquaresUpdateRequest, request: Req class AppearanceResponse(BaseModel): """Effective system-wide appearance defaults.""" - default_theme: Literal["light", "dark", "lightblue", "lightgreen", "iceblue"] = Field( - ..., description="System default theme — light, dark, lightblue, lightgreen or iceblue" + default_theme: Literal["light", "dark", "lightblue", "lightgreen", "iceblue", "lightyellow"] = Field( + ..., description="System default theme — light, dark, lightblue, lightgreen, iceblue or lightyellow" ) default_skill_view: Literal["card", "list"] = Field(..., description="System default skill list display mode — card or list") default_agent_view: Literal["card", "list"] = Field(..., description="System default agent list display mode — card or list") @@ -546,7 +546,7 @@ class AppearanceResponse(BaseModel): class AppearanceUpdateRequest(BaseModel): - default_theme: Literal["light", "dark", "lightblue", "lightgreen", "iceblue"] | None = Field(default=None) + default_theme: Literal["light", "dark", "lightblue", "lightgreen", "iceblue", "lightyellow"] | None = Field(default=None) default_skill_view: Literal["card", "list"] | None = Field(default=None) default_agent_view: Literal["card", "list"] | None = Field(default=None) default_layout_mode: Literal["full", "compact"] | None = Field(default=None) diff --git a/offline-backend-20260512/backend/packages/harness/deerflow/config/system_settings.py b/offline-backend-20260512/backend/packages/harness/deerflow/config/system_settings.py index e4512a49..9e715095 100644 --- a/offline-backend-20260512/backend/packages/harness/deerflow/config/system_settings.py +++ b/offline-backend-20260512/backend/packages/harness/deerflow/config/system_settings.py @@ -102,9 +102,9 @@ class AppearanceSettings(BaseModel): toggle, and any future first-time loads. """ - default_theme: Literal["light", "dark", "lightblue", "lightgreen", "iceblue"] = Field( + default_theme: Literal["light", "dark", "lightblue", "lightgreen", "iceblue", "lightyellow"] = Field( default="light", - description="Theme applied for users who haven't picked their own (light / dark / lightblue / lightgreen / iceblue)", + description="Theme applied for users who haven't picked their own (light / dark / lightblue / lightgreen / iceblue / lightyellow)", ) default_skill_view: Literal["card", "list"] = Field( default="list",