@gemboss/ui 0.47.0 → 0.50.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 +315 -0
- package/README.md +162 -18
- package/catalog/editor.html +1 -1
- package/catalog/index.html +53 -49
- package/gemboss-ui.css +4 -4
- package/package.json +23 -2
- package/parts/components.css +3 -3
- package/parts/core.css +1 -1
- package/parts/shell.css +2 -2
- package/src/app-shell.css +1 -1
- package/src/assistant/chat.tsx +50 -6
- package/src/assistant/host.tsx +19 -7
- package/src/assistant/index.ts +1 -1
- package/src/assistant/sessions.tsx +2 -1
- package/src/assistant-chat.css +1 -1
- package/src/assistant.css +1 -1
- package/src/auth-signin-plain.js +1 -0
- package/src/auth-sso-plain.js +1 -1
- package/src/auth.tsx +105 -8
- package/src/briefing-card.css +1 -1
- package/src/collections.css +1 -1
- package/src/create-shell.css +1 -0
- package/src/create-shell.tsx +221 -0
- package/src/editor-insert.css +1 -0
- package/src/editor.css +1 -1
- package/src/empty-stage.css +1 -0
- package/src/empty-stage.tsx +31 -0
- package/src/icons.tsx +2 -0
- package/src/index-table.tsx +7 -4
- package/src/index.ts +16 -2
- package/src/kit-plain.css +1 -1
- package/src/kit-plain.js +1 -1
- package/src/language-switcher-plain.js +1 -1
- package/src/language-switcher.css +1 -1
- package/src/language-switcher.tsx +10 -41
- package/src/list-page.css +1 -0
- package/src/list-page.tsx +239 -0
- package/src/menu-extras.css +1 -0
- package/src/menu-keys.ts +199 -0
- package/src/menu-layer.ts +2 -1
- package/src/menu-plain.js +1 -0
- package/src/menu.css +1 -0
- package/src/menu.tsx +83 -35
- package/src/pager-extras.css +1 -0
- package/src/pager.css +1 -0
- package/src/pager.tsx +88 -0
- package/src/portal.css +1 -1
- package/src/portal.tsx +19 -4
- package/src/segmented.tsx +12 -2
- package/src/selection.tsx +3 -1
- package/src/session-rail-plain.js +1 -1
- package/src/settings-dialog.tsx +29 -2
- package/src/shell.css +1 -1
- package/src/stage-path.css +1 -0
- package/src/stage-path.tsx +89 -0
- package/src/stage.css +1 -0
- package/src/stage.tsx +52 -0
- package/src/starting-point.css +1 -0
- package/src/starting-point.tsx +93 -0
- package/src/status-list.css +1 -0
- package/src/status-list.tsx +65 -0
- package/src/status-matrix.css +1 -0
- package/src/status-matrix.tsx +131 -0
- package/src/team-chat.css +1 -1
- package/src/topnav-fold.css +1 -0
- package/src/translation-row.css +1 -0
- package/src/translation-row.tsx +113 -0
- package/src/ui.css +1 -1
package/src/pager.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ui-pager>a,.ui-pager>[aria-disabled=true]{min-width:32px;justify-content:center;box-sizing:border-box;gap:4px}.ui-pager>a[aria-current=page]{background:var(--ui-text);border-color:var(--ui-text);color:var(--ui-surface);font-size:var(--ui-fs-body);font-weight:600}.ui-pager>a[aria-current=page]:hover{background:var(--ui-text)}.ui-pager>[aria-disabled=true]{display:inline-flex;align-items:center;min-height:32px;padding:0 12px;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);color:var(--ui-text-muted);font-size:var(--ui-fs-body);opacity:.55;cursor:default}.ui-pager>[aria-disabled=true]:hover{background:none}.ui-pager__gap{min-width:16px;text-align:center;color:var(--ui-text-muted)}.ui-pager__range{margin-left:auto;color:var(--ui-text-muted);font-size:var(--ui-fs-body);font-variant-numeric:tabular-nums}@media (pointer: coarse),(max-width: 47.9975em){.ui-pager>a,.ui-pager>[aria-disabled=true]{min-width:44px;min-height:44px}}@media (max-width: 35.9975em){.ui-pager>a:not([rel]):not([aria-current]):not([aria-disabled]),.ui-pager__gap{display:none}}
|
package/src/pager.tsx
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import "./pager.css";
|
|
2
|
+
import "./pager-extras.css";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
// The numbered pager (README "Long lists", 24/10/2026): Previous · the pages around the current one · Next, and the range
|
|
6
|
+
// ("25–48 of 655") pushed right. Two ways to page:
|
|
7
|
+
// - `href(n)`: the position is in the URL (a work list people send each other). Links, drawn through `linkAs` (Next's Link);
|
|
8
|
+
// an edge that cannot move is a link with no href and aria-disabled, read as an unavailable link.
|
|
9
|
+
// - `onPage(n)`: the list pages in state (the admin's Products, whose search and filters are not in the URL either, so a
|
|
10
|
+
// page link would open page 3 of a different list). Buttons, the same look (pager-extras.css).
|
|
11
|
+
// Under 576px only Previous · the current page · Next stay and the range wraps under them.
|
|
12
|
+
|
|
13
|
+
/** The page numbers to show: the first, the last, the current one ± 1, and a gap only where it hides two pages or more (a gap
|
|
14
|
+
* hiding one page shows that page instead). */
|
|
15
|
+
export function pageWindow(page: number, count: number): (number | "gap")[] {
|
|
16
|
+
if (count < 1) return [];
|
|
17
|
+
const nums = [...new Set([1, count, page - 1, page, page + 1])].filter((n) => n >= 1 && n <= count).sort((a, b) => a - b);
|
|
18
|
+
const out: (number | "gap")[] = [];
|
|
19
|
+
nums.forEach((n, i) => {
|
|
20
|
+
const before = nums[i - 1];
|
|
21
|
+
if (before !== undefined && n - before === 2) out.push(before + 1);
|
|
22
|
+
else if (before !== undefined && n - before > 2) out.push("gap");
|
|
23
|
+
out.push(n);
|
|
24
|
+
});
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface PagerCommon {
|
|
29
|
+
/** The current page, from 1. */
|
|
30
|
+
page: number;
|
|
31
|
+
pageCount: number;
|
|
32
|
+
/** "25–48 of 655": what is on screen, out of how many. */
|
|
33
|
+
range?: React.ReactNode;
|
|
34
|
+
/** The nav's name for a screen reader. */
|
|
35
|
+
label?: string;
|
|
36
|
+
/** A page is on its way: nothing moves until it lands (every page is unavailable, the current one stays marked). */
|
|
37
|
+
busy?: boolean;
|
|
38
|
+
previousLabel?: string;
|
|
39
|
+
nextLabel?: string;
|
|
40
|
+
/** In a stack that already spaces its children (a card's): no margin of its own. */
|
|
41
|
+
flush?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/** One way to page, never none (a pager with neither drew controls that did nothing; review of the Pager). */
|
|
44
|
+
export type PagerProps = PagerCommon & (
|
|
45
|
+
/** The position is in the URL: links, through the app's link. */
|
|
46
|
+
| { href: (page: number) => string; linkAs?: React.ElementType; onPage?: never }
|
|
47
|
+
/** The list pages in state: buttons. */
|
|
48
|
+
| { onPage: (page: number) => void; href?: never; linkAs?: never }
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export function Pager({ page, pageCount, range, href, onPage, linkAs, label = "Pages", busy = false, previousLabel = "Previous", nextLabel = "Next", flush = false }: PagerProps) {
|
|
52
|
+
const count = Math.max(1, pageCount);
|
|
53
|
+
const current = Math.min(Math.max(1, page), count);
|
|
54
|
+
const Link: React.ElementType = linkAs ?? "a";
|
|
55
|
+
const asLinks = Boolean(href);
|
|
56
|
+
const prev = <><span aria-hidden="true">‹</span> {previousLabel}</>;
|
|
57
|
+
const next = <>{nextLabel} <span aria-hidden="true">›</span></>;
|
|
58
|
+
|
|
59
|
+
// Previous / Next: an edge that cannot move (or a page on its way) says so, and does nothing.
|
|
60
|
+
const edge = (to: number, rel: "prev" | "next", body: React.ReactNode) => {
|
|
61
|
+
const off = busy || to < 1 || to > count;
|
|
62
|
+
// A closed edge keeps `data-rel` (a link with no href has no `rel`), so the phone rule keeps it beside the current page.
|
|
63
|
+
if (asLinks) return off
|
|
64
|
+
? <a key={rel} role="link" aria-disabled="true" data-rel={rel}>{body}</a>
|
|
65
|
+
: <Link key={rel} href={href!(to)} rel={rel}>{body}</Link>;
|
|
66
|
+
return <button key={rel} type="button" data-rel={rel} aria-disabled={off || undefined} onClick={off ? undefined : () => onPage?.(to)}>{body}</button>;
|
|
67
|
+
};
|
|
68
|
+
// A page number: the current one is marked and goes nowhere; while a page is on its way the others are unavailable (a link
|
|
69
|
+
// with no href, a button that says so), not live controls that do nothing.
|
|
70
|
+
const num = (n: number) => {
|
|
71
|
+
const here = n === current;
|
|
72
|
+
const off = busy && !here;
|
|
73
|
+
if (asLinks) return off
|
|
74
|
+
? <a key={n} role="link" aria-disabled="true" aria-label={`Page ${n}`}>{n}</a>
|
|
75
|
+
: <Link key={n} href={href!(n)} aria-label={`Page ${n}`} aria-current={here ? "page" : undefined}>{n}</Link>;
|
|
76
|
+
return <button key={n} type="button" aria-label={`Page ${n}`} aria-current={here ? "page" : undefined} aria-disabled={off || undefined}
|
|
77
|
+
onClick={here || off ? undefined : () => onPage?.(n)}>{n}</button>;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<nav className={flush ? "ui-pager ui-pager--flush" : "ui-pager"} aria-label={label} aria-busy={busy || undefined}>
|
|
82
|
+
{edge(current - 1, "prev", prev)}
|
|
83
|
+
{pageWindow(current, count).map((n, i) => (n === "gap" ? <span key={`gap-${i}`} className="ui-pager__gap" aria-hidden="true">…</span> : num(n)))}
|
|
84
|
+
{edge(current + 1, "next", next)}
|
|
85
|
+
{range ? <span className="ui-pager__range">{range}</span> : null}
|
|
86
|
+
</nav>
|
|
87
|
+
);
|
|
88
|
+
}
|
package/src/portal.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.gb-topnav{display:flex;align-items:stretch;gap:4px;min-width:0;height:100%;margin-left:12px;padding-left:12px;border-left:1px solid var(--gemboss-divider);overflow-x:auto;scrollbar-width:none}.gb-topnav::-webkit-scrollbar{display:none}.gb-topnav-link{position:relative;display:inline-flex;align-items:center;align-self:stretch;flex:0 0 auto;min-height:36px;padding:0 10px;border-radius:8px;color:var(--gemboss-text-muted);font-size:14px;font-weight:520;text-decoration:none;white-space:nowrap}.gb-topnav-link:hover{color:var(--gemboss-text-strong);background:var(--gemboss-hover)}.gb-topnav-link:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gb-topnav-link[aria-current=page]{color:var(--gemboss-text-strong);font-weight:640}.gb-topnav-link[aria-current=page]:after{content:"";position:absolute;left:10px;right:10px;bottom:-1px;height:2px;border-radius:2px;background:var(--gemboss-text-strong)}@media (pointer: coarse){.gb-topnav-link{min-height:44px}}.gemboss-platform-topbar:has(.gb-topnav):has(>.gemboss-topbar-center:empty){grid-template-columns:minmax(0,1fr) auto}.gemboss-platform-topbar:has(.gb-topnav)>.gemboss-topbar-center:empty{display:none}.gemboss-topbar-start:has(.gb-topnav){min-width:0;height:100%}.gemboss-topbar-start:has(.gb-topnav)>.gb-brand{flex:0 0 auto}@media (max-width: 760px){.gb-topnav{margin-left:8px;padding-left:8px}.gb-topnav-link{min-height:44px;padding:0 8px}}.gb-topnav-row{display:flex;align-items:stretch;gap:4px;min-width:0;height:100%}.gb-topnav-fold{display:none;position:relative;align-self:stretch}.gb-topnav-fold>summary{list-style:none;cursor:pointer;gap:4px;height:100%}.gb-topnav-fold>summary::-webkit-details-marker{display:none}.gb-topnav-fold-btn[aria-current=page]:after{display:none}.gb-topnav-chevron{flex:0 0 auto;transition:transform .15s ease}.gb-topnav-fold[open] .gb-topnav-chevron{transform:rotate(180deg)}.gb-topnav-pop{position:fixed;top:56px;left:8px;min-width:200px;padding:6px;display:grid;gap:2px;z-index:60}.gb-topnav-item{display:flex;align-items:center;min-height:44px;padding:0 12px;border-radius:8px;color:var(--gemboss-text);font-size:14px;font-weight:520;text-decoration:none}.gb-topnav-item:hover{background:var(--gemboss-hover)}.gb-topnav-item:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gb-topnav-item[aria-current=page]{color:var(--gemboss-active-fg);background:var(--gemboss-active-bg);font-weight:640}@media (max-width: 600px){.gb-topnav{overflow:visible}.gb-topnav-row{display:none}.gb-topnav-fold{display:flex}}@media (prefers-reduced-motion: reduce){.gb-topnav-chevron{transition:none}}.gb-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gb-avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border-radius:50%;overflow:hidden;font-weight:700;line-height:1;letter-spacing:.01em;user-select:none}.gb-avatar--24{width:24px;height:24px;font-size:9.5px}.gb-avatar--32{width:32px;height:32px;font-size:11px}.gb-avatar--40{width:40px;height:40px;font-size:13px}.gb-avatar--56{width:56px;height:56px;font-size:18px}.gb-avatar-img{width:100%;height:100%;object-fit:cover;display:block}.gb-avatar[data-tone]{background:color-mix(in srgb,var(--gb-tone) 16%,#ffffff);color:color-mix(in srgb,var(--gb-tone) 70%,#000000)}.gb-avatar[data-tone="0"]{--gb-tone: #5661f5}.gb-avatar[data-tone="1"]{--gb-tone: #0a8f6a}.gb-avatar[data-tone="2"]{--gb-tone: #c26a04}.gb-avatar[data-tone="3"]{--gb-tone: #db2777}.gb-avatar[data-tone="4"]{--gb-tone: #0891b2}.gb-avatar[data-tone="5"]{--gb-tone: #7c3aed}.gb-avatar[data-tone="6"]{--gb-tone: #dc2626}.gb-avatar[data-tone="7"]{--gb-tone: #6b7280}.gb-leaderboard{display:grid;gap:6px;min-width:0}.gb-leaderboard-title{margin:0;display:flex;align-items:center;gap:6px;font-size:12px;font-weight:650;letter-spacing:.04em;text-transform:uppercase;color:var(--gemboss-text-muted)}.gb-leaderboard-caption{margin:-2px 0 2px;font-size:12px;color:var(--gemboss-text-muted)}.gb-leaderboard-list{list-style:none;margin:0;padding:0;display:grid;gap:0}.gb-leaderboard-link{display:flex;align-items:center;gap:10px;min-height:44px;padding:0 6px;border-radius:8px;color:var(--gemboss-text);text-decoration:none}a.gb-leaderboard-link:hover{background:var(--gemboss-hover)}a.gb-leaderboard-link:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gb-leaderboard-rank{width:20px;flex:0 0 auto;text-align:center;font-size:15px;line-height:1}.gb-leaderboard-rank.is-number{font-size:12px;font-weight:700;color:var(--gemboss-text-muted);font-variant-numeric:tabular-nums}.gb-leaderboard-name{flex:1 1 auto;min-width:0;font-size:13px;font-weight:560;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-leaderboard-value{flex:0 0 auto;font-size:13px;font-weight:650;color:var(--gemboss-text-muted);font-variant-numeric:tabular-nums}.gb-leaderboard-row.is-first .gb-leaderboard-value{color:#8a5a00;font-weight:750}.gb-leaderboard-row.is-current>.gb-leaderboard-link{background:var(--gemboss-active-bg)}.gb-leaderboard-badge{flex:0 1 auto;min-width:0;overflow:hidden}.gb-leaderboard-all{justify-self:center;display:inline-flex;align-items:center;min-height:24px;font-size:12px;font-weight:600;color:var(--gemboss-text-muted);text-decoration:none}.gb-leaderboard-all:hover{color:var(--gemboss-text-strong);text-decoration:underline}.gb-podium{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;align-items:end}.gb-podium-link{display:grid;justify-items:center;gap:6px;padding:14px 8px;border:1px solid var(--gemboss-divider);border-radius:12px;background:var(--gemboss-surface);color:var(--gemboss-text);text-decoration:none;text-align:center}a.gb-podium-link:hover{background:var(--gemboss-hover)}.gb-podium-slot{min-width:0}.gb-podium-slot.is-empty{visibility:hidden}.gb-podium-slot--1 .gb-podium-link{padding-top:22px;padding-bottom:20px;border-color:color-mix(in srgb,#d4a017 45%,var(--gemboss-divider))}.gb-podium-slot--2 .gb-podium-link{padding-bottom:12px}.gb-podium-slot--3 .gb-podium-link{padding-bottom:8px}.gb-podium-medal{font-size:22px;line-height:1}.gb-podium-name{max-width:100%;font-size:13px;font-weight:620;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-podium-value{font-size:15px;font-weight:750;font-variant-numeric:tabular-nums}.gb-podium-slot--1 .gb-podium-value{color:#8a5a00}.gb-podium-unit{font-size:11px;font-weight:500;color:var(--gemboss-text-muted)}.gb-podium-slot.is-current .gb-podium-link{border-color:var(--gemboss-text-strong);background:var(--gemboss-active-bg)}.gb-search-trigger,.gb-theme-toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer}.gb-search-trigger:hover,.gb-theme-toggle:hover{background:var(--gemboss-hover);color:var(--gemboss-text-strong)}.gb-search-trigger:focus-visible,.gb-theme-toggle:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}@media (pointer: coarse),(max-width: 760px){.gb-search-trigger,.gb-theme-toggle{width:44px;height:44px}}.gb-search-field{text-decoration:none;cursor:text}.gb-search-field:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:1px}.gb-search-field-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--gemboss-fs-body);color:var(--gemboss-field-placeholder)}dialog.ui-modal.gb-search{width:min(640px,100%);margin-top:8vh;max-height:min(560px,calc(100dvh - 16vh))}.gb-search-box{position:relative;display:flex;align-items:center;border-bottom:1px solid var(--ui-border)}.gb-search-icon{position:absolute;left:18px;color:var(--ui-text-muted);pointer-events:none}.gb-search-input{flex:1 1 auto;min-width:0;height:52px;padding:0 18px 0 46px;border:0;background:transparent;color:var(--ui-text);font:inherit;font-size:15px;outline:none}.gb-search-input::-webkit-search-cancel-button{display:none}.gb-search-results{flex:1 1 auto;min-height:0;overflow:auto;padding:8px}.gb-search-section+.gb-search-section{margin-top:8px}.gb-search-section-title{padding:6px 10px;font-size:12px;font-weight:600;color:var(--ui-text-muted)}.gb-search-item{display:grid;gap:2px;min-height:44px;align-content:center;padding:6px 10px;border-radius:8px;color:var(--ui-text);text-decoration:none}.gb-search-item.is-active{background:var(--ui-surface-2)}.gb-search-item-title{font-size:14px;font-weight:520;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-search-item-meta{display:flex;gap:8px;align-items:center;font-size:12px;color:var(--ui-text-muted)}.gb-search-empty{margin:0;padding:18px 18px 0;font-size:13px;color:var(--ui-text-muted)}.gb-search-empty:empty{padding:0}.gb-search-foot{display:flex;gap:16px;justify-content:flex-end;padding:8px 14px;border-top:1px solid var(--ui-border);font-size:12px;color:var(--ui-text-muted)}@media (max-width: 760px){dialog.ui-modal.gb-search{margin-top:12px}.gb-search-foot{display:none}}
|
|
1
|
+
.gb-topnav{display:flex;align-items:stretch;gap:4px;min-width:0;height:100%;margin-left:12px;padding-left:12px;border-left:1px solid var(--gemboss-divider);overflow-x:auto;scrollbar-width:none}.gb-topnav::-webkit-scrollbar{display:none}.gb-topnav-link{position:relative;display:inline-flex;align-items:center;align-self:stretch;flex:0 0 auto;min-height:36px;padding:0 10px;border-radius:8px;color:var(--gemboss-text-muted);font-size:14px;font-weight:520;text-decoration:none;white-space:nowrap}.gb-topnav-link:hover{color:var(--gemboss-text-strong);background:var(--gemboss-hover)}.gb-topnav-link:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gb-topnav-link[aria-current=page]{color:var(--gemboss-text-strong);font-weight:640}.gb-topnav-link[aria-current=page]:after{content:"";position:absolute;left:10px;right:10px;bottom:-1px;height:2px;border-radius:2px;background:var(--gemboss-text-strong)}@media (pointer: coarse){.gb-topnav-link{min-height:44px}}.gemboss-platform-topbar:has(.gb-topnav):has(>.gemboss-topbar-center:empty){grid-template-columns:minmax(0,1fr) auto}.gemboss-platform-topbar:has(.gb-topnav)>.gemboss-topbar-center:empty{display:none}.gemboss-topbar-start:has(.gb-topnav){min-width:0;height:100%}.gemboss-topbar-start:has(.gb-topnav)>.gb-brand{flex:0 0 auto}@media (max-width: 760px){.gb-topnav{margin-left:8px;padding-left:8px}.gb-topnav-link{min-height:44px;padding:0 8px}}.gb-topnav-row{display:flex;align-items:stretch;gap:4px;min-width:0;height:100%}.gb-topnav-fold{display:none;position:relative;align-self:stretch}.gb-topnav-fold>summary{list-style:none;cursor:pointer;gap:4px;height:100%}.gb-topnav-fold>summary::-webkit-details-marker{display:none}.gb-topnav-fold-btn[aria-current=page]:after{display:none}.gb-topnav-chevron{flex:0 0 auto;transition:transform .15s ease}.gb-topnav-fold[open] .gb-topnav-chevron{transform:rotate(180deg)}.gb-topnav-pop{position:fixed;top:56px;left:8px;min-width:200px;padding:6px;display:grid;gap:2px;z-index:60}.gb-topnav-item{display:flex;align-items:center;min-height:44px;padding:0 12px;border-radius:8px;color:var(--gemboss-text);font-size:14px;font-weight:520;text-decoration:none}.gb-topnav-item:hover{background:var(--gemboss-hover)}.gb-topnav-item:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gb-topnav-item[aria-current=page]{color:var(--gemboss-active-fg);background:var(--gemboss-active-bg);font-weight:640}@media (max-width: 600px){.gb-topnav{overflow:visible}.gb-topnav-row{display:none}.gb-topnav-fold{display:flex}}@media (prefers-reduced-motion: reduce){.gb-topnav-chevron{transition:none}}.gb-sr-only{position:absolute;left:0;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gb-avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;border-radius:50%;overflow:hidden;font-weight:700;line-height:1;letter-spacing:.01em;user-select:none}.gb-avatar--24{width:24px;height:24px;font-size:9.5px}.gb-avatar--32{width:32px;height:32px;font-size:11px}.gb-avatar--40{width:40px;height:40px;font-size:13px}.gb-avatar--56{width:56px;height:56px;font-size:18px}.gb-avatar-img{width:100%;height:100%;object-fit:cover;display:block}.gb-avatar[data-tone]{background:color-mix(in srgb,var(--gb-tone) 16%,#ffffff);color:color-mix(in srgb,var(--gb-tone) 70%,#000000)}.gb-avatar[data-tone="0"]{--gb-tone: #5661f5}.gb-avatar[data-tone="1"]{--gb-tone: #0a8f6a}.gb-avatar[data-tone="2"]{--gb-tone: #c26a04}.gb-avatar[data-tone="3"]{--gb-tone: #db2777}.gb-avatar[data-tone="4"]{--gb-tone: #0891b2}.gb-avatar[data-tone="5"]{--gb-tone: #7c3aed}.gb-avatar[data-tone="6"]{--gb-tone: #dc2626}.gb-avatar[data-tone="7"]{--gb-tone: #6b7280}.gb-leaderboard{display:grid;gap:6px;min-width:0}.gb-leaderboard-title{margin:0;display:flex;align-items:center;gap:6px;font-size:12px;font-weight:650;letter-spacing:.04em;text-transform:uppercase;color:var(--gemboss-text-muted)}.gb-leaderboard-caption{margin:-2px 0 2px;font-size:12px;color:var(--gemboss-text-muted)}.gb-leaderboard-list{list-style:none;margin:0;padding:0;display:grid;gap:0}.gb-leaderboard-link{display:flex;align-items:center;gap:10px;min-height:44px;padding:0 6px;border-radius:8px;color:var(--gemboss-text);text-decoration:none}a.gb-leaderboard-link:hover{background:var(--gemboss-hover)}a.gb-leaderboard-link:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gb-leaderboard-rank{width:20px;flex:0 0 auto;text-align:center;font-size:15px;line-height:1}.gb-leaderboard-rank.is-number{font-size:12px;font-weight:700;color:var(--gemboss-text-muted);font-variant-numeric:tabular-nums}.gb-leaderboard-name{flex:1 1 auto;min-width:0;font-size:13px;font-weight:560;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-leaderboard-value{flex:0 0 auto;font-size:13px;font-weight:650;color:var(--gemboss-text-muted);font-variant-numeric:tabular-nums}.gb-leaderboard-row.is-first .gb-leaderboard-value{color:#8a5a00;font-weight:750}.gb-leaderboard-row.is-current>.gb-leaderboard-link{background:var(--gemboss-active-bg)}.gb-leaderboard-badge{flex:0 1 auto;min-width:0;overflow:hidden}.gb-leaderboard-all{justify-self:center;display:inline-flex;align-items:center;min-height:24px;font-size:12px;font-weight:600;color:var(--gemboss-text-muted);text-decoration:none}.gb-leaderboard-all:hover{color:var(--gemboss-text-strong);text-decoration:underline}.gb-podium{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;align-items:end}.gb-podium-link{display:grid;justify-items:center;gap:6px;padding:14px 8px;border:1px solid var(--gemboss-divider);border-radius:12px;background:var(--gemboss-surface);color:var(--gemboss-text);text-decoration:none;text-align:center}a.gb-podium-link:hover{background:var(--gemboss-hover)}.gb-podium-slot{min-width:0}.gb-podium-slot.is-empty{visibility:hidden}.gb-podium-slot--1 .gb-podium-link{padding-top:22px;padding-bottom:20px;border-color:color-mix(in srgb,#d4a017 45%,var(--gemboss-divider))}.gb-podium-slot--2 .gb-podium-link{padding-bottom:12px}.gb-podium-slot--3 .gb-podium-link{padding-bottom:8px}.gb-podium-medal{font-size:22px;line-height:1}.gb-podium-name{max-width:100%;font-size:13px;font-weight:620;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-podium-value{font-size:15px;font-weight:750;font-variant-numeric:tabular-nums}.gb-podium-slot--1 .gb-podium-value{color:#8a5a00}.gb-podium-unit{font-size:11px;font-weight:500;color:var(--gemboss-text-muted)}.gb-podium-slot.is-current .gb-podium-link{border-color:var(--gemboss-text-strong);background:var(--gemboss-active-bg)}.gb-search-trigger,.gb-theme-toggle{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;flex:0 0 auto;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer}.gb-search-trigger:hover,.gb-theme-toggle:hover{background:var(--gemboss-hover);color:var(--gemboss-text-strong)}.gb-search-trigger:focus-visible,.gb-theme-toggle:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}@media (pointer: coarse),(max-width: 760px){.gb-search-trigger,.gb-theme-toggle{width:44px;height:44px}}.gb-search-field{text-decoration:none;cursor:text}.gb-search-field:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:1px}.gb-search-field-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--gemboss-fs-body);color:var(--gemboss-field-placeholder)}dialog.ui-modal.gb-search{width:min(640px,100%);margin-top:8vh;max-height:min(560px,calc(100dvh - 16vh))}.gb-search-box{position:relative;display:flex;align-items:center;border-bottom:1px solid var(--ui-border)}.gb-search-icon{position:absolute;left:18px;color:var(--ui-text-muted);pointer-events:none}.gb-search-input{flex:1 1 auto;min-width:0;height:52px;padding:0 18px 0 46px;border:0;background:transparent;color:var(--ui-text);font:inherit;font-size:15px;outline:none}.gb-search-input::-webkit-search-cancel-button{display:none}.gb-search-results{flex:1 1 auto;min-height:0;overflow:auto;padding:8px}.gb-search-section+.gb-search-section{margin-top:8px}.gb-search-section-title{padding:6px 10px;font-size:12px;font-weight:600;color:var(--ui-text-muted)}.gb-search-item{display:grid;gap:2px;min-height:44px;align-content:center;padding:6px 10px;border-radius:8px;color:var(--ui-text);text-decoration:none}.gb-search-item.is-active{background:var(--ui-surface-2)}.gb-search-item-title{font-size:14px;font-weight:520;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-search-item-meta{display:flex;gap:8px;align-items:center;font-size:12px;color:var(--ui-text-muted)}.gb-search-empty{margin:0;padding:18px 18px 0;font-size:13px;color:var(--ui-text-muted)}.gb-search-empty:empty{padding:0}.gb-search-foot{display:flex;gap:16px;justify-content:flex-end;padding:8px 14px;border-top:1px solid var(--ui-border);font-size:12px;color:var(--ui-text-muted)}@media (max-width: 760px){dialog.ui-modal.gb-search{margin-top:12px}.gb-search-foot{display:none}}
|
package/src/portal.tsx
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* Server components: no state, no hooks. Links are `<a>` unless a router link is passed as `as`.
|
|
19
19
|
*/
|
|
20
20
|
import "./portal.css"; // its own stylesheet travels with it (0.23.0): a surface that never renders it never loads it
|
|
21
|
+
import "./topnav-fold.css"; // 22/10/2026: TopbarNav's folded menu (foot, foldAt, the ellipsis), after the frozen bundle
|
|
21
22
|
import React from "react";
|
|
22
23
|
import { initialsOf } from "./initials";
|
|
23
24
|
|
|
@@ -34,26 +35,40 @@ export type TopbarNavItem = { href: string; label: React.ReactNode; active?: boo
|
|
|
34
35
|
* sign they are there. There the tabs fold into one button naming the open tab, and a list under it, as
|
|
35
36
|
* Featurebase's board does on a phone. A <details>, so it opens without JavaScript; keyed by the active
|
|
36
37
|
* tab, so following a link (a client-side navigation keeps the element) closes it.
|
|
38
|
+
*
|
|
39
|
+
* `foot` (22/10/2026): the app's own section at the foot of that list, under a line: what the topbar's end has no room
|
|
40
|
+
* for once the tabs fold. GemFeedback's bar (brand, tab menu, search, theme, Sign in) had no room for a fourth 55px
|
|
41
|
+
* button at 320–390, so its LanguageSwitcher was hidden there: it goes in the foot (`<LanguageSwitcher variant="inline"
|
|
42
|
+
* end={false} …>`), and its copy in the end slot carries `gb-topnav-unfolded`, shown only while the tabs are unfolded.
|
|
43
|
+
* One language control at every width, one at a time. `foldAt={760}` folds the tabs over the whole phone topbar
|
|
44
|
+
* (≤760px) instead of under 600px, for a bar whose end holds more (GemFeedback's tabs ran under the switcher at 601–687).
|
|
37
45
|
*/
|
|
38
|
-
export function TopbarNav({ items, as: L = "a", label = "Sections", className }: {
|
|
46
|
+
export function TopbarNav({ items, as: L = "a", label = "Sections", className, foot, foldAt = 600 }: {
|
|
39
47
|
items: TopbarNavItem[]; as?: LinkLike; label?: string; className?: string;
|
|
48
|
+
/** Shown at the foot of the folded list only (a language switcher); its copy in the topbar's end wears `gb-topnav-unfolded`. */
|
|
49
|
+
foot?: React.ReactNode;
|
|
50
|
+
/** The widest viewport at which the tabs fold: 600 (default) or 760, the whole phone topbar. */
|
|
51
|
+
foldAt?: 600 | 760;
|
|
40
52
|
}) {
|
|
41
53
|
const current = items.find((it) => it.active) ?? items[0];
|
|
42
54
|
const links = (cls: string) => items.map((it) => (
|
|
43
55
|
<L key={it.href} href={it.href} className={cls} aria-current={it.active ? "page" : undefined}>{it.label}</L>
|
|
44
56
|
));
|
|
45
57
|
return (
|
|
46
|
-
<nav className={cx("gb-topnav", className)} aria-label={label}>
|
|
58
|
+
<nav className={cx("gb-topnav", foldAt === 760 && "gb-topnav--fold-760", className)} aria-label={label}>
|
|
47
59
|
<div className="gb-topnav-row">{links("gb-topnav-link")}</div>
|
|
48
60
|
{current ? (
|
|
49
61
|
<details className="gb-topnav-fold" key={current.href}>
|
|
50
62
|
<summary className="gb-topnav-link gb-topnav-fold-btn" aria-current="page">
|
|
51
|
-
{current.label}
|
|
63
|
+
<span className="gb-topnav-fold-label">{current.label}</span>
|
|
52
64
|
<svg className="gb-topnav-chevron" width="12" height="12" viewBox="0 0 12 12" aria-hidden="true" focusable="false">
|
|
53
65
|
<path d="M3 4.5 6 7.5 9 4.5" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
|
|
54
66
|
</svg>
|
|
55
67
|
</summary>
|
|
56
|
-
<div className="gb-topnav-pop gemboss-popover-surface">
|
|
68
|
+
<div className="gb-topnav-pop gemboss-popover-surface">
|
|
69
|
+
{links("gb-topnav-item")}
|
|
70
|
+
{foot ? <div className="gb-topnav-foot">{foot}</div> : null}
|
|
71
|
+
</div>
|
|
57
72
|
</details>
|
|
58
73
|
) : null}
|
|
59
74
|
</nav>
|
package/src/segmented.tsx
CHANGED
|
@@ -27,8 +27,12 @@ export type SegmentedOption<T extends string> = {
|
|
|
27
27
|
disabled?: boolean;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
/** `scroll`'s layout: the group scrolls inside itself, each tab keeps its words on one line (kit-plain.css's rule, as styles). */
|
|
31
|
+
const SCROLL_GROUP: CSSProperties = { maxWidth: "100%", overflowX: "auto" };
|
|
32
|
+
const SCROLL_TAB: CSSProperties = { flex: "none", whiteSpace: "nowrap" };
|
|
33
|
+
|
|
30
34
|
export function Segmented<T extends string>({
|
|
31
|
-
options, value, onChange, ariaLabel, disabled, onClear, fill = false, className, style,
|
|
35
|
+
options, value, onChange, ariaLabel, disabled, onClear, fill = false, scroll = false, className, style,
|
|
32
36
|
}: {
|
|
33
37
|
options: SegmentedOption<T>[];
|
|
34
38
|
value: T | "";
|
|
@@ -47,13 +51,18 @@ export function Segmented<T extends string>({
|
|
|
47
51
|
onClear?: () => void;
|
|
48
52
|
/** Stretch to the row and share it equally: a field switch in the inspector's narrow column. */
|
|
49
53
|
fill?: boolean;
|
|
54
|
+
/** Keep each label on one line and scroll sideways inside the group when it is wider than its room, for a filter of many
|
|
55
|
+
* options on a phone: what kit-plain.css does for every plain surface. Set as layout styles here, not as a rule in ui.css:
|
|
56
|
+
* gemboss-ui.css had 0 bytes of room (weight gate, 22/10/2026). Not in a short flex column: a scroll container there loses
|
|
57
|
+
* its height. */
|
|
58
|
+
scroll?: boolean;
|
|
50
59
|
/** A hook class beside `ui-seg` (the editor kit's `gemboss-ei-seg`, which editor-plain.js finds). Never a look. */
|
|
51
60
|
className?: string;
|
|
52
61
|
/** On the group: the inspector narrows a two-option row with a max-width. */
|
|
53
62
|
style?: CSSProperties;
|
|
54
63
|
}) {
|
|
55
64
|
return (
|
|
56
|
-
<div className={`ui-seg${fill ? " ui-seg--fill" : ""}${className ? ` ${className}` : ""}`} style={style} role="group" aria-label={ariaLabel || undefined}>
|
|
65
|
+
<div className={`ui-seg${fill ? " ui-seg--fill" : ""}${className ? ` ${className}` : ""}`} style={scroll ? { ...SCROLL_GROUP, ...style } : style} role="group" aria-label={ariaLabel || undefined}>
|
|
57
66
|
{options.map((o) => {
|
|
58
67
|
const active = value === o.value;
|
|
59
68
|
return (
|
|
@@ -67,6 +76,7 @@ export function Segmented<T extends string>({
|
|
|
67
76
|
aria-label={o.ariaLabel}
|
|
68
77
|
aria-pressed={active}
|
|
69
78
|
className={`is-text${active ? " active" : ""}`}
|
|
79
|
+
style={scroll ? SCROLL_TAB : undefined}
|
|
70
80
|
onClick={() => segmentedClick(active, o.value, onChange, onClear)}
|
|
71
81
|
>
|
|
72
82
|
{o.label}
|
package/src/selection.tsx
CHANGED
|
@@ -23,7 +23,9 @@ export const ESCAPE_OWNERS = 'details[open], dialog[open], [role="dialog"], [rol
|
|
|
23
23
|
export function escapeTaken(root: Element, target: EventTarget | null): boolean {
|
|
24
24
|
const t = target as Element | null;
|
|
25
25
|
if (t && typeof t.closest === "function" && t.closest(ESCAPE_OWNERS)) return true;
|
|
26
|
-
|
|
26
|
+
// Shown, not merely boxed: a closed <details>' content still has boxes (content-visibility: hidden), and every ⋯ menu's
|
|
27
|
+
// list is role="menu" (23/10/2026), so a box test would hand every Escape in a table to its closed menus.
|
|
28
|
+
return Array.from(root.querySelectorAll(ESCAPE_OWNERS)).some((e) => (typeof e.checkVisibility === "function" ? e.checkVisibility() : e.getClientRects().length > 0));
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export function useSelection<R extends HTMLElement>(ids: string[], selectedProp: string[] | undefined, onSelectionChange: ((ids: string[]) => void) | undefined, enabled: boolean) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(g){"use strict";var q=g.gembossUI;if(!q){g.console&&g.console.error("@gemboss/ui session-rail-plain.js: load kit-plain.js first (it defines gembossUI)");return}if(q.sessionRail)return;var S="http://www.w3.org/2000/svg",j=function(r){return typeof Node<"u"&&r instanceof Node};function B(r,t){var i={},n;for(n in r)i[n]=r[n];for(n in t)i[n]=t[n];return i}function l(r,t,i){var n=document.createElement(r);if(t)for(var o in t){var d=t[o];d==null||d===!1||(o==="className"?n.className=d:n.setAttribute(o,d===!0?"":String(d)))}return(Array.isArray(i)?i:i==null?[]:[i]).forEach(function(a){n.appendChild(j(a)?a:document.createTextNode(String(a)))}),n}function Q(r){try{return g.localStorage.getItem(r)}catch{return null}}function J(r,t){try{g.localStorage.setItem(r,t)}catch{}}var O={newChat:"New chat",expand:"Expand sidebar",collapse:"Collapse sidebar",expandTitle:"Expand",collapseTitle:"Collapse",searchPlaceholder:"Search conversations\u2026",searchLabel:"Search history",clearSearch:"Clear search",noneFound:"No conversations found",noneYet:"No conversations yet",openNow:"Open now",pinned:"Pinned",today:"Today",yesterday:"Yesterday",previous7:"Previous 7 days",previous30:"Previous 30 days",older:"Older",working:"working",options:"Options",save:"Save",cancel:"Cancel",pin:"Pin",unpin:"Unpin",rename:"Rename",exportMarkdown:"Export Markdown",remove:"Delete",confirmRemove:"Delete this chat?",justNow:"just now",minutesAgo:function(r){return r+" min ago"},hoursAgo:function(r){return r+" hr ago"},daysAgo:function(r){return r+" day"+(r>1?"s":"")+" ago"},dateLocale:"en-US"};function H(r,t,i){t=t||O;var n=Math.floor(((i===void 0?Date.now():i)-r)/6e4);if(n<1)return t.justNow;if(n<60)return t.minutesAgo(n);var o=Math.floor(n/60);if(o<24)return t.hoursAgo(o);var d=Math.floor(o/24);return d<7?t.daysAgo(d):new Date(r).toLocaleDateString(t.dateLocale)}function P(r){return String(r).toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g,"").replace(/đ/g,"d")}function _(r,t,i){t=t||O;var n=r.filter(function(p){return p.pinned}),o=r.filter(function(p){return!p.pinned}),d=new Date(i===void 0?Date.now():i),a=new Date(d.getFullYear(),d.getMonth(),d.getDate()).getTime(),A=864e5,T=[{label:t.today,min:a},{label:t.yesterday,min:a-A},{label:t.previous7,min:a-7*A},{label:t.previous30,min:a-30*A},{label:t.older,min:-1/0}],f=T.map(function(p){return{label:p.label,items:[]}});o.forEach(function(p){for(var v=-1,L=0;L<T.length;L++)if(p.updatedAt>=T[L].min){v=L;break}f[v===-1?f.length-1:v].items.push(p)});var w=n.length?[{label:t.pinned,items:n}]:[];return w.concat(f.filter(function(p){return p.items.length>0}))}q.assistantSessions={relativeTime:H,normalizeForSearch:P,groupSessions:_,labels:O};function b(r){return function(t){var i=document.createElementNS(S,"svg");i.setAttribute("viewBox","0 0 20 20"),t&&i.setAttribute("class",t),i.setAttribute("aria-hidden","true"),i.setAttribute("focusable","false");var n=document.createElementNS(S,"g");return[["fill","none"],["stroke","currentColor"],["stroke-width","1.6"],["stroke-linecap","round"],["stroke-linejoin","round"]].forEach(function(o){n.setAttribute(o[0],o[1])}),r.forEach(function(o){var d=document.createElementNS(S,o.tag||"path");for(var a in o)a!=="tag"&&d.setAttribute(a,o[a]);n.appendChild(d)}),i.appendChild(n),i}}var X={compose:b([{d:"M11 4H5.5A1.5 1.5 0 0 0 4 5.5v9A1.5 1.5 0 0 0 5.5 16h9a1.5 1.5 0 0 0 1.5-1.5V9"},{d:"M14.5 3.5l2 2L10 12H8v-2z"}]),chevronLeft:b([{d:"M12 5l-5 5 5 5"}]),chevronRight:b([{d:"M8 5l5 5-5 5"}]),search:b([{tag:"circle",cx:"9",cy:"9",r:"5"},{d:"M13 13l3.5 3.5"}]),close:b([{d:"M6 6l8 8M14 6l-8 8"}]),check:b([{d:"M4.5 10.5l3.5 3.5 7.5-8"}]),more:b([{tag:"circle",cx:"5",cy:"10",r:".8"},{tag:"circle",cx:"10",cy:"10",r:".8"},{tag:"circle",cx:"15",cy:"10",r:".8"}]),pin:b([{d:"M8 3.5h4l-.5 5 2.5 2.5H6l2.5-2.5z"},{d:"M10 11v5.5"}]),pinFilled:function(r){var t=document.createElementNS(S,"svg");t.setAttribute("viewBox","0 0 20 20"),r&&t.setAttribute("class",r),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false");var i=document.createElementNS(S,"path");i.setAttribute("d","M8 3.5h4l-.5 5 2.5 2.5H6l2.5-2.5z"),i.setAttribute("fill","currentColor");var n=document.createElementNS(S,"path");return n.setAttribute("d","M10 11v5.5"),n.setAttribute("stroke","currentColor"),n.setAttribute("stroke-width","1.6"),n.setAttribute("stroke-linecap","round"),t.appendChild(i),t.appendChild(n),t},edit:b([{d:"M4 16h3l8.5-8.5-3-3L4 13z"}]),exportIcon:b([{d:"M10 3.5v9M6.5 7L10 3.5 13.5 7"},{d:"M4 12.5v3h12v-3"}]),remove:b([{d:"M5 6h10M8 6V4.5h4V6M6.5 6l.7 9.5h5.6l.7-9.5"}])};q.sessionRail=function(r){r=r||{};var t={sessions:[],unlistedIds:[],activeId:void 0,pendingId:null,busyIds:[],collapsed:!1,footer:null,titleMaxLength:200,newChatTitle:void 0},i={},n=O,o=X,d=r.storageKey||"",a={query:"",editingId:null,editValue:"",menuId:null,menuTop:0,menuLeft:0,confirmDeleteId:null},A=[];function T(e){["sessions","unlistedIds","busyIds"].forEach(function(s){e[s]!==void 0&&(t[s]=e[s]||[])}),["activeId","pendingId","footer","newChatTitle"].forEach(function(s){e[s]!==void 0&&(t[s]=e[s])}),e.collapsed!==void 0&&(t.collapsed=!!e.collapsed),e.titleMaxLength!==void 0&&(t.titleMaxLength=e.titleMaxLength||200),e.labels&&(n=B(n,e.labels)),e.icons&&(o=B(o,e.icons)),["onToggleCollapsed","onNewChat","onOpen","onRename","onTogglePin","onDelete","onExport"].forEach(function(s){e[s]!==void 0&&(i[s]=e[s])})}T(r),r.collapsed===void 0&&d&&(t.collapsed=Q(d)==="1");var f=l("aside",{className:"gemboss-assistant-rail"}),w=l("button",{type:"button",className:"gemboss-assistant-newchat"});w.addEventListener("click",function(){i.onNewChat&&i.onNewChat()});var p=l("button",{type:"button",className:"gemboss-assistant-collapse"});p.addEventListener("click",function(){if(i.onToggleCollapsed){i.onToggleCollapsed();return}t.collapsed=!t.collapsed,d&&J(d,t.collapsed?"1":"0"),K()}),f.appendChild(l("div",{className:"gemboss-assistant-rail-top"},[w,p]));var v=l("div",{className:"gemboss-assistant-search gemboss-field gemboss-field--group"}),L=o.search(),y=l("input",{className:"gemboss-field__bare"}),V=null;y.addEventListener("input",function(){a.query=y.value,F(),E()}),y.addEventListener("keydown",function(e){e.key==="Escape"&&(e.preventDefault(),Y(""),y.blur())}),v.appendChild(L),v.appendChild(y);var C=l("div",{className:"gemboss-assistant-threads"});f.appendChild(C);var z=[];function Y(e){a.query=e,y.value=e,F(),E()}function F(){var e;a.query?(e=l("button",{type:"button",className:"gemboss-assistant-search-clear","aria-label":n.clearSearch},o.close()),e.addEventListener("click",function(){Y("")})):e=l("kbd",{className:"gemboss-assistant-kbd"},"/"),V?v.replaceChild(e,V):v.appendChild(e),V=e}function M(){a.menuId!==null&&(a.menuId=null,U(),E())}function U(){A.forEach(function(e){e()}),A=[]}function Z(){U();var e=function(u){var m=C.querySelector(".gemboss-assistant-menu");(!m||!m.contains(u.target))&&M()},s=function(){M()};document.addEventListener("mousedown",e),g.addEventListener("scroll",s,!0),g.addEventListener("resize",s),A.push(function(){document.removeEventListener("mousedown",e),g.removeEventListener("scroll",s,!0),g.removeEventListener("resize",s)})}function $(e,s){if(a.menuId===s){M();return}var u=e.getBoundingClientRect(),m=184,c=200,h=u.bottom+c+8>g.innerHeight;a.menuLeft=Math.max(8,Math.min(u.right-m,g.innerWidth-m-8)),a.menuTop=h?Math.max(8,u.top-6-c):u.bottom+6,a.confirmDeleteId=null,a.menuId=s,Z(),E()}function ee(e){a.editingId=e.id,a.editValue=e.title,E()}function W(){a.editingId=null,a.editValue="",E()}function G(e){var s=a.editValue.trim();a.editingId=null,E(),!(!s||s===e.title)&&i.onRename&&i.onRename(e.id,s)}function D(e,s,u,m){var c=l("button",{type:"button",role:"menuitem",className:m?"danger":null},[e,l("span",null,s)]);return c.addEventListener("click",u),c}function te(e){var s=a.editingId===e.id,u=l("div",{className:"gemboss-assistant-thread"+(e.id===t.activeId||e.id===t.pendingId?" active":"")+(s?" editing":"")+(a.menuId===e.id?" menu-open":"")});if(s){var m=l("input",{className:"gemboss-field",maxlength:String(t.titleMaxLength)});m.value=a.editValue,m.addEventListener("input",function(){a.editValue=m.value}),m.addEventListener("keydown",function(x){x.key==="Enter"?(x.preventDefault(),G(e)):x.key==="Escape"&&(x.preventDefault(),W())});var c=l("button",{type:"button",className:"gemboss-assistant-thread-act","aria-label":n.save},o.check());c.addEventListener("click",function(){G(e)});var h=l("button",{type:"button",className:"gemboss-assistant-thread-act","aria-label":n.cancel},o.close());return h.addEventListener("click",W),u.appendChild(l("div",{className:"gemboss-assistant-thread-edit"},[m,c,h])),u}var I=l("span",{className:"gemboss-assistant-thread-titlerow"});t.busyIds.indexOf(e.id)>=0&&I.appendChild(l("span",{className:"gemboss-assistant-thread-running","aria-label":n.working})),e.pinned&&I.appendChild(o.pinFilled("gemboss-assistant-pin-dot")),I.appendChild(l("span",{className:"gemboss-assistant-thread-title"},e.title));var k=l("button",{type:"button",className:"gemboss-assistant-thread-main",title:e.title},[I,l("span",{className:"gemboss-assistant-thread-meta"},H(e.updatedAt,n))]);k.addEventListener("click",function(){i.onOpen&&i.onOpen(e.id)}),k.gbRailKey=e.id+":main";var R=l("button",{type:"button",className:"gemboss-assistant-thread-act","aria-label":n.options},o.more());if(R.addEventListener("mousedown",function(x){x.stopPropagation()}),R.addEventListener("click",function(){$(R,e.id)}),R.gbRailKey=e.id+":more",u.appendChild(k),u.appendChild(l("div",{className:"gemboss-assistant-thread-actions"},R)),a.menuId===e.id){var N=l("div",{className:"gemboss-popover-surface gemboss-assistant-menu",role:"menu"});N.style.position="fixed",N.style.top=a.menuTop+"px",N.style.left=a.menuLeft+"px",a.confirmDeleteId===e.id?(N.appendChild(l("div",{className:"gemboss-assistant-menu-confirm"},n.confirmRemove)),N.appendChild(D(o.remove(),n.remove,function(){M(),i.onDelete&&i.onDelete(e.id)},!0)),N.appendChild(D(o.close(),n.cancel,function(){a.confirmDeleteId=null,E()}))):(i.onTogglePin&&N.appendChild(D(e.pinned?o.pin():o.pinFilled(),e.pinned?n.unpin:n.pin,function(){M(),i.onTogglePin(e)})),N.appendChild(D(o.edit(),n.rename,function(){M(),ee(e)})),i.onExport&&N.appendChild(D(o.exportIcon(),n.exportMarkdown,function(){M(),i.onExport(e.id)})),N.appendChild(D(o.remove(),n.remove,function(){a.confirmDeleteId=e.id,E()},!0))),u.appendChild(N)}return u}function ne(){var e=P(a.query.trim());if(e){var s=t.sessions.filter(function(c){return P(c.title+" "+(c.preview||"")).indexOf(e)>=0});return s.length?[{label:"",items:s}]:[]}var u=_(t.sessions,n),m=t.unlistedIds.filter(function(c){return!t.sessions.some(function(h){return h.id===c})}).map(function(c){return{id:c,title:n.newChat,updatedAt:Date.now(),pinned:!1}});return m.length?[{label:n.openNow,items:m}].concat(u):u}function E(){for(var e=document.activeElement&&C.contains(document.activeElement)?document.activeElement:null,s=!!e&&e.tagName==="INPUT",u=e?e.gbRailKey:null;C.firstChild;)C.removeChild(C.firstChild);var m=ne();m.length?m.forEach(function(h){var I=l("div",{className:"gemboss-assistant-group"});h.label&&I.appendChild(l("div",{className:"gemboss-assistant-group-label"},h.label)),h.items.forEach(function(k){I.appendChild(te(k))}),C.appendChild(I)}):C.appendChild(l("div",{className:"gemboss-assistant-threads-empty"},a.query?n.noneFound:n.noneYet)),u&&Array.prototype.some.call(C.querySelectorAll("button"),function(h){return h.gbRailKey!==u?!1:(h.focus({preventScroll:!0}),!0)});var c=C.querySelector(".gemboss-assistant-thread-edit input");if(c&&(s||a.editingId!==null)){c.focus();try{c.setSelectionRange(c.value.length,c.value.length)}catch{}}}function K(){for(f.className="gemboss-assistant-rail"+(t.collapsed?" is-collapsed":"");w.firstChild;)w.removeChild(w.firstChild);for(w.title=t.newChatTitle!==void 0&&t.newChatTitle!==null?t.newChatTitle:n.newChat,w.appendChild(o.compose()),w.appendChild(l("span",null,n.newChat));p.firstChild;)p.removeChild(p.firstChild);p.setAttribute("aria-label",t.collapsed?n.expand:n.collapse),p.title=t.collapsed?n.expandTitle:n.collapseTitle,p.appendChild(t.collapsed?o.chevronRight():o.chevronLeft()),t.sessions.length>0?(y.setAttribute("placeholder",n.searchPlaceholder),y.setAttribute("aria-label",n.searchLabel),y.value!==a.query&&(y.value=a.query),F(),v.parentNode!==f&&f.insertBefore(v,C)):v.parentNode===f&&f.removeChild(v),E(),z.forEach(function(e){e.parentNode===f&&f.removeChild(e)}),z=t.footer?(Array.isArray(t.footer)?t.footer:[t.footer]).filter(j):[],z.forEach(function(e){f.appendChild(e)})}return K(),{el:f,update:function(e){T(e||{}),K()},focusSearch:function(){v.parentNode===f&&y.focus()},destroy:function(){U(),f.parentNode&&f.parentNode.removeChild(f)}}}})(typeof globalThis<"u"?globalThis:this);
|
|
1
|
+
(function(g){"use strict";var q=g.gembossUI;if(!q){g.console&&g.console.error("@gemboss/ui session-rail-plain.js: load kit-plain.js first (it defines gembossUI)");return}if(q.sessionRail)return;var S="http://www.w3.org/2000/svg",j=function(r){return typeof Node<"u"&&r instanceof Node};function B(r,t){var i={},n;for(n in r)i[n]=r[n];for(n in t)i[n]=t[n];return i}function l(r,t,i){var n=document.createElement(r);if(t)for(var o in t){var d=t[o];d==null||d===!1||(o==="className"?n.className=d:n.setAttribute(o,d===!0?"":String(d)))}return(Array.isArray(i)?i:i==null?[]:[i]).forEach(function(a){n.appendChild(j(a)?a:document.createTextNode(String(a)))}),n}function Q(r){try{return g.localStorage.getItem(r)}catch{return null}}function J(r,t){try{g.localStorage.setItem(r,t)}catch{}}var O={newChat:"New chat",expand:"Expand sidebar",collapse:"Collapse sidebar",expandTitle:"Expand",collapseTitle:"Collapse",searchPlaceholder:"Search conversations\u2026",searchLabel:"Search history",clearSearch:"Clear search",noneFound:"No conversations found",noneYet:"No conversations yet",openNow:"Open now",pinned:"Pinned",today:"Today",yesterday:"Yesterday",previous7:"Previous 7 days",previous30:"Previous 30 days",older:"Older",working:"working",options:"Options",save:"Save",cancel:"Cancel",pin:"Pin",unpin:"Unpin",rename:"Rename",exportMarkdown:"Export Markdown",remove:"Delete",confirmRemove:"Delete this chat?",justNow:"just now",minutesAgo:function(r){return r+" min ago"},hoursAgo:function(r){return r+" hr ago"},daysAgo:function(r){return r+" day"+(r>1?"s":"")+" ago"},dateLocale:"en-US"};function H(r,t,i){t=t||O;var n=Math.floor(((i===void 0?Date.now():i)-r)/6e4);if(n<1)return t.justNow;if(n<60)return t.minutesAgo(n);var o=Math.floor(n/60);if(o<24)return t.hoursAgo(o);var d=Math.floor(o/24);return d<7?t.daysAgo(d):new Date(r).toLocaleDateString(t.dateLocale)}function P(r){return String(r).toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g,"").replace(/đ/g,"d")}function _(r,t,i){t=t||O;var n=r.filter(function(p){return p.pinned}),o=r.filter(function(p){return!p.pinned}),d=new Date(i===void 0?Date.now():i),a=new Date(d.getFullYear(),d.getMonth(),d.getDate()).getTime(),A=864e5,T=[{label:t.today,min:a},{label:t.yesterday,min:a-A},{label:t.previous7,min:a-7*A},{label:t.previous30,min:a-30*A},{label:t.older,min:-1/0}],f=T.map(function(p){return{label:p.label,items:[]}});o.forEach(function(p){for(var v=-1,L=0;L<T.length;L++)if(p.updatedAt>=T[L].min){v=L;break}f[v===-1?f.length-1:v].items.push(p)});var w=n.length?[{label:t.pinned,items:n}]:[];return w.concat(f.filter(function(p){return p.items.length>0}))}q.assistantSessions={relativeTime:H,normalizeForSearch:P,groupSessions:_,labels:O};function b(r){return function(t){var i=document.createElementNS(S,"svg");i.setAttribute("viewBox","0 0 20 20"),t&&i.setAttribute("class",t),i.setAttribute("aria-hidden","true"),i.setAttribute("focusable","false");var n=document.createElementNS(S,"g");return[["fill","none"],["stroke","currentColor"],["stroke-width","1.6"],["stroke-linecap","round"],["stroke-linejoin","round"]].forEach(function(o){n.setAttribute(o[0],o[1])}),r.forEach(function(o){var d=document.createElementNS(S,o.tag||"path");for(var a in o)a!=="tag"&&d.setAttribute(a,o[a]);n.appendChild(d)}),i.appendChild(n),i}}var X={compose:b([{d:"M11 4H5.5A1.5 1.5 0 0 0 4 5.5v9A1.5 1.5 0 0 0 5.5 16h9a1.5 1.5 0 0 0 1.5-1.5V9"},{d:"M14.5 3.5l2 2L10 12H8v-2z"}]),chevronLeft:b([{d:"M12 5l-5 5 5 5"}]),chevronRight:b([{d:"M8 5l5 5-5 5"}]),search:b([{tag:"circle",cx:"9",cy:"9",r:"5"},{d:"M13 13l3.5 3.5"}]),close:b([{d:"M6 6l8 8M14 6l-8 8"}]),check:b([{d:"M4.5 10.5l3.5 3.5 7.5-8"}]),more:b([{tag:"circle",cx:"5",cy:"10",r:".8"},{tag:"circle",cx:"10",cy:"10",r:".8"},{tag:"circle",cx:"15",cy:"10",r:".8"}]),pin:b([{d:"M8 3.5h4l-.5 5 2.5 2.5H6l2.5-2.5z"},{d:"M10 11v5.5"}]),pinFilled:function(r){var t=document.createElementNS(S,"svg");t.setAttribute("viewBox","0 0 20 20"),r&&t.setAttribute("class",r),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false");var i=document.createElementNS(S,"path");i.setAttribute("d","M8 3.5h4l-.5 5 2.5 2.5H6l2.5-2.5z"),i.setAttribute("fill","currentColor");var n=document.createElementNS(S,"path");return n.setAttribute("d","M10 11v5.5"),n.setAttribute("stroke","currentColor"),n.setAttribute("stroke-width","1.6"),n.setAttribute("stroke-linecap","round"),t.appendChild(i),t.appendChild(n),t},edit:b([{d:"M4 16h3l8.5-8.5-3-3L4 13z"}]),exportIcon:b([{d:"M10 3.5v9M6.5 7L10 3.5 13.5 7"},{d:"M4 12.5v3h12v-3"}]),remove:b([{d:"M5 6h10M8 6V4.5h4V6M6.5 6l.7 9.5h5.6l.7-9.5"}])};q.sessionRail=function(r){r=r||{};var t={sessions:[],unlistedIds:[],activeId:void 0,pendingId:null,busyIds:[],collapsed:!1,footer:null,titleMaxLength:200,newChatTitle:void 0},i={},n=O,o=X,d=r.storageKey||"",a={query:"",editingId:null,editValue:"",menuId:null,menuTop:0,menuLeft:0,confirmDeleteId:null},A=[];function T(e){["sessions","unlistedIds","busyIds"].forEach(function(s){e[s]!==void 0&&(t[s]=e[s]||[])}),["activeId","pendingId","footer","newChatTitle"].forEach(function(s){e[s]!==void 0&&(t[s]=e[s])}),e.collapsed!==void 0&&(t.collapsed=!!e.collapsed),e.titleMaxLength!==void 0&&(t.titleMaxLength=e.titleMaxLength||200),e.labels&&(n=B(n,e.labels)),e.icons&&(o=B(o,e.icons)),["onToggleCollapsed","onNewChat","onOpen","onRename","onTogglePin","onDelete","onExport"].forEach(function(s){e[s]!==void 0&&(i[s]=e[s])})}T(r),r.collapsed===void 0&&d&&(t.collapsed=Q(d)==="1");var f=l("aside",{className:"gemboss-assistant-rail"}),w=l("button",{type:"button",className:"gemboss-assistant-newchat"});w.addEventListener("click",function(){i.onNewChat&&i.onNewChat()});var p=l("button",{type:"button",className:"gemboss-assistant-collapse"});p.addEventListener("click",function(){if(i.onToggleCollapsed){i.onToggleCollapsed();return}t.collapsed=!t.collapsed,d&&J(d,t.collapsed?"1":"0"),K()}),f.appendChild(l("div",{className:"gemboss-assistant-rail-top"},[w,p]));var v=l("div",{className:"gemboss-assistant-search gemboss-field gemboss-field--group"}),L=o.search(),y=l("input",{className:"gemboss-field__bare"}),V=null;y.addEventListener("input",function(){a.query=y.value,F(),E()}),y.addEventListener("keydown",function(e){e.key==="Escape"&&(e.preventDefault(),Y(""),y.blur())}),v.appendChild(L),v.appendChild(y);var C=l("div",{className:"gemboss-assistant-threads"});f.appendChild(C);var z=[];function Y(e){a.query=e,y.value=e,F(),E()}function F(){var e;a.query?(e=l("button",{type:"button",className:"gemboss-assistant-search-clear","aria-label":n.clearSearch},o.close()),e.addEventListener("click",function(){Y("")})):e=l("kbd",{className:"gemboss-assistant-kbd"},"/"),V?v.replaceChild(e,V):v.appendChild(e),V=e}function M(){a.menuId!==null&&(a.menuId=null,U(),E())}function U(){A.forEach(function(e){e()}),A=[]}function Z(){U();var e=function(u){var m=C.querySelector(".gemboss-assistant-menu");(!m||!m.contains(u.target))&&M()},s=function(){M()};document.addEventListener("mousedown",e),g.addEventListener("scroll",s,!0),g.addEventListener("resize",s),A.push(function(){document.removeEventListener("mousedown",e),g.removeEventListener("scroll",s,!0),g.removeEventListener("resize",s)})}function $(e,s){if(a.menuId===s){M();return}var u=e.getBoundingClientRect(),m=184,c=200,h=u.bottom+c+8>g.innerHeight;a.menuLeft=Math.max(8,Math.min(u.right-m,g.innerWidth-m-8)),a.menuTop=h?Math.max(8,u.top-6-c):u.bottom+6,a.confirmDeleteId=null,a.menuId=s,Z(),E()}function ee(e){a.editingId=e.id,a.editValue=e.title,E()}function W(){a.editingId=null,a.editValue="",E()}function G(e){var s=a.editValue.trim();a.editingId=null,E(),!(!s||s===e.title)&&i.onRename&&i.onRename(e.id,s)}function D(e,s,u,m){var c=l("button",{type:"button",role:"menuitem",className:m?"danger":null},[e,l("span",null,s)]);return c.addEventListener("click",u),c}function te(e){var s=a.editingId===e.id,u=l("div",{className:"gemboss-assistant-thread"+(e.id===t.activeId||e.id===t.pendingId?" active":"")+(s?" editing":"")+(a.menuId===e.id?" menu-open":"")});if(s){var m=l("input",{className:"gemboss-field",maxlength:String(t.titleMaxLength)});m.value=a.editValue,m.addEventListener("input",function(){a.editValue=m.value}),m.addEventListener("keydown",function(x){x.key==="Enter"?(x.preventDefault(),G(e)):x.key==="Escape"&&(x.preventDefault(),W())});var c=l("button",{type:"button",className:"gemboss-assistant-thread-act","aria-label":n.save},o.check());c.addEventListener("click",function(){G(e)});var h=l("button",{type:"button",className:"gemboss-assistant-thread-act","aria-label":n.cancel},o.close());return h.addEventListener("click",W),u.appendChild(l("div",{className:"gemboss-assistant-thread-edit"},[m,c,h])),u}var I=l("span",{className:"gemboss-assistant-thread-titlerow"});t.busyIds.indexOf(e.id)>=0&&I.appendChild(l("span",{className:"gemboss-assistant-thread-running","aria-label":n.working})),e.pinned&&I.appendChild(o.pinFilled("gemboss-assistant-pin-dot")),I.appendChild(l("span",{className:"gemboss-assistant-thread-title"},e.title));var k=l("button",{type:"button",className:"gemboss-assistant-thread-main",title:e.title},[I,l("span",{className:"gemboss-assistant-thread-meta"},H(e.updatedAt,n)+(e.preview?" \xB7 "+e.preview:""))]);k.addEventListener("click",function(){i.onOpen&&i.onOpen(e.id)}),k.gbRailKey=e.id+":main";var R=l("button",{type:"button",className:"gemboss-assistant-thread-act","aria-label":n.options},o.more());if(R.addEventListener("mousedown",function(x){x.stopPropagation()}),R.addEventListener("click",function(){$(R,e.id)}),R.gbRailKey=e.id+":more",u.appendChild(k),u.appendChild(l("div",{className:"gemboss-assistant-thread-actions"},R)),a.menuId===e.id){var N=l("div",{className:"gemboss-popover-surface gemboss-assistant-menu",role:"menu"});N.style.position="fixed",N.style.top=a.menuTop+"px",N.style.left=a.menuLeft+"px",a.confirmDeleteId===e.id?(N.appendChild(l("div",{className:"gemboss-assistant-menu-confirm"},n.confirmRemove)),N.appendChild(D(o.remove(),n.remove,function(){M(),i.onDelete&&i.onDelete(e.id)},!0)),N.appendChild(D(o.close(),n.cancel,function(){a.confirmDeleteId=null,E()}))):(i.onTogglePin&&N.appendChild(D(e.pinned?o.pin():o.pinFilled(),e.pinned?n.unpin:n.pin,function(){M(),i.onTogglePin(e)})),N.appendChild(D(o.edit(),n.rename,function(){M(),ee(e)})),i.onExport&&N.appendChild(D(o.exportIcon(),n.exportMarkdown,function(){M(),i.onExport(e.id)})),N.appendChild(D(o.remove(),n.remove,function(){a.confirmDeleteId=e.id,E()},!0))),u.appendChild(N)}return u}function ne(){var e=P(a.query.trim());if(e){var s=t.sessions.filter(function(c){return P(c.title+" "+(c.preview||"")).indexOf(e)>=0});return s.length?[{label:"",items:s}]:[]}var u=_(t.sessions,n),m=t.unlistedIds.filter(function(c){return!t.sessions.some(function(h){return h.id===c})}).map(function(c){return{id:c,title:n.newChat,updatedAt:Date.now(),pinned:!1}});return m.length?[{label:n.openNow,items:m}].concat(u):u}function E(){for(var e=document.activeElement&&C.contains(document.activeElement)?document.activeElement:null,s=!!e&&e.tagName==="INPUT",u=e?e.gbRailKey:null;C.firstChild;)C.removeChild(C.firstChild);var m=ne();m.length?m.forEach(function(h){var I=l("div",{className:"gemboss-assistant-group"});h.label&&I.appendChild(l("div",{className:"gemboss-assistant-group-label"},h.label)),h.items.forEach(function(k){I.appendChild(te(k))}),C.appendChild(I)}):C.appendChild(l("div",{className:"gemboss-assistant-threads-empty"},a.query?n.noneFound:n.noneYet)),u&&Array.prototype.some.call(C.querySelectorAll("button"),function(h){return h.gbRailKey!==u?!1:(h.focus({preventScroll:!0}),!0)});var c=C.querySelector(".gemboss-assistant-thread-edit input");if(c&&(s||a.editingId!==null)){c.focus();try{c.setSelectionRange(c.value.length,c.value.length)}catch{}}}function K(){for(f.className="gemboss-assistant-rail"+(t.collapsed?" is-collapsed":"");w.firstChild;)w.removeChild(w.firstChild);for(w.title=t.newChatTitle!==void 0&&t.newChatTitle!==null?t.newChatTitle:n.newChat,w.appendChild(o.compose()),w.appendChild(l("span",null,n.newChat));p.firstChild;)p.removeChild(p.firstChild);p.setAttribute("aria-label",t.collapsed?n.expand:n.collapse),p.title=t.collapsed?n.expandTitle:n.collapseTitle,p.appendChild(t.collapsed?o.chevronRight():o.chevronLeft()),t.sessions.length>0?(y.setAttribute("placeholder",n.searchPlaceholder),y.setAttribute("aria-label",n.searchLabel),y.value!==a.query&&(y.value=a.query),F(),v.parentNode!==f&&f.insertBefore(v,C)):v.parentNode===f&&f.removeChild(v),E(),z.forEach(function(e){e.parentNode===f&&f.removeChild(e)}),z=t.footer?(Array.isArray(t.footer)?t.footer:[t.footer]).filter(j):[],z.forEach(function(e){f.appendChild(e)})}return K(),{el:f,update:function(e){T(e||{}),K()},focusSearch:function(){v.parentNode===f&&y.focus()},destroy:function(){U(),f.parentNode&&f.parentNode.removeChild(f)}}}})(typeof globalThis<"u"?globalThis:this);
|
package/src/settings-dialog.tsx
CHANGED
|
@@ -16,10 +16,13 @@
|
|
|
16
16
|
* still while it is open.
|
|
17
17
|
*/
|
|
18
18
|
import "./settings-dialog.css";
|
|
19
|
-
import React, { useEffect, useId, useMemo, useState } from "react";
|
|
19
|
+
import React, { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
20
20
|
import { Icon } from "./icons";
|
|
21
21
|
import { useModalDialog } from "./dialog";
|
|
22
22
|
|
|
23
|
+
// Before paint in a browser, so the strip never shows a frame at its old scroll; useEffect where there is no layout.
|
|
24
|
+
const useBeforePaint = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
25
|
+
|
|
23
26
|
const cx = (...p: Array<string | false | null | undefined>) => p.filter(Boolean).join(" ");
|
|
24
27
|
|
|
25
28
|
export interface SettingsSectionItem {
|
|
@@ -99,6 +102,30 @@ export function SettingsDialog({
|
|
|
99
102
|
// No silent fallback to the first section: the rail, the title and the popup's name would describe one section while the
|
|
100
103
|
// surface's children show another (review #4073).
|
|
101
104
|
const active = (sections as SettingsSectionItem[]).find((s) => s.id === activeId);
|
|
105
|
+
// Under 861px the rail is one strip that scrolls sideways, and opening on a section past its edge showed a row that did not
|
|
106
|
+
// say where you are: Domain in the GemBoss admin at 390px started at x=380 (21/10/2026). Bring the active one into view by
|
|
107
|
+
// the strip's own scroll, so only the strip moves. Again when the rail's sections change (a search cleared brings the
|
|
108
|
+
// active one back) and when the strip changes size (the dialog showing, the window crossing 861px, a font loading).
|
|
109
|
+
const strip = useRef<HTMLDivElement>(null);
|
|
110
|
+
useBeforePaint(() => {
|
|
111
|
+
const box = strip.current;
|
|
112
|
+
if (!open || !box) return undefined;
|
|
113
|
+
const reveal = () => {
|
|
114
|
+
const on = box.querySelector<HTMLElement>("[aria-current]");
|
|
115
|
+
if (!on) return;
|
|
116
|
+
const b = box.getBoundingClientRect();
|
|
117
|
+
const r = on.getBoundingClientRect();
|
|
118
|
+
if (r.left < b.left) box.scrollLeft -= b.left - r.left + 8;
|
|
119
|
+
else if (r.right > b.right) box.scrollLeft += r.right - b.right + 8;
|
|
120
|
+
if (r.top < b.top) box.scrollTop -= b.top - r.top + 8;
|
|
121
|
+
else if (r.bottom > b.bottom) box.scrollTop += r.bottom - b.bottom + 8;
|
|
122
|
+
};
|
|
123
|
+
reveal();
|
|
124
|
+
if (typeof ResizeObserver === "undefined") return undefined;
|
|
125
|
+
const ro = new ResizeObserver(reveal);
|
|
126
|
+
ro.observe(box);
|
|
127
|
+
return () => ro.disconnect();
|
|
128
|
+
}, [open, active?.id, groups]);
|
|
102
129
|
const close = () => ref.current?.close();
|
|
103
130
|
const item = (s: SettingsSectionItem) => {
|
|
104
131
|
const on = s.id === active?.id;
|
|
@@ -125,7 +152,7 @@ export function SettingsDialog({
|
|
|
125
152
|
onKeyDown={(e) => { if (e.key === "Escape") { e.preventDefault(); close(); } }} />
|
|
126
153
|
</label>
|
|
127
154
|
</div>
|
|
128
|
-
<div className="ui-settings__scroll">
|
|
155
|
+
<div className="ui-settings__scroll" ref={strip}>
|
|
129
156
|
{groups.length === 0 ? <p className="ui-settings__empty">{noMatch(query)}</p> : groups.map((g, i) => (
|
|
130
157
|
<div key={`${i}:${g.title}`} className="ui-settings__group">
|
|
131
158
|
{g.title ? <h3 className="ui-settings__group-title">{g.title}</h3> : null}
|
package/src/shell.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.gemboss-popover-surface{background:var(--gemboss-surface);background:color-mix(in srgb,var(--gemboss-surface) 93%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg);box-shadow:var(--gemboss-shadow-raised)}@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){.gemboss-popover-surface{background:var(--gemboss-surface)}}.icon-nav{position:fixed;top:56px;left:0;z-index:200;height:calc(100dvh - 56px);background:var(--gemboss-rail-bg);border-right:1px solid var(--gemboss-divider);display:flex;flex-direction:column;padding-top:8px;overflow:hidden}.gemboss-account-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:220px;z-index:320;overflow:hidden}.gemboss-account-menu-item,.ui-menu__item{display:block;width:100%;min-height:44px;padding:12px 16px;border:0;background:transparent;font:inherit;font-size:13px;color:var(--gemboss-text);text-align:left;text-decoration:none;cursor:pointer;transition:background var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gemboss-account-menu-item:hover,.ui-menu__item:hover{background:var(--gemboss-hover)}.gemboss-account-menu-item:focus-visible,.ui-menu__item:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px;background:var(--gemboss-hover)}.gemboss-account-menu-item.danger,.ui-menu__item--danger{color:var(--gemboss-danger-strong)}.gemboss-account-chip{width:30px;height:30px;border:1px solid #cfd6ce;border-radius:var(--gemboss-radius-full);background:#f5f7f4;color:#303633;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer}.gemboss-platform-main{box-sizing:border-box;min-height:100dvh;padding-top:56px;background:var(--gemboss-app-bg)}.icon-nav{top:56px;height:calc(100dvh - 56px);background:var(--gemboss-nav-bg);border-right-color:var(--gemboss-divider)}@media (max-width: 1040px){.gemboss-platform-topbar{grid-template-columns:minmax(120px,1fr) minmax(220px,520px) minmax(120px,1fr)}}@media (max-width: 760px){.gemboss-platform-main{margin-left:0}}.gemboss-account-chip{width:32px;height:32px;border-radius:50%;background:var(--gemboss-primary);color:#fff;font-weight:600;font-size:12px;display:inline-flex;align-items:center;justify-content:center;border:none;cursor:pointer;transition:transform var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{transform:scale(1.05)}.gemboss-account-chip:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gemboss-platform-main{margin-top:56px;min-height:calc(100vh - 56px);padding:24px;background:#fafafb}@media (max-width: 768px){.gemboss-platform-main{margin-left:0;padding:16px}}.gemboss-platform-shell{display:block;min-height:100vh;background:var(--gemboss-app-bg)}.gemboss-platform-topbar{position:fixed;inset:0 0 auto;z-index:300;height:56px;border-bottom:1px solid var(--gemboss-divider);background:var(--gemboss-topbar-bg);display:grid;grid-template-columns:minmax(200px,1fr) minmax(280px,560px) minmax(200px,1fr);align-items:center;gap:16px;padding:0 16px;box-shadow:var(--gemboss-shadow-resting)}:root:has(.gemboss-platform-topbar){scroll-padding-top:64px}.gemboss-account-chip{width:32px;height:32px;border:1px solid var(--gemboss-chip-line);border-radius:var(--gemboss-radius-full);background:var(--gemboss-surface);color:var(--gemboss-chip-ink);display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer;transition:border-color var(--gemboss-transition-base) ease,background-color var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{border-color:var(--gemboss-chip-line-hover);background:var(--gemboss-chip-bg-hover);transform:none}.icon-nav{position:fixed;top:56px;left:0;z-index:200;height:calc(100dvh - 56px);border-right:1px solid var(--gemboss-divider);background:var(--gemboss-nav-bg);padding-top:12px}.gemboss-platform-main{min-height:calc(100vh - 56px);margin-top:56px;background:var(--gemboss-app-bg);padding:24px}@media (max-width: 1120px){.gemboss-platform-topbar{grid-template-columns:220px minmax(220px,1fr) auto;gap:12px}}@media (max-width: 760px){.gemboss-platform-topbar{height:auto;min-height:56px;grid-template-columns:minmax(0,1fr) auto;padding:12px}.gemboss-account-chip,.icon-nav{display:none}.gemboss-platform-main{margin-left:0;padding:16px}}.gnav-scroll{scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-assistant-railfoot.is-button{width:100%;border:none;background:none;cursor:pointer;text-align:left;font:inherit;border-radius:8px;transition:background .12s ease,color .12s ease}.gemboss-assistant-railfoot.is-button:hover{background:var(--gemboss-primary-soft);color:var(--gemboss-primary-dark)}.gemboss-assistant-empty{padding:24px 20px;color:var(--gemboss-text-muted);font-size:13px}@media (max-width: 760px){.gemboss-platform-topbar{display:flex;align-items:center;gap:8px;height:56px;min-height:56px;padding:0 12px}.gemboss-account-chip{display:inline-flex}.gemboss-platform-main{padding-top:16px;padding-bottom:calc(56px + env(safe-area-inset-bottom))}}@media (pointer: coarse){.gemboss-account-chip{width:44px;height:44px}.gnav-item{min-height:44px}.gemboss-assistant-collapse,.gemboss-assistant-newchat{min-height:44px;min-width:44px}}.icon-nav{width:240px;padding:12px 0 0;overflow:hidden;background:var(--gemboss-nav-bg);display:flex;flex-direction:column}.gnav-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding-inline:12px}.gnav-bottom{padding:0 12px 12px}.gnav-item{display:flex;align-items:center;gap:12px;width:100%;padding:8px 12px;margin:1px 0;border:0;background:transparent;cursor:pointer;text-align:left;border-radius:var(--gemboss-radius-md);text-decoration:none;font-family:inherit;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:500;line-height:1.2;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gnav-item:hover{background:var(--gemboss-nav-hover)}.gnav-item:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gnav-item.active{color:var(--gemboss-active-fg);font-weight:600}.gnav-group:not(.has-active-child)>.gnav-item.active{background:var(--gemboss-active-bg)}.gnav-group:not(.has-active-child)>.gnav-item.active:hover{background:var(--gemboss-active-bg)}.gnav-group.has-active-child>.gnav-item.active:hover{background:var(--gemboss-nav-hover)}.gnav-ico{flex:0 0 20px;width:20px;height:20px;display:grid;place-items:center}.gnav-ico svg{width:20px;height:20px;fill:currentColor}.gnav-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gnav-sub{list-style:none;margin:1px 0 6px;padding:0}.gnav-subitem{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 12px 6px 44px;margin:1px 0;border-radius:var(--gemboss-radius-sm);color:var(--gemboss-text-muted);font-size:13px;line-height:1.2;text-decoration:none;white-space:nowrap;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}@media (pointer: coarse){.gnav-subitem{min-height:44px}}.gnav-subitem:hover{background:var(--gemboss-nav-hover);color:var(--gemboss-text)}.gnav-subitem.active{color:var(--gemboss-active-fg);font-weight:600;background:var(--gemboss-active-bg)}.gnav-subitem.active:hover{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-subitem.active:before{content:"";position:absolute;left:20px;top:50%;transform:translateY(-50%);width:3px;height:15px;border-radius:2px;background:var(--gemboss-primary)}.gnav-subitem.is-soon{opacity:.5;cursor:default}.gnav-subitem em{font-style:normal;font-size:var(--gemboss-fs-micro);font-weight:600;letter-spacing:.04em;text-transform:uppercase;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-sm);padding:1px 6px}.gnav-sep{height:1px;background:var(--gemboss-divider);margin:8px 6px}.gnav-item.gnav-assistant{color:var(--gemboss-accent-strong);font-weight:600;background:var(--gemboss-accent-soft)}.gnav-item.gnav-assistant .gnav-ico svg{fill:var(--gemboss-accent)}.gnav-item.gnav-assistant:hover{background:color-mix(in srgb,var(--gemboss-accent) 16%,var(--gemboss-surface))}.gnav-item.gnav-assistant.active{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-item.gnav-assistant.active .gnav-ico svg{fill:var(--gemboss-active-fg)}.gemboss-platform-main{margin-left:240px}.gemboss-mobile-menu-btn,.gemboss-mobile-nav-backdrop{display:none}@media (max-width: 760px){.gemboss-platform-main{margin-left:0;padding-bottom:env(safe-area-inset-bottom)}.gemboss-mobile-menu-btn{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:38px;height:38px;margin-left:-2px;border:0;border-radius:8px;background:transparent;cursor:pointer;color:var(--gemboss-text)}.gemboss-mobile-menu-btn:active{background:var(--gemboss-hover)}.icon-nav{display:flex;width:min(82vw,300px);transform:translate(-100%);transition:transform .26s cubic-bezier(.4,0,.2,1),box-shadow .26s cubic-bezier(.4,0,.2,1);z-index:1000;box-shadow:none}.gemboss-platform-shell.is-mobile-nav-open .icon-nav{transform:translate(0);box-shadow:2px 0 26px #1f1e1d33}.gemboss-mobile-nav-backdrop{display:block;position:fixed;inset:56px 0 0;width:100%;border:0;padding:0;background:#14131261;opacity:0;pointer-events:none;transition:opacity .22s ease;z-index:999}.gemboss-platform-shell.is-mobile-nav-open .gemboss-mobile-nav-backdrop{opacity:1;pointer-events:auto}}@media (max-width: 305.98px){.gemboss-platform-topbar{padding:0 8px}}@media (min-width: 306px) and (max-width: 460px){.gemboss-platform-topbar{padding:0 8px}.gemboss-mobile-menu-btn,.gemboss-account-chip{width:44px;height:44px}}.gemboss-assistant-chatslot{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;min-width:0}.gemboss-assistant-chatslot[hidden]{display:none}.gemboss-assistant-page>.gemboss-assistant-tabs{flex:0 0 auto;display:flex;align-items:center;gap:4px;padding:4px 8px 0;overflow-x:auto;scrollbar-width:none}.gemboss-assistant-tabs::-webkit-scrollbar{display:none}.gemboss-assistant-tab{display:flex;align-items:center;flex:0 1 auto;min-width:0;max-width:190px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-md);background:transparent}.gemboss-assistant-tab.active{background:var(--gemboss-active-bg);border-color:var(--gemboss-active-bg)}.gemboss-assistant-tab-main{display:flex;align-items:center;gap:6px;min-width:0;min-height:44px;padding:0 4px 0 8px;border:0;background:transparent;font:inherit;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-tab.active .gemboss-assistant-tab-main{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gemboss-assistant-tab-dot{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-divider)}.gemboss-assistant-tab-dot.is-running{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}.gemboss-assistant-tab-close{flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;padding:0}.gemboss-assistant-tab-close:hover{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-close svg{width:14px;height:14px}.gemboss-assistant-sronly{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gemboss-assistant-thread-running{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}@media (prefers-reduced-motion: reduce){.gemboss-assistant-tab-dot.is-running,.gemboss-assistant-thread-running{animation:none}}.gemboss-assistant-route-claim{display:block;height:100%}.gemboss-assistant-layout.is-dock{height:auto;min-height:0}.gemboss-assistant-layout.is-dock .gemboss-assistant-page{height:auto;max-width:none;padding:4px 0 8px}.gnav-item.gnav-assistant{position:relative}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after,body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{content:"";position:absolute;top:6px;left:26px;width:8px;height:8px;border-radius:50%;border:2px solid var(--gemboss-surface)}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{background:var(--gemboss-success-strong)}@media (prefers-reduced-motion: reduce){body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{animation:none}}.gemboss-assistant-layout{display:flex;height:calc(100dvh - 56px);width:100%;min-height:0}.gemboss-assistant-rail{flex:0 0 264px;width:264px;display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--gemboss-divider);background:transparent;padding:16px 12px 12px;gap:12px;transition:flex-basis .18s ease,width .18s ease}.gemboss-assistant-rail-top{display:flex;align-items:center;gap:6px}.gemboss-assistant-newchat{display:flex;align-items:center;gap:8px;flex:1 1 auto;min-width:0;padding:12px;border:1px solid var(--gemboss-divider);border-radius:12px;background:transparent;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:600;cursor:pointer;transition:background .12s ease,border-color .12s ease}.gemboss-assistant-newchat:hover{background:#00000009;border-color:var(--gemboss-text-muted)}.gemboss-assistant-newchat svg{width:17px;height:17px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-newchat span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}.gemboss-assistant-kbd{flex:0 0 auto;font-size:var(--gemboss-fs-micro);font-weight:600;line-height:1;padding:4px 6px;border:1px solid var(--gemboss-divider);border-radius:6px;background:transparent;color:var(--gemboss-text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gemboss-assistant-search:focus-within .gemboss-assistant-kbd{display:none}.gemboss-assistant-collapse{flex:0 0 auto;display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-collapse:hover{background:#0000000d;color:var(--gemboss-text)}.gemboss-assistant-collapse svg{width:16px;height:16px;fill:currentColor}.gemboss-assistant-search{gap:6px}.gemboss-assistant-search>svg{width:15px;height:15px;fill:var(--gemboss-text-muted);flex:0 0 auto}.gemboss-assistant-search-clear{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:6px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-search-clear:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-search-clear svg{width:13px;height:13px;fill:currentColor}.gemboss-assistant-railfoot{flex:0 0 auto;display:flex;align-items:center;gap:6px;padding:8px 12px 2px;border-top:1px solid var(--gemboss-divider);margin-top:4px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption);line-height:1.35}.gemboss-assistant-railfoot svg{width:13px;height:13px;flex:0 0 auto;fill:currentColor;opacity:.8}.gemboss-assistant-threads{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:2px}.gemboss-assistant-threads-empty{padding:16px 8px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption)}.gemboss-assistant-group{display:flex;flex-direction:column;gap:2px}.gemboss-assistant-group+.gemboss-assistant-group{margin-top:12px}.gemboss-assistant-group-label{padding:4px 12px;font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--gemboss-text-muted);text-transform:uppercase}.gemboss-assistant-thread{position:relative;display:flex;align-items:center;border-radius:8px;transition:background .12s ease}.gemboss-assistant-thread:hover{background:var(--gemboss-hover, rgba(0,0,0,.04))}.gemboss-assistant-thread.active{background:#00000012}.gemboss-assistant-thread-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:8px 12px;border:0;background:transparent;text-align:left;cursor:pointer}.gemboss-assistant-thread-titlerow{display:flex;align-items:center;gap:6px;width:100%;min-width:0}.gemboss-assistant-pin-dot{width:12px;height:12px;flex:0 0 auto;fill:var(--gemboss-text-muted)}.gemboss-assistant-thread-title{flex:1 1 auto;min-width:0;font-size:13px;font-weight:500;color:var(--gemboss-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gemboss-assistant-thread-meta{font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-assistant-thread.menu-open{background:#00000012}.gemboss-assistant-thread.menu-open .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-menu{z-index:60;width:184px;padding:6px;display:flex;flex-direction:column}.gemboss-assistant-menu-confirm{padding:8px 12px 6px;font-size:var(--gemboss-fs-caption);font-weight:600;color:var(--gemboss-text)}.gemboss-assistant-menu button{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:0;border-radius:8px;background:transparent;text-align:left;font-size:13px;color:var(--gemboss-text);cursor:pointer}.gemboss-assistant-menu button:hover{background:var(--gemboss-hover, rgba(0,0,0,.05))}.gemboss-assistant-menu button.danger{color:var(--gemboss-danger-strong)}.gemboss-assistant-menu button svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-thread-actions{position:absolute;right:6px;display:flex;gap:2px;opacity:0;transition:opacity .12s ease}.gemboss-assistant-thread:hover .gemboss-assistant-thread-actions,.gemboss-assistant-thread:focus-within .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-thread-act{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-thread-act:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-thread-act.danger:hover{color:var(--gemboss-danger-strong)}.gemboss-assistant-thread-act svg{width:15px;height:15px;fill:currentColor}.gemboss-assistant-thread.editing{background:#00000012}.gemboss-assistant-thread-edit{display:flex;align-items:center;gap:2px;width:100%;padding:6px}.gemboss-assistant-thread-edit input{flex:1 1 auto;min-width:0}.gemboss-assistant-layout .gemboss-assistant-page{height:100%;max-width:820px;flex:1 1 auto;min-width:0;padding-top:16px}.gemboss-assistant-layout .gemboss-assistant-page.is-switching{opacity:.55;transition:opacity .12s ease;pointer-events:none}.gemboss-assistant-rail.is-collapsed{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat span,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-search,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-railfoot,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-threads{display:none}@media (max-width: 760px){.gemboss-assistant-rail{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-newchat span,.gemboss-assistant-search,.gemboss-assistant-railfoot,.gemboss-assistant-threads,.gemboss-assistant-collapse{display:none}}.gemboss-assistant-page{height:calc(100dvh - 56px);width:100%;max-width:760px;margin:0 auto;padding:24px 0 16px;display:flex;flex-direction:column;min-height:0}.gemboss-assistant-page>*{flex:1 1 auto;min-height:0}.gemboss-assistant-empty{flex:1;display:grid;place-items:center;color:var(--gemboss-text-muted);font-size:14px}.gemboss-platform-shell{display:flow-root}.gemboss-platform-main{padding-bottom:calc(24px + var(--gemboss-invite-h, 0px))}@keyframes gemboss-assistant-pulse{0%,to{opacity:1}50%{opacity:.35}}.gb-account{position:relative}.gb-account>summary{list-style:none}.gb-account>summary::-webkit-details-marker{display:none}.gb-account-head{padding:12px 16px;border-bottom:1px solid var(--gemboss-divider)}.gb-account-name{font-size:13px;font-weight:600;color:var(--gemboss-text-strong)}.gb-account-email{font-size:12px;color:var(--gemboss-text-muted)}.gb-account-role{display:inline-block;margin-top:4px;padding:1px 6px;border-radius:4px;font-size:11px;font-weight:600;color:var(--gemboss-active-fg);background:var(--gemboss-active-bg)}.gb-account-form{margin:0}.gnav-scroll::-webkit-scrollbar{width:9px}.gnav-scroll::-webkit-scrollbar-track{background:transparent}.gnav-scroll::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:6px;border:2px solid transparent;background-clip:content-box}
|
|
1
|
+
.gemboss-popover-surface{background:var(--gemboss-surface);background:color-mix(in srgb,var(--gemboss-surface) 93%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg);box-shadow:var(--gemboss-shadow-raised)}@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){.gemboss-popover-surface{background:var(--gemboss-surface)}}.icon-nav{position:fixed;top:56px;left:0;z-index:200;height:calc(100dvh - 56px);background:var(--gemboss-rail-bg);border-right:1px solid var(--gemboss-divider);display:flex;flex-direction:column;padding-top:8px;overflow:hidden}.gemboss-account-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:220px;z-index:320;overflow:hidden}.gemboss-account-menu-item,.ui-menu__item{box-sizing:border-box;width:100%;min-height:32px;padding:4px 16px;border:0;background:transparent;font:inherit;font-size:13px;color:var(--gemboss-text);text-align:left;text-decoration:none;cursor:pointer;transition:background var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gemboss-account-menu-item{display:block}.ui-menu__item{display:flex;align-items:center;gap:8px;padding-inline:6px;white-space:nowrap;border-radius:var(--gemboss-radius-sm)}@media (pointer: coarse),(max-width: 47.9975em){.gemboss-account-menu-item,.ui-menu__item{min-height:44px;padding:12px 16px}}.gemboss-account-menu-item:hover,.ui-menu__item:hover{background:var(--gemboss-hover)}.gemboss-account-menu-item:focus-visible,.ui-menu__item:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px;background:var(--gemboss-hover)}.gemboss-account-menu-item.danger,.ui-menu__item--danger{color:var(--gemboss-danger-strong)}.gemboss-account-chip{width:30px;height:30px;border:1px solid #cfd6ce;border-radius:var(--gemboss-radius-full);background:#f5f7f4;color:#303633;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer}.gemboss-platform-main{box-sizing:border-box;min-height:100dvh;padding-top:56px;background:var(--gemboss-app-bg)}.icon-nav{top:56px;height:calc(100dvh - 56px);background:var(--gemboss-nav-bg);border-right-color:var(--gemboss-divider)}@media (max-width: 760px){.gemboss-platform-main{margin-left:0}}.gemboss-account-chip{width:32px;height:32px;border-radius:50%;background:var(--gemboss-primary);color:#fff;font-weight:600;font-size:12px;display:inline-flex;align-items:center;justify-content:center;border:none;cursor:pointer;transition:transform var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{transform:scale(1.05)}.gemboss-account-chip:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gemboss-platform-main{margin-top:56px;min-height:calc(100vh - 56px);padding:24px;background:#fafafb}@media (max-width: 768px){.gemboss-platform-main{margin-left:0;padding:16px}}.gemboss-platform-shell{display:block;min-height:100vh;background:var(--gemboss-app-bg)}.gemboss-platform-topbar{position:fixed;inset:0 0 auto;z-index:300;height:56px;border-bottom:1px solid var(--gemboss-divider);background:var(--gemboss-topbar-bg);display:grid;grid-template-columns:minmax(200px,1fr) minmax(0,560px) minmax(max-content,1fr);align-items:center;gap:16px;padding:0 16px;box-shadow:var(--gemboss-shadow-resting)}:root:has(.gemboss-platform-topbar){scroll-padding-top:64px}.gemboss-account-chip{width:32px;height:32px;border:1px solid var(--gemboss-chip-line);border-radius:var(--gemboss-radius-full);background:var(--gemboss-surface);color:var(--gemboss-chip-ink);display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer;transition:border-color var(--gemboss-transition-base) ease,background-color var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{border-color:var(--gemboss-chip-line-hover);background:var(--gemboss-chip-bg-hover);transform:none}.icon-nav{position:fixed;top:56px;left:0;z-index:200;height:calc(100dvh - 56px);border-right:1px solid var(--gemboss-divider);background:var(--gemboss-nav-bg);padding-top:12px}.gemboss-platform-main{min-height:calc(100vh - 56px);margin-top:56px;background:var(--gemboss-app-bg);padding:24px}@media (max-width: 1120px){.gemboss-platform-topbar{grid-template-columns:220px minmax(0,1fr) max-content;gap:12px}}@media (max-width: 760px){.gemboss-platform-topbar{height:auto;min-height:56px;grid-template-columns:minmax(0,1fr) auto;padding:12px}.gemboss-account-chip,.icon-nav{display:none}.gemboss-platform-main{margin-left:0;padding:16px}}.gnav-scroll{scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-assistant-railfoot.is-button{width:100%;border:none;background:none;cursor:pointer;text-align:left;font:inherit;border-radius:8px;transition:background .12s ease,color .12s ease}.gemboss-assistant-railfoot.is-button:hover{background:var(--gemboss-primary-soft);color:var(--gemboss-primary-dark)}.gemboss-assistant-empty{padding:24px 20px;color:var(--gemboss-text-muted);font-size:13px}@media (max-width: 760px){.gemboss-platform-topbar{display:flex;align-items:center;gap:8px;height:56px;min-height:56px;padding:0 12px}.gemboss-account-chip{display:inline-flex}.gemboss-platform-main{padding-top:16px;padding-bottom:calc(56px + env(safe-area-inset-bottom))}}@media (pointer: coarse){.gemboss-account-chip{width:44px;height:44px}.gnav-item{min-height:44px}.gemboss-assistant-collapse,.gemboss-assistant-newchat{min-height:44px;min-width:44px}}.icon-nav{width:240px;padding:12px 0 0;overflow:hidden;background:var(--gemboss-nav-bg);display:flex;flex-direction:column}.gnav-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding-inline:12px}.gnav-bottom{padding:0 12px 12px}.gnav-item{display:flex;align-items:center;gap:12px;width:100%;padding:8px 12px;margin:1px 0;border:0;background:transparent;cursor:pointer;text-align:left;border-radius:var(--gemboss-radius-md);text-decoration:none;font-family:inherit;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:500;line-height:1.2;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gnav-item:hover{background:var(--gemboss-nav-hover)}.gnav-item:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gnav-item.active{color:var(--gemboss-active-fg);font-weight:600}.gnav-group:not(.has-active-child)>.gnav-item.active{background:var(--gemboss-active-bg)}.gnav-group:not(.has-active-child)>.gnav-item.active:hover{background:var(--gemboss-active-bg)}.gnav-group.has-active-child>.gnav-item.active:hover{background:var(--gemboss-nav-hover)}.gnav-ico{flex:0 0 20px;width:20px;height:20px;display:grid;place-items:center}.gnav-ico svg{width:20px;height:20px;fill:currentColor}.gnav-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gnav-sub{list-style:none;margin:1px 0 6px;padding:0}.gnav-subitem{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 12px 6px 44px;margin:1px 0;border-radius:var(--gemboss-radius-sm);color:var(--gemboss-text-muted);font-size:13px;line-height:1.2;text-decoration:none;white-space:nowrap;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}@media (pointer: coarse){.gnav-subitem{min-height:44px}}.gnav-subitem:hover{background:var(--gemboss-nav-hover);color:var(--gemboss-text)}.gnav-subitem.active{color:var(--gemboss-active-fg);font-weight:600;background:var(--gemboss-active-bg)}.gnav-subitem.active:hover{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-subitem.active:before{content:"";position:absolute;left:20px;top:50%;transform:translateY(-50%);width:3px;height:15px;border-radius:2px;background:var(--gemboss-primary)}.gnav-subitem.is-soon{opacity:.5;cursor:default}.gnav-subitem em{font-style:normal;font-size:var(--gemboss-fs-micro);font-weight:600;letter-spacing:.04em;text-transform:uppercase;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-sm);padding:1px 6px}.gnav-sep{height:1px;background:var(--gemboss-divider);margin:8px 6px}.gnav-item.gnav-assistant{color:var(--gemboss-accent-strong);font-weight:600;background:var(--gemboss-accent-soft)}.gnav-item.gnav-assistant .gnav-ico svg{fill:var(--gemboss-accent)}.gnav-item.gnav-assistant:hover{background:color-mix(in srgb,var(--gemboss-accent) 16%,var(--gemboss-surface))}.gnav-item.gnav-assistant.active{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-item.gnav-assistant.active .gnav-ico svg{fill:var(--gemboss-active-fg)}.gemboss-platform-main{margin-left:240px}.gemboss-mobile-menu-btn,.gemboss-mobile-nav-backdrop{display:none}@media (max-width: 760px){.gemboss-platform-main{margin-left:0;padding-bottom:env(safe-area-inset-bottom)}.gemboss-mobile-menu-btn{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:38px;height:38px;margin-left:-2px;border:0;border-radius:8px;background:transparent;cursor:pointer;color:var(--gemboss-text)}.gemboss-mobile-menu-btn:active{background:var(--gemboss-hover)}.icon-nav{display:flex;width:min(82vw,300px);transform:translate(-100%);transition:transform .26s cubic-bezier(.4,0,.2,1),box-shadow .26s cubic-bezier(.4,0,.2,1);z-index:1000;box-shadow:none}.gemboss-platform-shell.is-mobile-nav-open .icon-nav{transform:translate(0);box-shadow:2px 0 26px #1f1e1d33}.gemboss-mobile-nav-backdrop{display:block;position:fixed;inset:56px 0 0;width:100%;border:0;padding:0;background:#14131261;opacity:0;pointer-events:none;transition:opacity .22s ease;z-index:999}.gemboss-platform-shell.is-mobile-nav-open .gemboss-mobile-nav-backdrop{opacity:1;pointer-events:auto}}@media (max-width: 305.98px){.gemboss-platform-topbar{padding:0 8px}}@media (min-width: 306px) and (max-width: 460px){.gemboss-platform-topbar{padding:0 8px}.gemboss-mobile-menu-btn,.gemboss-account-chip{width:44px;height:44px}}.gemboss-assistant-chatslot{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;min-width:0}.gemboss-assistant-chatslot[hidden]{display:none}.gemboss-assistant-page>.gemboss-assistant-tabs{flex:0 0 auto;display:flex;align-items:center;gap:4px;padding:4px 8px 0;overflow-x:auto;scrollbar-width:none}.gemboss-assistant-tabs::-webkit-scrollbar{display:none}.gemboss-assistant-tab{display:flex;align-items:center;flex:0 1 auto;min-width:0;max-width:190px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-md);background:transparent}.gemboss-assistant-tab.active{background:var(--gemboss-active-bg);border-color:var(--gemboss-active-bg)}.gemboss-assistant-tab-main{display:flex;align-items:center;gap:6px;min-width:0;min-height:44px;padding:0 4px 0 8px;border:0;background:transparent;font:inherit;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-tab.active .gemboss-assistant-tab-main{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gemboss-assistant-tab-dot{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-divider)}.gemboss-assistant-tab-dot.is-running{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}.gemboss-assistant-tab-close{flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;padding:0}.gemboss-assistant-tab-close:hover{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-close svg{width:14px;height:14px}.gemboss-assistant-sronly{position:absolute;left:0;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gemboss-assistant-thread-running{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}@media (prefers-reduced-motion: reduce){.gemboss-assistant-tab-dot.is-running,.gemboss-assistant-thread-running{animation:none}}.gemboss-assistant-route-claim{display:block;height:100%}.gemboss-assistant-layout.is-dock{height:auto;min-height:0}.gemboss-assistant-layout.is-dock .gemboss-assistant-page{height:auto;max-width:none;padding:4px 0 8px}.gnav-item.gnav-assistant{position:relative}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after,body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{content:"";position:absolute;top:6px;left:26px;width:8px;height:8px;border-radius:50%;border:2px solid var(--gemboss-surface)}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{background:var(--gemboss-success-strong)}@media (prefers-reduced-motion: reduce){body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{animation:none}}.gemboss-assistant-layout{display:flex;height:calc(100dvh - 56px);width:100%;min-height:0}.gemboss-assistant-rail{flex:0 0 264px;width:264px;display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--gemboss-divider);background:transparent;padding:16px 12px 12px;gap:12px;transition:flex-basis .18s ease,width .18s ease}.gemboss-assistant-rail-top{display:flex;align-items:center;gap:6px}.gemboss-assistant-newchat{display:flex;align-items:center;gap:8px;flex:1 1 auto;min-width:0;padding:12px;border:1px solid var(--gemboss-divider);border-radius:12px;background:transparent;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:600;cursor:pointer;transition:background .12s ease,border-color .12s ease}.gemboss-assistant-newchat:hover{background:#00000009;border-color:var(--gemboss-text-muted)}.gemboss-assistant-newchat svg{width:17px;height:17px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-newchat span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}.gemboss-assistant-kbd{flex:0 0 auto;font-size:var(--gemboss-fs-micro);font-weight:600;line-height:1;padding:4px 6px;border:1px solid var(--gemboss-divider);border-radius:6px;background:transparent;color:var(--gemboss-text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gemboss-assistant-search:focus-within .gemboss-assistant-kbd{display:none}.gemboss-assistant-collapse{flex:0 0 auto;display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-collapse:hover{background:#0000000d;color:var(--gemboss-text)}.gemboss-assistant-collapse svg{width:16px;height:16px;fill:currentColor}.gemboss-assistant-search{gap:6px}.gemboss-assistant-search>svg{width:15px;height:15px;fill:var(--gemboss-text-muted);flex:0 0 auto}.gemboss-assistant-search-clear{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:6px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-search-clear:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-search-clear svg{width:13px;height:13px;fill:currentColor}.gemboss-assistant-railfoot{flex:0 0 auto;display:flex;align-items:center;gap:6px;padding:8px 12px 2px;border-top:1px solid var(--gemboss-divider);margin-top:4px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption);line-height:1.35}.gemboss-assistant-railfoot svg{width:13px;height:13px;flex:0 0 auto;fill:currentColor;opacity:.8}.gemboss-assistant-threads{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:2px}.gemboss-assistant-threads-empty{padding:16px 8px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption)}.gemboss-assistant-group{display:flex;flex-direction:column;gap:2px}.gemboss-assistant-group+.gemboss-assistant-group{margin-top:12px}.gemboss-assistant-group-label{padding:4px 12px;font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--gemboss-text-muted);text-transform:uppercase}.gemboss-assistant-thread{position:relative;display:flex;align-items:center;border-radius:8px;transition:background .12s ease}.gemboss-assistant-thread:hover{background:var(--gemboss-hover, rgba(0,0,0,.04))}.gemboss-assistant-thread.active{background:#00000012}.gemboss-assistant-thread-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:8px 12px;border:0;background:transparent;text-align:left;cursor:pointer}.gemboss-assistant-thread-titlerow{display:flex;align-items:center;gap:6px;width:100%;min-width:0}.gemboss-assistant-pin-dot{width:12px;height:12px;flex:0 0 auto;fill:var(--gemboss-text-muted)}.gemboss-assistant-thread-title{flex:1 1 auto;min-width:0;font-size:13px;font-weight:500;color:var(--gemboss-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gemboss-assistant-thread-meta{max-width:100%;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gemboss-assistant-thread.menu-open{background:#00000012}.gemboss-assistant-thread.menu-open .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-menu{z-index:60;width:184px;padding:6px;display:flex;flex-direction:column}.gemboss-assistant-menu-confirm{padding:8px 12px 6px;font-size:var(--gemboss-fs-caption);font-weight:600;color:var(--gemboss-text)}.gemboss-assistant-menu button{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:0;border-radius:8px;background:transparent;text-align:left;font-size:13px;color:var(--gemboss-text);cursor:pointer}.gemboss-assistant-menu button:hover{background:var(--gemboss-hover, rgba(0,0,0,.05))}.gemboss-assistant-menu button.danger{color:var(--gemboss-danger-strong)}.gemboss-assistant-menu button svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-thread-actions{position:absolute;right:6px;display:flex;gap:2px;opacity:0;transition:opacity .12s ease}.gemboss-assistant-thread:hover .gemboss-assistant-thread-actions,.gemboss-assistant-thread:focus-within .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-thread-act{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-thread-act:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-thread-act.danger:hover{color:var(--gemboss-danger-strong)}.gemboss-assistant-thread-act svg{width:15px;height:15px;fill:currentColor}.gemboss-assistant-thread.editing{background:#00000012}.gemboss-assistant-thread-edit{display:flex;align-items:center;gap:2px;width:100%;padding:6px}.gemboss-assistant-thread-edit input{flex:1 1 auto;min-width:0}.gemboss-assistant-layout .gemboss-assistant-page{height:100%;max-width:820px;flex:1 1 auto;min-width:0;padding-top:16px}.gemboss-assistant-layout .gemboss-assistant-page.is-switching{opacity:.55;transition:opacity .12s ease;pointer-events:none}.gemboss-assistant-rail.is-collapsed{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat span,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-search,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-railfoot,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-threads{display:none}@media (max-width: 760px){.gemboss-assistant-rail{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-newchat span,.gemboss-assistant-search,.gemboss-assistant-railfoot,.gemboss-assistant-threads,.gemboss-assistant-collapse{display:none}}.gemboss-assistant-page{height:calc(100dvh - 56px);width:100%;max-width:760px;margin:0 auto;padding:24px 0 16px;display:flex;flex-direction:column;min-height:0}.gemboss-assistant-page>*{flex:1 1 auto;min-height:0}.gemboss-assistant-empty{flex:1;display:grid;place-items:center;color:var(--gemboss-text-muted);font-size:14px}.gemboss-platform-shell{display:flow-root}.gemboss-platform-main{padding-bottom:calc(24px + var(--gemboss-invite-h, 0px))}@keyframes gemboss-assistant-pulse{0%,to{opacity:1}50%{opacity:.35}}.gb-account{position:relative}.gb-account>summary{list-style:none}.gb-account>summary::-webkit-details-marker{display:none}.gb-account-head{padding:12px 16px;border-bottom:1px solid var(--gemboss-divider)}.gb-account-name{font-size:13px;font-weight:600;color:var(--gemboss-text-strong)}.gb-account-email{font-size:12px;color:var(--gemboss-text-muted)}.gb-account-role{display:inline-block;margin-top:4px;padding:1px 6px;border-radius:4px;font-size:11px;font-weight:600;color:var(--gemboss-active-fg);background:var(--gemboss-active-bg)}.gb-account-form{margin:0}.gnav-scroll::-webkit-scrollbar{width:9px}.gnav-scroll::-webkit-scrollbar-track{background:transparent}.gnav-scroll::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:6px;border:2px solid transparent;background-clip:content-box}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ui-stagepath{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,190px),1fr));gap:var(--ui-space-2);margin:0;padding:0;list-style:none}.ui-stagepath__stage{position:relative;display:flex;align-items:flex-start;gap:var(--ui-space-2);min-width:0;padding:var(--ui-space-3);border:1px solid var(--ui-border);border-radius:var(--ui-radius-lg);background:var(--ui-surface)}.ui-stagepath__stage--current{border-color:var(--gemboss-primary);box-shadow:inset 0 0 0 1px var(--gemboss-primary)}.ui-stagepath__n{flex:none;display:inline-grid;place-items:center;width:24px;height:24px;border-radius:50%;background:var(--ui-surface-2);font-size:var(--ui-fs-caption);font-weight:700;color:var(--ui-text-strong)}.ui-stagepath__stage--current .ui-stagepath__n{background:var(--gemboss-primary);color:var(--gemboss-on-primary)}.ui-stagepath__stage--done .ui-stagepath__n{background:var(--gemboss-success-soft);color:var(--gemboss-success-strong)}.ui-stagepath__text{display:grid;flex:1;gap:4px;min-width:0}.ui-stagepath__name{font-size:var(--ui-fs-body);line-height:20px;font-weight:650;color:var(--ui-text-strong);text-decoration:none;overflow-wrap:anywhere}a.ui-stagepath__name:after{content:"";position:absolute;inset:0;border-radius:inherit}a.ui-stagepath__name:hover{text-decoration:underline}a.ui-stagepath__name:focus-visible{outline:none}a.ui-stagepath__name:focus-visible:after{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-stagepath__count{font-size:var(--ui-fs-caption);line-height:16px;color:var(--ui-text-muted);font-variant-numeric:tabular-nums}.ui-stagepath__bar{appearance:none;display:block;width:100%;height:4px;border:0;border-radius:999px;overflow:hidden;background:var(--ui-border);color:var(--gemboss-success)}.ui-stagepath__bar::-webkit-progress-bar{background:inherit;border-radius:inherit}.ui-stagepath__bar::-webkit-progress-value{background:currentColor;border-radius:inherit}.ui-stagepath__bar::-moz-progress-bar{background:currentColor;border-radius:inherit}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage path — @gemboss/ui, unreleased (after 0.49.0). An ordered path of stages in which each one has to finish before the next
|
|
3
|
+
* one counts: GemPress's translation review (redesign approved by Chris 23/10/2026) unlocks a language header & footer first, then
|
|
4
|
+
* pages, then the blog, then the docs, because a translated page is not worth publishing inside an untranslated frame. GemPress drew
|
|
5
|
+
* it with its own CSS (`gp-unlock`); GemNews and GemCommunity translations are next, so it lives here. Not `SetupGuide` (steps a
|
|
6
|
+
* person ticks, one open at a time, with a body each) and not `ProgressRing` (one count): this is several counts, in an order.
|
|
7
|
+
*
|
|
8
|
+
* The contract it draws, which every surface keeps:
|
|
9
|
+
* - the stages in their order, each with its number; a stage DONE (`done >= total`, so a stage with nothing in it holds nothing up)
|
|
10
|
+
* shows a green ✓ in place of its number;
|
|
11
|
+
* - ONE current stage, the one being worked on: an ink outline and an ink number (`current`; by default the first stage not done,
|
|
12
|
+
* `null` for none). It is `aria-current="step"`;
|
|
13
|
+
* - the count in words under the name ("3 / 35 pages approved"), and a thin bar that says the same: the words are what a screen
|
|
14
|
+
* reader hears, the bar is hidden from it. The words are the surface's to change (`caption`, `format`): the path does no plural
|
|
15
|
+
* and names no language;
|
|
16
|
+
* - a stage with `href` is a link, and the whole card is its target.
|
|
17
|
+
*
|
|
18
|
+
* Presentational and server-renderable: no state, no effect. The colours are tokens, so the dark palette follows. The bar is a
|
|
19
|
+
* `<progress>`, not a width in a style attribute, so it fills under a CSP that forbids inline style (GemPress, gemcare). Its
|
|
20
|
+
* stylesheet travels with it (`stage-path.css`, own entry; `@gemboss/ui/stage-path.css` for a plain-HTML surface, which writes the
|
|
21
|
+
* classes listed at the top of that file).
|
|
22
|
+
*/
|
|
23
|
+
import "./stage-path.css";
|
|
24
|
+
import React, { type ReactNode } from "react";
|
|
25
|
+
|
|
26
|
+
const cx = (...p: Array<string | false | null | undefined>) => p.filter(Boolean).join(" ");
|
|
27
|
+
/** A count as the path draws it: a whole number, 0 or more; anything that is not a finite number is 0. */
|
|
28
|
+
const whole = (n: unknown) => (typeof n === "number" && Number.isFinite(n) ? Math.max(Math.round(n), 0) : 0);
|
|
29
|
+
|
|
30
|
+
export interface StagePathStage {
|
|
31
|
+
/** Unique in the path; what `current` names. */
|
|
32
|
+
key: string;
|
|
33
|
+
name: ReactNode;
|
|
34
|
+
/** How many are approved. Clamped into 0..total. */
|
|
35
|
+
done: number;
|
|
36
|
+
total: number;
|
|
37
|
+
/** The word after the total, in the number the surface wants printed: "pages", "parts". */
|
|
38
|
+
unit?: string;
|
|
39
|
+
/** Where the stage opens (its review queue). The whole card is the link. */
|
|
40
|
+
href?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface StagePathProps {
|
|
44
|
+
stages: readonly StagePathStage[];
|
|
45
|
+
/** The stage being worked on. Default: the first stage not done. `null`: none (every stage is waiting on something else). */
|
|
46
|
+
current?: string | null;
|
|
47
|
+
/** The list's name for a screen reader (default "Unlock path"). */
|
|
48
|
+
label?: string;
|
|
49
|
+
/** The words under a stage's name. Default "3 / 35 pages approved". */
|
|
50
|
+
caption?: (count: { done: number; total: number; unit?: string }) => ReactNode;
|
|
51
|
+
/** A number as the surface writes it ("1,204"). Default `String`. */
|
|
52
|
+
format?: (n: number) => string;
|
|
53
|
+
className?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Whether a stage is done: every item approved, and a stage with nothing in it is done. Pure, for a page that writes the markup. */
|
|
57
|
+
export function stagePathDone(stage: Pick<StagePathStage, "done" | "total">): boolean {
|
|
58
|
+
return whole(stage.done) >= whole(stage.total);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function StagePath({ stages, current, label = "Unlock path", caption, format = String, className }: StagePathProps) {
|
|
62
|
+
if (!stages.length) return null; // nothing to unlock is no path
|
|
63
|
+
const rows = stages.map((s) => {
|
|
64
|
+
const total = whole(s.total);
|
|
65
|
+
return { s, total, done: Math.min(whole(s.done), total), finished: stagePathDone(s) };
|
|
66
|
+
});
|
|
67
|
+
const now = current === undefined ? rows.find((r) => !r.finished)?.s.key : current;
|
|
68
|
+
return (
|
|
69
|
+
<ol className={cx("ui-stagepath", className)} aria-label={label}>
|
|
70
|
+
{rows.map(({ s, total, done, finished }, i) => {
|
|
71
|
+
const on = now != null && s.key === now;
|
|
72
|
+
return (
|
|
73
|
+
<li key={s.key} className={cx("ui-stagepath__stage", finished && "ui-stagepath__stage--done", on && "ui-stagepath__stage--current")}
|
|
74
|
+
aria-current={on ? "step" : undefined}>
|
|
75
|
+
<span className="ui-stagepath__n" aria-hidden="true">{finished ? "✓" : i + 1}</span>
|
|
76
|
+
<span className="ui-stagepath__text">
|
|
77
|
+
{s.href ? <a className="ui-stagepath__name" href={s.href}>{s.name}</a> : <span className="ui-stagepath__name">{s.name}</span>}
|
|
78
|
+
<span className="ui-stagepath__count">
|
|
79
|
+
{caption ? caption({ done, total, unit: s.unit }) : `${format(done)} / ${format(total)}${s.unit ? ` ${s.unit}` : ""} approved`}
|
|
80
|
+
</span>
|
|
81
|
+
{/* 0 of 0 is a stage with nothing to hold up: a full bar, as its ✓ says. */}
|
|
82
|
+
<progress className="ui-stagepath__bar" value={total ? done : 1} max={total || 1} aria-hidden="true" />
|
|
83
|
+
</span>
|
|
84
|
+
</li>
|
|
85
|
+
);
|
|
86
|
+
})}
|
|
87
|
+
</ol>
|
|
88
|
+
);
|
|
89
|
+
}
|
package/src/stage.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ui-stage{--ui-stage-top: #1d2058;--ui-stage-deep: #0d0f2e;--ui-stage-glow: rgba(139, 147, 255, .5);--ui-stage-glow-low: rgba(86, 97, 245, .34);--ui-stage-glass: rgba(255, 255, 255, .08);--ui-stage-glass-line: rgba(255, 255, 255, .14);--ui-stage-ink: rgba(255, 255, 255, .88);--ui-stage-ink-dim: rgba(255, 255, 255, .6);--ui-stage-number: #a5abff;--ui-stage-lift: 0 16px 32px -12px rgba(4, 5, 26, .72), 0 4px 8px -2px rgba(4, 5, 26, .36);position:relative;display:flex;flex-direction:column;justify-content:center;gap:8px;padding:16px;overflow:hidden;border-radius:var(--gemboss-radius-lg, 12px);color:var(--ui-stage-ink);font-size:var(--gemboss-fs-caption, 12px);line-height:16px;background:radial-gradient(130% 90% at 100% 0%,var(--ui-stage-glow),transparent 55%),radial-gradient(90% 80% at 0% 100%,var(--ui-stage-glow-low),transparent 60%),linear-gradient(160deg,var(--ui-stage-top),var(--ui-stage-deep))}.ui-stage:before{content:"";position:absolute;inset:0;pointer-events:none;background-image:radial-gradient(rgba(255,255,255,.1) 1px,transparent 1.5px);background-size:16px 16px;-webkit-mask-image:linear-gradient(170deg,#000,transparent 70%);mask-image:linear-gradient(170deg,#000,transparent 70%)}.ui-stage>*{position:relative}.ui-stage__win{display:flex;flex-direction:column;overflow:hidden;border-radius:var(--gemboss-radius-md, 8px);background:var(--gemboss-surface, #ffffff);color:var(--gemboss-text, #1b1c1e);box-shadow:var(--ui-stage-lift)}.ui-stage__bar{flex:none;display:flex;align-items:center;gap:4px;height:16px;padding:0 8px;border-bottom:1px solid var(--gemboss-divider, #e5e7ea);font-size:var(--gemboss-fs-micro, 11px);color:var(--gemboss-text-muted, #686b71)}.ui-stage__bar i{width:6px;height:6px;border-radius:999px;background:var(--gemboss-divider, #e5e7ea)}.ui-stage__bar b{margin-left:4px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ui-stage__shot{display:block;width:100%;height:auto}.ui-stage__body{display:flex;flex-direction:column;gap:6px;padding:8px}.ui-stage__line{display:block;height:6px;border-radius:999px;background:var(--gemboss-divider, #e5e7ea)}.ui-stage__line--short{width:55%}.ui-stage__line--strong{height:8px;width:70%;background:var(--gemboss-text, #1b1c1e)}.ui-stage__tile{display:flex;align-items:center;gap:6px;padding:8px 12px;border-radius:var(--gemboss-radius-md, 8px);background:var(--ui-stage-glass);color:var(--ui-stage-ink)}.ui-stage__tile em{font-style:normal;font-family:ui-monospace,SF Mono,Menlo,monospace;color:var(--ui-stage-number)}.ui-stage__tile--on{background:var(--gemboss-surface, #ffffff);color:var(--gemboss-text, #1b1c1e);box-shadow:0 0 0 1px #fff6,0 0 24px var(--ui-stage-glow)}.ui-stage__tile--on em{color:var(--gemboss-accent, #5661f5)}.ui-stage__bubble{align-self:flex-start;max-width:85%;padding:6px 12px;border-radius:12px;border:1px solid var(--ui-stage-glass-line);background:var(--ui-stage-glass);color:var(--ui-stage-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ui-stage__bubble--me{align-self:flex-end;border-color:transparent;background:var(--gemboss-surface, #ffffff);color:var(--gemboss-text, #1b1c1e);box-shadow:var(--ui-stage-lift)}
|