@agentaily/design-system 0.1.1 → 0.3.0
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/DESIGN.md +58 -7
- package/README.md +10 -6
- package/dist/components/ai/Confirmation.js +58 -22
- package/dist/components/ai/Confirmation.js.map +1 -1
- package/dist/components/ai/Queue.d.ts +23 -0
- package/dist/components/ai/Queue.js +52 -1
- package/dist/components/ai/Queue.js.map +1 -1
- package/dist/components/ai/ToolCall.js +69 -30
- package/dist/components/ai/ToolCall.js.map +1 -1
- package/dist/components/auth/AccountControl.d.ts +23 -0
- package/dist/components/auth/AccountControl.js +47 -0
- package/dist/components/auth/AccountControl.js.map +1 -0
- package/dist/components/auth/AuthDialog.d.ts +39 -0
- package/dist/components/auth/AuthDialog.js +327 -0
- package/dist/components/auth/AuthDialog.js.map +1 -0
- package/dist/components/auth/SignInPage.d.ts +48 -0
- package/dist/components/auth/SignInPage.js +217 -0
- package/dist/components/auth/SignInPage.js.map +1 -0
- package/dist/components/chat/CodeBlock.js +3 -2
- package/dist/components/chat/CodeBlock.js.map +1 -1
- package/dist/components/chat/ConversationThread.d.ts +67 -0
- package/dist/components/chat/ConversationThread.js +129 -0
- package/dist/components/chat/ConversationThread.js.map +1 -0
- package/dist/components/code/Artifact.js +44 -9
- package/dist/components/code/Artifact.js.map +1 -1
- package/dist/components/code/JSXPreview.js +19 -12
- package/dist/components/code/JSXPreview.js.map +1 -1
- package/dist/components/code/Snippet.js +2 -2
- package/dist/components/code/Snippet.js.map +1 -1
- package/dist/components/code/Terminal.js +24 -10
- package/dist/components/code/Terminal.js.map +1 -1
- package/dist/components/code/WebPreview.js +44 -10
- package/dist/components/code/WebPreview.js.map +1 -1
- package/dist/components/display/Skeleton.js +17 -4
- package/dist/components/display/Skeleton.js.map +1 -1
- package/dist/components/display/StatusPill.d.ts +12 -0
- package/dist/components/display/StatusPill.js +17 -0
- package/dist/components/display/StatusPill.js.map +1 -0
- package/dist/components/inputs/Form.d.ts +164 -0
- package/dist/components/inputs/Form.js +484 -0
- package/dist/components/inputs/Form.js.map +1 -0
- package/dist/components/inputs/Input.d.ts +2 -0
- package/dist/components/inputs/Input.js +14 -10
- package/dist/components/inputs/Input.js.map +1 -1
- package/dist/components/inputs/SecretField.d.ts +21 -0
- package/dist/components/inputs/SecretField.js +70 -0
- package/dist/components/inputs/SecretField.js.map +1 -0
- package/dist/components/layout/AppShell.d.ts +30 -0
- package/dist/components/layout/AppShell.js +117 -0
- package/dist/components/layout/AppShell.js.map +1 -0
- package/dist/components/layout/DesignerShell.d.ts +39 -0
- package/dist/components/layout/DesignerShell.js +146 -0
- package/dist/components/layout/DesignerShell.js.map +1 -0
- package/dist/components/layout/DocsLayout.d.ts +24 -0
- package/dist/components/layout/DocsLayout.js +113 -0
- package/dist/components/layout/DocsLayout.js.map +1 -0
- package/dist/components/layout/SettingsPage.d.ts +31 -0
- package/dist/components/layout/SettingsPage.js +92 -0
- package/dist/components/layout/SettingsPage.js.map +1 -0
- package/dist/components/review/MarkupLayer.d.ts +20 -0
- package/dist/components/review/MarkupLayer.js +237 -0
- package/dist/components/review/MarkupLayer.js.map +1 -0
- package/dist/components/settings/HelpSteps.d.ts +20 -0
- package/dist/components/settings/HelpSteps.js +40 -0
- package/dist/components/settings/HelpSteps.js.map +1 -0
- package/dist/components/settings/IntegrationSettings.d.ts +15 -0
- package/dist/components/settings/IntegrationSettings.js +630 -0
- package/dist/components/settings/IntegrationSettings.js.map +1 -0
- package/dist/components/settings/TestRow.d.ts +21 -0
- package/dist/components/settings/TestRow.js +66 -0
- package/dist/components/settings/TestRow.js.map +1 -0
- package/dist/components/utilities/BrandMark.d.ts +17 -0
- package/dist/components/utilities/BrandMark.js +43 -0
- package/dist/components/utilities/BrandMark.js.map +1 -0
- package/dist/components/utilities/Icon.d.ts +28 -0
- package/dist/components/utilities/Icon.js +196 -0
- package/dist/components/utilities/Icon.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -1
- package/dist/styles.css +67 -64
- package/package.json +2 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centered single-column settings frame: sticky bar (brand + actions), heading,
|
|
3
|
+
* optional tab row, and section cards as `children`. Use the bundled
|
|
4
|
+
* `SettingsPage.Card` for consistent section cards.
|
|
5
|
+
*/
|
|
6
|
+
export interface SettingsTab {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SettingsPageProps {
|
|
11
|
+
/** Bar brand lockup. @default <BrandMark wordmark blink={false} /> */
|
|
12
|
+
brand?: React.ReactNode;
|
|
13
|
+
/** Mono breadcrumb word shown after the brand (rendered as "/ <word>"). @default "settings" */
|
|
14
|
+
word?: string;
|
|
15
|
+
/** @default "Settings" */
|
|
16
|
+
title?: string;
|
|
17
|
+
subtitle?: string;
|
|
18
|
+
/** Tab row — strings or {id,label}. */
|
|
19
|
+
tabs?: (SettingsTab | string)[];
|
|
20
|
+
activeTab?: string;
|
|
21
|
+
onTabChange?: (id: string) => void;
|
|
22
|
+
/** Right side of the sticky bar (Cancel / Save). */
|
|
23
|
+
actions?: React.ReactNode;
|
|
24
|
+
/** Section cards (ideally SettingsPage.Card). */
|
|
25
|
+
children?: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
export declare function SettingsPage(props: SettingsPageProps): JSX.Element;
|
|
28
|
+
export declare namespace SettingsPage {
|
|
29
|
+
interface CardProps { title?: string; description?: string; children?: React.ReactNode; }
|
|
30
|
+
function Card(props: CardProps): JSX.Element;
|
|
31
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { BrandMark } from "../utilities/BrandMark.js";
|
|
4
|
+
const AX_SPAGE_CSS = `
|
|
5
|
+
.ax-spage { height: 100%; overflow-y: auto; background: var(--surface-page); }
|
|
6
|
+
.ax-spage__bar { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 12px; height: 56px; padding: 0 22px;
|
|
7
|
+
border-bottom: 1px solid var(--border-default); background: var(--bg-overlay); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
|
|
8
|
+
.ax-spage__sp { flex: 1; }
|
|
9
|
+
.ax-spage__crumb { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-faint); }
|
|
10
|
+
.ax-spage__crumb::before { content: "/"; color: var(--text-faint); opacity: 0.6; }
|
|
11
|
+
.ax-spage__col { max-width: 640px; margin: 0 auto; padding: 48px 28px 96px; }
|
|
12
|
+
.ax-spage__h { margin: 0; font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-body); }
|
|
13
|
+
.ax-spage__sub { margin: 10px 0 0; font-size: var(--text-md); color: var(--text-muted); }
|
|
14
|
+
.ax-spage__tabs { display: flex; gap: 4px; margin: 26px 0 4px; border-bottom: 1px solid var(--border-default); }
|
|
15
|
+
.ax-spage__tab { padding: 9px 12px; font-size: var(--text-sm); color: var(--text-muted); cursor: pointer; border: none; background: none;
|
|
16
|
+
font-family: inherit; border-bottom: 2px solid transparent; margin-bottom: -1px; }
|
|
17
|
+
.ax-spage__tab:hover { color: var(--text-body); }
|
|
18
|
+
.ax-spage__tab[data-on="true"] { color: var(--text-body); border-bottom-color: var(--accent); }
|
|
19
|
+
.ax-spage__card { border: 1px solid var(--border-default); border-radius: var(--radius-3); background: var(--surface-card); padding: 22px; margin-top: 22px; }
|
|
20
|
+
.ax-spage__cardh { margin: 0 0 4px; font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-medium); color: var(--text-body); }
|
|
21
|
+
.ax-spage__cardd { margin: 0 0 18px; font-size: var(--text-sm); color: var(--text-muted); }
|
|
22
|
+
@media (max-width: 600px) {
|
|
23
|
+
.ax-spage__bar { padding: 0 16px; }
|
|
24
|
+
.ax-spage__col { padding: 32px 18px 72px; }
|
|
25
|
+
.ax-spage__tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
|
|
26
|
+
.ax-spage__tabs::-webkit-scrollbar { display: none; }
|
|
27
|
+
.ax-spage__tab { white-space: nowrap; flex: none; }
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-spage-css")) {
|
|
31
|
+
const s = document.createElement("style");
|
|
32
|
+
s.id = "ax-spage-css";
|
|
33
|
+
s.textContent = AX_SPAGE_CSS;
|
|
34
|
+
document.head.appendChild(s);
|
|
35
|
+
}
|
|
36
|
+
function SettingsPage({
|
|
37
|
+
brand,
|
|
38
|
+
word = "settings",
|
|
39
|
+
title = "Settings",
|
|
40
|
+
subtitle,
|
|
41
|
+
tabs = [],
|
|
42
|
+
activeTab,
|
|
43
|
+
onTabChange,
|
|
44
|
+
actions,
|
|
45
|
+
children
|
|
46
|
+
}) {
|
|
47
|
+
const [internal, setInternal] = useState(activeTab || tabs[0] && (tabs[0].id || tabs[0]));
|
|
48
|
+
const active = activeTab !== void 0 ? activeTab : internal;
|
|
49
|
+
const go = (id) => {
|
|
50
|
+
if (onTabChange) onTabChange(id);
|
|
51
|
+
else setInternal(id);
|
|
52
|
+
};
|
|
53
|
+
return /* @__PURE__ */ jsxs("div", { className: "ax-spage", children: [
|
|
54
|
+
/* @__PURE__ */ jsxs("header", { className: "ax-spage__bar", children: [
|
|
55
|
+
brand || /* @__PURE__ */ jsx(BrandMark, { size: 18, wordmark: true, blink: false }),
|
|
56
|
+
word ? /* @__PURE__ */ jsx("span", { className: "ax-spage__crumb", children: word }) : null,
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: "ax-spage__sp" }),
|
|
58
|
+
actions
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-spage__col", children: [
|
|
61
|
+
/* @__PURE__ */ jsx("h1", { className: "ax-spage__h", children: title }),
|
|
62
|
+
subtitle ? /* @__PURE__ */ jsx("p", { className: "ax-spage__sub", children: subtitle }) : null,
|
|
63
|
+
tabs.length ? /* @__PURE__ */ jsx("div", { className: "ax-spage__tabs", children: tabs.map((t) => {
|
|
64
|
+
const id = t.id || t;
|
|
65
|
+
const label = t.label || t;
|
|
66
|
+
return /* @__PURE__ */ jsx(
|
|
67
|
+
"button",
|
|
68
|
+
{
|
|
69
|
+
className: "ax-spage__tab",
|
|
70
|
+
"data-on": active === id,
|
|
71
|
+
onClick: () => go(id),
|
|
72
|
+
children: label
|
|
73
|
+
},
|
|
74
|
+
id
|
|
75
|
+
);
|
|
76
|
+
}) }) : null,
|
|
77
|
+
children
|
|
78
|
+
] })
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
function SettingsCard({ title, description, children }) {
|
|
82
|
+
return /* @__PURE__ */ jsxs("div", { className: "ax-spage__card", children: [
|
|
83
|
+
title ? /* @__PURE__ */ jsx("h2", { className: "ax-spage__cardh", children: title }) : null,
|
|
84
|
+
description ? /* @__PURE__ */ jsx("p", { className: "ax-spage__cardd", children: description }) : null,
|
|
85
|
+
children
|
|
86
|
+
] });
|
|
87
|
+
}
|
|
88
|
+
SettingsPage.Card = SettingsCard;
|
|
89
|
+
export {
|
|
90
|
+
SettingsPage
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=SettingsPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SettingsPage.js","sources":["../../../src/components/layout/SettingsPage.jsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { BrandMark } from \"../utilities/BrandMark.jsx\";\n\n// SettingsPage — centered single-column settings frame: sticky bar (brand +\n// actions), heading, optional tabs, and section cards in `children`.\nconst AX_SPAGE_CSS = `\n.ax-spage { height: 100%; overflow-y: auto; background: var(--surface-page); }\n.ax-spage__bar { position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 12px; height: 56px; padding: 0 22px;\n border-bottom: 1px solid var(--border-default); background: var(--bg-overlay); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }\n.ax-spage__sp { flex: 1; }\n.ax-spage__crumb { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-faint); }\n.ax-spage__crumb::before { content: \"/\"; color: var(--text-faint); opacity: 0.6; }\n.ax-spage__col { max-width: 640px; margin: 0 auto; padding: 48px 28px 96px; }\n.ax-spage__h { margin: 0; font-family: var(--font-display); font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-body); }\n.ax-spage__sub { margin: 10px 0 0; font-size: var(--text-md); color: var(--text-muted); }\n.ax-spage__tabs { display: flex; gap: 4px; margin: 26px 0 4px; border-bottom: 1px solid var(--border-default); }\n.ax-spage__tab { padding: 9px 12px; font-size: var(--text-sm); color: var(--text-muted); cursor: pointer; border: none; background: none;\n font-family: inherit; border-bottom: 2px solid transparent; margin-bottom: -1px; }\n.ax-spage__tab:hover { color: var(--text-body); }\n.ax-spage__tab[data-on=\"true\"] { color: var(--text-body); border-bottom-color: var(--accent); }\n.ax-spage__card { border: 1px solid var(--border-default); border-radius: var(--radius-3); background: var(--surface-card); padding: 22px; margin-top: 22px; }\n.ax-spage__cardh { margin: 0 0 4px; font-family: var(--font-display); font-size: var(--text-lg); font-weight: var(--weight-medium); color: var(--text-body); }\n.ax-spage__cardd { margin: 0 0 18px; font-size: var(--text-sm); color: var(--text-muted); }\n@media (max-width: 600px) {\n .ax-spage__bar { padding: 0 16px; }\n .ax-spage__col { padding: 32px 18px 72px; }\n .ax-spage__tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; }\n .ax-spage__tabs::-webkit-scrollbar { display: none; }\n .ax-spage__tab { white-space: nowrap; flex: none; }\n}\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-spage-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-spage-css\";\n s.textContent = AX_SPAGE_CSS;\n document.head.appendChild(s);\n}\n\nexport function SettingsPage({\n brand,\n word = \"settings\",\n title = \"Settings\",\n subtitle,\n tabs = [],\n activeTab,\n onTabChange,\n actions,\n children,\n}) {\n const [internal, setInternal] = useState(activeTab || (tabs[0] && (tabs[0].id || tabs[0])));\n const active = activeTab !== undefined ? activeTab : internal;\n const go = (id) => {\n if (onTabChange) onTabChange(id);\n else setInternal(id);\n };\n\n return (\n <div className=\"ax-spage\">\n <header className=\"ax-spage__bar\">\n {brand || <BrandMark size={18} wordmark blink={false} />}\n {word ? <span className=\"ax-spage__crumb\">{word}</span> : null}\n <span className=\"ax-spage__sp\"></span>\n {actions}\n </header>\n\n <div className=\"ax-spage__col\">\n <h1 className=\"ax-spage__h\">{title}</h1>\n {subtitle ? <p className=\"ax-spage__sub\">{subtitle}</p> : null}\n\n {tabs.length ? (\n <div className=\"ax-spage__tabs\">\n {tabs.map((t) => {\n const id = t.id || t;\n const label = t.label || t;\n return (\n <button\n key={id}\n className=\"ax-spage__tab\"\n data-on={active === id}\n onClick={() => go(id)}\n >\n {label}\n </button>\n );\n })}\n </div>\n ) : null}\n\n {children}\n </div>\n </div>\n );\n}\n\n// convenience section card\nfunction SettingsCard({ title, description, children }) {\n return (\n <div className=\"ax-spage__card\">\n {title ? <h2 className=\"ax-spage__cardh\">{title}</h2> : null}\n {description ? <p className=\"ax-spage__cardd\">{description}</p> : null}\n {children}\n </div>\n );\n}\nSettingsPage.Card = SettingsCard;\n"],"names":[],"mappings":";;;AAKA,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BrB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,cAAc,GAAG;AAC/E,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACA,OAAO,CAAA;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAG;AACD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,aAAc,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,KAAK,CAAC,EAAG;AAC1F,QAAM,SAAS,cAAc,SAAY,YAAY;AACrD,QAAM,KAAK,CAAC,OAAO;AACjB,QAAI,yBAAyB,EAAE;AAAA,qBACd,EAAE;AAAA,EACrB;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,IAAA,qBAAC,UAAA,EAAO,WAAU,iBACf,UAAA;AAAA,MAAA,6BAAU,WAAA,EAAU,MAAM,IAAI,UAAQ,MAAC,OAAO,OAAO;AAAA,MACrD,OAAO,oBAAC,QAAA,EAAK,WAAU,mBAAmB,gBAAK,IAAU;AAAA,MAC1D,oBAAC,QAAA,EAAK,WAAU,eAAA,CAAe;AAAA,MAC9B;AAAA,IAAA,GACH;AAAA,IAEA,qBAAC,OAAA,EAAI,WAAU,iBACb,UAAA;AAAA,MAAA,oBAAC,MAAA,EAAG,WAAU,eAAe,UAAA,OAAM;AAAA,MAClC,WAAW,oBAAC,KAAA,EAAE,WAAU,iBAAiB,oBAAS,IAAO;AAAA,MAEzD,KAAK,SACJ,oBAAC,OAAA,EAAI,WAAU,kBACZ,UAAA,KAAK,IAAI,CAAC,MAAM;AACf,cAAM,KAAK,EAAE,MAAM;AACnB,cAAM,QAAQ,EAAE,SAAS;AACzB,eACE;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,WAAS,WAAW;AAAA,YACpB,SAAS,MAAM,GAAG,EAAE;AAAA,YAEnB,UAAA;AAAA,UAAA;AAAA,UALI;AAAA,QAAA;AAAA,MAQX,CAAC,GACH,IACE;AAAA,MAEH;AAAA,IAAA,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAGA,SAAS,aAAa,EAAE,OAAO,aAAa,YAAY;AACtD,SACE,qBAAC,OAAA,EAAI,WAAU,kBACZ,UAAA;AAAA,IAAA,QAAQ,oBAAC,MAAA,EAAG,WAAU,mBAAmB,iBAAM,IAAQ;AAAA,IACvD,cAAc,oBAAC,KAAA,EAAE,WAAU,mBAAmB,uBAAY,IAAO;AAAA,IACjE;AAAA,EAAA,GACH;AAEJ;AACA,aAAa,OAAO;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Element-targeting overlay for "point at what to change" review. Hover
|
|
3
|
+
* highlights any element carrying `data-mk-label`; click selects it; a note
|
|
4
|
+
* composer emits `onSend("〔label · kind〕note")`. Mount inside a
|
|
5
|
+
* position:relative container — the layer fills it (inset:0). Esc deselects,
|
|
6
|
+
* then closes. Personal tool — nothing is persisted.
|
|
7
|
+
*/
|
|
8
|
+
export interface MarkupLayerProps {
|
|
9
|
+
/** Called on Esc (when nothing selected) or the 退出 button. */
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
/** Called with the composed message: `〔label · kind〕note`. */
|
|
12
|
+
onSend?: (message: string) => void;
|
|
13
|
+
/** Composer textarea placeholder. */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
/** Hint pill text before a target is picked. */
|
|
16
|
+
hintIdle?: string;
|
|
17
|
+
/** Hint pill text while composing on a selected target. */
|
|
18
|
+
hintActive?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function MarkupLayer(props: MarkupLayerProps): JSX.Element;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useEffect } from "react";
|
|
3
|
+
import { Icon } from "../utilities/Icon.js";
|
|
4
|
+
const AX_MARKUP_CSS = `
|
|
5
|
+
.ax-markup { position: absolute; inset: 0; z-index: 20; pointer-events: none; box-shadow: inset 0 0 0 2px var(--focus-soft); }
|
|
6
|
+
.ax-markup__canvas { position: absolute; inset: 0; cursor: crosshair; touch-action: none; pointer-events: auto; }
|
|
7
|
+
.ax-markup__box { position: absolute; pointer-events: none; border: 1.5px solid var(--accent);
|
|
8
|
+
border-radius: var(--radius-1); background: rgba(127,127,127,0.06); z-index: 22;
|
|
9
|
+
transition: left 80ms var(--ease-out), top 80ms var(--ease-out), width 80ms var(--ease-out), height 80ms var(--ease-out); }
|
|
10
|
+
.ax-markup__box.is-selected { box-shadow: 0 0 0 3px var(--focus-soft); background: rgba(127,127,127,0.10); transition: none; }
|
|
11
|
+
.ax-markup__tag { position: absolute; top: 0; left: -1.5px; transform: translateY(-100%);
|
|
12
|
+
display: inline-flex; align-items: center; padding: 2px 7px; background: var(--accent); color: var(--accent-fg);
|
|
13
|
+
font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: 0.01em;
|
|
14
|
+
border-radius: var(--radius-1) var(--radius-1) 0 0; white-space: nowrap; }
|
|
15
|
+
.ax-markup__tagkind { opacity: 0.7; }
|
|
16
|
+
.ax-markup__pop { position: absolute; width: 248px; z-index: 30; display: flex; flex-direction: column; gap: 9px;
|
|
17
|
+
padding: 11px; background: var(--surface-card); border: 1px solid var(--border-strong);
|
|
18
|
+
border-radius: var(--radius-3); box-shadow: var(--shadow-3); pointer-events: auto; }
|
|
19
|
+
.ax-markup__poptarget { display: flex; align-items: center; gap: 6px; color: var(--text-muted); }
|
|
20
|
+
.ax-markup__poptag { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body); }
|
|
21
|
+
.ax-markup__ta { width: 100%; min-height: 64px; resize: none; padding: 8px 10px; background: var(--surface-page);
|
|
22
|
+
color: var(--text-body); border: 1px solid var(--border-default); border-radius: var(--radius-2);
|
|
23
|
+
font-family: var(--font-body); font-size: var(--text-sm); line-height: var(--leading-snug); outline: none; }
|
|
24
|
+
.ax-markup__ta:focus { border-color: var(--fg-2); box-shadow: 0 0 0 3px var(--focus-soft); }
|
|
25
|
+
.ax-markup__ta::placeholder { color: var(--text-faint); }
|
|
26
|
+
.ax-markup__popbtns { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }
|
|
27
|
+
.ax-markup__cancel, .ax-markup__done { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px;
|
|
28
|
+
border-radius: var(--radius-2); font-family: var(--font-body); font-size: var(--text-sm); cursor: pointer;
|
|
29
|
+
border: 1px solid transparent; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }
|
|
30
|
+
.ax-markup__cancel { background: none; color: var(--text-faint); }
|
|
31
|
+
.ax-markup__cancel:hover { color: var(--text-body); background: var(--surface-raised); }
|
|
32
|
+
.ax-markup__done { background: var(--accent); color: var(--accent-fg); }
|
|
33
|
+
.ax-markup__done:hover { background: var(--accent-hover); }
|
|
34
|
+
.ax-markup__done:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
35
|
+
.ax-markup__pill { position: absolute; top: 16px; left: 50%; transform: translateX(-50%); z-index: 25;
|
|
36
|
+
display: flex; align-items: center; gap: 11px; padding: 7px 7px 7px 14px; max-width: calc(100% - 32px);
|
|
37
|
+
background: var(--surface-card); border: 1px solid var(--border-strong); border-radius: var(--radius-full);
|
|
38
|
+
box-shadow: var(--shadow-2); pointer-events: auto; }
|
|
39
|
+
.ax-markup__dot { flex: none; width: 7px; height: 7px; border-radius: var(--radius-full); background: var(--accent);
|
|
40
|
+
animation: ax-mk-pulse 1.6s var(--ease-out) infinite; }
|
|
41
|
+
@keyframes ax-mk-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
|
|
42
|
+
@media (prefers-reduced-motion: reduce) { .ax-markup__dot { animation: none; } }
|
|
43
|
+
.ax-markup__pilltxt { font-size: var(--text-sm); color: var(--text-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
44
|
+
.ax-markup__pillsep { flex: none; width: 1px; height: 18px; background: var(--border-strong); }
|
|
45
|
+
.ax-markup__pillx { flex: none; display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 11px;
|
|
46
|
+
border: none; background: var(--surface-raised); color: var(--text-muted); border-radius: var(--radius-full);
|
|
47
|
+
font-family: var(--font-body); font-size: var(--text-sm); cursor: pointer; transition: color var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out); }
|
|
48
|
+
.ax-markup__pillx:hover { color: var(--text-body); background: var(--border-strong); }
|
|
49
|
+
`;
|
|
50
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-markup-css")) {
|
|
51
|
+
const s = document.createElement("style");
|
|
52
|
+
s.id = "ax-markup-css";
|
|
53
|
+
s.textContent = AX_MARKUP_CSS;
|
|
54
|
+
document.head.appendChild(s);
|
|
55
|
+
}
|
|
56
|
+
function MarkupLayer({
|
|
57
|
+
onClose,
|
|
58
|
+
onSend,
|
|
59
|
+
placeholder = "告诉 Agentaily 这里要怎么改…",
|
|
60
|
+
hintIdle = "移到要改的地方,点击它再描述修改",
|
|
61
|
+
hintActive = "输入修改要求,发送到左侧对话"
|
|
62
|
+
}) {
|
|
63
|
+
const layerRef = useRef(null);
|
|
64
|
+
const capRef = useRef(null);
|
|
65
|
+
const [hover, setHover] = useState(null);
|
|
66
|
+
const [selected, setSelected] = useState(null);
|
|
67
|
+
const [note, setNote] = useState("");
|
|
68
|
+
const findTarget = (cx, cy) => {
|
|
69
|
+
const cap = capRef.current;
|
|
70
|
+
if (!cap) return null;
|
|
71
|
+
const prev = cap.style.pointerEvents;
|
|
72
|
+
cap.style.pointerEvents = "none";
|
|
73
|
+
const el = document.elementFromPoint(cx, cy);
|
|
74
|
+
cap.style.pointerEvents = prev || "auto";
|
|
75
|
+
if (!el) return null;
|
|
76
|
+
return el.closest("[data-mk-label]") || null;
|
|
77
|
+
};
|
|
78
|
+
const boxFor = (el) => {
|
|
79
|
+
const r = el.getBoundingClientRect();
|
|
80
|
+
const lr = layerRef.current.getBoundingClientRect();
|
|
81
|
+
return {
|
|
82
|
+
left: r.left - lr.left,
|
|
83
|
+
top: r.top - lr.top,
|
|
84
|
+
w: r.width,
|
|
85
|
+
h: r.height,
|
|
86
|
+
label: el.getAttribute("data-mk-label"),
|
|
87
|
+
kind: el.getAttribute("data-mk-kind") || ""
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
const onMove = (e) => {
|
|
91
|
+
if (selected) return;
|
|
92
|
+
const t = findTarget(e.clientX, e.clientY);
|
|
93
|
+
setHover(t ? boxFor(t) : null);
|
|
94
|
+
};
|
|
95
|
+
const onLeave = () => {
|
|
96
|
+
if (!selected) setHover(null);
|
|
97
|
+
};
|
|
98
|
+
const onClickCap = (e) => {
|
|
99
|
+
const t = findTarget(e.clientX, e.clientY);
|
|
100
|
+
if (!t) {
|
|
101
|
+
setSelected(null);
|
|
102
|
+
setNote("");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
setSelected(boxFor(t));
|
|
106
|
+
setNote("");
|
|
107
|
+
setHover(null);
|
|
108
|
+
};
|
|
109
|
+
const send = () => {
|
|
110
|
+
if (!selected || !note.trim()) return;
|
|
111
|
+
const tag = selected.kind ? `${selected.label} · ${selected.kind}` : selected.label;
|
|
112
|
+
onSend && onSend(`〔${tag}〕${note.trim()}`);
|
|
113
|
+
setSelected(null);
|
|
114
|
+
setNote("");
|
|
115
|
+
};
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
const onKey = (e) => {
|
|
118
|
+
if (e.key !== "Escape") return;
|
|
119
|
+
if (selected) {
|
|
120
|
+
setSelected(null);
|
|
121
|
+
setNote("");
|
|
122
|
+
} else onClose && onClose();
|
|
123
|
+
};
|
|
124
|
+
window.addEventListener("keydown", onKey);
|
|
125
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
126
|
+
}, [selected, onClose]);
|
|
127
|
+
const box = selected || hover;
|
|
128
|
+
const popStyle = () => {
|
|
129
|
+
const W = layerRef.current ? layerRef.current.clientWidth : 800;
|
|
130
|
+
const H = layerRef.current ? layerRef.current.clientHeight : 600;
|
|
131
|
+
let left = selected.left;
|
|
132
|
+
if (left + 268 > W) left = Math.max(8, W - 268);
|
|
133
|
+
let top = selected.top + selected.h + 10;
|
|
134
|
+
if (top + 150 > H) top = Math.max(8, selected.top - 158);
|
|
135
|
+
return { left, top };
|
|
136
|
+
};
|
|
137
|
+
return /* @__PURE__ */ jsxs("div", { className: "ax-markup", ref: layerRef, children: [
|
|
138
|
+
/* @__PURE__ */ jsx(
|
|
139
|
+
"div",
|
|
140
|
+
{
|
|
141
|
+
className: "ax-markup__canvas",
|
|
142
|
+
ref: capRef,
|
|
143
|
+
onMouseMove: onMove,
|
|
144
|
+
onMouseLeave: onLeave,
|
|
145
|
+
onClick: onClickCap
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
box ? /* @__PURE__ */ jsx(
|
|
149
|
+
"div",
|
|
150
|
+
{
|
|
151
|
+
className: "ax-markup__box" + (selected ? " is-selected" : ""),
|
|
152
|
+
style: { left: box.left, top: box.top, width: box.w, height: box.h },
|
|
153
|
+
children: /* @__PURE__ */ jsxs("span", { className: "ax-markup__tag", children: [
|
|
154
|
+
box.label,
|
|
155
|
+
box.kind ? /* @__PURE__ */ jsxs("span", { className: "ax-markup__tagkind", children: [
|
|
156
|
+
" · ",
|
|
157
|
+
box.kind
|
|
158
|
+
] }) : null
|
|
159
|
+
] })
|
|
160
|
+
}
|
|
161
|
+
) : null,
|
|
162
|
+
selected ? /* @__PURE__ */ jsxs("div", { className: "ax-markup__pop", style: popStyle(), onClick: (e) => e.stopPropagation(), children: [
|
|
163
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-markup__poptarget", children: [
|
|
164
|
+
/* @__PURE__ */ jsx(Icon, { name: "target", size: 13 }),
|
|
165
|
+
/* @__PURE__ */ jsxs("span", { className: "ax-markup__poptag", children: [
|
|
166
|
+
selected.label,
|
|
167
|
+
selected.kind ? ` · ${selected.kind}` : ""
|
|
168
|
+
] })
|
|
169
|
+
] }),
|
|
170
|
+
/* @__PURE__ */ jsx(
|
|
171
|
+
"textarea",
|
|
172
|
+
{
|
|
173
|
+
className: "ax-markup__ta",
|
|
174
|
+
autoFocus: true,
|
|
175
|
+
value: note,
|
|
176
|
+
placeholder,
|
|
177
|
+
onChange: (e) => setNote(e.target.value),
|
|
178
|
+
onKeyDown: (e) => {
|
|
179
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
180
|
+
e.preventDefault();
|
|
181
|
+
send();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-markup__popbtns", children: [
|
|
187
|
+
/* @__PURE__ */ jsx(
|
|
188
|
+
"button",
|
|
189
|
+
{
|
|
190
|
+
type: "button",
|
|
191
|
+
className: "ax-markup__cancel",
|
|
192
|
+
onClick: () => {
|
|
193
|
+
setSelected(null);
|
|
194
|
+
setNote("");
|
|
195
|
+
},
|
|
196
|
+
children: "取消"
|
|
197
|
+
}
|
|
198
|
+
),
|
|
199
|
+
/* @__PURE__ */ jsxs(
|
|
200
|
+
"button",
|
|
201
|
+
{
|
|
202
|
+
type: "button",
|
|
203
|
+
className: "ax-markup__done",
|
|
204
|
+
disabled: !note.trim(),
|
|
205
|
+
onClick: send,
|
|
206
|
+
children: [
|
|
207
|
+
"发送到对话",
|
|
208
|
+
/* @__PURE__ */ jsx(Icon, { name: "arrow", size: 13 })
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] })
|
|
213
|
+
] }) : null,
|
|
214
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-markup__pill", children: [
|
|
215
|
+
/* @__PURE__ */ jsx("span", { className: "ax-markup__dot" }),
|
|
216
|
+
/* @__PURE__ */ jsx("span", { className: "ax-markup__pilltxt", children: selected ? hintActive : hintIdle }),
|
|
217
|
+
/* @__PURE__ */ jsx("span", { className: "ax-markup__pillsep" }),
|
|
218
|
+
/* @__PURE__ */ jsxs(
|
|
219
|
+
"button",
|
|
220
|
+
{
|
|
221
|
+
type: "button",
|
|
222
|
+
className: "ax-markup__pillx",
|
|
223
|
+
onClick: () => onClose && onClose(),
|
|
224
|
+
"aria-label": "退出",
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ jsx(Icon, { name: "x", size: 14 }),
|
|
227
|
+
/* @__PURE__ */ jsx("span", { children: "退出" })
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
] })
|
|
232
|
+
] });
|
|
233
|
+
}
|
|
234
|
+
export {
|
|
235
|
+
MarkupLayer
|
|
236
|
+
};
|
|
237
|
+
//# sourceMappingURL=MarkupLayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkupLayer.js","sources":["../../../src/components/review/MarkupLayer.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { Icon } from \"../utilities/Icon.jsx\";\n\n// MarkupLayer — element-targeting overlay. Hover highlights the real node under\n// the cursor (any element carrying data-mk-label); click selects it; type a note\n// and it's emitted via onSend with the element's identity prefixed — so users\n// point at what they mean instead of describing it. Personal tool, no persistence.\n//\n// Mount inside a position:relative container; the layer fills it (inset:0).\n// Targetable elements opt in with: data-mk-label=\"标题\" data-mk-kind=\"文本\"(optional).\nconst AX_MARKUP_CSS = `\n.ax-markup { position: absolute; inset: 0; z-index: 20; pointer-events: none; box-shadow: inset 0 0 0 2px var(--focus-soft); }\n.ax-markup__canvas { position: absolute; inset: 0; cursor: crosshair; touch-action: none; pointer-events: auto; }\n.ax-markup__box { position: absolute; pointer-events: none; border: 1.5px solid var(--accent);\n border-radius: var(--radius-1); background: rgba(127,127,127,0.06); z-index: 22;\n transition: left 80ms var(--ease-out), top 80ms var(--ease-out), width 80ms var(--ease-out), height 80ms var(--ease-out); }\n.ax-markup__box.is-selected { box-shadow: 0 0 0 3px var(--focus-soft); background: rgba(127,127,127,0.10); transition: none; }\n.ax-markup__tag { position: absolute; top: 0; left: -1.5px; transform: translateY(-100%);\n display: inline-flex; align-items: center; padding: 2px 7px; background: var(--accent); color: var(--accent-fg);\n font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: 0.01em;\n border-radius: var(--radius-1) var(--radius-1) 0 0; white-space: nowrap; }\n.ax-markup__tagkind { opacity: 0.7; }\n.ax-markup__pop { position: absolute; width: 248px; z-index: 30; display: flex; flex-direction: column; gap: 9px;\n padding: 11px; background: var(--surface-card); border: 1px solid var(--border-strong);\n border-radius: var(--radius-3); box-shadow: var(--shadow-3); pointer-events: auto; }\n.ax-markup__poptarget { display: flex; align-items: center; gap: 6px; color: var(--text-muted); }\n.ax-markup__poptag { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body); }\n.ax-markup__ta { width: 100%; min-height: 64px; resize: none; padding: 8px 10px; background: var(--surface-page);\n color: var(--text-body); border: 1px solid var(--border-default); border-radius: var(--radius-2);\n font-family: var(--font-body); font-size: var(--text-sm); line-height: var(--leading-snug); outline: none; }\n.ax-markup__ta:focus { border-color: var(--fg-2); box-shadow: 0 0 0 3px var(--focus-soft); }\n.ax-markup__ta::placeholder { color: var(--text-faint); }\n.ax-markup__popbtns { display: flex; align-items: center; justify-content: flex-end; gap: 8px; }\n.ax-markup__cancel, .ax-markup__done { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 12px;\n border-radius: var(--radius-2); font-family: var(--font-body); font-size: var(--text-sm); cursor: pointer;\n border: 1px solid transparent; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }\n.ax-markup__cancel { background: none; color: var(--text-faint); }\n.ax-markup__cancel:hover { color: var(--text-body); background: var(--surface-raised); }\n.ax-markup__done { background: var(--accent); color: var(--accent-fg); }\n.ax-markup__done:hover { background: var(--accent-hover); }\n.ax-markup__done:disabled { opacity: 0.4; cursor: not-allowed; }\n.ax-markup__pill { position: absolute; top: 16px; left: 50%; transform: translateX(-50%); z-index: 25;\n display: flex; align-items: center; gap: 11px; padding: 7px 7px 7px 14px; max-width: calc(100% - 32px);\n background: var(--surface-card); border: 1px solid var(--border-strong); border-radius: var(--radius-full);\n box-shadow: var(--shadow-2); pointer-events: auto; }\n.ax-markup__dot { flex: none; width: 7px; height: 7px; border-radius: var(--radius-full); background: var(--accent);\n animation: ax-mk-pulse 1.6s var(--ease-out) infinite; }\n@keyframes ax-mk-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }\n@media (prefers-reduced-motion: reduce) { .ax-markup__dot { animation: none; } }\n.ax-markup__pilltxt { font-size: var(--text-sm); color: var(--text-body); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.ax-markup__pillsep { flex: none; width: 1px; height: 18px; background: var(--border-strong); }\n.ax-markup__pillx { flex: none; display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 11px;\n border: none; background: var(--surface-raised); color: var(--text-muted); border-radius: var(--radius-full);\n font-family: var(--font-body); font-size: var(--text-sm); cursor: pointer; transition: color var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out); }\n.ax-markup__pillx:hover { color: var(--text-body); background: var(--border-strong); }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-markup-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-markup-css\";\n s.textContent = AX_MARKUP_CSS;\n document.head.appendChild(s);\n}\n\nexport function MarkupLayer({\n onClose,\n onSend,\n placeholder = \"告诉 Agentaily 这里要怎么改…\",\n hintIdle = \"移到要改的地方,点击它再描述修改\",\n hintActive = \"输入修改要求,发送到左侧对话\",\n}) {\n const layerRef = useRef(null);\n const capRef = useRef(null);\n const [hover, setHover] = useState(null);\n const [selected, setSelected] = useState(null);\n const [note, setNote] = useState(\"\");\n\n const findTarget = (cx, cy) => {\n const cap = capRef.current;\n if (!cap) return null;\n const prev = cap.style.pointerEvents;\n cap.style.pointerEvents = \"none\";\n const el = document.elementFromPoint(cx, cy);\n cap.style.pointerEvents = prev || \"auto\";\n if (!el) return null;\n return el.closest(\"[data-mk-label]\") || null;\n };\n\n const boxFor = (el) => {\n const r = el.getBoundingClientRect();\n const lr = layerRef.current.getBoundingClientRect();\n return {\n left: r.left - lr.left,\n top: r.top - lr.top,\n w: r.width,\n h: r.height,\n label: el.getAttribute(\"data-mk-label\"),\n kind: el.getAttribute(\"data-mk-kind\") || \"\",\n };\n };\n\n const onMove = (e) => {\n if (selected) return;\n const t = findTarget(e.clientX, e.clientY);\n setHover(t ? boxFor(t) : null);\n };\n const onLeave = () => {\n if (!selected) setHover(null);\n };\n const onClickCap = (e) => {\n const t = findTarget(e.clientX, e.clientY);\n if (!t) {\n setSelected(null);\n setNote(\"\");\n return;\n }\n setSelected(boxFor(t));\n setNote(\"\");\n setHover(null);\n };\n\n const send = () => {\n if (!selected || !note.trim()) return;\n const tag = selected.kind ? `${selected.label} · ${selected.kind}` : selected.label;\n onSend && onSend(`〔${tag}〕${note.trim()}`);\n setSelected(null);\n setNote(\"\");\n };\n\n useEffect(() => {\n const onKey = (e) => {\n if (e.key !== \"Escape\") return;\n if (selected) {\n setSelected(null);\n setNote(\"\");\n } else onClose && onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [selected, onClose]);\n\n const box = selected || hover;\n\n const popStyle = () => {\n const W = layerRef.current ? layerRef.current.clientWidth : 800;\n const H = layerRef.current ? layerRef.current.clientHeight : 600;\n let left = selected.left;\n if (left + 268 > W) left = Math.max(8, W - 268);\n let top = selected.top + selected.h + 10;\n if (top + 150 > H) top = Math.max(8, selected.top - 158);\n return { left, top };\n };\n\n return (\n <div className=\"ax-markup\" ref={layerRef}>\n <div\n className=\"ax-markup__canvas\"\n ref={capRef}\n onMouseMove={onMove}\n onMouseLeave={onLeave}\n onClick={onClickCap}\n />\n\n {box ? (\n <div\n className={\"ax-markup__box\" + (selected ? \" is-selected\" : \"\")}\n style={{ left: box.left, top: box.top, width: box.w, height: box.h }}\n >\n <span className=\"ax-markup__tag\">\n {box.label}\n {box.kind ? <span className=\"ax-markup__tagkind\"> · {box.kind}</span> : null}\n </span>\n </div>\n ) : null}\n\n {selected ? (\n <div className=\"ax-markup__pop\" style={popStyle()} onClick={(e) => e.stopPropagation()}>\n <div className=\"ax-markup__poptarget\">\n <Icon name=\"target\" size={13} />\n <span className=\"ax-markup__poptag\">\n {selected.label}\n {selected.kind ? ` · ${selected.kind}` : \"\"}\n </span>\n </div>\n <textarea\n className=\"ax-markup__ta\"\n autoFocus\n value={note}\n placeholder={placeholder}\n onChange={(e) => setNote(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n send();\n }\n }}\n />\n <div className=\"ax-markup__popbtns\">\n <button\n type=\"button\"\n className=\"ax-markup__cancel\"\n onClick={() => {\n setSelected(null);\n setNote(\"\");\n }}\n >\n 取消\n </button>\n <button\n type=\"button\"\n className=\"ax-markup__done\"\n disabled={!note.trim()}\n onClick={send}\n >\n 发送到对话\n <Icon name=\"arrow\" size={13} />\n </button>\n </div>\n </div>\n ) : null}\n\n <div className=\"ax-markup__pill\">\n <span className=\"ax-markup__dot\" />\n <span className=\"ax-markup__pilltxt\">{selected ? hintActive : hintIdle}</span>\n <span className=\"ax-markup__pillsep\" />\n <button\n type=\"button\"\n className=\"ax-markup__pillx\"\n onClick={() => onClose && onClose()}\n aria-label=\"退出\"\n >\n <Icon name=\"x\" size={14} />\n <span>退出</span>\n </button>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":";;;AAUA,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CtB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,eAAe,GAAG;AAChF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,WAAW;AAAA,EACX,aAAa;AACf,GAAG;AACD,QAAM,WAAW,OAAO,IAAI;AAC5B,QAAM,SAAS,OAAO,IAAI;AAC1B,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,IAAI;AACvC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,IAAI;AAC7C,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AAEnC,QAAM,aAAa,CAAC,IAAI,OAAO;AAC7B,UAAM,MAAM,OAAO;AACnB,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,OAAO,IAAI,MAAM;AACvB,QAAI,MAAM,gBAAgB;AAC1B,UAAM,KAAK,SAAS,iBAAiB,IAAI,EAAE;AAC3C,QAAI,MAAM,gBAAgB,QAAQ;AAClC,QAAI,CAAC,GAAI,QAAO;AAChB,WAAO,GAAG,QAAQ,iBAAiB,KAAK;AAAA,EAC1C;AAEA,QAAM,SAAS,CAAC,OAAO;AACrB,UAAM,IAAI,GAAG,sBAAA;AACb,UAAM,KAAK,SAAS,QAAQ,sBAAA;AAC5B,WAAO;AAAA,MACL,MAAM,EAAE,OAAO,GAAG;AAAA,MAClB,KAAK,EAAE,MAAM,GAAG;AAAA,MAChB,GAAG,EAAE;AAAA,MACL,GAAG,EAAE;AAAA,MACL,OAAO,GAAG,aAAa,eAAe;AAAA,MACtC,MAAM,GAAG,aAAa,cAAc,KAAK;AAAA,IAAA;AAAA,EAE7C;AAEA,QAAM,SAAS,CAAC,MAAM;AACpB,QAAI,SAAU;AACd,UAAM,IAAI,WAAW,EAAE,SAAS,EAAE,OAAO;AACzC,aAAS,IAAI,OAAO,CAAC,IAAI,IAAI;AAAA,EAC/B;AACA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,SAAU,UAAS,IAAI;AAAA,EAC9B;AACA,QAAM,aAAa,CAAC,MAAM;AACxB,UAAM,IAAI,WAAW,EAAE,SAAS,EAAE,OAAO;AACzC,QAAI,CAAC,GAAG;AACN,kBAAY,IAAI;AAChB,cAAQ,EAAE;AACV;AAAA,IACF;AACA,gBAAY,OAAO,CAAC,CAAC;AACrB,YAAQ,EAAE;AACV,aAAS,IAAI;AAAA,EACf;AAEA,QAAM,OAAO,MAAM;AACjB,QAAI,CAAC,YAAY,CAAC,KAAK,OAAQ;AAC/B,UAAM,MAAM,SAAS,OAAO,GAAG,SAAS,KAAK,MAAM,SAAS,IAAI,KAAK,SAAS;AAC9E,cAAU,OAAO,IAAI,GAAG,IAAI,KAAK,KAAA,CAAM,EAAE;AACzC,gBAAY,IAAI;AAChB,YAAQ,EAAE;AAAA,EACZ;AAEA,YAAU,MAAM;AACd,UAAM,QAAQ,CAAC,MAAM;AACnB,UAAI,EAAE,QAAQ,SAAU;AACxB,UAAI,UAAU;AACZ,oBAAY,IAAI;AAChB,gBAAQ,EAAE;AAAA,MACZ,kBAAkB,QAAA;AAAA,IACpB;AACA,WAAO,iBAAiB,WAAW,KAAK;AACxC,WAAO,MAAM,OAAO,oBAAoB,WAAW,KAAK;AAAA,EAC1D,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,QAAM,MAAM,YAAY;AAExB,QAAM,WAAW,MAAM;AACrB,UAAM,IAAI,SAAS,UAAU,SAAS,QAAQ,cAAc;AAC5D,UAAM,IAAI,SAAS,UAAU,SAAS,QAAQ,eAAe;AAC7D,QAAI,OAAO,SAAS;AACpB,QAAI,OAAO,MAAM,EAAG,QAAO,KAAK,IAAI,GAAG,IAAI,GAAG;AAC9C,QAAI,MAAM,SAAS,MAAM,SAAS,IAAI;AACtC,QAAI,MAAM,MAAM,EAAG,OAAM,KAAK,IAAI,GAAG,SAAS,MAAM,GAAG;AACvD,WAAO,EAAE,MAAM,IAAA;AAAA,EACjB;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,aAAY,KAAK,UAC9B,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,KAAK;AAAA,QACL,aAAa;AAAA,QACb,cAAc;AAAA,QACd,SAAS;AAAA,MAAA;AAAA,IAAA;AAAA,IAGV,MACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,oBAAoB,WAAW,iBAAiB;AAAA,QAC3D,OAAO,EAAE,MAAM,IAAI,MAAM,KAAK,IAAI,KAAK,OAAO,IAAI,GAAG,QAAQ,IAAI,EAAA;AAAA,QAEjE,UAAA,qBAAC,QAAA,EAAK,WAAU,kBACb,UAAA;AAAA,UAAA,IAAI;AAAA,UACJ,IAAI,OAAO,qBAAC,QAAA,EAAK,WAAU,sBAAqB,UAAA;AAAA,YAAA;AAAA,YAAI,IAAI;AAAA,UAAA,EAAA,CAAK,IAAU;AAAA,QAAA,EAAA,CAC1E;AAAA,MAAA;AAAA,IAAA,IAEA;AAAA,IAEH,WACC,qBAAC,OAAA,EAAI,WAAU,kBAAiB,OAAO,SAAA,GAAY,SAAS,CAAC,MAAM,EAAE,mBACnE,UAAA;AAAA,MAAA,qBAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,QAAA,oBAAC,MAAA,EAAK,MAAK,UAAS,MAAM,IAAI;AAAA,QAC9B,qBAAC,QAAA,EAAK,WAAU,qBACb,UAAA;AAAA,UAAA,SAAS;AAAA,UACT,SAAS,OAAO,MAAM,SAAS,IAAI,KAAK;AAAA,QAAA,EAAA,CAC3C;AAAA,MAAA,GACF;AAAA,MACA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,WAAS;AAAA,UACT,OAAO;AAAA,UACP;AAAA,UACA,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,UACvC,WAAW,CAAC,MAAM;AAChB,gBAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACpC,gBAAE,eAAA;AACF,mBAAA;AAAA,YACF;AAAA,UACF;AAAA,QAAA;AAAA,MAAA;AAAA,MAEF,qBAAC,OAAA,EAAI,WAAU,sBACb,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,SAAS,MAAM;AACb,0BAAY,IAAI;AAChB,sBAAQ,EAAE;AAAA,YACZ;AAAA,YACD,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAGD;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,UAAU,CAAC,KAAK,KAAA;AAAA,YAChB,SAAS;AAAA,YACV,UAAA;AAAA,cAAA;AAAA,cAEC,oBAAC,MAAA,EAAK,MAAK,SAAQ,MAAM,GAAA,CAAI;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MAC/B,EAAA,CACF;AAAA,IAAA,EAAA,CACF,IACE;AAAA,IAEJ,qBAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,iBAAA,CAAiB;AAAA,0BAChC,QAAA,EAAK,WAAU,sBAAsB,UAAA,WAAW,aAAa,UAAS;AAAA,MACvE,oBAAC,QAAA,EAAK,WAAU,qBAAA,CAAqB;AAAA,MACrC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,MAAM,WAAW,QAAA;AAAA,UAC1B,cAAW;AAAA,UAEX,UAAA;AAAA,YAAA,oBAAC,MAAA,EAAK,MAAK,KAAI,MAAM,IAAI;AAAA,YACzB,oBAAC,UAAK,UAAA,KAAA,CAAE;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IACV,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapsible "how to get this credential" guide — auto-numbered steps and an
|
|
3
|
+
* optional external link. Built on the DS Collapsible. Steps accept rich nodes
|
|
4
|
+
* (e.g. <code> spans).
|
|
5
|
+
*/
|
|
6
|
+
export interface HelpStepsLink {
|
|
7
|
+
href: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
export interface HelpStepsProps {
|
|
11
|
+
/** Collapsible trigger label. */
|
|
12
|
+
title: string;
|
|
13
|
+
/** Ordered steps; each may be a string or rich node. */
|
|
14
|
+
steps: React.ReactNode[];
|
|
15
|
+
/** Optional external link rendered under the steps. */
|
|
16
|
+
link?: HelpStepsLink;
|
|
17
|
+
/** @default false */
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function HelpSteps(props: HelpStepsProps): JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Collapsible } from "../display/Collapsible.js";
|
|
4
|
+
import { Icon } from "../utilities/Icon.js";
|
|
5
|
+
const AX_HELPSTEPS_CSS = `
|
|
6
|
+
.s-help { margin-top: 2px; }
|
|
7
|
+
.s-help__list { margin: 4px 0 6px; padding: 0; list-style: none; counter-reset: step; display: flex; flex-direction: column; gap: 11px; }
|
|
8
|
+
.s-help__item { display: flex; gap: 11px; font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-snug); }
|
|
9
|
+
.s-help__num { counter-increment: step; flex: none; width: 19px; height: 19px; border-radius: var(--radius-1);
|
|
10
|
+
border: 1px solid var(--border-strong); font-family: var(--font-mono); font-size: 10px; color: var(--text-faint);
|
|
11
|
+
display: flex; align-items: center; justify-content: center; }
|
|
12
|
+
.s-help__num::before { content: counter(step); }
|
|
13
|
+
.s-help__item code { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body);
|
|
14
|
+
background: var(--surface-raised); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 1px 5px; }
|
|
15
|
+
.s-help__link { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); color: var(--text-body);
|
|
16
|
+
text-decoration: none; border-bottom: 1px solid var(--border-strong); padding-bottom: 1px; }
|
|
17
|
+
.s-help__link:hover { border-color: var(--text-body); }
|
|
18
|
+
`;
|
|
19
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-helpsteps-css")) {
|
|
20
|
+
const s = document.createElement("style");
|
|
21
|
+
s.id = "ax-helpsteps-css";
|
|
22
|
+
s.textContent = AX_HELPSTEPS_CSS;
|
|
23
|
+
document.head.appendChild(s);
|
|
24
|
+
}
|
|
25
|
+
function HelpSteps({ title, steps = [], link, defaultOpen = false }) {
|
|
26
|
+
return /* @__PURE__ */ jsx("div", { className: "s-help", children: /* @__PURE__ */ jsxs(Collapsible, { label: title, defaultOpen, children: [
|
|
27
|
+
/* @__PURE__ */ jsx("ol", { className: "s-help__list", children: steps.map((st, i) => /* @__PURE__ */ jsxs("li", { className: "s-help__item", children: [
|
|
28
|
+
/* @__PURE__ */ jsx("span", { className: "s-help__num" }),
|
|
29
|
+
/* @__PURE__ */ jsx("span", { children: st })
|
|
30
|
+
] }, i)) }),
|
|
31
|
+
link ? /* @__PURE__ */ jsxs("a", { className: "s-help__link", href: link.href, target: "_blank", rel: "noopener noreferrer", children: [
|
|
32
|
+
/* @__PURE__ */ jsx(Icon, { name: "external", size: 13 }),
|
|
33
|
+
link.label
|
|
34
|
+
] }) : null
|
|
35
|
+
] }) });
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
HelpSteps
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=HelpSteps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HelpSteps.js","sources":["../../../src/components/settings/HelpSteps.jsx"],"sourcesContent":["import React from \"react\";\nimport { Collapsible } from \"../display/Collapsible.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\n\n// HelpSteps — a collapsible \"如何获取…\" guide: numbered steps + an optional\n// external link. Built on the DS Collapsible. Steps may contain <code> spans.\nconst AX_HELPSTEPS_CSS = `\n.s-help { margin-top: 2px; }\n.s-help__list { margin: 4px 0 6px; padding: 0; list-style: none; counter-reset: step; display: flex; flex-direction: column; gap: 11px; }\n.s-help__item { display: flex; gap: 11px; font-size: var(--text-sm); color: var(--text-muted); line-height: var(--leading-snug); }\n.s-help__num { counter-increment: step; flex: none; width: 19px; height: 19px; border-radius: var(--radius-1);\n border: 1px solid var(--border-strong); font-family: var(--font-mono); font-size: 10px; color: var(--text-faint);\n display: flex; align-items: center; justify-content: center; }\n.s-help__num::before { content: counter(step); }\n.s-help__item code { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-body);\n background: var(--surface-raised); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 1px 5px; }\n.s-help__link { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-sm); color: var(--text-body);\n text-decoration: none; border-bottom: 1px solid var(--border-strong); padding-bottom: 1px; }\n.s-help__link:hover { border-color: var(--text-body); }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-helpsteps-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-helpsteps-css\";\n s.textContent = AX_HELPSTEPS_CSS;\n document.head.appendChild(s);\n}\n\nexport function HelpSteps({ title, steps = [], link, defaultOpen = false }) {\n return (\n <div className=\"s-help\">\n <Collapsible label={title} defaultOpen={defaultOpen}>\n <ol className=\"s-help__list\">\n {steps.map((st, i) => (\n <li className=\"s-help__item\" key={i}>\n <span className=\"s-help__num\"></span>\n <span>{st}</span>\n </li>\n ))}\n </ol>\n {link ? (\n <a className=\"s-help__link\" href={link.href} target=\"_blank\" rel=\"noopener noreferrer\">\n <Icon name=\"external\" size={13} />\n {link.label}\n </a>\n ) : null}\n </Collapsible>\n </div>\n );\n}\n"],"names":[],"mappings":";;;;AAMA,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAezB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,kBAAkB,GAAG;AACnF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,UAAU,EAAE,OAAO,QAAQ,CAAA,GAAI,MAAM,cAAc,SAAS;AAC1E,SACE,oBAAC,SAAI,WAAU,UACb,+BAAC,aAAA,EAAY,OAAO,OAAO,aACzB,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,gBACX,UAAA,MAAM,IAAI,CAAC,IAAI,MACd,qBAAC,MAAA,EAAG,WAAU,gBACZ,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,cAAA,CAAc;AAAA,MAC9B,oBAAC,UAAM,UAAA,GAAA,CAAG;AAAA,IAAA,KAFsB,CAGlC,CACD,GACH;AAAA,IACC,OACC,qBAAC,KAAA,EAAE,WAAU,gBAAe,MAAM,KAAK,MAAM,QAAO,UAAS,KAAI,uBAC/D,UAAA;AAAA,MAAA,oBAAC,MAAA,EAAK,MAAK,YAAW,MAAM,IAAI;AAAA,MAC/B,KAAK;AAAA,IAAA,EAAA,CACR,IACE;AAAA,EAAA,EAAA,CACN,EAAA,CACF;AAEJ;"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fullscreen integration modal: connect a DeepSeek key (conversation engine) and
|
|
3
|
+
* a Feishu Bitable (data sink). Self-persists to localStorage, reports a 0/2
|
|
4
|
+
* readiness state, and gates Save until both connect. Composes SecretField,
|
|
5
|
+
* StatusPill, TestRow, HelpSteps. The monthly usage-cap block is opt-in.
|
|
6
|
+
*/
|
|
7
|
+
export interface IntegrationSettingsProps {
|
|
8
|
+
/** Close handler (Esc + the × button + overlay). */
|
|
9
|
+
onClose?: () => void;
|
|
10
|
+
/** Show the DeepSeek monthly usage-cap warning + toggle. @default true */
|
|
11
|
+
showUsageCap?: boolean;
|
|
12
|
+
/** localStorage key for the persisted config. @default "agentaily.integrations.v1" */
|
|
13
|
+
storageKey?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function IntegrationSettings(props: IntegrationSettingsProps): JSX.Element;
|