代码修改
This commit is contained in:
1 parent
91ba47bf47
commit
25153dbd84
31 files changed
+536
-62
No files matched your search
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
}
|
||||
@@ -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 (
|
||||
<Link
|
||||
key={agent.id}
|
||||
@@ -279,6 +279,7 @@ export function AgentChatSidebar({ activeAgentId }: { activeAgentId?: string })
|
||||
)}
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(135deg, ${from}, ${to})`,
|
||||
color: foreground,
|
||||
}}
|
||||
>
|
||||
<Bot className="size-[19px]" />
|
||||
|
||||
@@ -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 (
|
||||
<Link
|
||||
key={`${keyPrefix}:${agent.id}`}
|
||||
@@ -236,7 +236,10 @@ export function AgentModuleSidebar({
|
||||
isActive &&
|
||||
"ring-2 ring-[#83c1ff]/35 shadow-[0_0_18px_rgba(43,143,254,0.45)]",
|
||||
)}
|
||||
style={{ backgroundImage: `linear-gradient(135deg, ${from}, ${to})` }}
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(135deg, ${from}, ${to})`,
|
||||
color: foreground,
|
||||
}}
|
||||
>
|
||||
<Bot className="size-[19px]" />
|
||||
</span>
|
||||
|
||||
@@ -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" },
|
||||
];
|
||||
|
||||
|
||||
@@ -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() {
|
||||
<div className="mt-1 flex flex-col gap-1">
|
||||
{frequent.map((agent) => {
|
||||
const isActive = activeAgentId === agent.id;
|
||||
const { from, to } = agentColor(agent.id, isDark);
|
||||
const { from, to, foreground } = agentColor(agent.id, theme);
|
||||
return (
|
||||
<button
|
||||
key={agent.id}
|
||||
@@ -366,7 +366,10 @@ export function GeneralQaSidebar() {
|
||||
isActive &&
|
||||
"ring-2 ring-[#83c1ff]/35 shadow-[0_0_18px_rgba(43,143,254,0.45)]",
|
||||
)}
|
||||
style={{ backgroundImage: `linear-gradient(135deg, ${from}, ${to})` }}
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(135deg, ${from}, ${to})`,
|
||||
color: foreground,
|
||||
}}
|
||||
>
|
||||
<Bot className="size-[19px]" />
|
||||
</span>
|
||||
@@ -464,9 +467,9 @@ export function GeneralQaSidebar() {
|
||||
<Link
|
||||
href={href}
|
||||
className={cn(
|
||||
"relative flex h-9 min-w-0 flex-1 items-center gap-2 rounded-lg px-2.5 text-[13px] transition-colors",
|
||||
"gq-history-item relative flex h-9 min-w-0 flex-1 items-center gap-2 rounded-lg px-2.5 text-[13px] transition-colors",
|
||||
isActive
|
||||
? "border border-primary/40 bg-primary/5 font-medium text-primary"
|
||||
? "gq-history-item--active border border-primary/40 bg-primary/5 font-medium text-primary"
|
||||
: "text-muted-foreground hover:bg-accent/60 hover:text-foreground",
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -214,7 +214,7 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
};
|
||||
|
||||
const handleSetGlobalDefault = async (
|
||||
value: "light" | "dark" | "lightblue" | "lightgreen" | "iceblue",
|
||||
value: "light" | "dark" | "lightblue" | "lightgreen" | "iceblue" | "lightyellow",
|
||||
) => {
|
||||
if (value === globalDefault) return;
|
||||
try {
|
||||
@@ -228,7 +228,9 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
? "绿色"
|
||||
: value === "iceblue"
|
||||
? "冰川蓝"
|
||||
: "浅蓝";
|
||||
: value === "lightyellow"
|
||||
? "浅黄色"
|
||||
: "浅蓝";
|
||||
toast.success(`已将系统默认主题设置为${label}`);
|
||||
} catch (e) {
|
||||
toast.error(e instanceof Error ? e.message : "保存失败");
|
||||
@@ -396,6 +398,12 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
description: t.settings.appearance.iceblueDescription,
|
||||
icon: SnowflakeIcon,
|
||||
},
|
||||
{
|
||||
id: "lightyellow",
|
||||
label: t.settings.appearance.lightyellow,
|
||||
description: t.settings.appearance.lightyellowDescription,
|
||||
icon: SunIcon,
|
||||
},
|
||||
],
|
||||
[
|
||||
t.settings.appearance.dark,
|
||||
@@ -408,6 +416,8 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
t.settings.appearance.lightgreenDescription,
|
||||
t.settings.appearance.iceblue,
|
||||
t.settings.appearance.iceblueDescription,
|
||||
t.settings.appearance.lightyellow,
|
||||
t.settings.appearance.lightyellowDescription,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -425,7 +435,7 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
label={option.label}
|
||||
description={option.description}
|
||||
active={currentTheme === option.id}
|
||||
mode={option.id as "light" | "dark" | "lightblue" | "lightgreen" | "iceblue"}
|
||||
mode={option.id as "light" | "dark" | "lightblue" | "lightgreen" | "iceblue" | "lightyellow"}
|
||||
onSelect={(value) => setTheme(value)}
|
||||
/>
|
||||
))}
|
||||
@@ -597,6 +607,16 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
<SnowflakeIcon className="mr-1.5 size-4" />
|
||||
冰川蓝
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant={globalDefault === "lightyellow" ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => void handleSetGlobalDefault("lightyellow")}
|
||||
disabled={updateAppearance.isPending}
|
||||
>
|
||||
<SunIcon className="mr-1.5 size-4" />
|
||||
浅黄色
|
||||
</Button>
|
||||
<p className="text-muted-foreground ml-2 text-xs">
|
||||
当前系统默认:
|
||||
{globalDefault === "light"
|
||||
@@ -607,7 +627,9 @@ export function AppearanceSettingsPage({ onClose }: { onClose?: () => void }) {
|
||||
? "绿色"
|
||||
: globalDefault === "iceblue"
|
||||
? "冰川蓝"
|
||||
: "浅蓝"}
|
||||
: globalDefault === "lightyellow"
|
||||
? "浅黄色"
|
||||
: "浅蓝"}
|
||||
</p>
|
||||
</div>
|
||||
</SettingsSection>
|
||||
@@ -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",
|
||||
)}
|
||||
>
|
||||
<div className="border-border/50 flex items-center gap-2 border-b px-3 py-2">
|
||||
@@ -1176,7 +1200,9 @@ function ThemePreviewCard({
|
||||
? "bg-[#07c05f]"
|
||||
: previewMode === "iceblue"
|
||||
? "bg-[#9BCEF1]"
|
||||
: "bg-[#cf1322]",
|
||||
: previewMode === "lightyellow"
|
||||
? "bg-[#F3FBD9]"
|
||||
: "bg-[#cf1322]",
|
||||
)}
|
||||
/>
|
||||
<div className="h-2 w-10 rounded-full bg-current/20" />
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<ThemeType, ThemeConfig> = {
|
||||
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<ThemeProviderProps> = ({ 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<ThemeProviderProps> = ({ children }) => {
|
||||
? 'lightgreen'
|
||||
: effectiveTheme === 'iceblue'
|
||||
? 'iceblue'
|
||||
: 'light'
|
||||
: effectiveTheme === 'lightyellow'
|
||||
? 'lightyellow'
|
||||
: 'light'
|
||||
: readPersistedTheme();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -291,7 +317,12 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ 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');
|
||||
|
||||
@@ -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<BrandTheme, string> = {
|
||||
light: fallbackLogoLight,
|
||||
lightblue: fallbackLogoLightblue,
|
||||
lightgreen: fallbackLogoLight,
|
||||
iceblue: fallbackLogoLightblue,
|
||||
lightyellow: fallbackLogoLight,
|
||||
dark: fallbackLogoDark,
|
||||
};
|
||||
|
||||
@@ -18,6 +19,7 @@ const headerRuntimeKeys: Record<BrandTheme, string> = {
|
||||
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<BrandTheme, string> = {
|
||||
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",
|
||||
};
|
||||
|
||||
|
||||
@@ -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.",
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -432,12 +432,14 @@ export const zhCN: Translations = {
|
||||
lightblue: "浅蓝",
|
||||
lightgreen: "绿色",
|
||||
iceblue: "冰川蓝",
|
||||
lightyellow: "浅黄色",
|
||||
systemDescription: "自动跟随系统主题。",
|
||||
lightDescription: "更明亮的配色,适合日间使用。",
|
||||
darkDescription: "更暗的配色,减少眩光方便专注。",
|
||||
lightblueDescription: "以蓝色为主色的清爽浅色配色。",
|
||||
lightgreenDescription: "采用 WeKnora 绿色的清爽浅色配色。",
|
||||
iceblueDescription: "以 #9BCEF1 为主色,搭配冰蓝留白与沉稳交互色。",
|
||||
lightyellowDescription: "以 #F3FBD9 为主色,搭配柔和浅黄留白与深橄榄交互色。",
|
||||
languageTitle: "语言",
|
||||
languageDescription: "在不同语言之间切换。",
|
||||
},
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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]",
|
||||
|
||||
@@ -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() {
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-12 w-10 shrink-0 items-center justify-center rounded shadow-sm",
|
||||
isDark ? "bg-violet-400 text-slate-950" : "bg-[#4d3f74] text-white",
|
||||
isDark
|
||||
? "bg-violet-400 text-slate-950"
|
||||
: isLightYellow
|
||||
? "bg-[#4C6330] text-white"
|
||||
: "bg-[#4d3f74] text-white",
|
||||
)}
|
||||
>
|
||||
<BookOpen className="h-6 w-6" />
|
||||
@@ -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",
|
||||
)}
|
||||
>
|
||||
<Plus className="h-3.5 w-3.5" />
|
||||
@@ -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]",
|
||||
|
||||
@@ -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[];
|
||||
|
||||
@@ -793,7 +793,7 @@ export default function ScheduledTasksPage({
|
||||
</Button>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="destructive"
|
||||
variant={theme === "iceblue" || theme === "lightyellow" ? "default" : "destructive"}
|
||||
title="删除"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
@@ -1034,7 +1034,7 @@ export default function ScheduledTasksPage({
|
||||
{selectedTaskCanEditRuns && run.can_edit !== false && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
variant={theme === "iceblue" || theme === "lightyellow" ? "default" : "destructive"}
|
||||
onClick={() => handleDeleteRun(run.id)}
|
||||
>
|
||||
<Trash2 className="size-4" />
|
||||
|
||||
@@ -742,6 +742,58 @@
|
||||
color: #2D587A;
|
||||
}
|
||||
|
||||
/* Pale yellow: #F3FBD9 surfaces pair with dark olive interaction text. */
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-primary-btn,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog-save,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-switch-on {
|
||||
background-color: #F3FBD9;
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-primary-btn,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog-save {
|
||||
color: #303D23;
|
||||
box-shadow: 0 2px 6px rgba(243, 251, 217, 0.72);
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-primary-btn:hover,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog-save:hover {
|
||||
background-color: #E4EFBF;
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-primary-btn:active,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog-save:active {
|
||||
background-color: #DCEBAD;
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-search-input:focus {
|
||||
border-color: rgba(76, 99, 48, 0.5);
|
||||
box-shadow: 0 0 0 4px rgba(243, 251, 217, 0.72);
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-view-toggle-btn.is-active,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-cat-toggle-btn.is-active,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-count strong,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-table tr:hover .lam-row-name,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-param-popover-close,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-param-key,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-card:hover .lam-card-title,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog-close:hover,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-add-param-btn:hover {
|
||||
color: #4C6330;
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-add-param-btn:hover,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-input:focus,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog input[type="text"]:focus {
|
||||
border-color: #B4C985;
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-input:focus,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog input[type="text"]:focus,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog [data-slot="input"]:focus-visible,
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog textarea:focus-visible,
|
||||
[data-theme="lightyellow"] .light-app-management-page .t-select.t-is-focused .t-input,
|
||||
[data-theme="lightyellow"] .light-app-management-page .t-select.t-is-focused .t-input__wrap {
|
||||
box-shadow: 0 0 0 2px rgba(243, 251, 217, 0.78);
|
||||
}
|
||||
[data-theme="lightyellow"] .light-app-management-page .lam-dialog-icon {
|
||||
background-color: #EEF6D4;
|
||||
color: #4C6330;
|
||||
}
|
||||
|
||||
/* WeKnora green theme. */
|
||||
[data-theme="lightgreen"] .light-app-management-page .lam-primary-btn,
|
||||
[data-theme="lightgreen"] .light-app-management-page .lam-dialog-save,
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
background-color: #F9FDF9;
|
||||
}
|
||||
|
||||
[data-theme="lightyellow"] .light-app-management-page,
|
||||
[data-theme="lightyellow"] .light-app-list-page {
|
||||
background-color: #FCFDF5;
|
||||
}
|
||||
|
||||
.dark .light-app-management-page,
|
||||
.dark .light-app-list-page {
|
||||
background-color: var(--color-bg-page);
|
||||
|
||||
@@ -4945,7 +4945,7 @@ function PositionAgentList({
|
||||
{!isCollapsed && (
|
||||
<div className="mt-1 flex flex-col gap-1">
|
||||
{group.agents.map((agent) => {
|
||||
const { from, to } = agentColor(agent.id, isDark);
|
||||
const { from, to, foreground } = agentColor(agent.id, theme);
|
||||
return (
|
||||
<button
|
||||
key={`${group.key}:${agent.id}`}
|
||||
@@ -4962,6 +4962,7 @@ function PositionAgentList({
|
||||
className="mt-0.5 flex size-10 shrink-0 items-center justify-center rounded-lg text-white shadow-sm"
|
||||
style={{
|
||||
backgroundImage: `linear-gradient(135deg, ${from}, ${to})`,
|
||||
color: foreground,
|
||||
}}
|
||||
>
|
||||
<Bot className="size-[19px]" />
|
||||
|
||||
@@ -62,6 +62,33 @@
|
||||
background: #fddadc;
|
||||
}
|
||||
|
||||
/* Ice blue only: reuse the active global background token instead of the
|
||||
* default red workspace canvas. Other themes do not match these selectors. */
|
||||
:root[data-theme="iceblue"] .roundtable-planning,
|
||||
.iceblue .roundtable-planning {
|
||||
--rt-page-bg: var(--background);
|
||||
}
|
||||
|
||||
:root[data-theme="iceblue"] .roundtable-planning.bg-\[\#fef6f6\],
|
||||
:root[data-theme="iceblue"] .roundtable-planning .bg-\[\#fef6f6\],
|
||||
.iceblue .roundtable-planning.bg-\[\#fef6f6\],
|
||||
.iceblue .roundtable-planning .bg-\[\#fef6f6\] {
|
||||
background-color: var(--rt-page-bg) !important;
|
||||
}
|
||||
|
||||
/* Pale yellow uses its global background token instead of the default red canvas. */
|
||||
:root[data-theme="lightyellow"] .roundtable-planning,
|
||||
.lightyellow .roundtable-planning {
|
||||
--rt-page-bg: var(--background);
|
||||
}
|
||||
|
||||
:root[data-theme="lightyellow"] .roundtable-planning.bg-\[\#fef6f6\],
|
||||
:root[data-theme="lightyellow"] .roundtable-planning .bg-\[\#fef6f6\],
|
||||
.lightyellow .roundtable-planning.bg-\[\#fef6f6\],
|
||||
.lightyellow .roundtable-planning .bg-\[\#fef6f6\] {
|
||||
background-color: var(--rt-page-bg) !important;
|
||||
}
|
||||
|
||||
/* 深色模式:跟随全局 ThemeContext(html.dark)或组件 .roundtable-planning--dark
|
||||
*
|
||||
* 仅在本页 + 深色下,把语义 token 覆盖为《深蓝色 UI 规范》取值
|
||||
|
||||
@@ -29,13 +29,13 @@ import { cn } from "@/lib/utils";
|
||||
|
||||
import { useTheme } from "../contexts/ThemeContext";
|
||||
|
||||
const iconButtonClass = (isDark: boolean, isIceBlue: boolean) =>
|
||||
const iconButtonClass = (isDark: boolean, isPaleLightTheme: boolean) =>
|
||||
cn(
|
||||
"size-8 shrink-0 rounded-sm",
|
||||
isDark
|
||||
? "text-slate-400 hover:bg-slate-800/50 hover:text-white"
|
||||
: isIceBlue
|
||||
? "text-[#18324A] hover:bg-white/55 hover:text-[#18324A] active:bg-white/75"
|
||||
: isPaleLightTheme
|
||||
? "text-[var(--foreground)] hover:bg-white/55 hover:text-[var(--foreground)] active:bg-white/75"
|
||||
: "text-white hover:bg-[var(--brand-950)] active:bg-[#8a0618]",
|
||||
);
|
||||
|
||||
@@ -50,7 +50,7 @@ type HeaderProps = {
|
||||
const Header = ({ collapsed }: HeaderProps) => {
|
||||
const { theme } = useTheme();
|
||||
const isDark = theme === "dark";
|
||||
const isIceBlue = theme === "iceblue";
|
||||
const isPaleLightTheme = theme === "iceblue" || theme === "lightyellow";
|
||||
const darkLogoPosition =
|
||||
readRuntimeEnv("VITE_DARK_LOGO_POSITION") === "left" ? "left" : "center";
|
||||
const isDarkLogoOnLeft = darkLogoPosition === "left";
|
||||
@@ -152,11 +152,11 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
// 右侧操作区(换肤/通知/用户)—— 深浅两套布局共用
|
||||
const actionCluster = (
|
||||
<>
|
||||
<CompactShortcutButtons tone={isDark ? "banner-dark" : isIceBlue ? "content" : "banner-light"} />
|
||||
<ThemeSwitcher tone={isDark ? "banner-dark" : isIceBlue ? "content" : "banner-light"} />
|
||||
<CompactShortcutButtons tone={isDark ? "banner-dark" : isPaleLightTheme ? "content" : "banner-light"} />
|
||||
<ThemeSwitcher tone={isDark ? "banner-dark" : isPaleLightTheme ? "content" : "banner-light"} />
|
||||
|
||||
<LayoutModeSwitcher
|
||||
tone={isDark ? "banner-dark" : isIceBlue ? "content" : "banner-light"}
|
||||
tone={isDark ? "banner-dark" : isPaleLightTheme ? "content" : "banner-light"}
|
||||
fallback="full"
|
||||
/>
|
||||
|
||||
@@ -165,7 +165,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
onClick={() => setNotificationOpen(true)}
|
||||
className={cn(iconButtonClass(isDark, isIceBlue), "relative")}
|
||||
className={cn(iconButtonClass(isDark, isPaleLightTheme), "relative")}
|
||||
title="通知"
|
||||
>
|
||||
<Bell className="size-4" />
|
||||
@@ -186,7 +186,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
<div
|
||||
className={cn(
|
||||
"mx-1 h-8 w-px",
|
||||
isDark ? "bg-blue-800/30" : isIceBlue ? "bg-[#3D6E96]/25" : "bg-white/30",
|
||||
isDark ? "bg-blue-800/30" : isPaleLightTheme ? "bg-[var(--brand-900)]/25" : "bg-white/30",
|
||||
)}
|
||||
aria-hidden
|
||||
/>
|
||||
@@ -198,8 +198,8 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
"h-8 gap-2 rounded-sm px-2",
|
||||
isDark
|
||||
? "text-slate-200 hover:bg-slate-800/50"
|
||||
: isIceBlue
|
||||
? "text-[#18324A] hover:bg-white/55 active:bg-white/75"
|
||||
: isPaleLightTheme
|
||||
? "text-[var(--foreground)] hover:bg-white/55 active:bg-white/75"
|
||||
: "text-white hover:bg-[var(--brand-950)] active:bg-[#8a0618]",
|
||||
)}
|
||||
>
|
||||
@@ -219,11 +219,11 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
/>
|
||||
</div>
|
||||
<div className="hidden text-left sm:block">
|
||||
<p className={cn("text-sm leading-tight font-medium", isIceBlue ? "text-[#18324A]" : "text-white")}>
|
||||
<p className={cn("text-sm leading-tight font-medium", isPaleLightTheme ? "text-[var(--foreground)]" : "text-white")}>
|
||||
{displayName}
|
||||
</p>
|
||||
{positionName && (
|
||||
<p className={cn("text-[11px] leading-tight", isIceBlue ? "text-[#315B7B]" : "text-white/70")}>
|
||||
<p className={cn("text-[11px] leading-tight", isPaleLightTheme ? "text-[var(--muted-foreground)]" : "text-white/70")}>
|
||||
{positionName}
|
||||
</p>
|
||||
)}
|
||||
@@ -231,7 +231,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
<ChevronDown
|
||||
className={cn(
|
||||
"size-4 shrink-0",
|
||||
isDark ? "text-slate-500" : isIceBlue ? "text-[#315B7B]" : "text-white/80",
|
||||
isDark ? "text-slate-500" : isPaleLightTheme ? "text-[var(--muted-foreground)]" : "text-white/80",
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
@@ -323,7 +323,7 @@ const Header = ({ collapsed }: HeaderProps) => {
|
||||
onError={handleBrandLogoError}
|
||||
/>
|
||||
</div>
|
||||
<span className={cn("whitespace-nowrap text-lg font-semibold", isIceBlue ? "text-[#18324A]" : "text-white")}>
|
||||
<span className={cn("whitespace-nowrap text-lg font-semibold", isPaleLightTheme ? "text-[var(--foreground)]" : "text-white")}>
|
||||
{desensitizeText("CM业务中心")}
|
||||
</span>
|
||||
</div>
|
||||
@@ -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) => {
|
||||
/>
|
||||
</div>
|
||||
{!collapsed && (
|
||||
<span className={cn("text-sm font-semibold", isIceBlue ? "text-[#18324A]" : "text-white")}>
|
||||
<span className={cn("text-sm font-semibold", isPaleLightTheme ? "text-[var(--foreground)]" : "text-white")}>
|
||||
{desensitizeText("CM业务中心")}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<AppThemeColor, string[]> = {
|
||||
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";
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
-2
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user