@zmzai/theme 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/brand/logo/favicon.png +0 -0
- package/src/components/icon/Icon.tsx +1 -0
- package/src/components/index.ts +1 -0
- package/src/components/navbar/Navbar.tsx +77 -8
- package/src/components/subtask/SubtaskPart.tsx +36 -0
- package/src/components/subtask/index.ts +1 -0
- package/src/components/subtask/subtask.css +11 -0
package/package.json
CHANGED
|
Binary file
|
|
@@ -28,6 +28,7 @@ const paths: Record<string, { d: string; fill?: boolean }> = {
|
|
|
28
28
|
external: { d: "M4 12V4h4M4 12L12 4M8 3.5h4.5V8" },
|
|
29
29
|
|
|
30
30
|
// === 导航/语义 ===
|
|
31
|
+
menu: { d: "M3.5 5h9M3.5 8h9M3.5 11h9" },
|
|
31
32
|
home: { d: "M2.5 7.5L8 3l5.5 4.5M4 6.5V13.5h8V6.5" },
|
|
32
33
|
grid: { d: "M3.5 3.5h3.5v3.5H3.5zM9 3.5h3.5v3.5H9zM3.5 9h3.5v3.5H3.5zM9 9h3.5v3.5H9z" },
|
|
33
34
|
key: { d: "M11 3.5a3.5 3.5 0 1 1-2 6.3L5.5 13.3 4 11.8l1.4-1.4L4 8.9 5 8l2.2 2.2A3.5 3.5 0 0 1 11 3.5zM11.8 6.2v.01" },
|
package/src/components/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { type ReactNode } from "react";
|
|
3
|
+
import { type ReactNode, useEffect, useState } from "react";
|
|
4
4
|
import { cn } from "../../utils/cn";
|
|
5
5
|
import { Logo } from "../../brand/logo";
|
|
6
6
|
import { Wordmark } from "../../brand/wordmark";
|
|
7
|
+
import { Icon } from "../icon/Icon";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* navItemClass — 导航项统一样式(全域导航一致)。
|
|
@@ -34,6 +35,8 @@ export interface NavbarProps {
|
|
|
34
35
|
badge?: ReactNode;
|
|
35
36
|
/** 品牌区点击链接(通常回首页,如 "/");不传则品牌区不可点击 */
|
|
36
37
|
brandHref?: string;
|
|
38
|
+
/** 开启移动端菜单:<md 断点时导航与操作区收进汉堡下拉(默认 false 保持横向滚动) */
|
|
39
|
+
mobileMenu?: boolean;
|
|
37
40
|
className?: string;
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -50,13 +53,37 @@ export interface NavbarProps {
|
|
|
50
53
|
* <Link href="/audit" className={navItemClass(pathname === "/audit")}>运行审计</Link>
|
|
51
54
|
* </Navbar>
|
|
52
55
|
*/
|
|
53
|
-
export function Navbar({ sublabel, brand, children, actions, badge, brandHref, className }: NavbarProps) {
|
|
56
|
+
export function Navbar({ sublabel, brand, children, actions, badge, brandHref, mobileMenu = false, className }: NavbarProps) {
|
|
57
|
+
const [open, setOpen] = useState(false);
|
|
58
|
+
|
|
59
|
+
// Esc 关闭面板
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!open) return;
|
|
62
|
+
const onKey = (e: KeyboardEvent) => {
|
|
63
|
+
if (e.key === "Escape") setOpen(false);
|
|
64
|
+
};
|
|
65
|
+
window.addEventListener("keydown", onKey);
|
|
66
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
67
|
+
}, [open]);
|
|
68
|
+
|
|
54
69
|
const brandNode = brand ?? (
|
|
55
70
|
<span className="inline-flex items-center gap-2">
|
|
56
71
|
<Logo size={22} />
|
|
57
72
|
<Wordmark size={16} sublabel={sublabel} />
|
|
58
73
|
</span>
|
|
59
74
|
);
|
|
75
|
+
const nav = children ? (
|
|
76
|
+
<nav
|
|
77
|
+
className="flex min-w-0 items-center gap-1 overflow-x-auto"
|
|
78
|
+
aria-label="主导航"
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</nav>
|
|
82
|
+
) : null;
|
|
83
|
+
const actionBox = actions ? (
|
|
84
|
+
<div className="flex shrink-0 items-center gap-2.5">{actions}</div>
|
|
85
|
+
) : null;
|
|
86
|
+
|
|
60
87
|
return (
|
|
61
88
|
<header
|
|
62
89
|
className={cn(
|
|
@@ -74,12 +101,54 @@ export function Navbar({ sublabel, brand, children, actions, badge, brandHref, c
|
|
|
74
101
|
)}
|
|
75
102
|
{badge}
|
|
76
103
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
104
|
+
|
|
105
|
+
{mobileMenu ? (
|
|
106
|
+
<>
|
|
107
|
+
{/* 桌面端:导航 + 操作区原样 */}
|
|
108
|
+
<div className="hidden min-w-0 items-center gap-2.5 md:flex">
|
|
109
|
+
{nav}
|
|
110
|
+
{actionBox}
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
{/* 移动端:汉堡按钮 + 下拉面板(点击面板内任意处关闭) */}
|
|
114
|
+
<div className="relative md:hidden">
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
aria-label={open ? "关闭菜单" : "打开菜单"}
|
|
118
|
+
aria-expanded={open}
|
|
119
|
+
onClick={() => setOpen((v) => !v)}
|
|
120
|
+
className="inline-flex h-9 w-9 items-center justify-center rounded-full text-ink-2 transition-colors hover:bg-surface-2 hover:text-ink"
|
|
121
|
+
>
|
|
122
|
+
<Icon name={open ? "cross" : "menu"} size={16} />
|
|
123
|
+
</button>
|
|
124
|
+
{open ? (
|
|
125
|
+
<div
|
|
126
|
+
onClick={() => setOpen(false)}
|
|
127
|
+
className="absolute right-0 top-full mt-2 flex w-60 flex-col gap-1 rounded-xl border border-line bg-paper p-2 shadow-lg"
|
|
128
|
+
>
|
|
129
|
+
{children ? (
|
|
130
|
+
<nav
|
|
131
|
+
className="flex flex-col items-stretch gap-1"
|
|
132
|
+
aria-label="主导航"
|
|
133
|
+
>
|
|
134
|
+
{children}
|
|
135
|
+
</nav>
|
|
136
|
+
) : null}
|
|
137
|
+
{actions ? (
|
|
138
|
+
<div className="mt-1 flex flex-col items-stretch gap-1 border-t border-line pt-2">
|
|
139
|
+
{actions}
|
|
140
|
+
</div>
|
|
141
|
+
) : null}
|
|
142
|
+
</div>
|
|
143
|
+
) : null}
|
|
144
|
+
</div>
|
|
145
|
+
</>
|
|
146
|
+
) : (
|
|
147
|
+
<>
|
|
148
|
+
{nav}
|
|
149
|
+
{actionBox}
|
|
150
|
+
</>
|
|
151
|
+
)}
|
|
83
152
|
</header>
|
|
84
153
|
);
|
|
85
154
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import "./subtask.css";
|
|
4
|
+
|
|
5
|
+
import { Badge } from "../badge/Badge";
|
|
6
|
+
import { Icon } from "../icon/Icon";
|
|
7
|
+
|
|
8
|
+
export interface SubtaskPartProps {
|
|
9
|
+
/** 子任务描述;缺省时回退显示 agent 名 */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** 执行该子任务的智能体名 */
|
|
12
|
+
agent?: string;
|
|
13
|
+
/** 子任务 prompt(mono 小字显示) */
|
|
14
|
+
prompt?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* SubtaskPart — 执行树中的子任务行(分支线样式与 ToolCard 一致)。
|
|
19
|
+
*
|
|
20
|
+
* 上下文增强(执行树 ::before 分支线)依赖消费端容器留出左侧空间,
|
|
21
|
+
* 与 ToolCard 的执行树用法相同。
|
|
22
|
+
*/
|
|
23
|
+
export function SubtaskPart({ description, agent, prompt }: SubtaskPartProps) {
|
|
24
|
+
return (
|
|
25
|
+
<div className="subtask-row">
|
|
26
|
+
<span className="subtask-icon" aria-hidden>
|
|
27
|
+
<Icon name="chevron-down" size={12} />
|
|
28
|
+
</span>
|
|
29
|
+
<span className="subtask-copy">
|
|
30
|
+
<strong>{description || agent}</strong>
|
|
31
|
+
{prompt ? <small>{prompt}</small> : null}
|
|
32
|
+
</span>
|
|
33
|
+
<Badge variant="outline" size="sm">子任务</Badge>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./SubtaskPart";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* SubtaskPart — 执行树中的子任务行。token 依赖消费端 @theme
|
|
2
|
+
(--color-line、--color-accent、--color-muted、--font-mono)。
|
|
3
|
+
执行树分支线(::before)等上下文增强由消费端自己的 CSS 叠加。 */
|
|
4
|
+
|
|
5
|
+
.subtask-row { position: relative; display: flex; align-items: center; gap: 0.5rem; min-height: 2.15rem; padding: 0.38rem 0.4rem; background: transparent; }
|
|
6
|
+
/* 执行树分支线(挂在左侧时间轴上;独立使用时容器需留出左侧空间) */
|
|
7
|
+
.subtask-row::before { position: absolute; top: 1.08rem; left: -0.81rem; width: 0.81rem; height: 1px; background: var(--color-line); content: ""; }
|
|
8
|
+
.subtask-icon { display: grid; width: 1rem; height: 1rem; place-items: center; color: var(--color-accent); }
|
|
9
|
+
.subtask-copy { display: grid; min-width: 0; flex: 1; gap: 0.1rem; }
|
|
10
|
+
.subtask-copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; font-weight: 600; }
|
|
11
|
+
.subtask-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--color-muted); font-family: var(--font-mono); font-size: 0.6rem; }
|