@gemboss/ui 0.35.7 → 0.39.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/CHANGELOG.md +290 -0
- package/README.md +178 -6
- package/catalog/editor.html +33 -15
- package/catalog/index.html +2020 -122
- package/gemboss-ui.css +3 -3
- package/package.json +15 -2
- package/parts/components.css +2 -2
- package/parts/core.css +1 -1
- package/parts/shell.css +1 -1
- package/src/assistant-chat.css +1 -1
- package/src/auth-field.css +1 -0
- package/src/auth-field.tsx +74 -0
- package/src/auth-sso-plain.js +1 -0
- package/src/auth.css +1 -1
- package/src/auth.tsx +64 -1
- package/src/brand.tsx +9 -3
- package/src/chat-composer.css +1 -1
- package/src/chat.css +1 -1
- package/src/collections.css +1 -1
- package/src/editor/controls.tsx +105 -4
- package/src/editor/frame.tsx +8 -4
- package/src/editor/index.ts +7 -3
- package/src/editor/panel.tsx +34 -10
- package/src/editor/repeater.tsx +244 -0
- package/src/editor/sortable.tsx +50 -24
- package/src/editor/tiles.tsx +51 -0
- package/src/editor-repeater.css +1 -0
- package/src/editor-tiles.css +1 -0
- package/src/editor.css +1 -1
- package/src/icons.tsx +2 -0
- package/src/index.ts +9 -1
- package/src/kit-plain.js +1 -1
- package/src/service-switcher-plain.js +1 -0
- package/src/service-switcher.css +1 -0
- package/src/service-switcher.tsx +222 -0
- package/src/services.ts +91 -0
- package/src/shell.css +1 -1
- package/src/toggle-bar.tsx +60 -0
- package/src/ui.css +1 -1
package/src/auth.tsx
CHANGED
|
@@ -37,7 +37,7 @@ const BACKDROP: Record<AuthBackdrop, string> = { facet: "", grid: "gb-auth-panel
|
|
|
37
37
|
* The whole screen. `children` is everything inside the card below the heading: the form, then any
|
|
38
38
|
* lines under it.
|
|
39
39
|
*/
|
|
40
|
-
export function AuthLayout({ brand, tagline, mark, panel, backdrop = "facet", className, children }: {
|
|
40
|
+
export function AuthLayout({ brand, tagline, mark, panel, backdrop = "facet", art, className, children }: {
|
|
41
41
|
/** The page heading (h1) in the card. */
|
|
42
42
|
brand: React.ReactNode;
|
|
43
43
|
/** One line under the heading; the first thing shed on a short screen. */
|
|
@@ -48,6 +48,9 @@ export function AuthLayout({ brand, tagline, mark, panel, backdrop = "facet", cl
|
|
|
48
48
|
panel?: { eyebrow?: React.ReactNode; heading: React.ReactNode; body?: React.ReactNode };
|
|
49
49
|
/** The panel's ground pattern; see `AuthBackdrop`. Only drawn where the panel is (900 wide AND 520 tall). */
|
|
50
50
|
backdrop?: AuthBackdrop;
|
|
51
|
+
/** Drawn on the panel, under its words (16/10/2026): `AuthPageField`, or anything else that is decoration. Pair it
|
|
52
|
+
* with `backdrop="none"`. Only drawn where the panel is. */
|
|
53
|
+
art?: React.ReactNode;
|
|
51
54
|
className?: string;
|
|
52
55
|
children?: React.ReactNode;
|
|
53
56
|
}) {
|
|
@@ -105,6 +108,7 @@ export function AuthLayout({ brand, tagline, mark, panel, backdrop = "facet", cl
|
|
|
105
108
|
them. Nothing in it is focusable — it is decoration beside the form, not a second path. */}
|
|
106
109
|
{panel ? (
|
|
107
110
|
<aside className={cx("gb-auth-panel", BACKDROP[backdrop])}>
|
|
111
|
+
{art}
|
|
108
112
|
<div className="gb-auth-panel-in">
|
|
109
113
|
{panel.eyebrow ? <p className="gb-auth-eyebrow">{panel.eyebrow}</p> : null}
|
|
110
114
|
<h2 className="gb-auth-panel-h">{panel.heading}</h2>
|
|
@@ -117,6 +121,65 @@ export function AuthLayout({ brand, tagline, mark, panel, backdrop = "facet", cl
|
|
|
117
121
|
);
|
|
118
122
|
}
|
|
119
123
|
|
|
124
|
+
/**
|
|
125
|
+
* "Continue with GemBoss" (16/10/2026): the internal tools' second door, above their password form (Chris, 16/10/2026: "có
|
|
126
|
+
* cả continue với gemboss hoặc nhập mật khẩu"). Protocol: gemboss docs/fleet-sso.md. It links to GemBoss's sign-in
|
|
127
|
+
* door for this `service`; GemBoss sends a person who is signed in there and on the internal list straight back, with a
|
|
128
|
+
* one-use token the tool redeems at its own route. Below it, "or" and the form the tool always had.
|
|
129
|
+
*
|
|
130
|
+
* Once a browser has come in through GemBoss the tool sets `gb_sso=1`, and from then on this page continues by itself,
|
|
131
|
+
* so a person still signed in to GemBoss never sees a form. It does not when the tool sent a reason back (`?sso=…`:
|
|
132
|
+
* that sign-in did not work, so the page stays and says why) or `?password=1` (the person asked for the form).
|
|
133
|
+
*/
|
|
134
|
+
export const GEMBOSS_ISSUER = "https://admin.gemboss.ai";
|
|
135
|
+
const SSO_REASONS: Record<string, string> = {
|
|
136
|
+
not_member: "Your GemBoss account does not have access here. Use the password.",
|
|
137
|
+
invalid: "That sign-in did not go through. Try again, or use the password.",
|
|
138
|
+
off: "Signing in with GemBoss is not available here yet. Use the password.",
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/** The GemBoss door for one tool, with the path on the tool to come back to. */
|
|
142
|
+
export function gemBossSignInUrl(service: string, next = "/", issuer = GEMBOSS_ISSUER): string {
|
|
143
|
+
return `${issuer}/api/auth/sso/authorize?service=${encodeURIComponent(service)}&next=${encodeURIComponent(next)}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Whether this visit should go to GemBoss without a click: the browser came in that way before, and nothing says stay. */
|
|
147
|
+
export function continuesByItself(cookie: string, search: string): boolean {
|
|
148
|
+
const q = new URLSearchParams(search);
|
|
149
|
+
if (q.has("sso") || q.get("password") === "1") return false;
|
|
150
|
+
return /(?:^|;\s*)gb_sso=1(?:;|$)/.test(cookie);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function AuthContinueWithGemBoss({ service, next = "/", issuer = GEMBOSS_ISSUER }: {
|
|
154
|
+
/** This tool's id in GemBoss's list of tools that redeem (FLEET_SSO_SERVICES). */
|
|
155
|
+
service: string;
|
|
156
|
+
/** Where on this tool to land afterwards: a path. */
|
|
157
|
+
next?: string;
|
|
158
|
+
issuer?: string;
|
|
159
|
+
}) {
|
|
160
|
+
const href = gemBossSignInUrl(service, next, issuer);
|
|
161
|
+
const [going, setGoing] = useState(false);
|
|
162
|
+
const [reason, setReason] = useState<string | null>(null);
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
const r = new URLSearchParams(window.location.search).get("sso");
|
|
165
|
+
if (r) setReason(SSO_REASONS[r] ?? SSO_REASONS.invalid);
|
|
166
|
+
if (continuesByItself(document.cookie, window.location.search)) {
|
|
167
|
+
setGoing(true);
|
|
168
|
+
window.location.replace(href);
|
|
169
|
+
}
|
|
170
|
+
}, [href]);
|
|
171
|
+
return (
|
|
172
|
+
<div className="gb-auth-sso">
|
|
173
|
+
<a className="gb-auth-sso-btn" href={href} onClick={() => setGoing(true)}>
|
|
174
|
+
<GemMark size={18} tile="var(--gb-mark-bg)" />
|
|
175
|
+
{going ? "Continuing with GemBoss…" : "Continue with GemBoss"}
|
|
176
|
+
</a>
|
|
177
|
+
{reason ? <p className="gb-auth-sso-why" role="status">{reason}</p> : null}
|
|
178
|
+
<p className="gb-auth-or">or use the password</p>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
120
183
|
export function AuthForm({ className, children, ...rest }: React.FormHTMLAttributes<HTMLFormElement>) {
|
|
121
184
|
return <form className={cx("gb-auth-form", className)} {...rest}>{children}</form>;
|
|
122
185
|
}
|
package/src/brand.tsx
CHANGED
|
@@ -9,14 +9,19 @@
|
|
|
9
9
|
* - gem: the logo file's paths and stroke weights, same 0.31 scale, in a 32×40 box drawn 26px tall;
|
|
10
10
|
* - name: the logo's text at the same scale — 20.5 × 0.65 = 13.3px, 700, -0.13px tracking, #14151a.
|
|
11
11
|
* `BrandLockup name="GemBoss"` is meant to be indistinguishable from the admin's image.
|
|
12
|
+
*
|
|
13
|
+
* `switcher` (0.36.0): the ServiceSwitcher button right after the logo, which opens every other Gem service. The logo
|
|
14
|
+
* still goes to `href`, as without it. Without the prop the lockup renders exactly as before. The import below brings
|
|
15
|
+
* service-switcher.css with this module whether or not a surface passes it (README "ServiceSwitcher").
|
|
12
16
|
*/
|
|
13
17
|
import React from "react";
|
|
18
|
+
import { ServiceSwitcher, type ServiceSwitcherProps } from "./service-switcher";
|
|
14
19
|
|
|
15
20
|
type AnchorProps = React.AnchorHTMLAttributes<HTMLAnchorElement>;
|
|
16
21
|
|
|
17
|
-
export function BrandLockup({ name, href = "/", label, className, ...rest }:
|
|
18
|
-
{ name: string; label?: string } & AnchorProps) {
|
|
19
|
-
|
|
22
|
+
export function BrandLockup({ name, href = "/", label, className, switcher, ...rest }:
|
|
23
|
+
{ name: string; label?: string; switcher?: Omit<ServiceSwitcherProps, "className"> } & AnchorProps) {
|
|
24
|
+
const link = (
|
|
20
25
|
<a className={className ? `gb-brand ${className}` : "gb-brand"} href={href} aria-label={label ?? `${name} home`} {...rest}>
|
|
21
26
|
<svg className="gb-brand-gem" viewBox="0 0 32 40" width="20.8" height="26" aria-hidden="true" focusable="false">
|
|
22
27
|
<g transform="translate(0,0.8) scale(0.31)">
|
|
@@ -28,4 +33,5 @@ export function BrandLockup({ name, href = "/", label, className, ...rest }:
|
|
|
28
33
|
<span className="gb-brand-name">{name}</span>
|
|
29
34
|
</a>
|
|
30
35
|
);
|
|
36
|
+
return switcher ? <>{link}<ServiceSwitcher {...switcher} /></> : link;
|
|
31
37
|
}
|
package/src/chat-composer.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.gemboss-ec-toolbar{flex:1 0 100%;display:flex;align-items:center;gap:4px;min-width:0}.gemboss-ec-toolbar-lead{flex:1 1 auto;display:flex;align-items:center;gap:4px;min-width:0}.gemboss-ec-toolbar-lead:empty{display:none}.gemboss-ec-toolbar-lead:empty+*{margin-left:auto}.gemboss-ec-toolbar-tools{display:flex;align-items:center;gap:4px;flex:none;min-width:0}.gemboss-ec-toolbar-tools:empty{display:none}.gemboss-ec-input:has(>.gemboss-ec-toolbar>.gemboss-ec-toolbar-lead:empty){flex-wrap:nowrap;align-items:flex-end}.gemboss-ec-input:has(>.gemboss-ec-toolbar>.gemboss-ec-toolbar-lead:empty)>textarea{flex:1 1 0}.gemboss-ec-input:has(>.gemboss-ec-toolbar>.gemboss-ec-toolbar-lead:empty)>.gemboss-ec-toolbar{flex:0 0 auto}@media (pointer: coarse){.gemboss-ec-input .gemboss-ec-stop{width:44px;height:44px;min-width:44px}.gemboss-ec-input .gemboss-ec-stop-send{min-height:44px}}.gemboss-ec-stop{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;border:none;border-radius:50%;background:var(--gemboss-
|
|
1
|
+
.gemboss-ec-toolbar{flex:1 0 100%;display:flex;align-items:center;gap:4px;min-width:0}.gemboss-ec-toolbar-lead{flex:1 1 auto;display:flex;align-items:center;gap:4px;min-width:0}.gemboss-ec-toolbar-lead:empty{display:none}.gemboss-ec-toolbar-lead:empty+*{margin-left:auto}.gemboss-ec-toolbar-tools{display:flex;align-items:center;gap:4px;flex:none;min-width:0}.gemboss-ec-toolbar-tools:empty{display:none}.gemboss-ec-input:has(>.gemboss-ec-toolbar>.gemboss-ec-toolbar-lead:empty){flex-wrap:nowrap;align-items:flex-end}.gemboss-ec-input:has(>.gemboss-ec-toolbar>.gemboss-ec-toolbar-lead:empty)>textarea{flex:1 1 0}.gemboss-ec-input:has(>.gemboss-ec-toolbar>.gemboss-ec-toolbar-lead:empty)>.gemboss-ec-toolbar{flex:0 0 auto}@media (pointer: coarse){.gemboss-ec-input .gemboss-ec-stop{width:44px;height:44px;min-width:44px}.gemboss-ec-input .gemboss-ec-stop-send{min-height:44px}}.gemboss-ec-stop{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;border:none;border-radius:50%;background:var(--gemboss-danger);color:var(--gemboss-on-primary, #fff);cursor:pointer}.gemboss-ec-stop svg{width:12px;height:12px;fill:currentColor}.gemboss-ec-stop:disabled{opacity:.6;cursor:default}.gemboss-ec-stop:hover{filter:brightness(1.08)}.gemboss-ec-stop:focus-visible{outline:2px solid var(--ui-focus, #5661f5);outline-offset:2px}
|
package/src/chat.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.gemboss-ec{--gemboss-ec-inset: 16px}@media (max-width: 640px){.gemboss-ec{--gemboss-ec-inset: 12px}}.gemboss-ec-head{padding:16px var(--gemboss-ec-inset, 16px);border-bottom:1px solid var(--gemboss-divider);display:flex;flex-direction:column;gap:2px}.gemboss-ec-title{font-family:var(--gemboss-serif);font-size:15px;font-weight:600}.gemboss-ec-sub{font-size:12px;color:var(--gemboss-text-muted)}.gemboss-ec-scroll{flex:1;min-height:0;overflow-y:auto;padding:var(--gemboss-ec-inset, 16px);display:flex;flex-direction:column;gap:16px;scrollbar-gutter:stable}.gemboss-ec-scroll{scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-ec-scroll::-webkit-scrollbar{width:9px}.gemboss-ec-scroll::-webkit-scrollbar-track{background:transparent}.gemboss-ec-scroll::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:6px;border:2px solid transparent;background-clip:content-box}.gemboss-ec-msg{display:flex;flex-direction:column;gap:8px;max-width:100%}.gemboss-ec-msg.user{align-items:flex-end}.gemboss-ec-msg.assistant{align-items:flex-start}.gemboss-ec-bubble{font-size:var(--gemboss-fs-body);line-height:1.5;padding:12px;border-radius:16px;max-width:min(90%,68ch);white-space:pre-wrap;word-break:break-word}.gemboss-ec-msg.user .gemboss-ec-bubble{background:var(--gemboss-primary);color:var(--gemboss-on-primary, #fff);border-bottom-right-radius:4px}.gemboss-ec-msg.assistant .gemboss-ec-bubble{background:var(--gemboss-surface);color:var(--gemboss-text);border:1px solid var(--gemboss-divider);border-bottom-left-radius:4px}.gemboss-ec-msg.user .gemboss-ec-bubble,:root[data-theme=dark] .gemboss-ec-msg.assistant .gemboss-ec-bubble{--gemboss-ec-md-ink: color-mix(in srgb, currentColor 78%, transparent);--gemboss-ec-md-line: color-mix(in srgb, currentColor 32%, transparent);--gemboss-ec-md-fill: color-mix(in srgb, currentColor 14%, transparent)}:is(.gemboss-ec-msg.user,:root[data-theme=dark] .gemboss-ec-msg.assistant) .gemboss-ec-bubble :is(.gemboss-md-h3,.gemboss-md-quote){color:var(--gemboss-ec-md-ink)}:is(.gemboss-ec-msg.user,:root[data-theme=dark] .gemboss-ec-msg.assistant) .gemboss-ec-bubble :is(.gemboss-md-quote,.gemboss-md-rule,.gemboss-md-table th,.gemboss-md-table td,.gemboss-md-codeblock,.gemboss-md-img){border-color:var(--gemboss-ec-md-line)}:is(.gemboss-ec-msg.user,:root[data-theme=dark] .gemboss-ec-msg.assistant) .gemboss-ec-bubble :is(.gemboss-md-code,.gemboss-md-table th,.gemboss-md-codeblock,.gemboss-md-img){background:var(--gemboss-ec-md-fill)}.gemboss-ec-toolbar>button[type=submit] svg{width:18px;height:18px;fill:currentColor}.gemboss-ec-pending{display:inline-flex;align-items:center;gap:8px;padding:6px 2px;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-ec-pending-star{color:var(--gemboss-primary);font-size:12px;line-height:1;animation:gemboss-star-pulse 1.1s ease-in-out infinite}.gemboss-ec-pending-verb{color:var(--gemboss-text);animation:gemboss-verb-in .4s ease-out}.gemboss-ec-pending-meta{font-variant-numeric:tabular-nums;opacity:.7;font-size:var(--gemboss-fs-caption)}@keyframes gemboss-star-pulse{0%,to{transform:scale(.85);opacity:.55}50%{transform:scale(1.15);opacity:1}}@keyframes gemboss-verb-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:none}}.gemboss-ec-cursor{display:inline-block;width:2px;height:1.05em;margin-left:2px;vertical-align:-2px;background:var(--gemboss-primary);border-radius:2px;animation:gemboss-cursor-blink 1s steps(1) infinite}@keyframes gemboss-cursor-blink{0%,45%{opacity:1}50%,95%{opacity:.15}to{opacity:1}}@media (prefers-reduced-motion: reduce){.gemboss-ec-pending-star,.gemboss-ec-cursor{animation:none}}.gemboss-ec-md-link{color:var(--gemboss-primary-dark);font-weight:600;text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--gemboss-primary) 35%,transparent);cursor:pointer}.gemboss-ec-md-link:hover{border-bottom-color:var(--gemboss-primary)}strong>.gemboss-ec-md-link{font-weight:inherit}.gemboss-ec-md-link:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:2px}.gemboss-ec-msg.user .gemboss-ec-md-link{color:inherit;border-bottom-color:color-mix(in srgb,currentColor 55%,transparent)}.gemboss-ec-msg.user .gemboss-ec-md-link:hover{border-bottom-color:currentColor}.gemboss-ec-starters{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}.gemboss-ec-starter{text-align:left;font-size:13px;padding:6px 12px;border-radius:var(--gemboss-radius-full);cursor:pointer;background:var(--gemboss-surface);border:1px solid var(--gemboss-divider);color:var(--gemboss-text);white-space:nowrap;max-width:100%}.gemboss-ec-starter:hover{border-color:var(--gemboss-primary);background:#5661f50f}.gemboss-ec-input{display:flex;flex-wrap:wrap;align-items:center;gap:4px;margin:12px;padding:8px;border:1px solid var(--gemboss-divider);border-radius:16px;background:var(--gemboss-surface);transition:border-color var(--gemboss-transition-fast) ease,box-shadow var(--gemboss-transition-fast) ease}.gemboss-ec-input:focus-within{border-color:var(--gemboss-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--gemboss-primary) 12%,transparent)}.gemboss-ec-input textarea{flex:1 0 100%;min-width:0;width:100%;box-sizing:border-box;resize:none;border-radius:0;background:transparent;border:1px solid transparent;padding:6px 8px;font-size:var(--gemboss-fs-body);font-family:inherit;min-height:0;max-height:84px;line-height:1.5;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-ec-input textarea::-webkit-scrollbar{width:7px}.gemboss-ec-input textarea::-webkit-scrollbar-track{background:transparent}.gemboss-ec-input textarea::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:4px;border:2px solid transparent;background-clip:content-box}.gemboss-ec-input textarea:focus{outline:none}.gemboss-ec-toolbar>button[type=submit]{flex:0 0 auto;width:44px;height:44px;min-width:44px;min-height:44px;border-radius:50%;border:0;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;background:var(--gemboss-primary);color:var(--gemboss-on-primary, #fff);font-size:16px;font-weight:700;transition:background var(--gemboss-transition-fast) ease,filter var(--gemboss-transition-fast) ease}.gemboss-ec-toolbar>button[type=submit]:hover:not(:disabled){background:var(--gemboss-primary-dark)}.gemboss-ec-toolbar>button[type=submit]:active:not(:disabled){background:var(--gemboss-primary-dark);filter:brightness(.94)}.gemboss-ec-toolbar>button[type=submit]:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gemboss-ec-toolbar>button[type=submit]:disabled{background:var(--gemboss-divider);color:var(--gemboss-text-muted);opacity:1;cursor:default}.gemboss-narr{list-style:none;margin:0;padding:8px 0 0;display:flex;flex-direction:column;gap:8px}.gemboss-narr-row{display:flex;align-items:center;gap:8px;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-narr-dot{width:16px;height:16px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:10px;flex:0 0 auto}.gemboss-narr-row.ok .gemboss-narr-dot{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gemboss-narr-row.failed .gemboss-narr-dot{background:#fde8e6;color:var(--gemboss-danger)}.gemboss-narr-row.running .gemboss-narr-dot{background:transparent}.gemboss-narr-dot-engine{background:transparent!important;color:inherit}.gemboss-narr-row.ok .gemboss-narr-dot-engine{color:var(--gemboss-text)}.gemboss-narr-row.failed .gemboss-narr-dot-engine{color:var(--gemboss-danger)}.gemboss-narr-row.ok .gemboss-narr-text,.gemboss-narr-row.failed .gemboss-narr-text{color:var(--gemboss-text)}.gemboss-narr-row.steer .gemboss-narr-dot{background:transparent;color:var(--gemboss-text-muted)}.gemboss-narr-steer{color:var(--gemboss-text);font-weight:500;overflow-wrap:anywhere}.gemboss-narr-spin{width:11px;height:11px;border:2px solid var(--gemboss-divider-soft);border-top-color:var(--gemboss-primary);border-radius:50%;animation:gemboss-spin .7s linear infinite}@keyframes gemboss-spin{to{transform:rotate(360deg)}}.gemboss-narr-row.thinking{align-items:flex-start}.gemboss-narr-row.thinking .gemboss-narr-dot{color:var(--gemboss-text-muted);background:transparent}.gemboss-narr-thinking-live{font-style:italic;color:var(--gemboss-text-muted);white-space:pre-wrap;opacity:.9;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.gemboss-narr-thinking{font-size:var(--gemboss-fs-caption)}.gemboss-narr-thinking>summary{cursor:pointer;color:var(--gemboss-text-muted);list-style:none;user-select:none}.gemboss-narr-thinking>summary::-webkit-details-marker{display:none}.gemboss-narr-thinking>summary:before{content:"\25b8 "}.gemboss-narr-thinking[open]>summary:before{content:"\25be "}.gemboss-narr-thinking-body{margin-top:6px;padding:8px;border-left:2px solid var(--gemboss-divider-soft);color:var(--gemboss-text-muted);font-style:italic;white-space:pre-wrap;line-height:1.5}.gemboss-narr-row.trace code{font-family:var(--gemboss-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:var(--gemboss-fs-caption);word-break:break-word}.gemboss-narr-trace-call{color:var(--gemboss-text-muted);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.gemboss-narr-trace{font-size:var(--gemboss-fs-caption);min-width:0}.gemboss-narr-trace>summary{cursor:pointer;color:var(--gemboss-text-muted);list-style:none;user-select:none;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.gemboss-narr-trace[open]>summary{display:block;overflow:visible}.gemboss-narr-trace>summary::-webkit-details-marker{display:none}.gemboss-narr-trace>summary,.gemboss-narr-thinking>summary{min-height:24px;box-sizing:border-box;padding-block:2px}.gemboss-narr-trace>summary:before{content:"\25b8 "}.gemboss-narr-trace[open]>summary:before{content:"\25be "}.gemboss-narr-trace-body{margin-top:6px;padding:8px;border-left:2px solid var(--gemboss-divider-soft);color:var(--gemboss-text-muted);white-space:pre-wrap;line-height:1.5;overflow-x:auto}@media (max-width: 640px){.gemboss-ec-input textarea{min-height:0}.gemboss-ec-scroll{padding:var(--gemboss-ec-inset, 12px)}}.gemboss-ec-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}.gemboss-ec-chip{background:var(--gemboss-surface);border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-full);padding:8px 16px;font-size:13px;cursor:pointer;color:var(--gemboss-text);min-height:44px}.gemboss-ec-chip:hover{border-color:var(--gemboss-primary);color:var(--gemboss-active-fg)}.gemboss-ec-chip:disabled{opacity:.5;cursor:default}@media (pointer: fine){.gemboss-ec-starters{row-gap:16px}.gemboss-ec-tab,.gemboss-ec-starter,.gemboss-ec-upload,.gemboss-ec-workmode,.gemboss-ec-input .gemboss-ec-attach-btn,.gemboss-ec-stop,.gemboss-ec-stop-send,.gemboss-ec-toolbar>button[type=submit]{position:relative}.gemboss-ec-tab:after,.gemboss-ec-starter:after,.gemboss-ec-upload:after,.gemboss-ec-workmode:before,.gemboss-ec-input .gemboss-ec-attach-btn:after,.gemboss-ec-stop:after,.gemboss-ec-stop-send:after,.gemboss-ec-toolbar>button[type=submit]:after{content:"";position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:44px;pointer-events:auto;z-index:1}}@media (pointer: coarse){.gemboss-ec-toolbar>button[type=submit]{width:44px;height:44px;font-size:17px}.gemboss-ec-starter,.gemboss-ec-opt,.gemboss-ec-input textarea{min-height:44px}}.gemboss-md-p{margin:0 0 8px}.gemboss-md-p:last-child{margin-bottom:0}.gemboss-md-h{margin:16px 0 6px;font-weight:650;line-height:1.3}.gemboss-md-h:first-child{margin-top:0}.gemboss-md-h1{font-size:17px}.gemboss-md-h2{font-size:15px}.gemboss-md-h3{font-size:var(--gemboss-fs-body);color:var(--gemboss-text-subdued, #616161)}.gemboss-md-list{margin:0 0 8px;padding-left:20px}.gemboss-md-list li{margin:2px 0}.gemboss-md-quote{margin:0 0 8px;padding:2px 0 2px 12px;border-left:3px solid var(--gemboss-border, #e3e3e3);color:var(--gemboss-text-subdued, #616161)}.gemboss-md-rule{margin:12px 0;border:0;border-top:1px solid var(--gemboss-border, #e3e3e3)}.gemboss-md-code{padding:1px 6px;border-radius:6px;background:var(--gemboss-surface-subdued, #f1f1f1);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em;word-break:break-word}.gemboss-md-tablewrap{margin:0 0 12px;overflow-x:auto}.gemboss-md-table{border-collapse:collapse;font-size:var(--gemboss-fs-caption);min-width:100%}.gemboss-md-table th,.gemboss-md-table td{border:1px solid var(--gemboss-border, #e3e3e3);padding:6px 8px;text-align:left;vertical-align:top;white-space:nowrap}.gemboss-md-table th{background:var(--gemboss-surface-subdued, #f7f7f7);font-weight:600}.gemboss-md-imglink{display:inline-block;max-width:100%;margin:4px 0 8px;border-radius:8px;line-height:0}.gemboss-md-imglink:focus-visible{outline:2px solid var(--gemboss-focus, var(--ui-focus, #5661f5));outline-offset:2px}.gemboss-md-img{display:block;max-width:100%;max-height:320px;height:auto;border:1px solid var(--gemboss-border, #e3e3e3);border-radius:8px;background:var(--gemboss-surface-subdued, #f7f7f7);object-fit:contain}.gemboss-md-codeblock{position:relative;margin:0 0 12px;border:1px solid var(--gemboss-border, #e3e3e3);border-radius:8px;background:var(--gemboss-surface-subdued, #f7f7f7);overflow:hidden}.gemboss-md-codelang{display:block;padding:4px 12px 0;color:var(--gemboss-text-subdued, #8a8a8a);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.gemboss-md-codeblock pre{margin:0;padding:8px 12px;overflow-x:auto}.gemboss-md-codeblock code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5;white-space:pre}.gemboss-md-codemore{display:block;width:100%;padding:6px 12px;border:0;border-top:1px solid var(--gemboss-border, #e3e3e3);background:transparent;color:var(--gemboss-text-subdued, #616161);font-size:12px;text-align:left;cursor:pointer}.gemboss-md-codemore:hover{background:#00000008}.gemboss-narr-row.source{align-items:flex-start}.gemboss-narr-source{min-width:0;flex:1}.gemboss-narr-source-head{font-size:11px;color:var(--gemboss-text-muted, #686b71);margin-bottom:4px}.gemboss-narr-source-head code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gemboss-narr-source-code{margin:0;padding:8px 12px;border-radius:8px;max-height:220px;overflow:auto;background:var(--gemboss-primary-soft, #f2f3f5);border:1px solid var(--gemboss-divider, #e5e7ea);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--gemboss-fs-micro);line-height:17px;white-space:pre;tab-size:2}.gemboss-narr-source-code .c-com{color:#6a7a86;font-style:italic}.gemboss-narr-source-code .c-str{color:#9a3412}.gemboss-narr-source-code .c-num{color:#1d6fa5}.gemboss-narr-source-code .c-kw{color:#7c3aed;font-weight:600}.gemboss-narr-source-code .c-key{color:#0b6b3a}.gemboss-narr-source-code .c-tag{color:#b0197a}.gemboss-narr-source-code .c-attr{color:#7c3aed}.gemboss-narr-source-code .c-pun{color:#6a6d73}@media (max-width: 520px){.gemboss-narr-source-code{max-height:160px;font-size:11px}}.gemboss-narr-dot-quiet{visibility:hidden}
|
|
1
|
+
.gemboss-ec{--gemboss-ec-inset: 16px}@media (max-width: 640px){.gemboss-ec{--gemboss-ec-inset: 12px}}.gemboss-ec-head{padding:16px var(--gemboss-ec-inset, 16px);border-bottom:1px solid var(--gemboss-divider);display:flex;flex-direction:column;gap:2px}.gemboss-ec-title{font-family:var(--gemboss-serif);font-size:15px;font-weight:600}.gemboss-ec-sub{font-size:12px;color:var(--gemboss-text-muted)}.gemboss-ec-scroll{flex:1;min-height:0;overflow-y:auto;padding:var(--gemboss-ec-inset, 16px);display:flex;flex-direction:column;gap:16px;scrollbar-gutter:stable}.gemboss-ec-scroll{scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-ec-scroll::-webkit-scrollbar{width:9px}.gemboss-ec-scroll::-webkit-scrollbar-track{background:transparent}.gemboss-ec-scroll::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:6px;border:2px solid transparent;background-clip:content-box}.gemboss-ec-msg{display:flex;flex-direction:column;gap:8px;max-width:100%}.gemboss-ec-msg.user{align-items:flex-end}.gemboss-ec-msg.assistant{align-items:flex-start}.gemboss-ec-bubble{font-size:var(--gemboss-fs-body);line-height:1.5;padding:12px;border-radius:16px;max-width:min(90%,68ch);white-space:pre-wrap;word-break:break-word}.gemboss-ec-msg.user .gemboss-ec-bubble{background:var(--gemboss-primary);color:var(--gemboss-on-primary, #fff);border-bottom-right-radius:4px}.gemboss-ec-msg.assistant .gemboss-ec-bubble{background:var(--gemboss-surface);color:var(--gemboss-text);border:1px solid var(--gemboss-divider);border-bottom-left-radius:4px}.gemboss-ec-msg.user .gemboss-ec-bubble,:root[data-theme=dark] .gemboss-ec-msg.assistant .gemboss-ec-bubble{--gemboss-ec-md-ink: color-mix(in srgb, currentColor 78%, transparent);--gemboss-ec-md-line: color-mix(in srgb, currentColor 32%, transparent);--gemboss-ec-md-fill: color-mix(in srgb, currentColor 14%, transparent)}:is(.gemboss-ec-msg.user,:root[data-theme=dark] .gemboss-ec-msg.assistant) .gemboss-ec-bubble :is(.gemboss-md-h3,.gemboss-md-quote){color:var(--gemboss-ec-md-ink)}:is(.gemboss-ec-msg.user,:root[data-theme=dark] .gemboss-ec-msg.assistant) .gemboss-ec-bubble :is(.gemboss-md-quote,.gemboss-md-rule,.gemboss-md-table th,.gemboss-md-table td,.gemboss-md-codeblock,.gemboss-md-img){border-color:var(--gemboss-ec-md-line)}:is(.gemboss-ec-msg.user,:root[data-theme=dark] .gemboss-ec-msg.assistant) .gemboss-ec-bubble :is(.gemboss-md-code,.gemboss-md-table th,.gemboss-md-codeblock,.gemboss-md-img){background:var(--gemboss-ec-md-fill)}.gemboss-ec-toolbar>button[type=submit] svg{width:18px;height:18px;fill:currentColor}.gemboss-ec-pending{display:inline-flex;align-items:center;gap:8px;padding:6px 2px;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-ec-pending-star{color:var(--gemboss-primary);font-size:12px;line-height:1;animation:gemboss-star-pulse 1.1s ease-in-out infinite}.gemboss-ec-pending-verb{color:var(--gemboss-text);animation:gemboss-verb-in .4s ease-out}.gemboss-ec-pending-meta{font-variant-numeric:tabular-nums;opacity:.7;font-size:var(--gemboss-fs-caption)}@keyframes gemboss-star-pulse{0%,to{transform:scale(.85);opacity:.55}50%{transform:scale(1.15);opacity:1}}@keyframes gemboss-verb-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:none}}.gemboss-ec-cursor{display:inline-block;width:2px;height:1.05em;margin-left:2px;vertical-align:-2px;background:var(--gemboss-primary);border-radius:2px;animation:gemboss-cursor-blink 1s steps(1) infinite}@keyframes gemboss-cursor-blink{0%,45%{opacity:1}50%,95%{opacity:.15}to{opacity:1}}@media (prefers-reduced-motion: reduce){.gemboss-ec-pending-star,.gemboss-ec-cursor{animation:none}}.gemboss-ec-md-link{color:var(--gemboss-primary-dark);font-weight:600;text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--gemboss-primary) 35%,transparent);cursor:pointer}.gemboss-ec-md-link:hover{border-bottom-color:var(--gemboss-primary)}strong>.gemboss-ec-md-link{font-weight:inherit}.gemboss-ec-md-link:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:2px}.gemboss-ec-msg.user .gemboss-ec-md-link{color:inherit;border-bottom-color:color-mix(in srgb,currentColor 55%,transparent)}.gemboss-ec-msg.user .gemboss-ec-md-link:hover{border-bottom-color:currentColor}.gemboss-ec-starters{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}.gemboss-ec-starter{text-align:left;font-size:13px;padding:6px 12px;border-radius:var(--gemboss-radius-full);cursor:pointer;background:var(--gemboss-surface);border:1px solid var(--gemboss-divider);color:var(--gemboss-text);white-space:nowrap;max-width:100%}.gemboss-ec-starter:hover{border-color:var(--gemboss-primary);background:#5661f50f}.gemboss-ec-input{display:flex;flex-wrap:wrap;align-items:center;gap:4px;margin:12px;padding:8px;border:1px solid var(--gemboss-divider);border-radius:16px;background:var(--gemboss-surface);transition:border-color var(--gemboss-transition-fast) ease,box-shadow var(--gemboss-transition-fast) ease}.gemboss-ec-input:focus-within{border-color:var(--gemboss-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--gemboss-primary) 12%,transparent)}.gemboss-ec-input textarea{flex:1 0 100%;min-width:0;width:100%;box-sizing:border-box;resize:none;border-radius:0;background:transparent;border:1px solid transparent;padding:6px 8px;font-size:var(--gemboss-fs-body);font-family:inherit;min-height:0;max-height:84px;line-height:1.5;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-ec-input textarea::-webkit-scrollbar{width:7px}.gemboss-ec-input textarea::-webkit-scrollbar-track{background:transparent}.gemboss-ec-input textarea::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:4px;border:2px solid transparent;background-clip:content-box}.gemboss-ec-input textarea:focus{outline:none}.gemboss-ec-toolbar>button[type=submit]{flex:0 0 auto;width:44px;height:44px;min-width:44px;min-height:44px;border-radius:50%;border:0;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;background:var(--gemboss-primary);color:var(--gemboss-on-primary, #fff);font-size:16px;font-weight:700;transition:background var(--gemboss-transition-fast) ease,filter var(--gemboss-transition-fast) ease}.gemboss-ec-toolbar>button[type=submit]:hover:not(:disabled){background:var(--gemboss-primary-dark)}.gemboss-ec-toolbar>button[type=submit]:active:not(:disabled){background:var(--gemboss-primary-dark);filter:brightness(.94)}.gemboss-ec-toolbar>button[type=submit]:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gemboss-ec-toolbar>button[type=submit]:disabled{background:var(--gemboss-divider);color:var(--gemboss-text-muted);opacity:1;cursor:default}.gemboss-narr{list-style:none;margin:0;padding:8px 0 0;display:flex;flex-direction:column;gap:8px}.gemboss-narr-row{display:flex;align-items:center;gap:8px;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-narr-dot{width:16px;height:16px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:10px;flex:0 0 auto}.gemboss-narr-row.ok .gemboss-narr-dot{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gemboss-narr-row.failed .gemboss-narr-dot{background:#fde8e6;color:var(--gemboss-danger)}.gemboss-narr-row.running .gemboss-narr-dot{background:transparent}.gemboss-narr-dot-engine{background:transparent!important;color:inherit}.gemboss-narr-row.ok .gemboss-narr-dot-engine{color:var(--gemboss-text)}.gemboss-narr-row.failed .gemboss-narr-dot-engine{color:var(--gemboss-danger)}.gemboss-narr-row.ok .gemboss-narr-text,.gemboss-narr-row.failed .gemboss-narr-text{color:var(--gemboss-text)}.gemboss-narr-row.steer .gemboss-narr-dot{background:transparent;color:var(--gemboss-text-muted)}.gemboss-narr-steer{color:var(--gemboss-text);font-weight:500;overflow-wrap:anywhere}.gemboss-narr-spin{width:11px;height:11px;border:2px solid var(--gemboss-divider-soft);border-top-color:var(--gemboss-primary);border-radius:50%;animation:gemboss-spin .7s linear infinite}@keyframes gemboss-spin{to{transform:rotate(360deg)}}.gemboss-narr-row.thinking{align-items:flex-start}.gemboss-narr-row.thinking .gemboss-narr-dot{color:var(--gemboss-text-muted);background:transparent}.gemboss-narr-thinking-live{font-style:italic;color:var(--gemboss-text-muted);white-space:pre-wrap;opacity:.9;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.gemboss-narr-thinking{font-size:var(--gemboss-fs-caption)}.gemboss-narr-thinking>summary{cursor:pointer;color:var(--gemboss-text-muted);list-style:none;user-select:none}.gemboss-narr-thinking>summary::-webkit-details-marker{display:none}.gemboss-narr-thinking>summary:before{content:"\25b8 "}.gemboss-narr-thinking[open]>summary:before{content:"\25be "}.gemboss-narr-thinking-body{margin-top:6px;padding:8px;border-left:2px solid var(--gemboss-divider-soft);color:var(--gemboss-text-muted);font-style:italic;white-space:pre-wrap;line-height:1.5}.gemboss-narr-row.trace code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--gemboss-fs-caption);word-break:break-word}.gemboss-narr-trace-call{color:var(--gemboss-text-muted);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.gemboss-narr-trace{font-size:var(--gemboss-fs-caption);min-width:0}.gemboss-narr-trace>summary{cursor:pointer;color:var(--gemboss-text-muted);list-style:none;user-select:none;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.gemboss-narr-trace[open]>summary{display:block;overflow:visible}.gemboss-narr-trace>summary::-webkit-details-marker{display:none}.gemboss-narr-trace>summary,.gemboss-narr-thinking>summary{min-height:24px;box-sizing:border-box;padding-block:2px}.gemboss-narr-trace>summary:before{content:"\25b8 "}.gemboss-narr-trace[open]>summary:before{content:"\25be "}.gemboss-narr-trace-body{margin-top:6px;padding:8px;border-left:2px solid var(--gemboss-divider-soft);color:var(--gemboss-text-muted);white-space:pre-wrap;line-height:1.5;overflow-x:auto}@media (max-width: 640px){.gemboss-ec-input textarea{min-height:0}.gemboss-ec-scroll{padding:var(--gemboss-ec-inset, 12px)}}.gemboss-ec-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:4px}.gemboss-ec-chip{background:var(--gemboss-surface);border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-full);padding:8px 16px;font-size:13px;cursor:pointer;color:var(--gemboss-text);min-height:44px}.gemboss-ec-chip:hover{border-color:var(--gemboss-primary);color:var(--gemboss-active-fg)}.gemboss-ec-chip:disabled{opacity:.5;cursor:default}@media (pointer: fine){.gemboss-ec-starters{row-gap:16px}.gemboss-ec-tab,.gemboss-ec-starter,.gemboss-ec-upload,.gemboss-ec-workmode,.gemboss-ec-input .gemboss-ec-attach-btn,.gemboss-ec-stop,.gemboss-ec-stop-send,.gemboss-ec-toolbar>button[type=submit]{position:relative}.gemboss-ec-tab:after,.gemboss-ec-starter:after,.gemboss-ec-upload:after,.gemboss-ec-workmode:before,.gemboss-ec-input .gemboss-ec-attach-btn:after,.gemboss-ec-stop:after,.gemboss-ec-stop-send:after,.gemboss-ec-toolbar>button[type=submit]:after{content:"";position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);height:44px;pointer-events:auto;z-index:1}}@media (pointer: coarse){.gemboss-ec-toolbar>button[type=submit]{width:44px;height:44px;font-size:17px}.gemboss-ec-starter,.gemboss-ec-opt,.gemboss-ec-input textarea{min-height:44px}}.gemboss-md-p{margin:0 0 8px}.gemboss-md-p:last-child{margin-bottom:0}.gemboss-md-h{margin:16px 0 6px;font-weight:650;line-height:1.3}.gemboss-md-h:first-child{margin-top:0}.gemboss-md-h1{font-size:17px}.gemboss-md-h2{font-size:15px}.gemboss-md-h3{font-size:var(--gemboss-fs-body);color:var(--gemboss-text-muted)}.gemboss-md-list{margin:0 0 8px;padding-left:20px}.gemboss-md-list li{margin:2px 0}.gemboss-md-quote{margin:0 0 8px;padding:2px 0 2px 12px;border-left:3px solid var(--gemboss-divider);color:var(--gemboss-text-muted)}.gemboss-md-rule{margin:12px 0;border:0;border-top:1px solid var(--gemboss-divider)}.gemboss-md-code{padding:1px 6px;border-radius:6px;background:var(--gemboss-primary-soft);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em;word-break:break-word}.gemboss-md-tablewrap{margin:0 0 12px;overflow-x:auto}.gemboss-md-table{border-collapse:collapse;font-size:var(--gemboss-fs-caption);min-width:100%}.gemboss-md-table th,.gemboss-md-table td{border:1px solid var(--gemboss-divider);padding:6px 8px;text-align:left;vertical-align:top;white-space:nowrap}.gemboss-md-table th{background:var(--gemboss-primary-soft);font-weight:600}.gemboss-md-imglink{display:inline-block;max-width:100%;margin:4px 0 8px;border-radius:8px;line-height:0}.gemboss-md-imglink:focus-visible{outline:2px solid var(--ui-focus, #5661f5);outline-offset:2px}.gemboss-md-img{display:block;max-width:100%;max-height:320px;height:auto;border:1px solid var(--gemboss-divider);border-radius:8px;background:var(--gemboss-primary-soft);object-fit:contain}.gemboss-md-codeblock{position:relative;margin:0 0 12px;border:1px solid var(--gemboss-divider);border-radius:8px;background:var(--gemboss-primary-soft);overflow:hidden}.gemboss-md-codelang{display:block;padding:4px 12px 0;color:var(--gemboss-text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.gemboss-md-codeblock pre{margin:0;padding:8px 12px;overflow-x:auto}.gemboss-md-codeblock code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5;white-space:pre}.gemboss-md-codemore{display:block;width:100%;padding:6px 12px;border:0;border-top:1px solid var(--gemboss-divider);background:transparent;color:var(--gemboss-text-muted);font-size:12px;text-align:left;cursor:pointer}.gemboss-md-codemore:hover{background:#00000008}.gemboss-narr-row.source{align-items:flex-start}.gemboss-narr-source{min-width:0;flex:1}.gemboss-narr-source-head{font-size:11px;color:var(--gemboss-text-muted, #686b71);margin-bottom:4px}.gemboss-narr-source-head code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gemboss-narr-source-code{margin:0;padding:8px 12px;border-radius:8px;max-height:220px;overflow:auto;background:var(--gemboss-primary-soft, #f2f3f5);border:1px solid var(--gemboss-divider, #e5e7ea);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--gemboss-fs-micro);line-height:17px;white-space:pre;tab-size:2}.gemboss-narr-source-code .c-com{color:#6a7a86;font-style:italic}.gemboss-narr-source-code .c-str{color:#9a3412}.gemboss-narr-source-code .c-num{color:#1d6fa5}.gemboss-narr-source-code .c-kw{color:#7c3aed;font-weight:600}.gemboss-narr-source-code .c-key{color:#0b6b3a}.gemboss-narr-source-code .c-tag{color:#b0197a}.gemboss-narr-source-code .c-attr{color:#7c3aed}.gemboss-narr-source-code .c-pun{color:#6a6d73}@media (max-width: 520px){.gemboss-narr-source-code{max-height:160px;font-size:11px}}.gemboss-narr-dot-quiet{visibility:hidden}
|
package/src/collections.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--ui-coll-head-bg: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-hover: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-selected: color-mix(in srgb, var(--ui-text, #1b1c1e) 6%, var(--ui-surface, #fff));--ui-coll-check-w: 40px}.ui-table-wrap.ui-table-wrap--flush{border:0;border-radius:0;box-shadow:none;background:transparent}.ui-table--sticky-first tr{background:var(--ui-surface)}.ui-table--sticky-first tbody tr:hover{background:var(--ui-surface-2)}.ui-table--sticky-first :is(th,td):first-child{position:sticky;left:0;z-index:1;background:inherit}@supports (animation-timeline: scroll()){.ui-table-wrap:has(>.ui-table--sticky-first){scroll-timeline:--ui-coll-x inline}.ui-table--sticky-first :is(th,td):first-child{animation:ui-coll-edge linear both;animation-timeline:--ui-coll-x;animation-range:0 24px}}@keyframes ui-coll-edge{0%{box-shadow:none}to{box-shadow:1px 0 0 var(--ui-border),6px 0 8px -6px #0000002e}}.ui-table--compact :is(td,tbody th){padding-block:6px}.ui-table--compact thead th{padding-block:6px}.ui-table__totals>tr{background:var(--ui-coll-head-bg)}.ui-table__totals>tr>:is(td,th){background:var(--ui-coll-head-bg);font-weight:650;color:var(--ui-text);border-top:1px solid var(--ui-border);border-bottom:0}.ui-table__footer{padding:8px 12px;background:var(--ui-coll-head-bg);border-top:1px solid var(--ui-border);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center}.ui-table th.ui-table__rowhead{font-weight:450;color:var(--ui-text);text-align:left}.ui-table th.ui-table__rowhead:not(.is-num){white-space:normal;min-width:9.0625rem;overflow-wrap:anywhere}.ui-table th.ui-table__rowhead>a,.ui-table:where(:not(.ui-table--index)) tbody :is(td,th) li>a{display:inline-flex;align-items:center;min-height:24px}.ui-table:where(:not(.ui-table--index)) tbody :is(td,th){vertical-align:top}.ui-table:where(:not(.ui-table--index)) tbody :is(td>a,th.ui-table__rowhead>a,:is(td,th) li>a){margin-block:calc((1lh - 24px)/2)}.ui-table__sort{display:flex;width:max-content;max-width:100%;align-items:center;gap:4px;min-height:24px;margin-block:-2px;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:inherit;text-decoration:none;cursor:pointer;white-space:nowrap}.ui-table__sort:hover{color:var(--ui-text)}.ui-table__sort:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px;border-radius:4px}.ui-table__sort:after{content:"";flex:none;width:16px;height:16px;background:currentColor;opacity:0;-webkit-mask:var(--ui-coll-arrow) center / 16px no-repeat;mask:var(--ui-coll-arrow) center / 16px no-repeat;--ui-coll-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3.5v9M4.5 9 8 12.5 11.5 9' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}.ui-table__sort:is(:hover,:focus-visible):after{opacity:.45}th[aria-sort=ascending]>.ui-table__sort:after,th[aria-sort=descending]>.ui-table__sort:after{opacity:1}th[aria-sort=ascending]>.ui-table__sort:after{transform:rotate(180deg)}th[aria-sort=ascending]>.ui-table__sort,th[aria-sort=descending]>.ui-table__sort{color:var(--ui-text)}.ui-table .is-num>.ui-table__sort{flex-direction:row-reverse;margin-left:auto}.ui-trunc{display:block;max-width:var(--ui-trunc, 32ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-clamp-2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;white-space:normal;overflow-wrap:anywhere}.ui-index{position:relative;container:ui-index / inline-size;min-width:0}.ui-table--index{font-size:var(--ui-fs-body)}.ui-table--index tr{background:var(--ui-surface)}.ui-table.ui-table--index thead th{padding:8px 6px;background:var(--ui-coll-head-bg);color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;font-weight:550;text-transform:none;letter-spacing:0}.ui-table.ui-table--index :is(td,tbody th){padding:6px;line-height:20px;white-space:nowrap;vertical-align:middle;border-bottom:0;border-top:1px solid var(--ui-border)}.ui-table.ui-table--index :is(th,td):where(:first-child){padding-left:var(--ui-space-3)}.ui-table.ui-table--index :is(th,td):where(:last-child){padding-right:var(--ui-space-3)}.ui-table--index tbody tr:hover{background:var(--ui-coll-hover)}.ui-table--index tbody tr:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-table--index tbody tr:is([data-href],.is-linked){cursor:pointer}.ui-table--index tbody tr:has(.ui-table__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-table__title:focus-visible{outline:none}.ui-table__primary{min-width:0}.ui-table__primary-inner{display:flex;align-items:center;gap:var(--ui-space-3);min-width:0}.ui-table__primary-text{min-width:0}.ui-table__title{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-weight:650;text-decoration:none}a.ui-table__title:hover{text-decoration:underline}.ui-table--index .ui-table__title+.ui-sub,.ui-table--index .ui-sub{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:0;line-height:16px}.ui-table--index td>a.ui-table__title{display:block;min-height:0}.ui-table--index td>.ui-table__primary-inner>a.ui-table__title,.ui-table--index .ui-table__primary-text>a.ui-table__title{line-height:20px}.ui-table.ui-table--index .ui-table__check{width:var(--ui-coll-check-w);padding:6px 8px 6px 12px}.ui-table.ui-table--index thead .ui-table__check{padding:8px 8px 8px 12px}.ui-table__checkbox{display:flex;width:max-content;align-items:center;justify-content:center;min-width:24px;min-height:24px;margin:-2px 0;cursor:pointer}.ui-table__checkbox>input,.ui-list__check>input{width:16px;height:16px;margin:0;accent-color:var(--ui-accent);cursor:pointer}.ui-table__checkbox>input:focus-visible,.ui-list__check>input:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-table--index :is(.ui-table__check,.ui-table__primary){position:sticky;z-index:1;background:inherit}.ui-table--index .ui-table__check,.ui-table--index .ui-table__primary{left:0}.ui-table--index:has(.ui-table__check) .ui-table__primary{left:var(--ui-coll-check-w)}.ui-table__actions{width:1%;text-align:right}.ui-table__actions>*{vertical-align:middle}.ui-row-actions{display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-bulkbar{position:relative;z-index:3;display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;min-height:38px;margin-bottom:-38px;padding:4px 8px 4px 12px;background:var(--ui-surface);border:1px solid var(--ui-border);border-bottom-color:transparent;border-radius:var(--ui-radius-lg) var(--ui-radius-lg) 0 0;font-size:var(--ui-fs-body)}.ui-bulkbar[hidden]{display:none}.ui-bulkbar__count{flex:none;font-weight:550;font-variant-numeric:tabular-nums;white-space:nowrap}.ui-bulkbar__actions{display:inline-flex;flex-wrap:wrap;gap:var(--ui-space-2);margin-left:auto}.ui-bulkbar .ui-table__checkbox{margin-right:4px}.ui-bulkbar[data-fit=pending]{flex-wrap:nowrap}.ui-bulkbar[data-fit=pending]>.ui-bulkbar__actions{flex:0 1 auto;flex-wrap:nowrap;min-width:0;overflow:hidden}.ui-bulkbar__actions>.ui-bulkbar__more{flex:none}.ui-bulkbar__measure{position:absolute;top:0;left:0;display:inline-flex;gap:var(--ui-space-2);height:0;overflow:hidden;visibility:hidden;pointer-events:none;white-space:nowrap}.ui-bulkbar__measure>*{flex:none}.ui-index__sortbar{display:none}@container ui-index (max-width: 768px){.ui-table--index,.ui-table--index tbody{display:block;width:100%}.ui-table--index thead{display:none}.ui-table--index tbody tr{position:relative;display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 12px;min-height:44px;box-sizing:border-box;padding:10px 12px;border-top:1px solid var(--ui-border)}.ui-table--index tbody tr:first-child{border-top:0}.ui-table--index tbody tr:has(>.ui-table__check){padding-left:48px}.ui-table.ui-table--index tbody :is(td,th){display:block;padding:0;border:0;position:static;background:none;white-space:nowrap}.ui-table--index tbody .ui-table__primary{flex:1 0 100%;white-space:normal}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions){flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:18px}.ui-table--index tbody td[data-label]:not(.ui-table__primary):before{content:attr(data-label) " ";color:var(--ui-text-muted)}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-trunc{display:inline-block;vertical-align:bottom}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-sub{display:inline;margin-left:6px}.ui-table--index tbody td.is-num{text-align:left}.ui-table--index tbody td[data-condensed=hide]{display:none}.ui-table.ui-table--index tbody .ui-table__check{position:absolute;left:4px;top:4px;width:auto;padding:0}.ui-table.ui-table--index tbody .ui-table__actions{order:99;margin-left:auto;width:auto;padding:0;align-self:center}.ui-table--index .ui-table__checkbox{min-width:44px;min-height:44px;margin:0}.ui-table--index .ui-table__title,.ui-table--index .ui-sub,.ui-table--index .ui-table__title+.ui-sub{max-width:none}.ui-table--index tbody a.ui-table__title{position:relative;z-index:1;padding-block:2px;margin-block:-2px}.ui-index__sortbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);margin:0 0 var(--ui-space-3);font-size:var(--ui-fs-caption);color:var(--ui-text-muted)}.ui-index .ui-bulkbar{margin-bottom:var(--ui-space-2);border-bottom-color:var(--ui-border);border-radius:var(--ui-radius-lg)}.ui-index .ui-table-wrap{overflow-x:visible}}.ui-list{container:ui-list / inline-size;margin:0;padding:0;list-style:none;background:var(--ui-surface);border:1px solid var(--ui-border);border-radius:var(--ui-radius-lg);box-shadow:var(--ui-card-shadow)}.ui-list--flush{border:0;border-radius:0;box-shadow:none;background:transparent}.ui-list__item{position:relative;display:flex;align-items:flex-start;gap:var(--ui-space-3);box-sizing:border-box;padding:var(--ui-space-3);min-height:44px;border-top:1px solid var(--ui-border)}.ui-list>.ui-list__item:first-child{border-top:0}.ui-list>.ui-list__item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.ui-list>.ui-list__item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.ui-list__item:has(>.ui-list__body>.ui-list__title[href]):hover{background:var(--ui-coll-hover)}.ui-list__item:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-list__item:has(>.ui-list__body>.ui-list__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__media{flex:none;display:flex;align-items:center;min-height:40px}.ui-list__body{flex:1 1 auto;min-width:0}.ui-list__title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;font-weight:650;text-decoration:none}.ui-list__title[href]:after{content:"";position:absolute;inset:0;z-index:0}.ui-list__title:focus-visible{outline:none}.ui-list__sub{margin:0;color:var(--ui-text-muted);font-size:var(--ui-fs-body);line-height:20px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}.ui-list__meta{margin:2px 0 0;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list__badges{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.ui-list__aside{flex:none;align-self:center;color:var(--ui-text);font-variant-numeric:tabular-nums;text-align:right}.ui-list__actions{flex:none;align-self:center;display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-list__item :is(.ui-list__actions,.ui-list__aside a,.ui-list__body a:not(.ui-list__title),button,input,select,textarea,label,summary,details){position:relative;z-index:1}.ui-list__item>:is(.ui-list__actions,.ui-list__aside) a:not(.ui-btn){display:inline-flex;align-items:center;min-height:24px}@container ui-list (max-width: 400px){.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"media body body" "media aside actions";gap:0;align-items:start}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__media{grid-area:media;margin-inline-end:var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__body{grid-area:body}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__aside{grid-area:aside;justify-self:start;align-self:center;margin-top:4px;text-align:left}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__actions{grid-area:actions;justify-self:end;align-self:center;margin:4px 0 0 var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item--disclosure>:is(.ui-list__aside,.ui-list__actions){margin-top:8px}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child){grid-template-columns:auto minmax(0,1fr) auto auto;grid-template-areas:"media body aside actions";align-items:center}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>:is(.ui-list__aside,.ui-list__actions){margin-top:0}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>.ui-list__aside{margin-inline-start:var(--ui-space-3);text-align:right}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__panel{grid-column:1 / -1}}.ui-list__item--disclosure{flex-wrap:wrap}.ui-list__toggle{display:block;flex:1 1 0;min-width:0;min-height:24px;margin:0;padding:0;border:0;border-radius:var(--ui-radius-sm, 4px);background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}.ui-list__toggle:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-list__toggle>.ui-list__meta{display:block}@media (hover: hover){.ui-list__item--disclosure:not(.is-open):has(>.ui-list__toggle:hover){background:var(--ui-coll-hover)}}.ui-list__chev{display:inline-block;width:16px;height:16px;margin:0 4px 0 -2px;vertical-align:-3px;background:var(--ui-text-muted);-webkit-mask:var(--ui-chev) center / 16px no-repeat;mask:var(--ui-chev) center / 16px no-repeat;transition:transform .15s;--ui-chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}.ui-list__item--disclosure.is-open>.ui-list__toggle .ui-list__chev{transform:rotate(90deg)}@media (forced-colors: active){.ui-list__chev{forced-color-adjust:none;background:CanvasText}}.ui-list__panel{flex:1 0 100%;min-width:0;margin-top:var(--ui-space-2)}.ui-list__panel[hidden]{display:none}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__toggle{min-height:44px}}@media (prefers-reduced-motion: reduce){.ui-list__chev{transition:none}}.ui-resource>.ui-bulkbar{margin-bottom:0;border-bottom-color:var(--ui-border)}.ui-resource>.ui-bulkbar:has(+.ui-list--flush){border-width:0 0 1px;border-radius:0}.ui-resource>.ui-list,.ui-resource>[aria-busy]>.ui-list{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.ui-list__check{display:flex;flex:none;align-items:center;justify-content:center;min-width:24px;min-height:24px;cursor:pointer}.ui-list__check:not(:last-child){margin-inline-end:8px}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__check{min-width:44px;min-height:44px;margin-block:-2px;margin-inline-start:-12px}.ui-list__check:not(:last-child){margin-inline-end:-2px}.ui-resource>.ui-bulkbar>.ui-table__checkbox{min-width:44px;min-height:44px;margin:-8px -8px -8px -12px}}.ui-thumb{display:block;flex:none;width:40px;height:40px;box-sizing:border-box;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background:var(--ui-surface-2);overflow:hidden;object-fit:cover}.ui-thumb--xs{width:24px;height:24px;border-radius:var(--ui-radius-sm)}.ui-thumb--md{width:60px;height:60px}.ui-thumb--lg{width:80px;height:80px}.ui-thumb>img{display:block;width:100%;height:100%;object-fit:cover}.ui-list--compact>.ui-list__item{display:block;padding:0;min-height:0}.ui-list__row{display:flex;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;width:100%;min-height:36px;padding:8px 12px;border:0;background:none;color:var(--ui-text);font:inherit;font-size:var(--ui-fs-body);line-height:20px;text-align:left;text-decoration:none;border-radius:inherit}:is(a,button).ui-list__row{cursor:pointer}:is(a,button).ui-list__row:hover{background:var(--ui-coll-hover)}:is(a,button).ui-list__row:focus-visible{outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__row[aria-current=page],.ui-list__row.is-selected{background:var(--ui-coll-selected)}.ui-list__icon{flex:none;display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;color:var(--ui-text-muted)}.ui-list__icon>svg{width:16px;height:16px}.ui-list__label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-list__row>.ui-list__meta{flex:none;margin:0;font-variant-numeric:tabular-nums}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__row{min-height:44px}}.ui-list--activity>.ui-list__item{display:grid;grid-template-columns:20px minmax(0,1fr) auto;column-gap:var(--ui-space-2);align-items:start;padding:8px 12px;min-height:36px;border-top:0}.ui-list--activity>.ui-list__item:before{content:"";position:absolute;left:21.5px;top:0;bottom:0;width:1px;background:var(--ui-border)}.ui-list--activity>.ui-list__item:first-child:before{top:14px}.ui-list--activity>.ui-list__item:last-child:before{bottom:calc(100% - 14px)}.ui-list--activity>.ui-list__item:only-child:before{display:none}.ui-list__dot{position:relative;z-index:1;width:8px;height:8px;margin:6px 0 0 6px;border-radius:50%;background:var(--ui-text-muted);box-shadow:0 0 0 3px var(--ui-surface)}.ui-list__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-list__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-list__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-list__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-list--activity .ui-list__label{display:block;white-space:nowrap}.ui-list--activity a.ui-list__label{position:relative;color:var(--ui-text);text-decoration:none;padding-block:2px;margin-block:-2px}.ui-list--activity a.ui-list__label:hover{text-decoration:underline}.ui-list--activity a.ui-list__label:focus-visible{outline:2px solid var(--ui-focus);outline-offset:0;border-radius:4px}.ui-list--activity .ui-list__detail{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list--activity time,.ui-list--activity .ui-list__time{color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;white-space:nowrap;font-variant-numeric:tabular-nums}.ui-list__content{margin-top:4px;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;overflow-wrap:anywhere}.ui-list__content>p{margin:0}.ui-list__content>p+p{margin-top:4px}.ui-list--wrap>.ui-list__item>*>:is(.ui-list__label,.ui-list__detail,.ui-list__title){white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}.ui-list--wrap>.ui-list__item>.ui-list__row{align-items:flex-start}@media (pointer: coarse),(max-width: 47.9975em){.ui-list--wrap>.ui-list__item>.ui-list__row{padding-block:12px}}.ui-list--wrap>.ui-list__item>.ui-list__row>.ui-list__meta{line-height:20px}.ui-cardgrid{--ui-cardgrid-min: 240px;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--ui-cardgrid-min),100%),1fr));gap:var(--ui-space-4);margin:0;padding:0;list-style:none}.ui-cardgrid[data-min="200"]{--ui-cardgrid-min: 200px}.ui-cardgrid[data-min="320"]{--ui-cardgrid-min: 320px}.ui-cardgrid>*{min-width:0}.ui-board{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(240px,1fr);gap:var(--ui-space-4);align-items:start;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;padding-bottom:4px}@media (max-width: 47.9975em){.ui-board{grid-auto-columns:78%}}.ui-board__col{display:flex;flex-direction:column;gap:var(--ui-space-2);min-width:0;padding:var(--ui-space-2);scroll-snap-align:start;background:var(--ui-coll-head-bg);border-radius:var(--ui-radius-lg)}.ui-board__head{display:flex;align-items:center;gap:var(--ui-space-2);min-height:28px;padding:0 4px;font-size:var(--ui-fs-body);font-weight:650}.ui-board__name{min-width:0;margin:0;font:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-board__count{margin-left:auto;color:var(--ui-text-muted);font-weight:450;font-variant-numeric:tabular-nums}.ui-board__dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--ui-text-muted)}.ui-board__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-board__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-board__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-board__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-board__list{display:grid;gap:var(--ui-space-2);margin:0;padding:0;list-style:none}.ui-board__list>li{min-width:0}.ui-board__empty{margin:0;padding:var(--ui-space-4) var(--ui-space-2);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center;border:1px dashed var(--ui-border);border-radius:var(--ui-radius-md)}.ui-board__more>summary{list-style:none;justify-self:center;margin:4px auto 0;width:fit-content}.ui-board__more>summary::-webkit-details-marker{display:none}.ui-board__more[open]>summary{display:none}.ui-board__more{display:grid;gap:var(--ui-space-2)}.ui-board__next.ui-more{padding:4px 0 0}.ui-board__next .ui-more__error{color:var(--gemboss-danger-strong, #c70a24)}.ui-board[data-gb-move] .ui-board__list>li[data-id]{position:relative;border-radius:var(--ui-radius-lg);cursor:grab}.ui-board[data-gb-move] .ui-board__list>li[data-id]:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-board__list>li[data-gb-lifted]{outline:2px solid var(--ui-focus);outline-offset:2px;box-shadow:var(--gemboss-shadow-md, 0 4px 12px rgba(0,0,0,.12));border-radius:var(--ui-radius-lg)}.ui-board[data-gb-dragging] .ui-board__list>li[data-gb-lifted]{outline:0;opacity:.4}.ui-board__col[data-gb-over]{background:color-mix(in srgb,var(--ui-focus) 10%,var(--ui-coll-head-bg))}.ui-board__list>li[data-gb-drop]:before{content:"";position:absolute;left:0;right:0;height:2px;border-radius:1px;background:var(--ui-focus);pointer-events:none}.ui-board__list>li[data-gb-drop=before]:before{top:-5px}.ui-board__list>li[data-gb-drop=after]:before{bottom:-5px}.ui-empty--no-match{padding-block:32px}.ui-coll-error{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2) var(--ui-space-3);margin:var(--ui-space-3)}.ui-coll-error>:first-child{flex:1 1 240px;min-width:0}.ui-coll-count{margin-left:auto;color:var(--ui-text-muted);font-size:var(--ui-fs-body);font-variant-numeric:tabular-nums;white-space:nowrap}.ui-chip__x{margin-right:-4px;font-size:14px;line-height:1;opacity:.7}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]{position:relative}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>:not(.ui-bulkbar,.ui-coll-busy){opacity:.55;pointer-events:none;transition:opacity .15s}.ui-coll-busy{position:absolute;top:8px;right:8px;z-index:4}:is(.ui-skeleton--table,.ui-skeleton--list,.ui-skeleton--compact,.ui-skeleton--grid,.ui-skeleton--board) .ui-skeleton__line{height:8px;border-radius:4px}.ui-skeleton--table td .ui-skeleton__line{width:70%;margin-block:6px}.ui-skeleton--table td:first-child .ui-skeleton__line{width:85%}.ui-skeleton--table tbody tr:hover{background:none}.ui-skeleton__block{display:block;flex:none;width:40px;height:40px;border-radius:var(--ui-radius-md);background:var(--ui-surface-2)}.ui-skeleton__block--round{border-radius:50%;width:32px;height:32px}.ui-skeleton--list>.ui-list__item{align-items:center}.ui-skeleton--list .ui-list__body{display:grid;gap:12px}.ui-skeleton--list .ui-list__body>.ui-skeleton__line:last-child{width:60%}.ui-skeleton--compact .ui-list__row{gap:12px}.ui-skeleton--compact .ui-list__row>.ui-skeleton__line{flex:1 1 auto;max-width:60%}.ui-skeleton--grid .ui-card__body{display:grid;gap:12px;justify-items:stretch}.ui-skeleton--grid .ui-card__body>.ui-skeleton__line:last-child{width:50%}.ui-skeleton--board .ui-board__list>li{height:72px;border-radius:var(--ui-radius-md);background:var(--ui-surface)}@media (pointer: coarse){.ui-table__sort{min-height:44px;margin-block:-12px}.ui-table__checkbox{min-width:44px;min-height:44px;margin:-12px 0}}@media (pointer: coarse),(max-width: 47.9975em){.ui-table__sort{min-width:44px}}@media (prefers-reduced-motion: reduce){.ui-table--sticky-first :is(th,td):first-child{animation:none}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>*{transition:none}.ui-board{scroll-behavior:auto}}
|
|
1
|
+
:root{--ui-coll-head-bg: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-hover: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-selected: color-mix(in srgb, var(--ui-text, #1b1c1e) 6%, var(--ui-surface, #fff));--ui-coll-check-w: 40px}.ui-table-wrap.ui-table-wrap--flush{border:0;border-radius:0;box-shadow:none;background:transparent}.ui-table--sticky-first tr{background:var(--ui-surface)}.ui-table--sticky-first tbody tr:hover{background:var(--ui-surface-2)}.ui-table--sticky-first :is(th,td):first-child{position:sticky;left:0;z-index:1;background:inherit}@supports (animation-timeline: scroll()){.ui-table-wrap:has(>.ui-table--sticky-first){scroll-timeline:--ui-coll-x inline}.ui-table--sticky-first :is(th,td):first-child{animation:ui-coll-edge linear both;animation-timeline:--ui-coll-x;animation-range:0 24px}}@keyframes ui-coll-edge{0%{box-shadow:none}to{box-shadow:1px 0 0 var(--ui-border),6px 0 8px -6px #0000002e}}.ui-table--compact :is(td,tbody th){padding-block:6px}.ui-table--compact thead th{padding-block:6px}.ui-table__totals>tr{background:var(--ui-coll-head-bg)}.ui-table__totals>tr>:is(td,th){background:var(--ui-coll-head-bg);font-weight:650;color:var(--ui-text);border-top:1px solid var(--ui-border);border-bottom:0}.ui-table__footer{padding:8px 12px;background:var(--ui-coll-head-bg);border-top:1px solid var(--ui-border);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center}.ui-table th.ui-table__rowhead{font-weight:450;color:var(--ui-text);text-align:left}.ui-table th.ui-table__rowhead:not(.is-num){white-space:normal;min-width:9.0625rem;overflow-wrap:anywhere}.ui-table th.ui-table__rowhead>a,.ui-table:where(:not(.ui-table--index)) tbody :is(td,th) li>a{display:inline-flex;align-items:center;min-height:24px}.ui-table:where(:not(.ui-table--index)) tbody :is(td,th){vertical-align:top}.ui-table:where(:not(.ui-table--index)) tbody :is(td>a,th.ui-table__rowhead>a,:is(td,th) li>a){margin-block:calc((1lh - 24px)/2)}.ui-table__sort{display:flex;width:max-content;max-width:100%;align-items:center;gap:4px;min-height:24px;margin-block:-2px;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:inherit;text-decoration:none;cursor:pointer;white-space:nowrap}.ui-table__sort:hover{color:var(--ui-text)}.ui-table__sort:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px;border-radius:4px}.ui-table__sort:after{content:"";flex:none;width:16px;height:16px;background:currentColor;opacity:0;-webkit-mask:var(--ui-coll-arrow) center / 16px no-repeat;mask:var(--ui-coll-arrow) center / 16px no-repeat;--ui-coll-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3.5v9M4.5 9 8 12.5 11.5 9' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}.ui-table__sort:is(:hover,:focus-visible):after{opacity:.45}th[aria-sort=ascending]>.ui-table__sort:after,th[aria-sort=descending]>.ui-table__sort:after{opacity:1}th[aria-sort=ascending]>.ui-table__sort:after{transform:rotate(180deg)}th[aria-sort=ascending]>.ui-table__sort,th[aria-sort=descending]>.ui-table__sort{color:var(--ui-text)}.ui-table .is-num>.ui-table__sort{flex-direction:row-reverse;margin-left:auto}.ui-trunc{display:block;max-width:var(--ui-trunc, 32ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-clamp-2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;white-space:normal;overflow-wrap:anywhere}.ui-index{position:relative;container:ui-index / inline-size;min-width:0}.ui-table--index{font-size:var(--ui-fs-body)}.ui-table--index tr{background:var(--ui-surface)}.ui-table.ui-table--index thead th{padding:8px 6px;background:var(--ui-coll-head-bg);color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;font-weight:550;text-transform:none;letter-spacing:0}.ui-table.ui-table--index :is(td,tbody th){padding:6px;line-height:20px;white-space:nowrap;vertical-align:middle;border-bottom:0;border-top:1px solid var(--ui-border)}.ui-table.ui-table--index :is(th,td):where(:first-child){padding-left:var(--ui-space-3)}.ui-table.ui-table--index :is(th,td):where(:last-child){padding-right:var(--ui-space-3)}.ui-table--index tbody tr:hover{background:var(--ui-coll-hover)}.ui-table--index tbody tr:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-table--index tbody tr:is([data-href],.is-linked){cursor:pointer}.ui-table--index tbody tr:has(.ui-table__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-table__title:focus-visible{outline:none}.ui-table__primary{min-width:0}.ui-table__primary-inner{display:flex;align-items:center;gap:var(--ui-space-3);min-width:0}.ui-table__primary-text{min-width:0}.ui-table__title{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-weight:650;text-decoration:none}a.ui-table__title:hover{text-decoration:underline}.ui-table--index .ui-table__title+.ui-sub,.ui-table--index .ui-sub{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:0;line-height:16px}.ui-table--index td>a.ui-table__title{display:block;min-height:0}.ui-table--index td>.ui-table__primary-inner>a.ui-table__title,.ui-table--index .ui-table__primary-text>a.ui-table__title{line-height:20px}.ui-table.ui-table--index .ui-table__check{width:var(--ui-coll-check-w);padding:6px 8px 6px 12px}.ui-table.ui-table--index thead .ui-table__check{padding:8px 8px 8px 12px}.ui-table__checkbox{display:flex;width:max-content;align-items:center;justify-content:center;min-width:24px;min-height:24px;margin:-2px 0;cursor:pointer}.ui-table__checkbox>input,.ui-list__check>input{width:16px;height:16px;margin:0;accent-color:var(--ui-accent);cursor:pointer}.ui-table__checkbox>input:focus-visible,.ui-list__check>input:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-table--index :is(.ui-table__check,.ui-table__primary){position:sticky;z-index:1;background:inherit}.ui-table--index .ui-table__check,.ui-table--index .ui-table__primary{left:0}.ui-table--index:has(.ui-table__check) .ui-table__primary{left:var(--ui-coll-check-w)}.ui-table__actions{width:1%;text-align:right}.ui-table__actions>*{vertical-align:middle}.ui-row-actions{display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-bulkbar{position:relative;z-index:3;display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;min-height:38px;margin-bottom:-38px;padding:4px 8px 4px 12px;background:var(--ui-surface);border:1px solid var(--ui-border);border-bottom-color:transparent;border-radius:var(--ui-radius-lg) var(--ui-radius-lg) 0 0;font-size:var(--ui-fs-body)}.ui-bulkbar[hidden]{display:none}.ui-bulkbar__count{flex:none;font-weight:550;font-variant-numeric:tabular-nums;white-space:nowrap}.ui-bulkbar__actions{display:inline-flex;flex-wrap:wrap;gap:var(--ui-space-2);margin-left:auto}.ui-bulkbar .ui-table__checkbox{margin-right:4px}.ui-bulkbar[data-fit=pending]{flex-wrap:nowrap}.ui-bulkbar[data-fit=pending]>.ui-bulkbar__actions{flex:0 1 auto;flex-wrap:nowrap;min-width:0;overflow:hidden}.ui-bulkbar__actions>.ui-bulkbar__more{flex:none}.ui-bulkbar__measure{position:absolute;top:0;left:0;display:inline-flex;gap:var(--ui-space-2);height:0;overflow:hidden;visibility:hidden;pointer-events:none;white-space:nowrap}.ui-bulkbar__measure>*{flex:none}.ui-index__sortbar{display:none}@container ui-index (max-width: 768px){.ui-table--index,.ui-table--index tbody{display:block;width:100%}.ui-table--index thead{display:none}.ui-table--index tbody tr{position:relative;display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 12px;min-height:44px;box-sizing:border-box;padding:10px 12px;border-top:1px solid var(--ui-border)}.ui-table--index tbody tr:first-child{border-top:0}.ui-table--index tbody tr:has(>.ui-table__check){padding-left:48px}.ui-table.ui-table--index tbody :is(td,th){display:block;padding:0;border:0;position:static;background:none;white-space:nowrap}.ui-table--index tbody .ui-table__primary{flex:1 0 100%;white-space:normal}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions){flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:18px}.ui-table--index tbody td[data-label]:not(.ui-table__primary):before{content:attr(data-label) " ";color:var(--ui-text-muted)}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-trunc{display:inline-block;vertical-align:bottom}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-sub{display:inline;margin-left:6px}.ui-table--index tbody td.is-num{text-align:left}.ui-table--index tbody td[data-condensed=hide]{display:none}.ui-table.ui-table--index tbody .ui-table__check{position:absolute;left:4px;top:4px;width:auto;padding:0}.ui-table.ui-table--index tbody .ui-table__actions{order:99;margin-left:auto;width:auto;padding:0;align-self:center}.ui-table--index .ui-table__checkbox{min-width:44px;min-height:44px;margin:0}.ui-table--index .ui-table__title,.ui-table--index .ui-sub,.ui-table--index .ui-table__title+.ui-sub{max-width:none}.ui-table--index tbody a.ui-table__title{position:relative;z-index:1;padding-block:2px;margin-block:-2px}.ui-index__sortbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);margin:0 0 var(--ui-space-3);font-size:var(--ui-fs-caption);color:var(--ui-text-muted)}.ui-index .ui-bulkbar{margin-bottom:var(--ui-space-2);border-bottom-color:var(--ui-border);border-radius:var(--ui-radius-lg)}.ui-index .ui-table-wrap{overflow-x:visible}}.ui-list{container:ui-list / inline-size;margin:0;padding:0;list-style:none;background:var(--ui-surface);border:1px solid var(--ui-border);border-radius:var(--ui-radius-lg);box-shadow:var(--ui-card-shadow)}.ui-list--flush{border:0;border-radius:0;box-shadow:none;background:transparent}.ui-list__item{position:relative;display:flex;align-items:flex-start;gap:var(--ui-space-3);box-sizing:border-box;padding:var(--ui-space-3);min-height:44px;border-top:1px solid var(--ui-border)}.ui-list>.ui-list__item:first-child{border-top:0}.ui-list>.ui-list__item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.ui-list>.ui-list__item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.ui-list__item:has(>.ui-list__body>.ui-list__title[href]):hover{background:var(--ui-coll-hover)}.ui-list__item:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-list__item:has(>.ui-list__body>.ui-list__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__media{flex:none;display:flex;align-items:center;min-height:40px}.ui-list__body{flex:1 1 auto;min-width:0}.ui-list__title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;font-weight:650;text-decoration:none}.ui-list__title[href]:after{content:"";position:absolute;inset:0;z-index:0}.ui-list__title:focus-visible{outline:none}.ui-list__sub{margin:0;color:var(--ui-text-muted);font-size:var(--ui-fs-body);line-height:20px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}.ui-list__meta{margin:2px 0 0;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list__badges{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.ui-list__aside{flex:none;align-self:center;color:var(--ui-text);font-variant-numeric:tabular-nums;text-align:right}.ui-list__actions{flex:none;align-self:center;display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-list__item :is(.ui-list__actions,.ui-list__aside a,.ui-list__body a:not(.ui-list__title),button,input,select,textarea,label,summary,details){position:relative;z-index:1}.ui-list__item>:is(.ui-list__actions,.ui-list__aside) a:not(.ui-btn){display:inline-flex;align-items:center;min-height:24px}@container ui-list (max-width: 400px){.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"media body body" "media aside actions";gap:0;align-items:start}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__media{grid-area:media;margin-inline-end:var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__body{grid-area:body}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__aside{grid-area:aside;justify-self:start;align-self:center;margin-top:4px;text-align:left}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__actions{grid-area:actions;justify-self:end;align-self:center;margin:4px 0 0 var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item--disclosure>:is(.ui-list__aside,.ui-list__actions){margin-top:8px}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child){grid-template-columns:auto minmax(0,1fr) auto auto;grid-template-areas:"media body aside actions";align-items:center}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>:is(.ui-list__aside,.ui-list__actions){margin-top:0}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>.ui-list__aside{margin-inline-start:var(--ui-space-3);text-align:right}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__panel{grid-column:1 / -1}}.ui-list__item--disclosure{flex-wrap:wrap}.ui-list__toggle{display:block;flex:1 1 0;min-width:0;min-height:24px;margin:0;padding:0;border:0;border-radius:var(--ui-radius-sm, 4px);background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}.ui-list__toggle:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-list__toggle>.ui-list__meta{display:block}@media (hover: hover){.ui-list__item--disclosure:not(.is-open):has(>.ui-list__toggle:hover){background:var(--ui-coll-hover)}}.ui-list__chev{display:inline-block;width:16px;height:16px;margin:0 4px 0 -2px;vertical-align:-3px;background:var(--ui-text-muted);-webkit-mask:var(--ui-chev) center / 16px no-repeat;mask:var(--ui-chev) center / 16px no-repeat;transition:transform .15s;--ui-chev: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}.ui-list__item--disclosure.is-open>.ui-list__toggle .ui-list__chev{transform:rotate(90deg)}@media (forced-colors: active){.ui-list__chev{forced-color-adjust:none;background:CanvasText}}.ui-list__panel{flex:1 0 100%;min-width:0;margin-top:var(--ui-space-2)}.ui-list__panel[hidden]{display:none}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__toggle{min-height:44px}}@media (prefers-reduced-motion: reduce){.ui-list__chev{transition:none}}.ui-resource>.ui-bulkbar{margin-bottom:0;border-bottom-color:var(--ui-border)}.ui-resource>.ui-bulkbar:has(+.ui-list--flush){border-width:0 0 1px;border-radius:0}.ui-resource>.ui-list,.ui-resource>[aria-busy]>.ui-list{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.ui-list__check{display:flex;flex:none;align-items:center;justify-content:center;min-width:24px;min-height:24px;cursor:pointer}.ui-list__check:not(:last-child){margin-inline-end:8px}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__check{min-width:44px;min-height:44px;margin-block:-2px;margin-inline-start:-12px}.ui-list__check:not(:last-child){margin-inline-end:-2px}.ui-resource>.ui-bulkbar>.ui-table__checkbox{min-width:44px;min-height:44px;margin:-8px -8px -8px -12px}}.ui-thumb{display:block;flex:none;width:40px;height:40px;box-sizing:border-box;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background:var(--ui-surface-2);overflow:hidden;object-fit:cover}.ui-thumb--xs{width:24px;height:24px;border-radius:var(--ui-radius-sm)}.ui-thumb--md{width:60px;height:60px}.ui-thumb--lg{width:80px;height:80px}.ui-thumb>img{display:block;width:100%;height:100%;object-fit:cover}.ui-list--compact>.ui-list__item{display:block;padding:0;min-height:0}.ui-list__row{display:flex;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;width:100%;min-height:36px;padding:8px 12px;border:0;background:none;color:var(--ui-text);font:inherit;font-size:var(--ui-fs-body);line-height:20px;text-align:left;text-decoration:none;border-radius:inherit}:is(a,button).ui-list__row{cursor:pointer}:is(a,button).ui-list__row:hover{background:var(--ui-coll-hover)}:is(a,button).ui-list__row:focus-visible{outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__row[aria-current=page],.ui-list__row.is-selected{background:var(--ui-coll-selected)}.ui-list__icon{flex:none;display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;color:var(--ui-text-muted)}.ui-list__icon>svg{width:16px;height:16px}.ui-list__label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-list__row>.ui-list__meta{flex:none;margin:0;font-variant-numeric:tabular-nums}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__row{min-height:44px}}.ui-list--activity>.ui-list__item{display:grid;grid-template-columns:20px minmax(0,1fr) auto;column-gap:var(--ui-space-2);align-items:start;padding:8px 12px;min-height:36px;border-top:0}.ui-list--activity>.ui-list__item:before{content:"";position:absolute;left:21.5px;top:0;bottom:0;width:1px;background:var(--ui-border)}.ui-list--activity>.ui-list__item:first-child:before{top:14px}.ui-list--activity>.ui-list__item:last-child:before{bottom:calc(100% - 14px)}.ui-list--activity>.ui-list__item:only-child:before{display:none}.ui-list__dot{position:relative;z-index:1;width:8px;height:8px;margin:6px 0 0 6px;border-radius:50%;background:var(--ui-text-muted);box-shadow:0 0 0 3px var(--ui-surface)}.ui-list__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-list__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-list__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-list__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-list--activity .ui-list__label{display:block;white-space:nowrap}.ui-list--activity a.ui-list__label{position:relative;color:var(--ui-text);text-decoration:none;padding-block:2px;margin-block:-2px}.ui-list--activity a.ui-list__label:hover{text-decoration:underline}.ui-list--activity a.ui-list__label:focus-visible{outline:2px solid var(--ui-focus);outline-offset:0;border-radius:4px}.ui-list--activity .ui-list__detail{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list--activity time,.ui-list--activity .ui-list__time{color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;white-space:nowrap;font-variant-numeric:tabular-nums}.ui-list__content{margin-top:4px;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;overflow-wrap:anywhere}.ui-list__content>p{margin:0}.ui-list__content>p+p{margin-top:4px}.ui-list--wrap>.ui-list__item>*>:is(.ui-list__label,.ui-list__detail,.ui-list__title){white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}.ui-list--wrap>.ui-list__item>.ui-list__row{align-items:flex-start}@media (pointer: coarse),(max-width: 47.9975em){.ui-list--wrap>.ui-list__item>.ui-list__row{padding-block:12px}}.ui-list--wrap>.ui-list__item>.ui-list__row>.ui-list__meta{line-height:20px}.ui-cardgrid{--ui-cardgrid-min: 240px;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--ui-cardgrid-min),100%),1fr));gap:var(--ui-space-4);margin:0;padding:0;list-style:none}.ui-cardgrid[data-min="200"]{--ui-cardgrid-min: 200px}.ui-cardgrid[data-min="320"]{--ui-cardgrid-min: 320px}.ui-cardgrid>*{min-width:0}.ui-board{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(240px,1fr);gap:var(--ui-space-4);align-items:start;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;padding-bottom:4px}@media (max-width: 47.9975em){.ui-board{grid-auto-columns:78%}}.ui-board__col{display:flex;flex-direction:column;gap:var(--ui-space-2);min-width:0;padding:var(--ui-space-2);scroll-snap-align:start;background:var(--ui-coll-head-bg);border-radius:var(--ui-radius-lg)}.ui-board__head{display:flex;align-items:center;gap:var(--ui-space-2);min-height:28px;padding:0 4px;font-size:var(--ui-fs-body);font-weight:650}.ui-board__name{min-width:0;margin:0;font:inherit;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-board__count{margin-left:auto;color:var(--ui-text-muted);font-weight:450;font-variant-numeric:tabular-nums}.ui-board__dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--ui-text-muted)}.ui-board__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-board__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-board__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-board__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-board__list{display:grid;gap:var(--ui-space-2);margin:0;padding:0;list-style:none}.ui-board__list>li{min-width:0}.ui-board__empty{margin:0;padding:var(--ui-space-4) var(--ui-space-2);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center;border:1px dashed var(--ui-border);border-radius:var(--ui-radius-md)}.ui-board__more>summary{list-style:none;justify-self:center;margin:4px auto 0;width:fit-content}.ui-board__more>summary::-webkit-details-marker{display:none}.ui-board__more[open]>summary{display:none}.ui-board__more{display:grid;gap:var(--ui-space-2)}.ui-board__next.ui-more{padding:4px 0 0}.ui-board__next .ui-more__error{color:var(--gemboss-danger-strong, #c70a24)}.ui-board[data-gb-move] .ui-board__list>li[data-id]{position:relative;border-radius:var(--ui-radius-lg);cursor:grab}.ui-board[data-gb-move] .ui-board__list>li[data-id]:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-board__list>li[data-gb-lifted]{outline:2px solid var(--ui-focus);outline-offset:2px;box-shadow:var(--gemboss-shadow-raised);border-radius:var(--ui-radius-lg)}.ui-board[data-gb-dragging] .ui-board__list>li[data-gb-lifted]{outline:0;opacity:.4}.ui-board__col[data-gb-over]{background:color-mix(in srgb,var(--ui-focus) 10%,var(--ui-coll-head-bg))}.ui-board__list>li[data-gb-drop]:before{content:"";position:absolute;left:0;right:0;height:2px;border-radius:1px;background:var(--ui-focus);pointer-events:none}.ui-board__list>li[data-gb-drop=before]:before{top:-5px}.ui-board__list>li[data-gb-drop=after]:before{bottom:-5px}.ui-empty--no-match{padding-block:32px}.ui-coll-error{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2) var(--ui-space-3);margin:var(--ui-space-3)}.ui-coll-error>:first-child{flex:1 1 240px;min-width:0}.ui-coll-count{margin-left:auto;color:var(--ui-text-muted);font-size:var(--ui-fs-body);font-variant-numeric:tabular-nums;white-space:nowrap}.ui-chip__x{margin-right:-4px;font-size:14px;line-height:1;opacity:.7}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]{position:relative}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>:not(.ui-bulkbar,.ui-coll-busy){opacity:.55;pointer-events:none;transition:opacity .15s}.ui-coll-busy{position:absolute;top:8px;right:8px;z-index:4}:is(.ui-skeleton--table,.ui-skeleton--list,.ui-skeleton--compact,.ui-skeleton--grid,.ui-skeleton--board) .ui-skeleton__line{height:8px;border-radius:4px}.ui-skeleton--table td .ui-skeleton__line{width:70%;margin-block:6px}.ui-skeleton--table td:first-child .ui-skeleton__line{width:85%}.ui-skeleton--table tbody tr:hover{background:none}.ui-skeleton__block{display:block;flex:none;width:40px;height:40px;border-radius:var(--ui-radius-md);background:var(--ui-surface-2)}.ui-skeleton__block--round{border-radius:50%;width:32px;height:32px}.ui-skeleton--list>.ui-list__item{align-items:center}.ui-skeleton--list .ui-list__body{display:grid;gap:12px}.ui-skeleton--list .ui-list__body>.ui-skeleton__line:last-child{width:60%}.ui-skeleton--compact .ui-list__row{gap:12px}.ui-skeleton--compact .ui-list__row>.ui-skeleton__line{flex:1 1 auto;max-width:60%}.ui-skeleton--grid .ui-card__body{display:grid;gap:12px;justify-items:stretch}.ui-skeleton--grid .ui-card__body>.ui-skeleton__line:last-child{width:50%}.ui-skeleton--board .ui-board__list>li{height:72px;border-radius:var(--ui-radius-md);background:var(--ui-surface)}@media (pointer: coarse){.ui-table__sort{min-height:44px;margin-block:-12px}.ui-table__checkbox{min-width:44px;min-height:44px;margin:-12px 0}}@media (pointer: coarse),(max-width: 47.9975em){.ui-table__sort{min-width:44px}}@media (prefers-reduced-motion: reduce){.ui-table--sticky-first :is(th,td):first-child{animation:none}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>*{transition:none}.ui-board{scroll-behavior:auto}}
|
package/src/editor/controls.tsx
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// · the edge box hands each keystroke to the caller (`onChange(side, raw)`) and says when to commit (`onCommit`, on
|
|
12
12
|
// blur): the caller decides what an empty edge means, and the admin has three answers to that on purpose.
|
|
13
13
|
import "../editor.css"; // its own stylesheet travels with it (0.23.0): a surface that never renders it never loads it
|
|
14
|
-
import { useEffect, useState } from "react";
|
|
14
|
+
import { useEffect, useRef, useState } from "react";
|
|
15
15
|
import type React from "react";
|
|
16
16
|
import { cssUrl } from "./css-url";
|
|
17
17
|
import { swatchState } from "./swatch";
|
|
@@ -27,6 +27,8 @@ export interface SegOption<T extends string = string> {
|
|
|
27
27
|
value: T;
|
|
28
28
|
/** Default: the value itself. */
|
|
29
29
|
label?: React.ReactNode;
|
|
30
|
+
/** The button's own name, for a label that is a glyph (an arrow), said by a screen reader and shown on hover. */
|
|
31
|
+
name?: string;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export interface SegProps<T extends string = string> {
|
|
@@ -49,7 +51,69 @@ export interface SegProps<T extends string = string> {
|
|
|
49
51
|
export function Seg<T extends string = string>({ options, value, onChange, disabled, label, style }: SegProps<T>) {
|
|
50
52
|
return (
|
|
51
53
|
<Segmented<T> fill className="gemboss-ei-seg" style={style} ariaLabel={label ?? ""} value={(value ?? "") as T | ""} onChange={onChange} disabled={disabled}
|
|
52
|
-
options={options.map((o) => ({ value: o.value, label: o.label ?? o.value }))} />
|
|
54
|
+
options={options.map((o) => ({ value: o.value, label: o.label ?? o.value, ...(o.name ? { ariaLabel: o.name, title: o.name } : {}) }))} />
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── ValueControl ────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
export interface ValueControlProps {
|
|
61
|
+
/** The number box's id (the Field's `htmlFor`). */
|
|
62
|
+
id?: string;
|
|
63
|
+
/** The field's name: the chips are announced as "<label> presets". */
|
|
64
|
+
label: string;
|
|
65
|
+
/** The named values, smallest first, each `value` as the box would hold it ("" = none). Shown as "name · number". */
|
|
66
|
+
presets: ReadonlyArray<{ value: string; label: string; title?: string }>;
|
|
67
|
+
/** What the box holds now: the stored value or the text being typed. */
|
|
68
|
+
text: string;
|
|
69
|
+
/** What an empty box follows (another screen's value, the theme's), greyed. */
|
|
70
|
+
placeholder?: string;
|
|
71
|
+
/** The unit after the box ("px", "%", "ms"). */
|
|
72
|
+
suffix?: string;
|
|
73
|
+
/** A slider under the box, for a bounded range of ≤ ~100 stops. `value` is where its thumb sits. */
|
|
74
|
+
slider?: { min: number; max: number; step?: number; value: number };
|
|
75
|
+
/** A chip: the caller saves it at once. */
|
|
76
|
+
onPreset: (value: string) => void;
|
|
77
|
+
/** Each key typed. */
|
|
78
|
+
onText: (raw: string) => void;
|
|
79
|
+
/** The box let go (blur, Enter). */
|
|
80
|
+
onCommit: () => void;
|
|
81
|
+
/** Each move of the slider. */
|
|
82
|
+
onSlide?: (value: number) => void;
|
|
83
|
+
/** Keys in the box (↑ ↓ nudges are the caller's). */
|
|
84
|
+
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
85
|
+
/** A line under it (e.g. why a typed value was not kept as typed). */
|
|
86
|
+
note?: string;
|
|
87
|
+
/** The keyboard a phone shows: "decimal" (default) has no minus key on iOS, so a value that goes below 0 asks for "text". */
|
|
88
|
+
inputMode?: "decimal" | "text";
|
|
89
|
+
disabled?: boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* `.gemboss-ei-value` (0.38.0): a setting you can click, drag or type (Chris 15/10/2026: "vừa bấm được vừa nhập được, lười thì
|
|
94
|
+
* bấm"). The named values first, as the kit's segmented control (one lights when the box holds it; a value of its own lights
|
|
95
|
+
* none), then the number box with its unit and, for a bounded range, a slider. The caller owns the value: it turns chips, keys
|
|
96
|
+
* and moves into saves.
|
|
97
|
+
*/
|
|
98
|
+
export function ValueControl({ id, label, presets, text, placeholder, suffix, slider, onPreset, onText, onCommit, onSlide, onKeyDown, note, inputMode = "decimal", disabled }: ValueControlProps) {
|
|
99
|
+
const lit = presets.find((p) => p.value === text.trim())?.value;
|
|
100
|
+
return (
|
|
101
|
+
// A chip pressed right after typing keeps the box's focus: its blur would save what was typed, the save locks the field, and
|
|
102
|
+
// the chip's click landed on a disabled chip (the spacing box's own guard, review of slice 5). The chip is the choice.
|
|
103
|
+
<div className="gemboss-ei-value" onMouseDown={(e) => { if ((e.target as HTMLElement).closest('[role="group"] button')) e.preventDefault(); }}>
|
|
104
|
+
{presets.length ? <Seg label={`${label} presets`} value={lit} disabled={disabled} onChange={onPreset}
|
|
105
|
+
options={presets.map((p) => ({ value: p.value, label: p.label }))} /> : null}
|
|
106
|
+
<div className="gemboss-ei-value-row">
|
|
107
|
+
<span className="gemboss-ei-value-box">
|
|
108
|
+
<input id={id} className="gemboss-field gemboss-field--narrow gemboss-ei-inp" inputMode={inputMode} value={text} placeholder={placeholder}
|
|
109
|
+
disabled={disabled} aria-label={label} onChange={(e) => onText(e.target.value)} onBlur={onCommit}
|
|
110
|
+
onKeyDown={(e) => { onKeyDown?.(e); if (!e.defaultPrevented) blurOnEnter(e); }} />
|
|
111
|
+
{suffix ? <span className="gemboss-ei-suffix">{suffix}</span> : null}
|
|
112
|
+
</span>
|
|
113
|
+
{slider && onSlide ? <RangeControl min={slider.min} max={slider.max} step={slider.step} value={slider.value} disabled={disabled} onChange={onSlide} /> : null}
|
|
114
|
+
</div>
|
|
115
|
+
{note ? <p className="gemboss-ei-hint" role="status">{note}</p> : null}
|
|
116
|
+
</div>
|
|
53
117
|
);
|
|
54
118
|
}
|
|
55
119
|
|
|
@@ -132,11 +196,26 @@ export interface EdgeBoxProps {
|
|
|
132
196
|
narrow?: boolean;
|
|
133
197
|
/** Ids for the boxes, per side. */
|
|
134
198
|
ids?: Partial<Record<EdgeSide, string>>;
|
|
199
|
+
/**
|
|
200
|
+
* A side's letter dragged sideways (Figma's and Webflow's scrub, 0.37.0): `dx`, the pixels moved since the press, and the keys
|
|
201
|
+
* held now, for the caller to turn into a value. A mouse or a pen only: a finger on the letter scrolls the panel as before, and
|
|
202
|
+
* the box takes the number (its 44px under a finger is the control there). Present, each letter is a 24px drag row.
|
|
203
|
+
*/
|
|
204
|
+
onScrub?: (side: EdgeSide, dx: number, keys: { shiftKey: boolean; altKey: boolean }) => void;
|
|
205
|
+
/** The drag let go: `moved` when it changed anything (the caller saves once, one Undo step); not moved, it was a click. */
|
|
206
|
+
onScrubEnd?: (side: EdgeSide, moved: boolean) => void;
|
|
135
207
|
}
|
|
136
208
|
|
|
137
209
|
/** `.gemboss-ei-edgebox`: four px boxes, T · R · B · L, mono and centred. */
|
|
138
|
-
export function EdgeBox({ label, values, placeholders, onChange, onCommit, disabled, narrow = true, ids }: EdgeBoxProps) {
|
|
210
|
+
export function EdgeBox({ label, values, placeholders, onChange, onCommit, disabled, narrow = true, ids, onScrub, onScrubEnd }: EdgeBoxProps) {
|
|
139
211
|
const cls = narrow ? "gemboss-field gemboss-field--narrow gemboss-ei-inp" : "gemboss-field gemboss-ei-inp";
|
|
212
|
+
const drag = useRef<{ side: EdgeSide; id: number; x: number; moved: boolean } | null>(null);
|
|
213
|
+
const end = (e: React.PointerEvent<HTMLSpanElement>) => {
|
|
214
|
+
const d = drag.current;
|
|
215
|
+
if (!d || d.id !== e.pointerId) return;
|
|
216
|
+
drag.current = null;
|
|
217
|
+
onScrubEnd?.(d.side, d.moved);
|
|
218
|
+
};
|
|
140
219
|
return (
|
|
141
220
|
<div className="gemboss-ei-edgebox">
|
|
142
221
|
{SIDES.map((s) => (
|
|
@@ -144,7 +223,29 @@ export function EdgeBox({ label, values, placeholders, onChange, onCommit, disab
|
|
|
144
223
|
<input className={cls} inputMode="numeric" placeholder={placeholders?.[s] ?? "0"}
|
|
145
224
|
aria-label={`${label} ${SIDE_NAME[s]}`} id={ids?.[s]} value={values[s] ?? ""} disabled={disabled}
|
|
146
225
|
onChange={(e) => onChange(s, e.target.value)} onBlur={onCommit} onKeyDown={blurOnEnter} />
|
|
147
|
-
|
|
226
|
+
{onScrub ? (
|
|
227
|
+
// Rendered while disabled too: a field that locks in the middle of a drag (another save landing) must not drop the
|
|
228
|
+
// drag's handlers, or it never ends and nothing is saved (review of 3a). A drag only refuses to START when disabled.
|
|
229
|
+
<span className="gemboss-ei-edge-scrub" title={`Drag to change ${SIDE_NAME[s]}`} aria-disabled={disabled || undefined}
|
|
230
|
+
onPointerDown={(e) => {
|
|
231
|
+
if (disabled || e.pointerType === "touch" || e.button !== 0) return;
|
|
232
|
+
e.preventDefault();
|
|
233
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
234
|
+
drag.current = { side: s, id: e.pointerId, x: e.clientX, moved: false };
|
|
235
|
+
}}
|
|
236
|
+
onPointerMove={(e) => {
|
|
237
|
+
const d = drag.current;
|
|
238
|
+
if (!d || d.id !== e.pointerId) return;
|
|
239
|
+
const dx = e.clientX - d.x;
|
|
240
|
+
// A press that wanders a pixel is still a click.
|
|
241
|
+
if (!d.moved && Math.abs(dx) < 2) return;
|
|
242
|
+
d.moved = true;
|
|
243
|
+
onScrub(s, dx, { shiftKey: e.shiftKey, altKey: e.altKey });
|
|
244
|
+
}}
|
|
245
|
+
onPointerUp={end} onPointerCancel={end}
|
|
246
|
+
// Its own capture only (the event bubbles from nothing here, but the check is the fleet's rule).
|
|
247
|
+
onLostPointerCapture={(e) => { if (e.target === e.currentTarget) end(e); }}>{s.toUpperCase()}</span>
|
|
248
|
+
) : <span>{s.toUpperCase()}</span>}
|
|
148
249
|
</div>
|
|
149
250
|
))}
|
|
150
251
|
</div>
|
package/src/editor/frame.tsx
CHANGED
|
@@ -156,20 +156,24 @@ export function EditorBack({ as: Comp = "button", label = "Back", ...rest }:
|
|
|
156
156
|
|
|
157
157
|
/**
|
|
158
158
|
* The auto-save pill: "Saving…" with a spinner while an edit is in flight, "✓ Draft saved" once it lands.
|
|
159
|
-
* `idle` draws nothing unless `idleText` says what autosave means here (the section editor's "Autosaves",
|
|
159
|
+
* `idle` draws nothing unless `idleText` says what autosave means here (the section editor's "Autosaves", muted).
|
|
160
|
+
* `live` (default true): "Saving…" and "✓ Draft saved" are a polite live region. `live={false}` for a surface that speaks
|
|
161
|
+
* through a live region of its own, one that is in the page from its first render and says only what changed (the page
|
|
162
|
+
* editor's save pill): the pill is then words with a title, and nothing is announced twice.
|
|
160
163
|
*/
|
|
161
164
|
export function EditorSaveState({
|
|
162
165
|
state, savedText = "✓ Draft saved", savingText = "Saving…", savingTitle = "Saving draft…",
|
|
163
|
-
savedTitle = "Every change is saved to the draft automatically", idleText,
|
|
166
|
+
savedTitle = "Every change is saved to the draft automatically", idleText, live = true,
|
|
164
167
|
}: {
|
|
165
168
|
state: "idle" | "saving" | "saved";
|
|
166
169
|
savedText?: React.ReactNode; savingText?: React.ReactNode; savingTitle?: string; savedTitle?: string; idleText?: React.ReactNode;
|
|
170
|
+
live?: boolean;
|
|
167
171
|
}) {
|
|
168
172
|
if (state === "idle") {
|
|
169
|
-
return idleText != null && idleText !== false ? <span className="gemboss-editor-savestate" title={savedTitle}
|
|
173
|
+
return idleText != null && idleText !== false ? <span className="gemboss-editor-savestate is-idle" title={savedTitle}>{idleText}</span> : null;
|
|
170
174
|
}
|
|
171
175
|
return (
|
|
172
|
-
<span className={`gemboss-editor-savestate is-${state}`} role
|
|
176
|
+
<span className={`gemboss-editor-savestate is-${state}`} {...(live ? { role: "status", "aria-live": "polite" as const } : null)} title={state === "saving" ? savingTitle : savedTitle}>
|
|
173
177
|
{state === "saving" ? <><span className="gemboss-narr-spin" aria-hidden />{savingText}</> : savedText}
|
|
174
178
|
</span>
|
|
175
179
|
);
|
package/src/editor/index.ts
CHANGED
|
@@ -36,8 +36,8 @@ export {
|
|
|
36
36
|
type FieldProps, type InspectorGroupProps, type PanelHeaderProps, type PanelTab, type PanelTabsProps,
|
|
37
37
|
} from "./panel";
|
|
38
38
|
export {
|
|
39
|
-
ChipButton, ColorControl, EdgeBox, ImageControl, RangeControl, Seg,
|
|
40
|
-
type ColorControlProps, type EdgeBoxProps, type EdgeSide, type ImageControlProps, type RangeControlProps, type SegOption, type SegProps,
|
|
39
|
+
ChipButton, ColorControl, EdgeBox, ImageControl, RangeControl, Seg, ValueControl,
|
|
40
|
+
type ColorControlProps, type EdgeBoxProps, type EdgeSide, type ImageControlProps, type RangeControlProps, type SegOption, type SegProps, type ValueControlProps,
|
|
41
41
|
} from "./controls";
|
|
42
42
|
export { swatchState, type SwatchState } from "./swatch";
|
|
43
43
|
export { cssUrl } from "./css-url";
|
|
@@ -48,5 +48,9 @@ export {
|
|
|
48
48
|
EditorDrawer, LayerList, layerName,
|
|
49
49
|
type EditorDrawerProps, type LayerItem, type LayerListProps,
|
|
50
50
|
} from "./layers";
|
|
51
|
-
export { SortableLayerList, type SortableLayerListProps } from "./sortable";
|
|
51
|
+
export { SortableLayerList, type SortableLayerListProps, useRowDrag, dropIndex } from "./sortable";
|
|
52
|
+
// 16/10/2026: a setting that is a list, as rows (drag, duplicate, fold); its own CSS part, editor-repeater.css.
|
|
53
|
+
export { RepeaterList, useKeyedRows, type RepeaterListProps, type KeyedRows } from "./repeater";
|
|
54
|
+
// 16/10/2026: a closed choice of shapes (an image's ratio, a layout) as picture tiles; its own CSS part, editor-tiles.css.
|
|
55
|
+
export { ChoiceTiles, type ChoiceTile, type ChoiceTilesProps } from "./tiles";
|
|
52
56
|
export { LayerTree, type LayerTreeProps, type LayerTreeRow } from "./tree";
|
package/src/editor/panel.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// InspectorGroup's own open/closed when the caller does not hold it. Controls (Seg, Color, Range, EdgeBox, Image) are
|
|
6
6
|
// controls.tsx: their own module, because only a screen that edits values draws them.
|
|
7
7
|
import "../editor.css"; // its own stylesheet travels with it (0.23.0): a surface that never renders it never loads it
|
|
8
|
-
import { useState } from "react";
|
|
8
|
+
import { useId, useState } from "react";
|
|
9
9
|
import type React from "react";
|
|
10
10
|
|
|
11
11
|
// ── PanelTabs ───────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
@@ -161,29 +161,53 @@ export function InspectorGroup({ title, note, open, defaultOpen = true, onOpenCh
|
|
|
161
161
|
// ── Field ───────────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
162
162
|
|
|
163
163
|
export interface FieldProps {
|
|
164
|
-
/** 13px
|
|
164
|
+
/** 13px above the control (beside it in a `row`). `undefined` / `null` draws no label (a control named by its own aria-label). */
|
|
165
165
|
label?: React.ReactNode;
|
|
166
166
|
/** The control's id, so a click on the label focuses it. */
|
|
167
167
|
htmlFor?: string;
|
|
168
168
|
/** A value shown at the label's right edge, bold and tabular (a range's current value: `.gemboss-ei-rangeval`). */
|
|
169
169
|
labelValue?: React.ReactNode;
|
|
170
|
-
/**
|
|
170
|
+
/** The setting's help (`p.gemboss-ei-hint.gemboss-ei-help-text`). In a plugin's form a line under the control; inside an
|
|
171
|
+
* inspector group (`InspectorGroup`) a ? beside the label opens and closes it (0.39.0). */
|
|
171
172
|
hint?: React.ReactNode;
|
|
173
|
+
/** A one-value setting (a number, a select, a colour, chips): inside an inspector group the label goes LEFT and the control
|
|
174
|
+
* right, one row (0.39.0). Outside a group nothing changes. */
|
|
175
|
+
row?: boolean;
|
|
172
176
|
/** Added to `.gemboss-ei-fld` (the admin's `togrow`). */
|
|
173
177
|
className?: string;
|
|
174
178
|
style?: React.CSSProperties;
|
|
175
179
|
children?: React.ReactNode;
|
|
176
180
|
}
|
|
177
181
|
|
|
178
|
-
/**
|
|
179
|
-
|
|
182
|
+
/**
|
|
183
|
+
* One labelled setting: `div.gemboss-ei-fld` › label · control · help. 12px under each but the last.
|
|
184
|
+
*
|
|
185
|
+
* INSIDE AN INSPECTOR GROUP (0.39.0, Chris 16/10/2026: the settings panel looked bigger than the kit and Polaris; research
|
|
186
|
+
* `_local/gemboss/research/inspector-density-2026-10-16.md`). The controls were Polaris-sized already (field 32, chips 28);
|
|
187
|
+
* the panel was long: a label line over every control (70px a setting) and help text under it, 22% of a countdown's panel.
|
|
188
|
+
* There a `row` is label left, control right (GemPages: 52px a setting), the label is quiet (bodyMd, secondary) and the help
|
|
189
|
+
* is behind a ? (GemPages, PageFly). Outside a group, a plugin's settings form, a help line under a wide field is the
|
|
190
|
+
* Polaris form and stays.
|
|
191
|
+
*/
|
|
192
|
+
export function Field({ label, htmlFor, labelValue, hint, row = false, className, style, children }: FieldProps) {
|
|
193
|
+
const helpId = useId();
|
|
194
|
+
const [helpOpen, setHelpOpen] = useState(false);
|
|
195
|
+
const cls = ["gemboss-ei-fld", row && label != null ? "gemboss-ei-fld--row" : "", className].filter(Boolean).join(" ");
|
|
196
|
+
const labelNode = label != null ? (
|
|
197
|
+
<label htmlFor={htmlFor}>{label}{labelValue != null ? <span className="gemboss-ei-rangeval">{labelValue}</span> : null}</label>
|
|
198
|
+
) : null;
|
|
180
199
|
return (
|
|
181
|
-
<div className={
|
|
182
|
-
{label
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
<div className={cls} style={style}>
|
|
201
|
+
{/* A ? is a button, so it sits BESIDE the label, not in it (a label may hold no other labelable element). */}
|
|
202
|
+
{hint && labelNode ? (
|
|
203
|
+
<div className="gemboss-ei-lbl">
|
|
204
|
+
{labelNode}
|
|
205
|
+
<button type="button" className="gemboss-ei-help" aria-label={typeof label === "string" ? `About ${label}` : "About this setting"} aria-describedby={helpId} aria-expanded={helpOpen}
|
|
206
|
+
onClick={() => setHelpOpen((o) => !o)} onKeyDown={(e) => { if (e.key === "Escape") setHelpOpen(false); }}>?</button>
|
|
207
|
+
</div>
|
|
208
|
+
) : labelNode}
|
|
185
209
|
{children}
|
|
186
|
-
{hint ? <p className="gemboss-ei-hint">{hint}</p> : null}
|
|
210
|
+
{hint ? <p className="gemboss-ei-hint gemboss-ei-help-text" id={helpId}>{hint}</p> : null}
|
|
187
211
|
</div>
|
|
188
212
|
);
|
|
189
213
|
}
|