feat(theme): 浅蓝色主题适配 —— COH任务三子页 + 应用中心子页

- ThemeContext: 新增 data-theme="lightblue" 属性管理,支持红/蓝双浅色主题
- strategy-data.css: 新增 [data-theme="lightblue"] 变量覆盖块(与浅红默认共存)
- SentimentAnalyzes / TaskAnalyzes / ActionAnalyzes / KanbanColumn / TaskCard / ActionColumn:
  isDark ? dark : isLightBlue ? blue : red 三路适配
- LightAppListPage: 应用列表页品牌色(标题点、徽章、搜索 focus、计数、进入按钮)浅蓝适配
- LightAppNoteQAPage: 问答发送按钮浅蓝适配
- light-app-management.css: 新增 [data-theme="lightblue"] CSS 覆盖块(主按钮、保存、开关、输入 focus 等)
- light-app-pages.css: 浅蓝模式页面底色轻染 #F9FCFF

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
董宏凯andClaude Sonnet 4.6 committed 2026-06-15 18:16:06 +08:00
1 parent 1ad8da5ef2
commit b1b2540dc0
16 files changed
+292 -64

No files matched your search

+16 -11
View File
@@ -34,6 +34,7 @@ import { toast } from "sonner";
import { Pagination } from "@/components/ui/pagination";
import { cn } from "@/lib/utils";
import { useTheme } from "@/contexts/ThemeContext";
import { useLightApps, type LightApp } from "@/strategy-components/api/light-apps";
import { buildLightAppUrl } from "@/strategy-components/lib/light-app";
@@ -67,6 +68,8 @@ export default function LightAppListPage() {
const [search, setSearch] = useState("");
const [page, setPage] = useState(1);
const [copiedId, setCopiedId] = useState<string | null>(null);
const { theme } = useTheme();
const isLightBlue = theme === 'lightblue';
const { data: apps = [], isLoading } = useLightApps({
appType: "window_open",
@@ -115,13 +118,13 @@ export default function LightAppListPage() {
<div className="space-y-1">
<div className="flex items-center gap-2.5">
<span className="relative flex size-3">
<span className="absolute inline-flex size-full animate-ping rounded-full bg-[#CF1322] opacity-75 dark:bg-[#1677FF]" />
<span className="relative inline-flex size-3 rounded-full bg-[#CF1322] dark:bg-[#1677FF]" />
<span className={cn("absolute inline-flex size-full animate-ping rounded-full opacity-75", isLightBlue ? "bg-[#0062D9]" : "bg-[#CF1322]", "dark:bg-[#1677FF]")} />
<span className={cn("relative inline-flex size-3 rounded-full", isLightBlue ? "bg-[#0062D9]" : "bg-[#CF1322]", "dark:bg-[#1677FF]")} />
</span>
<h1 className="text-2xl font-bold tracking-tight text-zinc-900 dark:text-[#E8EDF5]">
应用列表
</h1>
<span className="rounded-[5px] border border-[#CF1322]/15 bg-[#FFF1F0] px-2 py-0.5 font-mono text-xs font-medium text-[#CF1322] dark:border-[#1677FF]/30 dark:bg-[#1677FF]/15 dark:text-[#4096FF]">
<span className={cn("rounded-[5px] border px-2 py-0.5 font-mono text-xs font-medium dark:border-[#1677FF]/30 dark:bg-[#1677FF]/15 dark:text-[#4096FF]", isLightBlue ? "border-[#0062D9]/15 bg-[#EAF4FF] text-[#0062D9]" : "border-[#CF1322]/15 bg-[#FFF1F0] text-[#CF1322]")}>
导航工作台
</span>
</div>
@@ -139,7 +142,7 @@ export default function LightAppListPage() {
value={search}
onChange={(e) => setSearch(e.target.value)}
placeholder="键入应用名称、目标地址、或描述,实时过滤检索…"
className="w-full rounded-[5px] border border-zinc-200 bg-zinc-50/50 py-3 pl-10 pr-10 text-sm transition focus:border-[#CF1322]/60 focus:bg-white focus:outline-none focus:ring-2 focus:ring-[#CF1322]/20 dark:border-[#1A2F5A] dark:bg-[#0C1836] dark:text-[#C5CFE0] dark:placeholder-[#4A6491] dark:focus:border-[#1677FF]/60 dark:focus:bg-[#122347] dark:focus:ring-[#1677FF]/25"
className={cn("w-full rounded-[5px] border border-zinc-200 bg-zinc-50/50 py-3 pl-10 pr-10 text-sm transition focus:bg-white focus:outline-none focus:ring-2 dark:border-[#1A2F5A] dark:bg-[#0C1836] dark:text-[#C5CFE0] dark:placeholder-[#4A6491] dark:focus:border-[#1677FF]/60 dark:focus:bg-[#122347] dark:focus:ring-[#1677FF]/25", isLightBlue ? "focus:border-[#0062D9]/60 focus:ring-[#0062D9]/20" : "focus:border-[#CF1322]/60 focus:ring-[#CF1322]/20")}
/>
{search && (
<button
@@ -158,13 +161,13 @@ export default function LightAppListPage() {
<div className="-mt-2 flex items-center justify-between">
<div className="text-xs font-medium text-zinc-500 dark:text-[#6E88B0]">
检索到最终结果:{" "}
<span className="font-bold text-[#CF1322] dark:text-[#4096FF]">{apps.length}</span> 个关联应用
<span className={cn("font-bold dark:text-[#4096FF]", isLightBlue ? "text-[#0062D9]" : "text-[#CF1322]")}>{apps.length}</span> 个关联应用
</div>
{search && (
<button
type="button"
onClick={() => setSearch("")}
className="text-xs font-medium text-[#CF1322] underline hover:text-[#A8071A] dark:text-[#4096FF] dark:hover:text-[#1677FF]"
className={cn("text-xs font-medium underline dark:text-[#4096FF] dark:hover:text-[#1677FF]", isLightBlue ? "text-[#0062D9] hover:text-[#0056C6]" : "text-[#CF1322] hover:text-[#A8071A]")}
>
重置过滤条件
</button>
@@ -235,8 +238,10 @@ function AppCard({
onCopy: () => void;
onOpen: () => void;
}) {
const { theme } = useTheme();
const isLightBlue = theme === 'lightblue';
const Icon = ICON_POOL[hashIndex(app.appId, ICON_POOL.length)];
const theme = THEME_POOL[hashIndex(app.appId, THEME_POOL.length)];
const cardTheme = THEME_POOL[hashIndex(app.appId, THEME_POOL.length)];
const parsedUrl = buildLightAppUrl(app);
const hasParams = (app.routeParams ?? []).some((p) => p.key) && parsedUrl !== app.url;
@@ -246,12 +251,12 @@ function AppCard({
{/* 上:图标 + 标题 + 描述 */}
<div>
<div className="mb-3.5 flex items-start gap-4">
<div className={cn("rounded-[5px] p-3 shadow-sm", theme.iconBg)}>
<div className={cn("rounded-[5px] p-3 shadow-sm", cardTheme.iconBg)}>
<Icon className="size-5.5" />
</div>
</div>
<h4 className="mb-2 line-clamp-1 text-base font-bold leading-snug text-zinc-900 transition-colors group-hover:text-[#CF1322] dark:text-[#E8EDF5] dark:group-hover:text-[#4096FF]">
<h4 className={cn("mb-2 line-clamp-1 text-base font-bold leading-snug text-zinc-900 transition-colors dark:text-[#E8EDF5] dark:group-hover:text-[#4096FF]", isLightBlue ? "group-hover:text-[#0062D9]" : "group-hover:text-[#CF1322]")}>
{app.name}
</h4>
@@ -265,7 +270,7 @@ function AppCard({
<div className="mb-4 rounded-[5px] bg-zinc-50/70 p-3 dark:bg-[#0C1836]">
<div className="mb-1 flex items-center justify-between text-[10px] font-semibold text-zinc-400 dark:text-[#6E88B0]">
<span>拼接后目标路由终端:</span>
<span className="text-[9px] font-bold uppercase tracking-wider text-[#CF1322] dark:text-[#4096FF]">
<span className={cn("text-[9px] font-bold uppercase tracking-wider dark:text-[#4096FF]", isLightBlue ? "text-[#0062D9]" : "text-[#CF1322]")}>
自动拼接已激活参
</span>
</div>
@@ -307,7 +312,7 @@ function AppCard({
<button
type="button"
onClick={onOpen}
className="flex items-center justify-center gap-1.5 rounded-[5px] bg-[#CF1322] px-3 py-2 text-xs font-semibold text-white shadow-[0_1px_3px_rgba(207,19,34,0.2)] transition hover:bg-[#A8071A] active:scale-[0.98] dark:bg-[#1677FF] dark:shadow-none dark:hover:bg-[#0958D9]"
className={cn("flex items-center justify-center gap-1.5 rounded-[5px] px-3 py-2 text-xs font-semibold text-white transition active:scale-[0.98] dark:bg-[#1677FF] dark:shadow-none dark:hover:bg-[#0958D9]", isLightBlue ? "bg-[#0062D9] shadow-[0_1px_3px_rgba(0,98,217,0.2)] hover:bg-[#0079FE]" : "bg-[#CF1322] shadow-[0_1px_3px_rgba(207,19,34,0.2)] hover:bg-[#A8071A]")}
>
<span>进入应用</span>
<ArrowUpRight className="size-3.5" />
@@ -9,6 +9,7 @@ import { cn } from "@/lib/utils";
export default function LightAppNoteQAPage() {
const { theme } = useTheme();
const isDark = theme === "dark";
const isLightBlue = theme === 'lightblue';
const [question, setQuestion] = useState("");
const handleSubmit = () => {
@@ -111,7 +112,9 @@ export default function LightAppNoteQAPage() {
"flex h-7 w-7 shrink-0 items-center justify-center rounded-full transition-colors",
isDark
? "bg-sky-500 text-white hover:bg-sky-400"
: "bg-[#F5222D] text-white hover:bg-[#CF1322]",
: isLightBlue
? "bg-[#0062D9] text-white hover:bg-[#0079FE]"
: "bg-[#F5222D] text-white hover:bg-[#CF1322]",
)}
aria-label="发送"
>
@@ -568,3 +568,108 @@
background: rgba(22, 119, 255, 0.08);
color: var(--color-link);
}
/* ══════════════════════════════════════════════════════════════════════
浅蓝主题覆盖([data-theme="lightblue"])
══════════════════════════════════════════════════════════════════════ */
/* ── 注册应用按钮 ─────────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-primary-btn {
background-color: #0062D9;
box-shadow: 0 2px 6px rgba(0, 98, 217, 0.2);
}
[data-theme="lightblue"] .light-app-management-page .lam-primary-btn:hover {
background-color: #0079FE;
}
[data-theme="lightblue"] .light-app-management-page .lam-primary-btn:active {
background-color: #0056C6;
}
/* ── 搜索框 focus ────────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-search-input:focus {
border-color: rgba(0, 98, 217, 0.4);
box-shadow: 0 0 0 4px rgba(0, 98, 217, 0.1);
}
/* ── 视图切换激活态 ──────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-view-toggle-btn.is-active {
color: #0062D9;
}
/* ── 结果计数 ───────────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-count strong {
color: #0062D9;
}
/* ── 表格行名 hover ──────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-table tr:hover .lam-row-name {
color: #0062D9;
}
/* ── 参数弹窗 ───────────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-param-popover-close {
color: #0062D9;
}
[data-theme="lightblue"] .light-app-management-page .lam-param-key {
color: #0062D9;
}
/* ── 卡片标题 hover ──────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-card:hover .lam-card-title {
color: #0062D9;
}
/* ── 弹窗图标 / 关闭按钮 ─────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-dialog-icon {
background-color: #EAF4FF;
color: #0062D9;
}
[data-theme="lightblue"] .light-app-management-page .lam-dialog-close:hover {
color: #0062D9;
}
/* ── 添加路由参数按钮 hover ───────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-add-param-btn:hover {
border-color: #0062D9;
color: #0062D9;
}
/* ── 表单输入框 focus ────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-input:focus,
[data-theme="lightblue"] .light-app-management-page .lam-dialog input[type="text"]:focus {
border-color: #0062D9;
box-shadow: 0 0 0 1px #0062D9;
}
[data-theme="lightblue"] .light-app-management-page .lam-dialog [data-slot="input"]:focus-visible,
[data-theme="lightblue"] .light-app-management-page .lam-dialog textarea:focus-visible {
border-color: #0062D9;
box-shadow: 0 0 0 2px rgba(0, 98, 217, 0.16);
}
/* ── TDesign Select focus / hover ────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .t-select:hover .t-input,
[data-theme="lightblue"] .light-app-management-page .t-select:hover .t-input__wrap {
border-color: rgba(0, 98, 217, 0.5);
}
[data-theme="lightblue"] .light-app-management-page .t-select.t-is-focused .t-input,
[data-theme="lightblue"] .light-app-management-page .t-select.t-is-focused .t-input__wrap {
border-color: #0062D9;
box-shadow: 0 0 0 2px rgba(0, 98, 217, 0.16);
}
/* ── 启用开关 ───────────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-switch-on {
background-color: #0062D9;
}
/* ── 保存按钮 ───────────────────────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page .lam-dialog-save {
background-color: #0062D9;
box-shadow: 0 2px 8px rgba(0, 98, 217, 0.2);
}
[data-theme="lightblue"] .light-app-management-page .lam-dialog-save:hover {
background-color: #0079FE;
}
[data-theme="lightblue"] .light-app-management-page .lam-dialog-save:active {
background-color: #0056C6;
}
@@ -1,6 +1,12 @@
@import "../../docs/ui规范-深蓝/tokens.css";
/** 轻应用中心列表 / 管理页 —— 深色模式共用页面底图(与 workspace 深蓝主题一致) */
/* ── 浅蓝主题:页面底色轻微蓝染 ──────────────────────────────────────── */
[data-theme="lightblue"] .light-app-management-page,
[data-theme="lightblue"] .light-app-list-page {
background-color: #F9FCFF;
}
.dark .light-app-management-page,
.dark .light-app-list-page {
background-color: var(--color-bg-page);