fix(plugins): 插件管理 - 强化开关状态配色与文案 (#330)
This commit is contained in:
1 parent
55ce3cb11f
commit
5a9dd3f9ec
4 files changed
+76
-4
No files matched your search
@@ -170,7 +170,12 @@ export default function AdminPluginsPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Switch loading={savingId === item.manifest.id} checked={available} aria-label={`${item.manifest.name}平台可用性`} onChange={(checked) => void changeAvailability(item, checked)} />
|
<div className="flex shrink-0 items-center gap-2">
|
||||||
|
<span className={`whitespace-nowrap text-xs font-medium ${available ? "text-status-success" : "text-foreground/52"}`}>
|
||||||
|
{available ? "平台开放" : "平台停用"}
|
||||||
|
</span>
|
||||||
|
<Switch className="plugin-state-switch" loading={savingId === item.manifest.id} checked={available} aria-label={`${item.manifest.name},当前${available ? "平台开放,点击停用" : "平台停用,点击开放"}`} onChange={(checked) => void changeAvailability(item, checked)} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-3 line-clamp-2 min-h-10 text-sm leading-5 text-foreground/58">{item.manifest.description || "未提供插件说明"}</p>
|
<p className="mt-3 line-clamp-2 min-h-10 text-sm leading-5 text-foreground/58">{item.manifest.description || "未提供插件说明"}</p>
|
||||||
<div className="mt-3 flex flex-wrap items-center justify-between gap-2 border-t border-border/60 pt-3 text-xs text-foreground/48">
|
<div className="mt-3 flex flex-wrap items-center justify-between gap-2 border-t border-border/60 pt-3 text-xs text-foreground/48">
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ export default function PluginsPage() {
|
|||||||
options={[
|
options={[
|
||||||
{ value: "all", label: "全部状态" },
|
{ value: "all", label: "全部状态" },
|
||||||
{ value: "enabled", label: "已启用" },
|
{ value: "enabled", label: "已启用" },
|
||||||
{ value: "disabled", label: "未启用" },
|
{ value: "disabled", label: "已停用" },
|
||||||
]}
|
]}
|
||||||
onChange={(value) => setStatusFilter(value as "all" | "enabled" | "disabled")}
|
onChange={(value) => setStatusFilter(value as "all" | "enabled" | "disabled")}
|
||||||
aria-label="按状态筛选"
|
aria-label="按状态筛选"
|
||||||
@@ -427,9 +427,9 @@ export default function PluginsPage() {
|
|||||||
<div className="plugin-card-actions">
|
<div className="plugin-card-actions">
|
||||||
<span role="status" className={`settings-channel-status ${enabled ? "is-ready" : ""}`}>
|
<span role="status" className={`settings-channel-status ${enabled ? "is-ready" : ""}`}>
|
||||||
<i aria-hidden="true" />
|
<i aria-hidden="true" />
|
||||||
{!state?.platformAvailable && state?.blockedReason ? state.blockedReason : enabled ? "已启用" : "未启用"}
|
{!state?.platformAvailable && state?.blockedReason ? state.blockedReason : enabled ? "已启用" : "已停用"}
|
||||||
</span>
|
</span>
|
||||||
<Switch disabled={!state?.canToggle} checked={enabled} aria-label={`${plugin.manifest.name}${enabled ? "停用" : "启用"}`} title={state?.blockedReason} onChange={(checked) => void togglePlugin(plugin, checked)} />
|
<Switch className="plugin-state-switch" disabled={!state?.canToggle} checked={enabled} aria-label={`${plugin.manifest.name},当前${enabled ? "已启用,点击停用" : "已停用,点击启用"}`} title={state?.blockedReason} onChange={(checked) => void togglePlugin(plugin, checked)} />
|
||||||
{canConfigure ? (
|
{canConfigure ? (
|
||||||
<Button
|
<Button
|
||||||
className="plugin-settings-button"
|
className="plugin-settings-button"
|
||||||
|
|||||||
@@ -693,6 +693,14 @@
|
|||||||
Layer 3: Component — 引用 Semantic,某组件专属
|
Layer 3: Component — 引用 Semantic,某组件专属
|
||||||
------------------------------------------------------------------------- */
|
------------------------------------------------------------------------- */
|
||||||
:root {
|
:root {
|
||||||
|
/* 插件可用性开关:状态色只服务插件页,不改变其他设置开关的中性语义。 */
|
||||||
|
--plugin-switch-checked-bg: #15803d;
|
||||||
|
--plugin-switch-checked-hover-bg: #16a34a;
|
||||||
|
--plugin-switch-checked-handle: #ffffff;
|
||||||
|
--plugin-switch-off-bg: #d4d4d8;
|
||||||
|
--plugin-switch-off-hover-bg: #a1a1aa;
|
||||||
|
--plugin-switch-off-handle: #52525b;
|
||||||
|
|
||||||
/* Library 卡片组件:所有作品库共用同一表面和状态合同。 */
|
/* Library 卡片组件:所有作品库共用同一表面和状态合同。 */
|
||||||
--library-surface: var(--card-surface);
|
--library-surface: var(--card-surface);
|
||||||
--library-surface-hover: var(--card-surface-hover);
|
--library-surface-hover: var(--card-surface-hover);
|
||||||
@@ -825,6 +833,15 @@
|
|||||||
--flow-step-current-glow: 0 0 0 4px var(--cn-active-stroke-soft); /* 当前节点光晕 */
|
--flow-step-current-glow: 0 0 0 4px var(--cn-active-stroke-soft); /* 当前节点光晕 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
--plugin-switch-checked-bg: #16a34a;
|
||||||
|
--plugin-switch-checked-hover-bg: #22c55e;
|
||||||
|
--plugin-switch-checked-handle: #ffffff;
|
||||||
|
--plugin-switch-off-bg: #3f3f46;
|
||||||
|
--plugin-switch-off-hover-bg: #52525b;
|
||||||
|
--plugin-switch-off-handle: #f4f4f5;
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
@@ -1879,6 +1896,30 @@
|
|||||||
background: var(--control-switch-off-handle) !important;
|
background: var(--control-switch-off-handle) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:where(.plugin-state-switch.ant-switch.ant-switch-checked) {
|
||||||
|
background: var(--plugin-switch-checked-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.plugin-state-switch.ant-switch.ant-switch-checked:not(.ant-switch-disabled)):hover {
|
||||||
|
background: var(--plugin-switch-checked-hover-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.plugin-state-switch.ant-switch.ant-switch-checked) .ant-switch-handle::before {
|
||||||
|
background: var(--plugin-switch-checked-handle) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.plugin-state-switch.ant-switch:not(.ant-switch-checked)) {
|
||||||
|
background: var(--plugin-switch-off-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.plugin-state-switch.ant-switch:not(.ant-switch-checked):not(.ant-switch-disabled)):hover {
|
||||||
|
background: var(--plugin-switch-off-hover-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.plugin-state-switch.ant-switch:not(.ant-switch-checked)) .ant-switch-handle::before {
|
||||||
|
background: var(--plugin-switch-off-handle) !important;
|
||||||
|
}
|
||||||
|
|
||||||
:where(.ant-switch):focus-visible {
|
:where(.ant-switch):focus-visible {
|
||||||
outline: 2px solid var(--control-focus-ring);
|
outline: 2px solid var(--control-focus-ring);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { describe, expect, test } from "bun:test";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { resolve } from "node:path";
|
||||||
|
|
||||||
|
describe("plugin state switches", () => {
|
||||||
|
test("uses a page-scoped green and neutral switch palette", () => {
|
||||||
|
const styles = readFileSync(resolve(import.meta.dir, "../src/styles/globals.css"), "utf8");
|
||||||
|
|
||||||
|
expect(styles).toContain("--plugin-switch-checked-bg: #15803d;");
|
||||||
|
expect(styles).toContain("--plugin-switch-checked-bg: #16a34a;");
|
||||||
|
expect(styles).toContain("--plugin-switch-off-bg: #d4d4d8;");
|
||||||
|
expect(styles).toContain("--plugin-switch-off-bg: #3f3f46;");
|
||||||
|
expect(styles).toContain(":where(.plugin-state-switch.ant-switch.ant-switch-checked)");
|
||||||
|
expect(styles).toContain(":where(.plugin-state-switch.ant-switch:not(.ant-switch-checked))");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("shows explicit state text on both plugin pages", () => {
|
||||||
|
const userPage = readFileSync(resolve(import.meta.dir, "../src/pages/plugins/index.tsx"), "utf8");
|
||||||
|
const adminPage = readFileSync(resolve(import.meta.dir, "../src/pages/admin/plugins/plugins-page.tsx"), "utf8");
|
||||||
|
|
||||||
|
expect(userPage).toContain('className="plugin-state-switch"');
|
||||||
|
expect(userPage).toContain('enabled ? "已启用" : "已停用"');
|
||||||
|
expect(adminPage).toContain('className="plugin-state-switch"');
|
||||||
|
expect(adminPage).toContain('available ? "平台开放" : "平台停用"');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user