@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,70 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Icon } from "../utilities/Icon.js";
|
|
4
|
+
const AX_SECRETFIELD_CSS = `
|
|
5
|
+
.s-field__label { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
|
|
6
|
+
.s-field__hint { font-size: var(--text-xs); color: var(--text-faint); margin: 6px 0 0; line-height: var(--leading-snug); }
|
|
7
|
+
.s-field__hint--err { color: var(--danger); }
|
|
8
|
+
.s-secret { position: relative; }
|
|
9
|
+
.s-secret .ax-input { padding-right: 42px; font-family: var(--font-mono); letter-spacing: 0.02em; }
|
|
10
|
+
.s-secret__eye { position: absolute; right: 6px; bottom: 6px; width: 24px; height: 24px; padding: 0;
|
|
11
|
+
display: flex; align-items: center; justify-content: center; border: none; background: none; cursor: pointer;
|
|
12
|
+
color: var(--text-faint); border-radius: var(--radius-1); transition: color var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out); }
|
|
13
|
+
.s-secret__eye:hover { color: var(--text-body); background: var(--surface-raised); }
|
|
14
|
+
`;
|
|
15
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-secretfield-css")) {
|
|
16
|
+
const s = document.createElement("style");
|
|
17
|
+
s.id = "ax-secretfield-css";
|
|
18
|
+
s.textContent = AX_SECRETFIELD_CSS;
|
|
19
|
+
document.head.appendChild(s);
|
|
20
|
+
}
|
|
21
|
+
function SecretField({
|
|
22
|
+
label,
|
|
23
|
+
value,
|
|
24
|
+
onChange,
|
|
25
|
+
placeholder,
|
|
26
|
+
hint,
|
|
27
|
+
error,
|
|
28
|
+
mono = true,
|
|
29
|
+
autoComplete = "off",
|
|
30
|
+
...rest
|
|
31
|
+
}) {
|
|
32
|
+
const [show, setShow] = useState(false);
|
|
33
|
+
const inputId = "secret-" + String(label || "").replace(/\s+/g, "-").toLowerCase();
|
|
34
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, children: [
|
|
35
|
+
label ? /* @__PURE__ */ jsx("label", { className: "s-field__label ax-label", htmlFor: inputId, children: label }) : null,
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "s-secret", children: [
|
|
37
|
+
/* @__PURE__ */ jsx(
|
|
38
|
+
"input",
|
|
39
|
+
{
|
|
40
|
+
id: inputId,
|
|
41
|
+
type: show ? "text" : "password",
|
|
42
|
+
className: "ax-input" + (mono ? " ax-input--mono" : "") + (error ? " ax-input--error" : ""),
|
|
43
|
+
value,
|
|
44
|
+
placeholder,
|
|
45
|
+
autoComplete,
|
|
46
|
+
spellCheck: "false",
|
|
47
|
+
onChange: (e) => onChange && onChange(e.target.value)
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"button",
|
|
52
|
+
{
|
|
53
|
+
type: "button",
|
|
54
|
+
className: "s-secret__eye",
|
|
55
|
+
onClick: () => setShow((v) => !v),
|
|
56
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
57
|
+
"aria-label": show ? "隐藏" : "显示",
|
|
58
|
+
title: show ? "隐藏" : "显示",
|
|
59
|
+
tabIndex: -1,
|
|
60
|
+
children: /* @__PURE__ */ jsx(Icon, { name: show ? "eyeOff" : "eye", size: 15 })
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
] }),
|
|
64
|
+
error ? /* @__PURE__ */ jsx("p", { className: "s-field__hint s-field__hint--err", children: error }) : hint ? /* @__PURE__ */ jsx("p", { className: "s-field__hint", children: hint }) : null
|
|
65
|
+
] });
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
SecretField
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=SecretField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecretField.js","sources":["../../../src/components/inputs/SecretField.jsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { Icon } from \"../utilities/Icon.jsx\";\n\n// SecretField — masked credential input with show/hide and an optional\n// \"never exposed\" hint line. Builds on the bundle's .ax-input. Owns the\n// shared field-level chrome (.s-secret / .s-field__label / .s-field__hint)\n// used across the settings surfaces.\nconst AX_SECRETFIELD_CSS = `\n.s-field__label { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }\n.s-field__hint { font-size: var(--text-xs); color: var(--text-faint); margin: 6px 0 0; line-height: var(--leading-snug); }\n.s-field__hint--err { color: var(--danger); }\n.s-secret { position: relative; }\n.s-secret .ax-input { padding-right: 42px; font-family: var(--font-mono); letter-spacing: 0.02em; }\n.s-secret__eye { position: absolute; right: 6px; bottom: 6px; width: 24px; height: 24px; padding: 0;\n display: flex; align-items: center; justify-content: center; border: none; background: none; cursor: pointer;\n color: var(--text-faint); border-radius: var(--radius-1); transition: color var(--dur-1) var(--ease-out), background var(--dur-1) var(--ease-out); }\n.s-secret__eye:hover { color: var(--text-body); background: var(--surface-raised); }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-secretfield-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-secretfield-css\";\n s.textContent = AX_SECRETFIELD_CSS;\n document.head.appendChild(s);\n}\n\nexport function SecretField({\n label,\n value,\n onChange,\n placeholder,\n hint,\n error,\n mono = true,\n autoComplete = \"off\",\n ...rest\n}) {\n const [show, setShow] = useState(false);\n const inputId =\n \"secret-\" +\n String(label || \"\")\n .replace(/\\s+/g, \"-\")\n .toLowerCase();\n return (\n <div {...rest}>\n {label ? (\n <label className=\"s-field__label ax-label\" htmlFor={inputId}>\n {label}\n </label>\n ) : null}\n <div className=\"s-secret\">\n <input\n id={inputId}\n type={show ? \"text\" : \"password\"}\n className={\n \"ax-input\" + (mono ? \" ax-input--mono\" : \"\") + (error ? \" ax-input--error\" : \"\")\n }\n value={value}\n placeholder={placeholder}\n autoComplete={autoComplete}\n spellCheck=\"false\"\n onChange={(e) => onChange && onChange(e.target.value)}\n />\n <button\n type=\"button\"\n className=\"s-secret__eye\"\n onClick={() => setShow((v) => !v)}\n onMouseDown={(e) => e.preventDefault()}\n aria-label={show ? \"隐藏\" : \"显示\"}\n title={show ? \"隐藏\" : \"显示\"}\n tabIndex={-1}\n >\n <Icon name={show ? \"eyeOff\" : \"eye\"} size={15} />\n </button>\n </div>\n {error ? (\n <p className=\"s-field__hint s-field__hint--err\">{error}</p>\n ) : hint ? (\n <p className=\"s-field__hint\">{hint}</p>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;AAOA,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAY3B,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,oBAAoB,GAAG;AACrF,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;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,eAAe;AAAA,EACf,GAAG;AACL,GAAG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,UACJ,YACA,OAAO,SAAS,EAAE,EACf,QAAQ,QAAQ,GAAG,EACnB,YAAA;AACL,SACE,qBAAC,OAAA,EAAK,GAAG,MACN,UAAA;AAAA,IAAA,4BACE,SAAA,EAAM,WAAU,2BAA0B,SAAS,SACjD,iBACH,IACE;AAAA,IACJ,qBAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,MAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,MAAM,OAAO,SAAS;AAAA,UACtB,WACE,cAAc,OAAO,oBAAoB,OAAO,QAAQ,qBAAqB;AAAA,UAE/E;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAW;AAAA,UACX,UAAU,CAAC,MAAM,YAAY,SAAS,EAAE,OAAO,KAAK;AAAA,QAAA;AAAA,MAAA;AAAA,MAEtD;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,UAChC,aAAa,CAAC,MAAM,EAAE,eAAA;AAAA,UACtB,cAAY,OAAO,OAAO;AAAA,UAC1B,OAAO,OAAO,OAAO;AAAA,UACrB,UAAU;AAAA,UAEV,8BAAC,MAAA,EAAK,MAAM,OAAO,WAAW,OAAO,MAAM,GAAA,CAAI;AAAA,QAAA;AAAA,MAAA;AAAA,IACjD,GACF;AAAA,IACC,QACC,oBAAC,KAAA,EAAE,WAAU,oCAAoC,UAAA,MAAA,CAAM,IACrD,OACF,oBAAC,KAAA,EAAE,WAAU,iBAAiB,gBAAK,IACjC;AAAA,EAAA,GACN;AAEJ;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The standard product frame: fixed sidebar (brand · nav · account) + main
|
|
3
|
+
* column (topbar · scrolling content). Every region is a slot. Nav is
|
|
4
|
+
* controlled via activeId/onNavigate, or self-manages if you omit them.
|
|
5
|
+
*/
|
|
6
|
+
export interface AppShellNavItem {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
/** Leading icon node (e.g. <Icon name="layout" size={16} />). */
|
|
10
|
+
icon?: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export interface AppShellProps {
|
|
13
|
+
/** Sidebar brand lockup. @default <BrandMark wordmark blink={false} /> */
|
|
14
|
+
brand?: React.ReactNode;
|
|
15
|
+
nav?: AppShellNavItem[];
|
|
16
|
+
/** Mono label above the nav. @default "Navigate" */
|
|
17
|
+
navLabel?: string;
|
|
18
|
+
/** Controlled active nav id; omit to let the shell manage it. */
|
|
19
|
+
activeId?: string;
|
|
20
|
+
onNavigate?: (id: string) => void;
|
|
21
|
+
/** Sidebar footer slot — typically <AccountControl /> or an account chip. */
|
|
22
|
+
account?: React.ReactNode;
|
|
23
|
+
/** Left side of the topbar (breadcrumb / title). */
|
|
24
|
+
crumb?: React.ReactNode;
|
|
25
|
+
/** Right side of the topbar (search, primary action, etc.). */
|
|
26
|
+
actions?: React.ReactNode;
|
|
27
|
+
/** Main content. */
|
|
28
|
+
children?: React.ReactNode;
|
|
29
|
+
}
|
|
30
|
+
export declare function AppShell(props: AppShellProps): JSX.Element;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import { BrandMark } from "../utilities/BrandMark.js";
|
|
4
|
+
import { Icon } from "../utilities/Icon.js";
|
|
5
|
+
const AX_APPSHELL_CSS = `
|
|
6
|
+
.ax-appshell { display: grid; grid-template-columns: 240px 1fr; height: 100%; background: var(--surface-page); overflow: hidden; }
|
|
7
|
+
.ax-appshell__sb { display: flex; flex-direction: column; background: var(--surface-panel); border-right: 1px solid var(--border-default); min-height: 0; }
|
|
8
|
+
.ax-appshell__brand { display: flex; align-items: center; gap: 9px; padding: 18px 18px 14px; }
|
|
9
|
+
.ax-appshell__group { padding: 10px 12px 4px; }
|
|
10
|
+
.ax-appshell__nav { display: flex; flex-direction: column; gap: 2px; padding: 0 10px; }
|
|
11
|
+
.ax-appshell__item { display: flex; align-items: center; gap: 11px; padding: 8px 10px; border-radius: var(--radius-2);
|
|
12
|
+
color: var(--text-muted); cursor: pointer; font-size: var(--text-sm); border: none; background: none; text-align: left;
|
|
13
|
+
font-family: inherit; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }
|
|
14
|
+
.ax-appshell__item:hover { background: var(--bg-3); color: var(--text-body); }
|
|
15
|
+
.ax-appshell__item[data-on="true"] { background: var(--accent); color: var(--accent-fg); }
|
|
16
|
+
.ax-appshell__foot { margin-top: auto; padding: 12px; border-top: 1px solid var(--border-default); }
|
|
17
|
+
.ax-appshell__main { display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
|
|
18
|
+
.ax-appshell__top { display: flex; align-items: center; gap: 12px; height: 56px; flex: none; padding: 0 22px; border-bottom: 1px solid var(--border-default); }
|
|
19
|
+
.ax-appshell__crumb { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }
|
|
20
|
+
.ax-appshell__crumb b { color: var(--text-body); font-weight: var(--weight-medium); }
|
|
21
|
+
.ax-appshell__sp { flex: 1; }
|
|
22
|
+
.ax-appshell__body { flex: 1; padding: 22px; overflow-y: auto; }
|
|
23
|
+
.ax-appshell__burger { display: none; }
|
|
24
|
+
.ax-appshell__scrim { display: none; }
|
|
25
|
+
@media (max-width: 860px) {
|
|
26
|
+
.ax-appshell { grid-template-columns: 1fr; }
|
|
27
|
+
.ax-appshell__sb { position: fixed; top: 0; left: 0; bottom: 0; width: 264px; z-index: 40;
|
|
28
|
+
transform: translateX(-100%); transition: transform var(--dur-2) var(--ease-out); box-shadow: var(--shadow-3); }
|
|
29
|
+
.ax-appshell__sb[data-open="true"] { transform: none; }
|
|
30
|
+
.ax-appshell__scrim { display: block; position: fixed; inset: 0; z-index: 39; background: var(--bg-overlay);
|
|
31
|
+
opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }
|
|
32
|
+
.ax-appshell__scrim[data-open="true"] { opacity: 1; pointer-events: auto; }
|
|
33
|
+
.ax-appshell__burger { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;
|
|
34
|
+
flex: none; margin-left: -6px; border: 1px solid var(--border-default); border-radius: var(--radius-2);
|
|
35
|
+
background: none; color: var(--text-muted); cursor: pointer; }
|
|
36
|
+
.ax-appshell__burger:hover { color: var(--text-body); border-color: var(--border-strong); }
|
|
37
|
+
.ax-appshell__top { padding: 0 16px; }
|
|
38
|
+
.ax-appshell__body { padding: 18px 16px; }
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-appshell-css")) {
|
|
42
|
+
const s = document.createElement("style");
|
|
43
|
+
s.id = "ax-appshell-css";
|
|
44
|
+
s.textContent = AX_APPSHELL_CSS;
|
|
45
|
+
document.head.appendChild(s);
|
|
46
|
+
}
|
|
47
|
+
function AppShell({
|
|
48
|
+
brand,
|
|
49
|
+
nav = [],
|
|
50
|
+
navLabel = "Navigate",
|
|
51
|
+
activeId,
|
|
52
|
+
onNavigate,
|
|
53
|
+
account,
|
|
54
|
+
crumb,
|
|
55
|
+
actions,
|
|
56
|
+
children
|
|
57
|
+
}) {
|
|
58
|
+
const [internal, setInternal] = useState(nav[0] && nav[0].id);
|
|
59
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
60
|
+
const active = activeId !== void 0 ? activeId : internal;
|
|
61
|
+
const go = (id) => {
|
|
62
|
+
if (onNavigate) onNavigate(id);
|
|
63
|
+
else setInternal(id);
|
|
64
|
+
setMenuOpen(false);
|
|
65
|
+
};
|
|
66
|
+
return /* @__PURE__ */ jsxs("div", { className: "ax-appshell", children: [
|
|
67
|
+
/* @__PURE__ */ jsx(
|
|
68
|
+
"div",
|
|
69
|
+
{
|
|
70
|
+
className: "ax-appshell__scrim",
|
|
71
|
+
"data-open": menuOpen,
|
|
72
|
+
onClick: () => setMenuOpen(false)
|
|
73
|
+
}
|
|
74
|
+
),
|
|
75
|
+
/* @__PURE__ */ jsxs("aside", { className: "ax-appshell__sb", "data-open": menuOpen, children: [
|
|
76
|
+
/* @__PURE__ */ jsx("div", { className: "ax-appshell__brand", children: brand || /* @__PURE__ */ jsx(BrandMark, { size: 20, wordmark: true, blink: false }) }),
|
|
77
|
+
nav.length ? /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
78
|
+
/* @__PURE__ */ jsx("div", { className: "ax-appshell__group", children: /* @__PURE__ */ jsx("span", { className: "ax-label", children: navLabel }) }),
|
|
79
|
+
/* @__PURE__ */ jsx("nav", { className: "ax-appshell__nav", children: nav.map((n) => /* @__PURE__ */ jsxs(
|
|
80
|
+
"button",
|
|
81
|
+
{
|
|
82
|
+
className: "ax-appshell__item",
|
|
83
|
+
"data-on": active === n.id,
|
|
84
|
+
onClick: () => go(n.id),
|
|
85
|
+
children: [
|
|
86
|
+
n.icon || null,
|
|
87
|
+
n.label
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
n.id
|
|
91
|
+
)) })
|
|
92
|
+
] }) : null,
|
|
93
|
+
account ? /* @__PURE__ */ jsx("div", { className: "ax-appshell__foot", children: account }) : null
|
|
94
|
+
] }),
|
|
95
|
+
/* @__PURE__ */ jsxs("main", { className: "ax-appshell__main", children: [
|
|
96
|
+
/* @__PURE__ */ jsxs("header", { className: "ax-appshell__top", children: [
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
"button",
|
|
99
|
+
{
|
|
100
|
+
className: "ax-appshell__burger",
|
|
101
|
+
"aria-label": "Menu",
|
|
102
|
+
onClick: () => setMenuOpen(true),
|
|
103
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "menu", size: 17 })
|
|
104
|
+
}
|
|
105
|
+
),
|
|
106
|
+
crumb ? /* @__PURE__ */ jsx("span", { className: "ax-appshell__crumb", children: crumb }) : null,
|
|
107
|
+
/* @__PURE__ */ jsx("span", { className: "ax-appshell__sp" }),
|
|
108
|
+
actions
|
|
109
|
+
] }),
|
|
110
|
+
/* @__PURE__ */ jsx("div", { className: "ax-appshell__body", children })
|
|
111
|
+
] })
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
export {
|
|
115
|
+
AppShell
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=AppShell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppShell.js","sources":["../../../src/components/layout/AppShell.jsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { BrandMark } from \"../utilities/BrandMark.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\n\n// AppShell — the standard product frame: fixed sidebar (brand · nav · account)\n// + main column (topbar · content). All regions are slots; nav can be\n// controlled or self-managed. Content goes in `children`.\nconst AX_APPSHELL_CSS = `\n.ax-appshell { display: grid; grid-template-columns: 240px 1fr; height: 100%; background: var(--surface-page); overflow: hidden; }\n.ax-appshell__sb { display: flex; flex-direction: column; background: var(--surface-panel); border-right: 1px solid var(--border-default); min-height: 0; }\n.ax-appshell__brand { display: flex; align-items: center; gap: 9px; padding: 18px 18px 14px; }\n.ax-appshell__group { padding: 10px 12px 4px; }\n.ax-appshell__nav { display: flex; flex-direction: column; gap: 2px; padding: 0 10px; }\n.ax-appshell__item { display: flex; align-items: center; gap: 11px; padding: 8px 10px; border-radius: var(--radius-2);\n color: var(--text-muted); cursor: pointer; font-size: var(--text-sm); border: none; background: none; text-align: left;\n font-family: inherit; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }\n.ax-appshell__item:hover { background: var(--bg-3); color: var(--text-body); }\n.ax-appshell__item[data-on=\"true\"] { background: var(--accent); color: var(--accent-fg); }\n.ax-appshell__foot { margin-top: auto; padding: 12px; border-top: 1px solid var(--border-default); }\n.ax-appshell__main { display: flex; flex-direction: column; overflow: hidden; min-width: 0; }\n.ax-appshell__top { display: flex; align-items: center; gap: 12px; height: 56px; flex: none; padding: 0 22px; border-bottom: 1px solid var(--border-default); }\n.ax-appshell__crumb { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }\n.ax-appshell__crumb b { color: var(--text-body); font-weight: var(--weight-medium); }\n.ax-appshell__sp { flex: 1; }\n.ax-appshell__body { flex: 1; padding: 22px; overflow-y: auto; }\n.ax-appshell__burger { display: none; }\n.ax-appshell__scrim { display: none; }\n@media (max-width: 860px) {\n .ax-appshell { grid-template-columns: 1fr; }\n .ax-appshell__sb { position: fixed; top: 0; left: 0; bottom: 0; width: 264px; z-index: 40;\n transform: translateX(-100%); transition: transform var(--dur-2) var(--ease-out); box-shadow: var(--shadow-3); }\n .ax-appshell__sb[data-open=\"true\"] { transform: none; }\n .ax-appshell__scrim { display: block; position: fixed; inset: 0; z-index: 39; background: var(--bg-overlay);\n opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }\n .ax-appshell__scrim[data-open=\"true\"] { opacity: 1; pointer-events: auto; }\n .ax-appshell__burger { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;\n flex: none; margin-left: -6px; border: 1px solid var(--border-default); border-radius: var(--radius-2);\n background: none; color: var(--text-muted); cursor: pointer; }\n .ax-appshell__burger:hover { color: var(--text-body); border-color: var(--border-strong); }\n .ax-appshell__top { padding: 0 16px; }\n .ax-appshell__body { padding: 18px 16px; }\n}\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-appshell-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-appshell-css\";\n s.textContent = AX_APPSHELL_CSS;\n document.head.appendChild(s);\n}\n\nexport function AppShell({\n brand,\n nav = [],\n navLabel = \"Navigate\",\n activeId,\n onNavigate,\n account,\n crumb,\n actions,\n children,\n}) {\n const [internal, setInternal] = useState(nav[0] && nav[0].id);\n const [menuOpen, setMenuOpen] = useState(false);\n const active = activeId !== undefined ? activeId : internal;\n const go = (id) => {\n if (onNavigate) onNavigate(id);\n else setInternal(id);\n setMenuOpen(false);\n };\n\n return (\n <div className=\"ax-appshell\">\n <div\n className=\"ax-appshell__scrim\"\n data-open={menuOpen}\n onClick={() => setMenuOpen(false)}\n ></div>\n <aside className=\"ax-appshell__sb\" data-open={menuOpen}>\n <div className=\"ax-appshell__brand\">\n {brand || <BrandMark size={20} wordmark blink={false} />}\n </div>\n {nav.length ? (\n <React.Fragment>\n <div className=\"ax-appshell__group\">\n <span className=\"ax-label\">{navLabel}</span>\n </div>\n <nav className=\"ax-appshell__nav\">\n {nav.map((n) => (\n <button\n key={n.id}\n className=\"ax-appshell__item\"\n data-on={active === n.id}\n onClick={() => go(n.id)}\n >\n {n.icon || null}\n {n.label}\n </button>\n ))}\n </nav>\n </React.Fragment>\n ) : null}\n {account ? <div className=\"ax-appshell__foot\">{account}</div> : null}\n </aside>\n\n <main className=\"ax-appshell__main\">\n <header className=\"ax-appshell__top\">\n <button\n className=\"ax-appshell__burger\"\n aria-label=\"Menu\"\n onClick={() => setMenuOpen(true)}\n >\n <Icon name=\"menu\" size={17} />\n </button>\n {crumb ? <span className=\"ax-appshell__crumb\">{crumb}</span> : null}\n <span className=\"ax-appshell__sp\"></span>\n {actions}\n </header>\n <div className=\"ax-appshell__body\">{children}</div>\n </main>\n </div>\n );\n}\n"],"names":[],"mappings":";;;;AAOA,MAAM,kBAAkB;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;AAqCxB,IAAI,OAAO,aAAa,eAAe,CAAC,SAAS,eAAe,iBAAiB,GAAG;AAClF,QAAM,IAAI,SAAS,cAAc,OAAO;AACxC,IAAE,KAAK;AACP,IAAE,cAAc;AAChB,WAAS,KAAK,YAAY,CAAC;AAC7B;AAEO,SAAS,SAAS;AAAA,EACvB;AAAA,EACA,MAAM,CAAA;AAAA,EACN,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAG;AACD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,EAAE;AAC5D,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,SAAS,aAAa,SAAY,WAAW;AACnD,QAAM,KAAK,CAAC,OAAO;AACjB,QAAI,uBAAuB,EAAE;AAAA,qBACZ,EAAE;AACnB,gBAAY,KAAK;AAAA,EACnB;AAEA,SACE,qBAAC,OAAA,EAAI,WAAU,eACb,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,aAAW;AAAA,QACX,SAAS,MAAM,YAAY,KAAK;AAAA,MAAA;AAAA,IAAA;AAAA,IAElC,qBAAC,SAAA,EAAM,WAAU,mBAAkB,aAAW,UAC5C,UAAA;AAAA,MAAA,oBAAC,OAAA,EAAI,WAAU,sBACZ,UAAA,SAAS,oBAAC,WAAA,EAAU,MAAM,IAAI,UAAQ,MAAC,OAAO,MAAA,CAAO,GACxD;AAAA,MACC,IAAI,SACH,qBAAC,MAAM,UAAN,EACC,UAAA;AAAA,QAAA,oBAAC,OAAA,EAAI,WAAU,sBACb,UAAA,oBAAC,UAAK,WAAU,YAAY,oBAAS,EAAA,CACvC;AAAA,4BACC,OAAA,EAAI,WAAU,oBACZ,UAAA,IAAI,IAAI,CAAC,MACR;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,WAAU;AAAA,YACV,WAAS,WAAW,EAAE;AAAA,YACtB,SAAS,MAAM,GAAG,EAAE,EAAE;AAAA,YAErB,UAAA;AAAA,cAAA,EAAE,QAAQ;AAAA,cACV,EAAE;AAAA,YAAA;AAAA,UAAA;AAAA,UANE,EAAE;AAAA,QAAA,CAQV,EAAA,CACH;AAAA,MAAA,EAAA,CACF,IACE;AAAA,MACH,UAAU,oBAAC,OAAA,EAAI,WAAU,qBAAqB,mBAAQ,IAAS;AAAA,IAAA,GAClE;AAAA,IAEA,qBAAC,QAAA,EAAK,WAAU,qBACd,UAAA;AAAA,MAAA,qBAAC,UAAA,EAAO,WAAU,oBAChB,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,cAAW;AAAA,YACX,SAAS,MAAM,YAAY,IAAI;AAAA,YAE/B,UAAA,oBAAC,MAAA,EAAK,MAAK,QAAO,MAAM,GAAA,CAAI;AAAA,UAAA;AAAA,QAAA;AAAA,QAE7B,QAAQ,oBAAC,QAAA,EAAK,WAAU,sBAAsB,iBAAM,IAAU;AAAA,QAC/D,oBAAC,QAAA,EAAK,WAAU,kBAAA,CAAkB;AAAA,QACjC;AAAA,MAAA,GACH;AAAA,MACA,oBAAC,OAAA,EAAI,WAAU,qBAAqB,SAAA,CAAS;AAAA,IAAA,EAAA,CAC/C;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-pane AI-designer frame: a chat column + a live preview, separated by a
|
|
3
|
+
* draggable divider, collapsing to one pane with a segmented switcher on phones.
|
|
4
|
+
* Pure frame — pass `chat` / `preview` / top-bar slots and mount your own
|
|
5
|
+
* overlays (AuthDialog, IntegrationSettings, MarkupLayer) as siblings. The
|
|
6
|
+
* preview pane is position:relative so a MarkupLayer can fill it.
|
|
7
|
+
*/
|
|
8
|
+
export interface DesignerShellProps {
|
|
9
|
+
/** Top-bar brand lockup. @default <BrandMark wordmark blink={false} /> */
|
|
10
|
+
brand?: React.ReactNode;
|
|
11
|
+
/** Breadcrumb after the brand. @default "设计器" */
|
|
12
|
+
crumb?: React.ReactNode;
|
|
13
|
+
/** Centered top-bar title slot. */
|
|
14
|
+
title?: React.ReactNode;
|
|
15
|
+
/** Top-bar actions (before the account control). */
|
|
16
|
+
actions?: React.ReactNode;
|
|
17
|
+
/** Account control, pinned to the far right (auto-separated from actions). */
|
|
18
|
+
account?: React.ReactNode;
|
|
19
|
+
/** Left pane content (thread + composer). */
|
|
20
|
+
chat?: React.ReactNode;
|
|
21
|
+
/** Right pane content (preview); the pane is position:relative. */
|
|
22
|
+
preview?: React.ReactNode;
|
|
23
|
+
/** Controlled chat-pane width fraction (0–1). Omit for uncontrolled (uses defaultSplit). */
|
|
24
|
+
split?: number;
|
|
25
|
+
/** Fires with the new fraction on divider drag — wire to a slider/Tweak so drag writes back. */
|
|
26
|
+
onSplitChange?: (fraction: number) => void;
|
|
27
|
+
/** Initial chat-pane width fraction when uncontrolled. @default 0.42 */
|
|
28
|
+
defaultSplit?: number;
|
|
29
|
+
/** Min/max chat-pane fraction while dragging. @default 0.28 / 0.7 */
|
|
30
|
+
minSplit?: number;
|
|
31
|
+
maxSplit?: number;
|
|
32
|
+
/** Phone segmented-switcher labels — any node (icon + count badge ok; use class `ax-dshell__mcount` for a count). @default { chat: "对话", preview: "预览" } */
|
|
33
|
+
mobileLabels?: { chat: React.ReactNode; preview: React.ReactNode };
|
|
34
|
+
/** Controlled phone pane: "chat" | "preview". Omit for uncontrolled (starts on chat). */
|
|
35
|
+
mobileView?: "chat" | "preview";
|
|
36
|
+
/** Fires when the phone switcher changes — set it to auto-jump to preview after generating. */
|
|
37
|
+
onMobileViewChange?: (view: "chat" | "preview") => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function DesignerShell(props: DesignerShellProps): JSX.Element;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
3
|
+
import { BrandMark } from "../utilities/BrandMark.js";
|
|
4
|
+
const AX_DESIGNERSHELL_CSS = `
|
|
5
|
+
.ax-dshell { display: flex; flex-direction: column; height: 100%; background: var(--surface-page); }
|
|
6
|
+
.ax-dshell__top { display: flex; align-items: center; gap: 16px; height: var(--topbar-h); flex: none; padding: 0 16px; border-bottom: 1px solid var(--border-default); background: var(--surface-panel); }
|
|
7
|
+
/* helper: use on a pane's sub-header (e.g. the preview tabs bar) so both panes' bars share --bar-h and line up */
|
|
8
|
+
.ax-dshell__panebar { display: flex; align-items: center; gap: 12px; height: var(--bar-h); flex: none; padding: 0 16px; border-bottom: 1px solid var(--border-default); background: var(--surface-panel); }
|
|
9
|
+
.ax-dshell__div { color: var(--text-faint); }
|
|
10
|
+
.ax-dshell__crumb { font-family: var(--font-mono); font-size: 13px; color: var(--text-muted); }
|
|
11
|
+
.ax-dshell__title { flex: 1; display: flex; align-items: center; gap: 10px; justify-content: center; }
|
|
12
|
+
.ax-dshell__actions { display: flex; align-items: center; gap: 8px; }
|
|
13
|
+
.ax-dshell__sep { width: 1px; height: 20px; background: var(--border-default); margin: 0 2px; flex: none; }
|
|
14
|
+
.ax-dshell__split { flex: 1; display: flex; min-height: 0; }
|
|
15
|
+
.ax-dshell__pane { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
|
|
16
|
+
.ax-dshell__pane--preview { flex: 1; position: relative; }
|
|
17
|
+
.ax-dshell__divider { width: 9px; flex: none; cursor: col-resize; display: flex; align-items: center; justify-content: center;
|
|
18
|
+
background: var(--surface-page); border-left: 1px solid var(--border-default); border-right: 1px solid var(--border-default); }
|
|
19
|
+
.ax-dshell__grip { width: 2px; height: 26px; border-radius: 2px; background: var(--border-strong); transition: background var(--dur-1) var(--ease-out); }
|
|
20
|
+
.ax-dshell__divider:hover .ax-dshell__grip { background: var(--text-faint); }
|
|
21
|
+
.ax-dshell__mbar { display: none; }
|
|
22
|
+
@media (max-width: 720px) {
|
|
23
|
+
.ax-dshell__split { flex-direction: column; }
|
|
24
|
+
.ax-dshell__divider { display: none; }
|
|
25
|
+
.ax-dshell__pane { width: 100% !important; flex: 1; }
|
|
26
|
+
.ax-dshell__split[data-mview="chat"] .ax-dshell__pane--preview { display: none; }
|
|
27
|
+
.ax-dshell__split[data-mview="preview"] .ax-dshell__pane--chat { display: none; }
|
|
28
|
+
.ax-dshell__div, .ax-dshell__crumb { display: none; }
|
|
29
|
+
.ax-dshell__mbar { display: flex; flex: none; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--border-default); background: var(--surface-panel); }
|
|
30
|
+
.ax-dshell__mseg { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px; height: 38px; border: 1px solid var(--border-default);
|
|
31
|
+
background: var(--surface-page); border-radius: var(--radius-2); font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-muted); cursor: pointer; }
|
|
32
|
+
.ax-dshell__mseg.is-on { background: var(--surface-card); border-color: var(--border-strong); color: var(--text-body); }
|
|
33
|
+
.ax-dshell__mcount { font-family: var(--font-mono); font-size: 11px; line-height: 16px; color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 0 5px; }
|
|
34
|
+
.ax-dshell__mseg.is-on .ax-dshell__mcount { color: var(--text-muted); }
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-dshell-css")) {
|
|
38
|
+
const s = document.createElement("style");
|
|
39
|
+
s.id = "ax-dshell-css";
|
|
40
|
+
s.textContent = AX_DESIGNERSHELL_CSS;
|
|
41
|
+
document.head.appendChild(s);
|
|
42
|
+
}
|
|
43
|
+
function DesignerShell({
|
|
44
|
+
brand,
|
|
45
|
+
crumb = "设计器",
|
|
46
|
+
title,
|
|
47
|
+
actions,
|
|
48
|
+
account,
|
|
49
|
+
chat,
|
|
50
|
+
preview,
|
|
51
|
+
split,
|
|
52
|
+
onSplitChange,
|
|
53
|
+
defaultSplit = 0.42,
|
|
54
|
+
minSplit = 0.28,
|
|
55
|
+
maxSplit = 0.7,
|
|
56
|
+
mobileLabels = { chat: "对话", preview: "预览" },
|
|
57
|
+
mobileView,
|
|
58
|
+
onMobileViewChange
|
|
59
|
+
}) {
|
|
60
|
+
const controlled = split !== void 0;
|
|
61
|
+
const [internalW, setInternalW] = useState(defaultSplit);
|
|
62
|
+
const leftW = controlled ? split : internalW;
|
|
63
|
+
const [internalMV, setInternalMV] = useState("chat");
|
|
64
|
+
const mview = mobileView !== void 0 ? mobileView : internalMV;
|
|
65
|
+
const setView = (v) => {
|
|
66
|
+
if (onMobileViewChange) onMobileViewChange(v);
|
|
67
|
+
if (mobileView === void 0) setInternalMV(v);
|
|
68
|
+
};
|
|
69
|
+
const dragging = useRef(false);
|
|
70
|
+
const splitRef = useRef(null);
|
|
71
|
+
const applyRef = useRef(null);
|
|
72
|
+
applyRef.current = (f) => {
|
|
73
|
+
const v = Math.min(maxSplit, Math.max(minSplit, f));
|
|
74
|
+
if (onSplitChange) onSplitChange(v);
|
|
75
|
+
if (!controlled) setInternalW(v);
|
|
76
|
+
};
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const move = (e) => {
|
|
79
|
+
if (!dragging.current || !splitRef.current) return;
|
|
80
|
+
const r = splitRef.current.getBoundingClientRect();
|
|
81
|
+
applyRef.current((e.clientX - r.left) / r.width);
|
|
82
|
+
};
|
|
83
|
+
const up = () => {
|
|
84
|
+
dragging.current = false;
|
|
85
|
+
document.body.style.cursor = "";
|
|
86
|
+
};
|
|
87
|
+
window.addEventListener("mousemove", move);
|
|
88
|
+
window.addEventListener("mouseup", up);
|
|
89
|
+
return () => {
|
|
90
|
+
window.removeEventListener("mousemove", move);
|
|
91
|
+
window.removeEventListener("mouseup", up);
|
|
92
|
+
};
|
|
93
|
+
}, []);
|
|
94
|
+
return /* @__PURE__ */ jsxs("div", { className: "ax-dshell", children: [
|
|
95
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-dshell__top", children: [
|
|
96
|
+
brand || /* @__PURE__ */ jsx(BrandMark, { size: 18, wordmark: true, blink: false }),
|
|
97
|
+
crumb ? /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
98
|
+
/* @__PURE__ */ jsx("span", { className: "ax-dshell__div", children: "/" }),
|
|
99
|
+
/* @__PURE__ */ jsx("span", { className: "ax-dshell__crumb", children: crumb })
|
|
100
|
+
] }) : null,
|
|
101
|
+
/* @__PURE__ */ jsx("div", { className: "ax-dshell__title", children: title }),
|
|
102
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-dshell__actions", children: [
|
|
103
|
+
actions,
|
|
104
|
+
actions && account ? /* @__PURE__ */ jsx("span", { className: "ax-dshell__sep" }) : null,
|
|
105
|
+
account
|
|
106
|
+
] })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-dshell__mbar", children: [
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
110
|
+
"button",
|
|
111
|
+
{
|
|
112
|
+
className: "ax-dshell__mseg" + (mview === "chat" ? " is-on" : ""),
|
|
113
|
+
onClick: () => setView("chat"),
|
|
114
|
+
children: mobileLabels.chat
|
|
115
|
+
}
|
|
116
|
+
),
|
|
117
|
+
/* @__PURE__ */ jsx(
|
|
118
|
+
"button",
|
|
119
|
+
{
|
|
120
|
+
className: "ax-dshell__mseg" + (mview === "preview" ? " is-on" : ""),
|
|
121
|
+
onClick: () => setView("preview"),
|
|
122
|
+
children: mobileLabels.preview
|
|
123
|
+
}
|
|
124
|
+
)
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsxs("div", { className: "ax-dshell__split", ref: splitRef, "data-mview": mview, children: [
|
|
127
|
+
/* @__PURE__ */ jsx("div", { className: "ax-dshell__pane ax-dshell__pane--chat", style: { width: leftW * 100 + "%" }, children: chat }),
|
|
128
|
+
/* @__PURE__ */ jsx(
|
|
129
|
+
"div",
|
|
130
|
+
{
|
|
131
|
+
className: "ax-dshell__divider",
|
|
132
|
+
onMouseDown: () => {
|
|
133
|
+
dragging.current = true;
|
|
134
|
+
document.body.style.cursor = "col-resize";
|
|
135
|
+
},
|
|
136
|
+
children: /* @__PURE__ */ jsx("span", { className: "ax-dshell__grip" })
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ jsx("div", { className: "ax-dshell__pane ax-dshell__pane--preview", children: preview })
|
|
140
|
+
] })
|
|
141
|
+
] });
|
|
142
|
+
}
|
|
143
|
+
export {
|
|
144
|
+
DesignerShell
|
|
145
|
+
};
|
|
146
|
+
//# sourceMappingURL=DesignerShell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DesignerShell.js","sources":["../../../src/components/layout/DesignerShell.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { BrandMark } from \"../utilities/BrandMark.jsx\";\n\n// DesignerShell — the two-pane \"AI designer\" frame: a chat column on the left\n// and a live preview on the right, separated by a draggable divider, collapsing\n// to a single pane with a segmented switcher on phones. Pure frame: pass `chat`\n// and `preview` nodes plus top-bar slots; mount your own overlays (AuthDialog,\n// IntegrationSettings, MarkupLayer) as siblings.\nconst AX_DESIGNERSHELL_CSS = `\n.ax-dshell { display: flex; flex-direction: column; height: 100%; background: var(--surface-page); }\n.ax-dshell__top { display: flex; align-items: center; gap: 16px; height: var(--topbar-h); flex: none; padding: 0 16px; border-bottom: 1px solid var(--border-default); background: var(--surface-panel); }\n/* helper: use on a pane's sub-header (e.g. the preview tabs bar) so both panes' bars share --bar-h and line up */\n.ax-dshell__panebar { display: flex; align-items: center; gap: 12px; height: var(--bar-h); flex: none; padding: 0 16px; border-bottom: 1px solid var(--border-default); background: var(--surface-panel); }\n.ax-dshell__div { color: var(--text-faint); }\n.ax-dshell__crumb { font-family: var(--font-mono); font-size: 13px; color: var(--text-muted); }\n.ax-dshell__title { flex: 1; display: flex; align-items: center; gap: 10px; justify-content: center; }\n.ax-dshell__actions { display: flex; align-items: center; gap: 8px; }\n.ax-dshell__sep { width: 1px; height: 20px; background: var(--border-default); margin: 0 2px; flex: none; }\n.ax-dshell__split { flex: 1; display: flex; min-height: 0; }\n.ax-dshell__pane { display: flex; flex-direction: column; min-width: 0; min-height: 0; }\n.ax-dshell__pane--preview { flex: 1; position: relative; }\n.ax-dshell__divider { width: 9px; flex: none; cursor: col-resize; display: flex; align-items: center; justify-content: center;\n background: var(--surface-page); border-left: 1px solid var(--border-default); border-right: 1px solid var(--border-default); }\n.ax-dshell__grip { width: 2px; height: 26px; border-radius: 2px; background: var(--border-strong); transition: background var(--dur-1) var(--ease-out); }\n.ax-dshell__divider:hover .ax-dshell__grip { background: var(--text-faint); }\n.ax-dshell__mbar { display: none; }\n@media (max-width: 720px) {\n .ax-dshell__split { flex-direction: column; }\n .ax-dshell__divider { display: none; }\n .ax-dshell__pane { width: 100% !important; flex: 1; }\n .ax-dshell__split[data-mview=\"chat\"] .ax-dshell__pane--preview { display: none; }\n .ax-dshell__split[data-mview=\"preview\"] .ax-dshell__pane--chat { display: none; }\n .ax-dshell__div, .ax-dshell__crumb { display: none; }\n .ax-dshell__mbar { display: flex; flex: none; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--border-default); background: var(--surface-panel); }\n .ax-dshell__mseg { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px; height: 38px; border: 1px solid var(--border-default);\n background: var(--surface-page); border-radius: var(--radius-2); font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-muted); cursor: pointer; }\n .ax-dshell__mseg.is-on { background: var(--surface-card); border-color: var(--border-strong); color: var(--text-body); }\n .ax-dshell__mcount { font-family: var(--font-mono); font-size: 11px; line-height: 16px; color: var(--text-faint); border: 1px solid var(--border-default); border-radius: var(--radius-1); padding: 0 5px; }\n .ax-dshell__mseg.is-on .ax-dshell__mcount { color: var(--text-muted); }\n}\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-dshell-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-dshell-css\";\n s.textContent = AX_DESIGNERSHELL_CSS;\n document.head.appendChild(s);\n}\n\nexport function DesignerShell({\n brand,\n crumb = \"设计器\",\n title,\n actions,\n account,\n chat,\n preview,\n split,\n onSplitChange,\n defaultSplit = 0.42,\n minSplit = 0.28,\n maxSplit = 0.7,\n mobileLabels = { chat: \"对话\", preview: \"预览\" },\n mobileView,\n onMobileViewChange,\n}) {\n const controlled = split !== undefined;\n const [internalW, setInternalW] = useState(defaultSplit);\n const leftW = controlled ? split : internalW;\n const [internalMV, setInternalMV] = useState(\"chat\");\n const mview = mobileView !== undefined ? mobileView : internalMV;\n const setView = (v) => {\n if (onMobileViewChange) onMobileViewChange(v);\n if (mobileView === undefined) setInternalMV(v);\n };\n const dragging = useRef(false);\n const splitRef = useRef(null);\n\n // latest applier (clamp + write back, controlled or internal), kept in a ref so\n // the window drag listeners always see current props without re-binding.\n const applyRef = useRef(null);\n applyRef.current = (f) => {\n const v = Math.min(maxSplit, Math.max(minSplit, f));\n if (onSplitChange) onSplitChange(v); // drag writes back to a controlled value (e.g. a slider)\n if (!controlled) setInternalW(v);\n };\n\n useEffect(() => {\n const move = (e) => {\n if (!dragging.current || !splitRef.current) return;\n const r = splitRef.current.getBoundingClientRect();\n applyRef.current((e.clientX - r.left) / r.width);\n };\n const up = () => {\n dragging.current = false;\n document.body.style.cursor = \"\";\n };\n window.addEventListener(\"mousemove\", move);\n window.addEventListener(\"mouseup\", up);\n return () => {\n window.removeEventListener(\"mousemove\", move);\n window.removeEventListener(\"mouseup\", up);\n };\n }, []);\n\n return (\n <div className=\"ax-dshell\">\n <div className=\"ax-dshell__top\">\n {brand || <BrandMark size={18} wordmark blink={false} />}\n {crumb ? (\n <React.Fragment>\n <span className=\"ax-dshell__div\">/</span>\n <span className=\"ax-dshell__crumb\">{crumb}</span>\n </React.Fragment>\n ) : null}\n <div className=\"ax-dshell__title\">{title}</div>\n <div className=\"ax-dshell__actions\">\n {actions}\n {actions && account ? <span className=\"ax-dshell__sep\"></span> : null}\n {account}\n </div>\n </div>\n\n <div className=\"ax-dshell__mbar\">\n <button\n className={\"ax-dshell__mseg\" + (mview === \"chat\" ? \" is-on\" : \"\")}\n onClick={() => setView(\"chat\")}\n >\n {mobileLabels.chat}\n </button>\n <button\n className={\"ax-dshell__mseg\" + (mview === \"preview\" ? \" is-on\" : \"\")}\n onClick={() => setView(\"preview\")}\n >\n {mobileLabels.preview}\n </button>\n </div>\n\n <div className=\"ax-dshell__split\" ref={splitRef} data-mview={mview}>\n <div className=\"ax-dshell__pane ax-dshell__pane--chat\" style={{ width: leftW * 100 + \"%\" }}>\n {chat}\n </div>\n <div\n className=\"ax-dshell__divider\"\n onMouseDown={() => {\n dragging.current = true;\n document.body.style.cursor = \"col-resize\";\n }}\n >\n <span className=\"ax-dshell__grip\"></span>\n </div>\n <div className=\"ax-dshell__pane ax-dshell__pane--preview\">{preview}</div>\n </div>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-pane documentation frame: left section nav, centered article, right
|
|
3
|
+
* on-this-page TOC. The article is `children`; nav + TOC are data-driven and
|
|
4
|
+
* controlled (via active/on props) or self-managed. Collapses to two panes < 1080px.
|
|
5
|
+
*/
|
|
6
|
+
export interface DocsSection {
|
|
7
|
+
title: string;
|
|
8
|
+
items: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface DocsLayoutProps {
|
|
11
|
+
/** Nav brand lockup. @default <BrandMark wordmark blink={false} /> */
|
|
12
|
+
brand?: React.ReactNode;
|
|
13
|
+
sections?: DocsSection[];
|
|
14
|
+
activeItem?: string;
|
|
15
|
+
onNavigate?: (item: string) => void;
|
|
16
|
+
toc?: string[];
|
|
17
|
+
activeToc?: string;
|
|
18
|
+
onTocChange?: (item: string) => void;
|
|
19
|
+
/** @default "On this page" */
|
|
20
|
+
tocLabel?: string;
|
|
21
|
+
/** Article content. */
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare function DocsLayout(props: DocsLayoutProps): JSX.Element;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { BrandMark } from "../utilities/BrandMark.js";
|
|
4
|
+
import { Icon } from "../utilities/Icon.js";
|
|
5
|
+
const AX_DOCS_CSS = `
|
|
6
|
+
.ax-docs { display: grid; grid-template-columns: 252px minmax(0,1fr) 220px; height: 100%; background: var(--surface-page); overflow: hidden; }
|
|
7
|
+
.ax-docs__nav { border-right: 1px solid var(--border-default); background: var(--surface-panel); overflow-y: auto; padding: 18px 0 32px; }
|
|
8
|
+
.ax-docs__brand { display: flex; align-items: center; gap: 9px; padding: 0 20px 16px; }
|
|
9
|
+
.ax-docs__sec { padding: 14px 20px 6px; }
|
|
10
|
+
.ax-docs__list { display: flex; flex-direction: column; padding: 0 12px; }
|
|
11
|
+
.ax-docs__item { padding: 7px 10px; border-radius: var(--radius-2); font-size: var(--text-sm); color: var(--text-muted); cursor: pointer;
|
|
12
|
+
border: none; background: none; text-align: left; font-family: inherit; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }
|
|
13
|
+
.ax-docs__item:hover { background: var(--bg-3); color: var(--text-body); }
|
|
14
|
+
.ax-docs__item[data-on="true"] { color: var(--text-body); font-weight: var(--weight-medium); background: var(--bg-3); }
|
|
15
|
+
.ax-docs__art { overflow-y: auto; }
|
|
16
|
+
.ax-docs__artinner { max-width: 680px; margin: 0 auto; padding: 56px 40px 96px; }
|
|
17
|
+
.ax-docs__toc { border-left: 1px solid var(--border-default); padding: 56px 22px; overflow-y: auto; }
|
|
18
|
+
.ax-docs__tochead { margin-bottom: 14px; }
|
|
19
|
+
.ax-docs__toclist { display: flex; flex-direction: column; gap: 9px; border-left: 1px solid var(--border-default); }
|
|
20
|
+
.ax-docs__toclink { padding-left: 14px; margin-left: -1px; font-size: var(--text-sm); color: var(--text-muted); cursor: pointer; border-left: 2px solid transparent; }
|
|
21
|
+
.ax-docs__toclink[data-on="true"] { color: var(--text-body); border-left-color: var(--accent); }
|
|
22
|
+
.ax-docs__mtop { display: none; }
|
|
23
|
+
.ax-docs__burger { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; flex: none;
|
|
24
|
+
border: 1px solid var(--border-default); border-radius: var(--radius-2); background: none; color: var(--text-muted); cursor: pointer; }
|
|
25
|
+
.ax-docs__burger:hover { color: var(--text-body); border-color: var(--border-strong); }
|
|
26
|
+
.ax-docs__scrim { display: none; }
|
|
27
|
+
@media (max-width: 1080px) { .ax-docs { grid-template-columns: 252px 1fr; } .ax-docs__toc { display: none; } }
|
|
28
|
+
@media (max-width: 760px) {
|
|
29
|
+
.ax-docs { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
|
|
30
|
+
.ax-docs__mtop { display: flex; align-items: center; gap: 12px; height: 52px; flex: none; padding: 0 16px;
|
|
31
|
+
border-bottom: 1px solid var(--border-default); background: var(--surface-panel); grid-column: 1; }
|
|
32
|
+
.ax-docs__nav { position: fixed; top: 0; left: 0; bottom: 0; width: 264px; z-index: 40;
|
|
33
|
+
transform: translateX(-100%); transition: transform var(--dur-2) var(--ease-out); box-shadow: var(--shadow-3); }
|
|
34
|
+
.ax-docs__nav[data-open="true"] { transform: none; }
|
|
35
|
+
.ax-docs__scrim { display: block; position: fixed; inset: 0; z-index: 39; background: var(--bg-overlay);
|
|
36
|
+
opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }
|
|
37
|
+
.ax-docs__scrim[data-open="true"] { opacity: 1; pointer-events: auto; }
|
|
38
|
+
.ax-docs__artinner { padding: 32px 18px 72px; }
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
if (typeof document !== "undefined" && !document.getElementById("ax-docs-css")) {
|
|
42
|
+
const s = document.createElement("style");
|
|
43
|
+
s.id = "ax-docs-css";
|
|
44
|
+
s.textContent = AX_DOCS_CSS;
|
|
45
|
+
document.head.appendChild(s);
|
|
46
|
+
}
|
|
47
|
+
function DocsLayout({
|
|
48
|
+
brand,
|
|
49
|
+
sections = [],
|
|
50
|
+
activeItem,
|
|
51
|
+
onNavigate,
|
|
52
|
+
toc = [],
|
|
53
|
+
activeToc,
|
|
54
|
+
onTocChange,
|
|
55
|
+
tocLabel = "On this page",
|
|
56
|
+
children
|
|
57
|
+
}) {
|
|
58
|
+
const [navInt, setNavInt] = useState(activeItem);
|
|
59
|
+
const [tocInt, setTocInt] = useState(activeToc || toc[0]);
|
|
60
|
+
const [navOpen, setNavOpen] = useState(false);
|
|
61
|
+
const active = activeItem !== void 0 ? activeItem : navInt;
|
|
62
|
+
const tocActive = activeToc !== void 0 ? activeToc : tocInt;
|
|
63
|
+
const go = (it) => {
|
|
64
|
+
if (onNavigate) onNavigate(it);
|
|
65
|
+
else setNavInt(it);
|
|
66
|
+
setNavOpen(false);
|
|
67
|
+
};
|
|
68
|
+
const goToc = (t) => {
|
|
69
|
+
if (onTocChange) onTocChange(t);
|
|
70
|
+
else setTocInt(t);
|
|
71
|
+
};
|
|
72
|
+
return /* @__PURE__ */ jsxs("div", { className: "ax-docs", children: [
|
|
73
|
+
/* @__PURE__ */ jsxs("header", { className: "ax-docs__mtop", children: [
|
|
74
|
+
/* @__PURE__ */ jsx("button", { className: "ax-docs__burger", "aria-label": "Menu", onClick: () => setNavOpen(true), children: /* @__PURE__ */ jsx(Icon, { name: "menu", size: 17 }) }),
|
|
75
|
+
brand || /* @__PURE__ */ jsx(BrandMark, { size: 18, wordmark: true, blink: false })
|
|
76
|
+
] }),
|
|
77
|
+
/* @__PURE__ */ jsx("div", { className: "ax-docs__scrim", "data-open": navOpen, onClick: () => setNavOpen(false) }),
|
|
78
|
+
/* @__PURE__ */ jsxs("aside", { className: "ax-docs__nav", "data-open": navOpen, children: [
|
|
79
|
+
/* @__PURE__ */ jsx("div", { className: "ax-docs__brand", children: brand || /* @__PURE__ */ jsx(BrandMark, { size: 20, wordmark: true, blink: false }) }),
|
|
80
|
+
sections.map((s) => /* @__PURE__ */ jsxs("div", { children: [
|
|
81
|
+
/* @__PURE__ */ jsx("div", { className: "ax-docs__sec", children: /* @__PURE__ */ jsx("span", { className: "ax-label", children: s.title }) }),
|
|
82
|
+
/* @__PURE__ */ jsx("div", { className: "ax-docs__list", children: s.items.map((it) => /* @__PURE__ */ jsx(
|
|
83
|
+
"button",
|
|
84
|
+
{
|
|
85
|
+
className: "ax-docs__item",
|
|
86
|
+
"data-on": active === it,
|
|
87
|
+
onClick: () => go(it),
|
|
88
|
+
children: it
|
|
89
|
+
},
|
|
90
|
+
it
|
|
91
|
+
)) })
|
|
92
|
+
] }, s.title))
|
|
93
|
+
] }),
|
|
94
|
+
/* @__PURE__ */ jsx("article", { className: "ax-docs__art", children: /* @__PURE__ */ jsx("div", { className: "ax-docs__artinner", children }) }),
|
|
95
|
+
/* @__PURE__ */ jsxs("aside", { className: "ax-docs__toc", children: [
|
|
96
|
+
/* @__PURE__ */ jsx("div", { className: "ax-docs__tochead", children: /* @__PURE__ */ jsx("span", { className: "ax-label", children: tocLabel }) }),
|
|
97
|
+
/* @__PURE__ */ jsx("div", { className: "ax-docs__toclist", children: toc.map((t) => /* @__PURE__ */ jsx(
|
|
98
|
+
"span",
|
|
99
|
+
{
|
|
100
|
+
className: "ax-docs__toclink",
|
|
101
|
+
"data-on": tocActive === t,
|
|
102
|
+
onClick: () => goToc(t),
|
|
103
|
+
children: t
|
|
104
|
+
},
|
|
105
|
+
t
|
|
106
|
+
)) })
|
|
107
|
+
] })
|
|
108
|
+
] });
|
|
109
|
+
}
|
|
110
|
+
export {
|
|
111
|
+
DocsLayout
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=DocsLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocsLayout.js","sources":["../../../src/components/layout/DocsLayout.jsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport { BrandMark } from \"../utilities/BrandMark.jsx\";\nimport { Icon } from \"../utilities/Icon.jsx\";\n\n// DocsLayout — three-pane documentation frame: left section nav, centered\n// article, right on-this-page TOC. Article goes in `children`; nav + TOC are\n// data-driven and controlled-or-self-managed.\nconst AX_DOCS_CSS = `\n.ax-docs { display: grid; grid-template-columns: 252px minmax(0,1fr) 220px; height: 100%; background: var(--surface-page); overflow: hidden; }\n.ax-docs__nav { border-right: 1px solid var(--border-default); background: var(--surface-panel); overflow-y: auto; padding: 18px 0 32px; }\n.ax-docs__brand { display: flex; align-items: center; gap: 9px; padding: 0 20px 16px; }\n.ax-docs__sec { padding: 14px 20px 6px; }\n.ax-docs__list { display: flex; flex-direction: column; padding: 0 12px; }\n.ax-docs__item { padding: 7px 10px; border-radius: var(--radius-2); font-size: var(--text-sm); color: var(--text-muted); cursor: pointer;\n border: none; background: none; text-align: left; font-family: inherit; transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out); }\n.ax-docs__item:hover { background: var(--bg-3); color: var(--text-body); }\n.ax-docs__item[data-on=\"true\"] { color: var(--text-body); font-weight: var(--weight-medium); background: var(--bg-3); }\n.ax-docs__art { overflow-y: auto; }\n.ax-docs__artinner { max-width: 680px; margin: 0 auto; padding: 56px 40px 96px; }\n.ax-docs__toc { border-left: 1px solid var(--border-default); padding: 56px 22px; overflow-y: auto; }\n.ax-docs__tochead { margin-bottom: 14px; }\n.ax-docs__toclist { display: flex; flex-direction: column; gap: 9px; border-left: 1px solid var(--border-default); }\n.ax-docs__toclink { padding-left: 14px; margin-left: -1px; font-size: var(--text-sm); color: var(--text-muted); cursor: pointer; border-left: 2px solid transparent; }\n.ax-docs__toclink[data-on=\"true\"] { color: var(--text-body); border-left-color: var(--accent); }\n.ax-docs__mtop { display: none; }\n.ax-docs__burger { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; flex: none;\n border: 1px solid var(--border-default); border-radius: var(--radius-2); background: none; color: var(--text-muted); cursor: pointer; }\n.ax-docs__burger:hover { color: var(--text-body); border-color: var(--border-strong); }\n.ax-docs__scrim { display: none; }\n@media (max-width: 1080px) { .ax-docs { grid-template-columns: 252px 1fr; } .ax-docs__toc { display: none; } }\n@media (max-width: 760px) {\n .ax-docs { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }\n .ax-docs__mtop { display: flex; align-items: center; gap: 12px; height: 52px; flex: none; padding: 0 16px;\n border-bottom: 1px solid var(--border-default); background: var(--surface-panel); grid-column: 1; }\n .ax-docs__nav { position: fixed; top: 0; left: 0; bottom: 0; width: 264px; z-index: 40;\n transform: translateX(-100%); transition: transform var(--dur-2) var(--ease-out); box-shadow: var(--shadow-3); }\n .ax-docs__nav[data-open=\"true\"] { transform: none; }\n .ax-docs__scrim { display: block; position: fixed; inset: 0; z-index: 39; background: var(--bg-overlay);\n opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease-out); }\n .ax-docs__scrim[data-open=\"true\"] { opacity: 1; pointer-events: auto; }\n .ax-docs__artinner { padding: 32px 18px 72px; }\n}\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"ax-docs-css\")) {\n const s = document.createElement(\"style\");\n s.id = \"ax-docs-css\";\n s.textContent = AX_DOCS_CSS;\n document.head.appendChild(s);\n}\n\nexport function DocsLayout({\n brand,\n sections = [],\n activeItem,\n onNavigate,\n toc = [],\n activeToc,\n onTocChange,\n tocLabel = \"On this page\",\n children,\n}) {\n const [navInt, setNavInt] = useState(activeItem);\n const [tocInt, setTocInt] = useState(activeToc || toc[0]);\n const [navOpen, setNavOpen] = useState(false);\n const active = activeItem !== undefined ? activeItem : navInt;\n const tocActive = activeToc !== undefined ? activeToc : tocInt;\n const go = (it) => {\n if (onNavigate) onNavigate(it);\n else setNavInt(it);\n setNavOpen(false);\n };\n const goToc = (t) => {\n if (onTocChange) onTocChange(t);\n else setTocInt(t);\n };\n\n return (\n <div className=\"ax-docs\">\n <header className=\"ax-docs__mtop\">\n <button className=\"ax-docs__burger\" aria-label=\"Menu\" onClick={() => setNavOpen(true)}>\n <Icon name=\"menu\" size={17} />\n </button>\n {brand || <BrandMark size={18} wordmark blink={false} />}\n </header>\n <div className=\"ax-docs__scrim\" data-open={navOpen} onClick={() => setNavOpen(false)}></div>\n <aside className=\"ax-docs__nav\" data-open={navOpen}>\n <div className=\"ax-docs__brand\">\n {brand || <BrandMark size={20} wordmark blink={false} />}\n </div>\n {sections.map((s) => (\n <div key={s.title}>\n <div className=\"ax-docs__sec\">\n <span className=\"ax-label\">{s.title}</span>\n </div>\n <div className=\"ax-docs__list\">\n {s.items.map((it) => (\n <button\n key={it}\n className=\"ax-docs__item\"\n data-on={active === it}\n onClick={() => go(it)}\n >\n {it}\n </button>\n ))}\n </div>\n </div>\n ))}\n </aside>\n\n <article className=\"ax-docs__art\">\n <div className=\"ax-docs__artinner\">{children}</div>\n </article>\n\n <aside className=\"ax-docs__toc\">\n <div className=\"ax-docs__tochead\">\n <span className=\"ax-label\">{tocLabel}</span>\n </div>\n <div className=\"ax-docs__toclist\">\n {toc.map((t) => (\n <span\n key={t}\n className=\"ax-docs__toclink\"\n data-on={tocActive === t}\n onClick={() => goToc(t)}\n >\n {t}\n </span>\n ))}\n </div>\n </aside>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|