@gemboss/ui 0.25.0 → 0.32.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 +276 -0
- package/README.md +370 -24
- package/catalog/editor.html +1 -1
- package/catalog/index.html +912 -63
- package/gemboss-ui.css +3 -3
- package/package.json +14 -2
- package/parts/components.css +2 -2
- package/parts/core.css +1 -1
- package/parts/shell.css +1 -1
- package/src/action-card.css +1 -0
- package/src/action-card.tsx +149 -0
- package/src/assistant/bridge.tsx +636 -0
- package/src/assistant/chat-markdown.ts +280 -0
- package/src/assistant/chat-turns.ts +120 -0
- package/src/assistant/chat.tsx +909 -0
- package/src/assistant/engine-mark-art.ts +45 -0
- package/src/assistant/engine-mark.tsx +39 -0
- package/src/assistant/engine.tsx +119 -12
- package/src/assistant/host.tsx +115 -32
- package/src/assistant/index.ts +8 -1
- package/src/assistant-chat.css +1 -0
- package/src/assistant-engine.css +1 -1
- package/src/assistant.css +1 -1
- package/src/auth.css +1 -1
- package/src/auth.tsx +17 -2
- package/src/chat-composer.css +1 -1
- package/src/chat-plain.js +6 -0
- package/src/chat.css +1 -1
- package/src/editor/frame.tsx +11 -4
- package/src/editor/index.ts +1 -1
- package/src/editor.css +1 -1
- package/src/engine-plain.js +1 -0
- package/src/index.ts +4 -1
- package/src/kit-plain.js +1 -1
- package/src/minichart.css +1 -0
- package/src/minichart.tsx +165 -0
- package/src/portal.css +1 -1
- package/src/search-dialog.tsx +67 -13
- package/src/setup-guide.css +1 -0
- package/src/setup-guide.tsx +116 -0
- package/src/ui.css +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(L){"use strict";var N=L.gembossUI;if(!N){L.console&&L.console.error("@gemboss/ui engine-plain.js: load kit-plain.js first (it defines gembossUI)");return}if(N.enginePicker)return;var Z={chip:"Engine",dialog:"Assistant engine",tabs:"Engine, setup and status",engineTab:"Engine",setupTab:"Setup",statusTab:"Status",engine:"Engine",model:"Model",effort:"Effort",defaultChoice:"Default",copy:"Copy command",copied:"Copied",copyFailed:"Select the command and copy it",pairingCode:"Pairing code",steps:"Paste the command into Terminal, then press Enter.",bridge:"Bridge on your machine",version:"Version",latest:"Latest",startsAtSignIn:"Starts at sign-in",machine:"Machine",lastSeen:"Last seen",yes:"Yes",no:"No",unknown:"Not known",running:"Running",outdated:"Outdated",offline:"Not connected",unpaired:"Not set up",checking:"Checking",updateDue:"Update available",close:"Close"},U={running:"ok",outdated:"warn",offline:"down",unpaired:"down",checking:"idle"},q={ok:"gb-engine-dot gb-engine-dot--ok",warn:"gb-engine-dot gb-engine-dot--warn",down:"gb-engine-dot gb-engine-dot--down",idle:"gb-engine-dot gb-engine-dot--idle"},$={success:"ui-badge ui-badge--success",warning:"ui-badge ui-badge--warning",critical:"ui-badge ui-badge--critical",info:"ui-badge ui-badge--info"},ee={warn:"gb-engine-notice gb-engine-notice--warn",down:"gb-engine-notice gb-engine-notice--down"},ne=["notes","modelControl","statusActions"],V=function(i){return i&&N.engineMark?N.engineMark(i,{decorative:!0}):null},I=typeof HTMLElement<"u"&&Object.prototype.hasOwnProperty.call(HTMLElement.prototype,"popover"),D=function(i){return typeof Node<"u"&&i instanceof Node},te=0;function r(i,g,t){var u=document.createElement(i);if(g)for(var l in g){var o=g[l];o==null||o===!1||(l==="text"?u.textContent=String(o):l==="className"?u.className=o:u.setAttribute(l,o===!0?"":String(o)))}return z(u,t),u}function z(i,g){return g==null||g===!1?i:Array.isArray(g)?(g.forEach(function(t){z(i,t)}),i):(i.appendChild(D(g)?g:document.createTextNode(String(g))),i)}function x(i){return typeof DocumentFragment<"u"&&i instanceof DocumentFragment?Array.prototype.slice.call(i.childNodes):i}var ae=function(i){return D(i)||Array.isArray(i)&&i.some(D)};function j(i,g){for(var t=Array.prototype.slice.call(g.childNodes),u=0;u<t.length;u++){var l=t[u],o=i.childNodes[u];o?o.nodeType===l.nodeType&&(o.nodeType!==1||o.tagName===l.tagName&&o.getAttribute("data-gb-key")===l.getAttribute("data-gb-key"))?ie(o,l):i.replaceChild(l,o):i.appendChild(l)}for(;i.childNodes.length>t.length;)i.removeChild(i.lastChild)}function ie(i,g){if(i.nodeType!==1){i.nodeValue!==g.nodeValue&&(i.nodeValue=g.nodeValue);return}var t,u;for(t=i.attributes.length-1;t>=0;t--)u=i.attributes[t].name,u!=="style"&&!g.hasAttribute(u)&&i.removeAttribute(u);for(t=0;t<g.attributes.length;t++)u=g.attributes[t],i.getAttribute(u.name)!==u.value&&i.setAttribute(u.name,u.value);i.hasAttribute("data-gb-slot")||(j(i,g),i.tagName==="SELECT"&&i.value!==g.getAttribute("data-value")&&(i.value=g.getAttribute("data-value")||""))}function re(i){var g=function(){try{var t=document.createElement("textarea");t.value=i,t.setAttribute("readonly",""),t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.select();var u=document.execCommand("copy");return t.remove(),u}catch{return!1}};try{if(navigator.clipboard&&navigator.clipboard.writeText)return navigator.clipboard.writeText(i).then(function(){return!0},g)}catch{}return Promise.resolve(g())}function oe(i,g){var t={},u="gb-engine-"+ ++te,l={open:!1,tab:"engine",said:"",saidTimer:0},o=Object.assign({},Z),M={};function G(e){Object.keys(e||{}).forEach(function(n){var a=e[n];if((n==="bridge"||n==="setup")&&a&&typeof a=="object"&&t[n]&&typeof t[n]=="object"&&(a=Object.assign({},t[n],a)),n==="labels"){o=Object.assign({},o,a||{});return}ne.indexOf(n)>=0&&(a=x(a)),n==="engines"&&Array.isArray(a)&&(a=a.map(function(s){return s&&s.note?Object.assign({},s,{note:x(s.note)}):s})),n==="setup"&&a&&a.steps&&(a=Object.assign({},a,{steps:x(a.steps)})),n==="bridge"&&a&&a.detail&&(a=Object.assign({},a,{detail:x(a.detail)})),t[n]=a})}G(g);var T=document.createElement("span");T.className="gb-engine"+(t.className?" "+t.className:"");var b=r("button",{type:"button",className:"gb-engine-chip","aria-haspopup":"dialog","aria-expanded":"false","aria-controls":u+"-panel"}),d=r("div",{id:u+"-panel",className:"gb-engine-panel gemboss-popover-surface",role:"dialog","aria-label":o.dialog,hidden:!0});I&&d.setAttribute("popover","manual"),T.appendChild(b),I?T.appendChild(d):document.body.appendChild(d),i.appendChild(T);function H(){return["engine"].concat(t.setup?["setup"]:[],t.bridge?["status"]:[])}function B(){return H().indexOf(l.tab)>=0?l.tab:"engine"}function A(e,n){return ae(n)?(M[e]=Array.isArray(n)?n.filter(D):[n],r("span",{"data-gb-slot":e,"data-gb-key":"slot-"+e,style:"display:contents"})):n}function le(){d.querySelectorAll("[data-gb-slot]").forEach(function(e){var n=M[e.getAttribute("data-gb-slot")]||[],a=Array.prototype.slice.call(e.childNodes);a.length===n.length&&a.every(function(s,c){return s===n[c]})||e.replaceChildren.apply(e,n)})}function de(){var e=t.bridge&&t.showBridgeDot!==!1?U[t.bridge.state]:null,n=(t.engines||[]).filter(function(c){return c.id===t.engine})[0],a=t.model?(t.models||[]).filter(function(c){return c.id===t.model})[0]:null,s=n?V(n.mark):null;return r("span",null,[e?r("span",{className:q[e],"aria-hidden":"true"}):null,r("span",{className:"gb-engine-chiplabel"},[n?n.label:t.engine||"",a?r("span",{className:"gb-engine-chipsub",text:" \xB7 "+a.label}):null]),s?r("span",{className:"gb-engine-chipmark"},s):null])}function ue(){var e=(t.engines||[]).filter(function(s){return s.id===t.engine})[0],n=t.model?(t.models||[]).filter(function(s){return s.id===t.model})[0]:null,a=t.bridge&&t.showBridgeDot!==!1&&t.bridge.state!=="running"?". "+o.bridge+": "+o[t.bridge.state]:"";return o.chip+": "+(e?e.label:t.engine)+(n?" \xB7 "+n.label:"")+a}function K(e,n,a,s,c,p){var m=t.locked||!c||!!p,F=typeof p=="string"?p:void 0;if(a.length>6||a.some(function(f){return f.group})){var w=r("select",{className:"ui-select ui-select--slim gb-engine-select",disabled:m,title:F,"data-kind":e,"data-value":s||""}),y=null,O;return a.forEach(function(f){var X=r("option",{value:f.id,title:f.title,text:f.label,selected:(s||"")===f.id});f.group?((!y||O!==f.group)&&(y=r("optgroup",{label:f.group}),O=f.group,w.appendChild(y)),y.appendChild(X)):(y=null,O=void 0,w.appendChild(X))}),r("label",{className:"gb-engine-field","data-gb-key":e},[r("span",{className:"gb-engine-label",text:n}),w])}var W=u+"-lbl-"+e;return r("div",{className:"gb-engine-field","data-gb-key":e},[r("span",{className:"gb-engine-label",id:W,text:n}),r("div",{className:"gb-engine-opts",role:"group","aria-labelledby":W},a.map(function(f){return r("button",{type:"button",className:"gb-engine-opt","aria-pressed":String((s||"")===f.id),disabled:m,title:F||f.title,text:f.label,"data-kind":e,"data-choice":f.id})}))])}function P(e){return!(t.locked||e.disabled||!t.onEngineChange)}function ce(){var e=u+"-lbl-engine",n=t.engines||[],a=(n.filter(function(c){return c.id===t.engine&&P(c)})[0]||n.filter(P)[0]||{}).id,s=[r("div",{className:"gb-engine-field","data-gb-key":"engine"},[r("span",{className:"gb-engine-label",id:e,text:o.engine}),r("div",{className:"gb-engine-list",role:"radiogroup","aria-labelledby":e},n.map(function(c){return r("button",{type:"button",role:"radio","aria-checked":String(c.id===t.engine),"data-engine":c.id,"data-gb-key":"engine-"+c.id,tabindex:c.id===a?"0":"-1",className:"gb-engine-row",disabled:!P(c)},[r("span",{className:"gb-engine-rowhead"},[r("span",{className:"gb-engine-rowname",text:c.label}),c.badge?r("span",{className:c.badgeTone?$[c.badgeTone]:"ui-badge",text:c.badge}):null]),c.note?r("span",{className:"gb-engine-note"},A("note-"+c.id,c.note)):null])}))])];return t.modelControl?s.push(r("div",{className:"gb-engine-field","data-gb-key":"model"},[r("span",{className:"gb-engine-label",text:o.model}),A("modelControl",t.modelControl)])):t.models&&t.models.length&&s.push(K("model",o.model,t.models,t.model,t.onModelChange)),t.efforts&&t.efforts.length&&s.push(K("effort",o.effort,t.efforts,t.effort,t.onEffortChange,t.effortDisabled)),t.notes&&s.push(r("div",{className:"gb-engine-notes"},A("notes",t.notes))),s}function ge(){var e=t.setup||{},n=t.bridge,a=[];return n&&(n.state==="outdated"||n.state==="offline"||n.state==="unpaired")&&a.push(r("p",{className:"gb-engine-callout "+(n.state==="outdated"?"gb-engine-callout--warn":"gb-engine-callout--down")},[r("strong",{text:o.bridge+": "+o[n.state].toLowerCase()+"."}),n.detail?" ":null,n.detail?A("detail",n.detail):null])),(e.steps||e.command)&&a.push(r("div",{className:"gb-engine-steps"},e.steps?A("steps",e.steps):r("p",{text:o.steps}))),e.command&&(a.push(r("pre",{className:"gb-engine-cmd"},r("code",{text:e.command}))),a.push(r("div",{className:"gb-engine-actions"},[r("button",{type:"button",className:"ui-btn ui-btn--primary","data-gb-copy":"",text:l.said==="copied"?o.copied:o.copy}),r("span",{className:"gb-engine-said",role:"status",text:l.said==="failed"?o.copyFailed:l.said==="copied"?o.copied:""})]))),e.pairingCode&&a.push(r("p",{className:"gb-engine-code"},[o.pairingCode+": ",r("code",{text:e.pairingCode})])),e.note&&a.push(r("p",{className:"gb-engine-note"},e.note)),a}function fe(){var e=t.bridge,n=r("dl",{className:"gb-engine-rows"}),a=function(p,m){n.appendChild(r("dt",{text:p})),n.appendChild(r("dd",null,m))},s=function(p){return p==null?o.unknown:p?o.yes:o.no};a(o.bridge,[r("span",{className:q[U[e.state]],"aria-hidden":"true"})," "+o[e.state]]),e.version&&a(o.version,e.version+(e.latest&&e.latest!==e.version?" \xB7 "+o.latest+" "+e.latest:"")),a(o.startsAtSignIn,s(e.autostart)),e.machine&&a(o.machine,e.machine),e.lastSeen&&a(o.lastSeen,e.lastSeen);var c=[n];return e.detail&&e.state!=="running"&&c.push(r("p",{className:"gb-engine-note"},A("detail",e.detail))),t.statusActions&&c.push(r("div",{className:"gb-engine-actions"},A("statusActions",t.statusActions))),c}function be(){var e=H(),n=B(),a=document.createElement("div");return e.length>1&&a.appendChild(r("div",{className:"ui-tabs gb-engine-tabs",role:"tablist","aria-label":o.tabs,"data-gb-key":"tabs"},e.map(function(s){return r("button",{type:"button",role:"tab",id:u+"-tab-"+s,"aria-controls":u+"-pane-"+s,"aria-selected":String(n===s),tabindex:n===s?"0":"-1","data-tab":s,"data-gb-key":"tab-"+s},[{engine:o.engineTab,setup:o.setupTab,status:o.statusTab}[s],s==="setup"&&t.bridge&&t.bridge.state==="outdated"?r("span",{className:"gb-engine-dot gb-engine-dot--warn",role:"img","aria-label":o.updateDue}):null])}))),a.appendChild(r("div",{className:"gb-engine-pane",role:e.length>1?"tabpanel":null,id:u+"-pane-"+n,"aria-labelledby":e.length>1?u+"-tab-"+n:null,"data-gb-key":"pane-"+n},n==="engine"?ce():n==="setup"?ge():fe())),a}var S=null;function h(){var e=ue();b.setAttribute("aria-label",e),b.title=e,b.setAttribute("aria-expanded",l.open?"true":"false");var n=(t.engines||[]).filter(function(s){return s.id===t.engine})[0];if(b.className=n&&V(n.mark)?"gb-engine-chip has-mark":"gb-engine-chip",j(b,de()),d.setAttribute("aria-label",o.dialog),M={},!l.open){j(d,document.createElement("div"));return}j(d,be()),le();var a=d.querySelector(".gb-engine-pane");C&&a!==S&&(S&&C.unobserve(S),a&&C.observe(a),S=a)}function E(){l.open&&N.placeFloating(d,b,t.end)}function Y(e){e!==t.engine&&(t.engine=e,t.onEngineChange&&t.onEngineChange(e),h())}function _(e,n,a){var s=e==="model"?t.model:t.effort,c=e==="model"?t.onModelChange:t.onEffortChange;!c||t.locked||((s||"")!==n&&(e==="model"?t.model=n:t.effort=n,c(n)),a?Q():h())}function J(e,n){if(e!==B()&&(l.tab=e,t.onTabChange&&t.onTabChange(e),h(),E()),n){var a=d.querySelector('[role="tab"][data-tab="'+e+'"]');a&&a.focus()}}d.addEventListener("click",function(e){var n=e.target.closest?e.target:e.target.parentElement,a=n&&n.closest("button");!a||!d.contains(a)||a.disabled||(a.hasAttribute("data-tab")?J(a.getAttribute("data-tab")):a.hasAttribute("data-engine")?Y(a.getAttribute("data-engine")):a.hasAttribute("data-choice")?_(a.getAttribute("data-kind"),a.getAttribute("data-choice"),!0):a.hasAttribute("data-gb-copy")&&pe())}),d.addEventListener("change",function(e){var n=e.target;n&&n.tagName==="SELECT"&&n.hasAttribute("data-kind")&&d.contains(n)&&_(n.getAttribute("data-kind"),n.value,!1)}),d.addEventListener("keydown",function(e){var n=e.target;if(!(!n||!n.getAttribute)){if(n.getAttribute("role")==="tab"){var a=H(),s=a.indexOf(B()),c=e.key==="ArrowRight"?a[(s+1)%a.length]:e.key==="ArrowLeft"?a[(s-1+a.length)%a.length]:e.key==="Home"?a[0]:e.key==="End"?a[a.length-1]:null;if(!c)return;e.preventDefault(),J(c,!0)}else if(n.hasAttribute("data-engine")){var p=e.key==="ArrowDown"||e.key==="ArrowRight"?1:e.key==="ArrowUp"||e.key==="ArrowLeft"?-1:0,m=(t.engines||[]).filter(P);if(!p||!m.length)return;e.preventDefault();var F=m.map(function(O){return O.id}).indexOf(n.getAttribute("data-engine")),w=m[(F+p+m.length)%m.length];Y(w.id);var y=d.querySelector('[data-engine="'+(L.CSS&&CSS.escape?CSS.escape(w.id):w.id)+'"]');y&&y.focus()}}});function pe(){var e=t.setup||{};e.command&&re(e.command).then(function(n){l.said=n?"copied":"failed",h(),clearTimeout(l.saidTimer),l.saidTimer=setTimeout(function(){l.said="",h()},2e3)})}var R=-1,k=0,C=typeof ResizeObserver>"u"?null:new ResizeObserver(function(){d.scrollHeight!==R&&(R=d.scrollHeight,E())});function me(e){if(!(e.key!=="Escape"||e.defaultPrevented||!l.open)&&!(e.isComposing||e.keyCode===229)){var n=document.activeElement,a=n&&n.closest?n.closest('dialog[open], [aria-modal="true"]'):null;a&&!d.contains(a)||(e.preventDefault(),n&&(d.contains(n)||b.contains(n))?(e.stopPropagation(),Q()):v(!1))}}function he(e){var n=e.target,a=n&&n.closest?n.closest('dialog[open], [aria-modal="true"]'):null;a&&!d.contains(a)&&v(!1)}function ve(e){var n=e.target;d.contains(n)||b.contains(n)||n&&n.closest&&n.closest('dialog[open], [aria-modal="true"], .ui-overlay')||v(!1)}function ye(e){var n=e.target;!n||d.contains(n)||n!==document&&n.nodeType!==9&&!n.contains(b)||k||(k=requestAnimationFrame(function(){k=0,E()}))}function Ne(e){var n=e?"addEventListener":"removeEventListener";document[n]("keydown",me,!0),document[n]("pointerdown",ve,!0),document[n]("focusin",he,!0),document[n]("scroll",ye,!0),window[n]("resize",E),e?C&&C.observe(d):(cancelAnimationFrame(k),k=0,C&&C.disconnect(),S=null,R=-1)}function v(e){if(e!==l.open){if(l.open=e,e||(l.tab="engine"),d.hidden=!e,e?d.setAttribute("data-open",""):d.removeAttribute("data-open"),I&&(e&&!d.matches(":popover-open")&&d.showPopover(),!e&&d.matches(":popover-open")&&d.hidePopover()),Ne(e),h(),E(),e){var n=d.querySelector('[role="tab"][aria-selected="true"]')||d.querySelector("button:not([disabled])");n&&n.focus()}t.onOpenChange&&t.onOpenChange(e)}}function Q(){v(!1),b.focus()}return b.addEventListener("click",function(){v(!l.open)}),h(),{element:T,panel:d,update:function(e){G(e),h()},openTab:function(e){var n=l.open;if(e!==l.tab&&(l.tab=e,t.onTabChange&&t.onTabChange(e)),!n)v(!0);else{h(),E();var a=d.querySelector('[role="tab"][aria-selected="true"]');a&&a.focus()}},open:function(){v(!0)},close:function(){v(!1)},isOpen:function(){return l.open},destroy:function(){v(!1),clearTimeout(l.saidTimer),T.remove(),d.remove()}}}function se(i){i=i||{};var g=i.tone==="warn"?"warn":"down",t=r("p",{className:ee[g]+(i.className?" "+i.className:""),role:"status"},[r("span",{className:q[g],"aria-hidden":"true"}),r("span",{className:"gb-engine-notice-text"},x(i.node)||i.text||"")]);if(i.onOpenSetup){var u=r("button",{type:"button",className:"gb-engine-notice-link",text:i.action||"Open setup"});u.addEventListener("click",i.onOpenSetup),t.appendChild(u)}return t}N.enginePicker=oe,N.bridgeNotice=se})(typeof globalThis<"u"?globalThis:this);
|
package/src/index.ts
CHANGED
|
@@ -24,8 +24,10 @@ export { SelectableResourceList } from "./resource-list-select";
|
|
|
24
24
|
export type { SelectableResourceItem, SelectableResourceListProps } from "./resource-list-select";
|
|
25
25
|
// The one switch (0.20.0): every "pick one" control in the admin, and the editor kit's Seg. Its own module (plain, no state).
|
|
26
26
|
export { Segmented, IconSegmented, type SegmentedOption } from "./segmented";
|
|
27
|
+
export { Sparkline, ShareBar, sparklinePaths, type SparkPoint, type SparkTone, type SparklineGeometry, type SharePart, type ShareTone } from "./minichart";
|
|
28
|
+
export { SetupGuide, type SetupStep, type SetupState } from "./setup-guide";
|
|
27
29
|
export { GemMark } from "./GemMark";
|
|
28
|
-
export { AuthError, AuthField, AuthFoot, AuthForm, AuthHelp, AuthLayout, PasswordField, AuthSubmit } from "./auth";
|
|
30
|
+
export { AuthError, AuthField, AuthFoot, AuthForm, AuthHelp, AuthLayout, PasswordField, AuthSubmit, type AuthBackdrop } from "./auth";
|
|
29
31
|
export { BrandLockup } from "./brand";
|
|
30
32
|
export { TopbarSearch } from "./search";
|
|
31
33
|
export { AccountMenu, AccountMenuItem } from "./account";
|
|
@@ -40,4 +42,5 @@ export { SearchDialog, type SearchItem, type SearchSection } from "./search-dial
|
|
|
40
42
|
export { ThemeToggle } from "./theme";
|
|
41
43
|
export { THEME_KEY, themeScript } from "./theme-script";
|
|
42
44
|
export { Reactions, ReactionPicker, type ReactionsProps } from "./reactions";
|
|
45
|
+
export { ActionCard, ActionCardItem, ActionCardSection, ActionChange, type ActionCardItemProps, type ActionCardOutcome, type ActionCardProps } from "./action-card";
|
|
43
46
|
export { isReactionEmoji, QUICK_REACTIONS, REACTION_EMOJI, REACTION_GROUPS, reactionLabel, reactionWords, searchReactions, toggleReaction, type Reaction } from "./reactions-data";
|
package/src/kit-plain.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(h){"use strict";if(h.gembossUI)return;var X='<svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><path d="M5 5l10 10M15 5L5 15" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" fill="none"/></svg>',Se='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, iframe, [tabindex]:not([tabindex="-1"])',ke=function(e){return Array.prototype.slice.call(e.querySelectorAll(Se)).filter(function(t){return t.checkVisibility?t.checkVisibility({visibilityProperty:!0}):t.getClientRects().length>0})},E=function(e){return String(e).replace(/[&<>"']/g,function(t){return{"&":"&","<":"<",">":">",'"':""","'":"'"}[t]})},p=[],xe=0,H=null;function z(e){var t=e.title||"",r=e.label||"",n=e.closeLabel||"Close",a=document.activeElement,i=document.createElement("div");i.className="ui-overlay"+(e.overlayClass?" "+e.overlayClass:""),i.setAttribute("role","presentation");var l="gb-modal-title-"+ ++xe;i.innerHTML='<div class="ui-modal'+(e.className?" "+e.className:"")+'" role="dialog" aria-modal="true" '+(t?'aria-labelledby="'+l+'"':'aria-label="'+E(r)+'"')+' tabindex="-1">'+(t?'<div class="ui-modal__head"><div class="ui-modal__title" id="'+l+'">'+t+'</div><button type="button" class="ui-modal__close" aria-label="'+E(n)+'">'+X+"</button></div>":"")+(e.body||"")+(e.foot?'<div class="ui-modal__foot">'+e.foot+"</div>":"")+"</div>";var u=i.firstChild,s=!1,c={panel:u,overlay:i,close:function(f,b){var A=b&&b.force;return p.indexOf(c)<0?Promise.resolve():!A&&e.beforeClose?s?Promise.resolve():(s=!0,Promise.resolve().then(function(){return e.beforeClose(f)}).catch(function(x){return console.error(x),!1}).then(function(x){s=!1,x&&p.indexOf(c)>=0&&d(f)})):(d(f),Promise.resolve())}};function d(f){p.splice(p.indexOf(c),1),removeEventListener("keydown",v),i.remove();var b=p[p.length-1];b||(document.body.style.overflow=H||"",H=null),a&&a.isConnected&&a.focus&&(!b||b.panel.contains(a))?a.focus():b&&b.panel.focus(),e.onClose&&e.onClose(f)}function v(f){if(!(f===S||p[p.length-1]!==c)){if(f.key==="Escape"){if(f.isComposing||f.keyCode===229)return;f.preventDefault(),c.close(null);return}if(f.key==="Tab"){var b=ke(u);if(b.length){var A=b[0],x=b[b.length-1];u.contains(document.activeElement)?!f.shiftKey&&document.activeElement===x?(f.preventDefault(),A.focus()):f.shiftKey&&document.activeElement===A&&(f.preventDefault(),x.focus()):(f.preventDefault(),A.focus())}}}}var m=!1;i.addEventListener("mousedown",function(f){m=f.target===i}),i.addEventListener("click",function(f){f.target===i&&m&&c.close(null),m=!1});var g=u.querySelector(".ui-modal__head .ui-modal__close");g&&(g.onclick=function(){c.close(null)});var S=window.event;addEventListener("keydown",v),p.length||(H=document.body.style.overflow),p.push(c);var O=document.body;try{for(var k=document.querySelectorAll("dialog[open]"),y=k.length-1;y>=0;y--)if(k[y].matches(":modal")){O=k[y];break}}catch{}return O.append(i),document.body.style.overflow="hidden",setTimeout(function(){(u.querySelector("[autofocus]")||u).focus()},0),c}function Le(e,t){t=t||{};var r=document.querySelector(".gemboss-toast-viewport"),n=!r;r||(r=document.createElement("div"),r.className="gemboss-toast-viewport",r.setAttribute("role","status"),r.setAttribute("aria-live","polite"),document.body.append(r));var a=document.createElement("div");a.className="gemboss-toast"+(t.error?" is-error":""),t.error&&a.setAttribute("role","alert");var i=document.createElement("span");i.className="gemboss-toast-text",i.textContent=String(e),a.append(i);var l=t.duration===0;if(l){var u=document.createElement("button");u.type="button",u.className="gemboss-toast-dismiss",u.setAttribute("aria-label",t.dismissLabel||"Dismiss"),u.innerHTML=X,u.onclick=function(){a.remove()},a.append(u)}n&&(r.dataset.readyAt=String(Date.now()+50));var s=Math.max(0,Number(r.dataset.readyAt||0)-Date.now()),c=function(){r.append(a)};return s||r._gbQueue?((r._gbQueue=r._gbQueue||[]).push(c),r._gbFlush||(r._gbFlush=setTimeout(function(){var d=r._gbQueue;r._gbQueue=null,r._gbFlush=null,d.forEach(function(v){v()})},s))):c(),l||setTimeout(function(){a.remove()},s+(t.duration||(t.error?6e3:3500))),a}var G=!1,we="details.ui-menu, details.gb-account",qe=".ui-menu__item, .gemboss-account-menu-item";function R(e){document.querySelectorAll("details.ui-menu[open], details.gb-account[open]").forEach(function(t){t!==e&&(t.open=!1)})}function Ce(){G||(G=!0,document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest(we);R(t),t&&e.target.closest(qe)&&(t.open=!1)}),addEventListener("blur",function(){R()}),addEventListener("keydown",function(e){var t=e.key==="Escape"&&!e.isComposing&&document.querySelector("details.ui-menu[open], details.gb-account[open]");if(t){e.preventDefault(),e.stopImmediatePropagation(),t.open=!1;var r=t.querySelector("summary");r&&r.focus()}},!0))}var J=!1,Y=typeof HTMLElement<"u"&&Object.prototype.hasOwnProperty.call(HTMLElement.prototype,"popover");function B(e){return{list:e.querySelector(":scope > .ui-menu__list"),button:e.querySelector(":scope > summary")}}function F(e){var t=B(e),r=t.list,n=t.button;if(!(!r||!n||!e.open||!Y)){r.getAttribute("popover")!=="manual"&&r.setAttribute("popover","manual"),r.matches(":popover-open")||r.showPopover(),r.style.maxHeight="",r.style.left="0px",r.style.top="0px";var a=n.getBoundingClientRect(),i=document.documentElement.clientWidth,l=h.innerHeight,u=r.offsetWidth,s=r.offsetHeight,c=l-a.bottom-4-8,d=a.top-4-8,v;s<=c||c>=d?(v=a.bottom+4,s>c&&(r.style.maxHeight=Math.max(c,0)+"px"),r.setAttribute("data-side","bottom")):(s>d&&(r.style.maxHeight=Math.max(d,0)+"px"),v=a.top-4-Math.min(s,d),r.setAttribute("data-side","top"));var m=e.classList.contains("ui-menu--end")?a.right-u:a.left;m=Math.max(8,Math.min(m,i-u-8)),r.style.left=Math.round(m)+"px",r.style.top=Math.round(v)+"px"}}function Me(e){var t=B(e).list;t&&t.hasAttribute("popover")&&t.matches(":popover-open")&&t.hidePopover()}function j(e){e&&e.closest&&e.closest(".ui-menu__list")||document.querySelectorAll("details.ui-menu[open]").forEach(function(t){var r=B(t).list;!r||!r.matches(":popover-open")||(!e||e.nodeType===9||e.contains&&e.contains(t))&&(t.open=!1)})}function Z(){J||!Y||typeof document>"u"||(J=!0,document.documentElement.setAttribute("data-gb-menus","float"),document.querySelectorAll("details.ui-menu[open]").forEach(F),document.addEventListener("toggle",function(e){var t=e.target;!t||!t.matches||!t.matches("details.ui-menu")||(t.open?F(t):Me(t))},!0),document.addEventListener("scroll",function(e){j(e.target)},!0),addEventListener("resize",function(){j(null)}))}Z();function Te(e){e=e||{};var t=e.tone==="critical";return new Promise(function(r){var n=z({title:E(e.title||""),label:e.title?"":e.label||"Confirm",closeLabel:e.closeLabel||e.cancelLabel,body:e.body?'<div class="ui-modal__body">'+E(e.body)+"</div>":"",foot:'<button type="button" class="ui-btn" data-gb-confirm="0"'+(t?" autofocus":"")+">"+E(e.cancelLabel||"Cancel")+'</button><button type="button" class="ui-btn ui-btn--primary'+(t?" ui-btn--critical":"")+'" data-gb-confirm="1"'+(t?"":" autofocus")+">"+E(e.confirmLabel||"OK")+"</button>",onClose:function(a){r(a===!0)}});n.panel.querySelectorAll("[data-gb-confirm]").forEach(function(a){a.onclick=function(){n.close(a.getAttribute("data-gb-confirm")==="1")}})})}var ee=!1;function Ne(){if(!ee){ee=!0;var e=function(){return document.querySelector(".gemboss-platform-shell")},t=function(n){var a=e();if(a){a.classList.toggle("is-mobile-nav-open",n);var i=a.querySelector(".gemboss-mobile-nav-backdrop");i&&(i.tabIndex=n?0:-1);var l=a.querySelector(".gemboss-mobile-menu-btn");if(l){var u=a.querySelector(".icon-nav[id]");u&&!l.hasAttribute("aria-controls")&&l.setAttribute("aria-controls",u.id),l.setAttribute("aria-expanded",String(n));var s=l.getAttribute(n?"data-label-close":"data-label-open");s&&l.setAttribute("aria-label",s)}}},r=function(){var n=e();return!!n&&n.classList.contains("is-mobile-nav-open")};document.addEventListener("click",function(n){var a=n.target;a.closest&&(a.closest(".gemboss-mobile-menu-btn")?t(!r()):(a.closest(".gemboss-mobile-nav-backdrop")||a.closest(".icon-nav .gnav-item, .icon-nav .gnav-subitem"))&&t(!1))}),addEventListener("keydown",function(n){n.key==="Escape"&&!n.isComposing&&n.keyCode!==229&&r()&&!p.length&&t(!1)}),addEventListener("gemboss:assistant-docked",function(){t(!1)}),t(r())}}var te=!1,re="M3 17 17 3";function ne(e){return document.getElementById(e.getAttribute("aria-controls")||"")||e.parentNode&&e.parentNode.querySelector("input")}function ae(e,t){var r=ne(e);if(r){r.type=t?"text":"password";var n=t?e.getAttribute("data-label-hide")||"Hide password":e.getAttribute("data-label-show")||"Show password";e.setAttribute("aria-label",n),e.setAttribute("title",n);var a=e.querySelector("svg"),i=a&&a.querySelector('path[d="'+re+'"]');if(a&&t&&!i){var l=document.createElementNS("http://www.w3.org/2000/svg","path");l.setAttribute("d",re),a.append(l)}i&&!t&&i.remove()}}function Oe(){te||(te=!0,document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest(".gb-auth-pw-toggle"),r=t&&ne(t);r&&ae(t,r.type==="password")}))}function De(){document.querySelectorAll(".gb-auth-pw-toggle").forEach(function(e){ae(e,!1)})}var ie=!1;function Pe(){ie||(ie=!0,document.addEventListener("keydown",function(e){var t=document.querySelector(".gemboss-topbar-search-input");if(t){var r=e.target,n=r&&(r.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(r.tagName));(e.key==="k"||e.key==="K")&&(e.metaKey||e.ctrlKey)&&!e.altKey?(e.preventDefault(),t.focus(),t.select()):e.key==="/"&&!n&&!e.metaKey&&!e.ctrlKey&&!e.altKey?(e.preventDefault(),t.focus()):e.key==="Escape"&&r===t&&t.blur()}}))}var Ke=120,He=15e3,Re=typeof HTMLScriptElement<"u"&&!!HTMLScriptElement.supports&&HTMLScriptElement.supports("speculationrules"),oe=!1,I=0,le=0,D=null,ue={},ce=!1;function L(e){var t=e&&e.closest?e.closest("a[href]"):null;if(!t||!(t.matches(".gnav-item, .gnav-subitem")||t.hasAttribute("data-gb-pending"))||t.getAttribute("data-gb-nav")==="next"||t.closest('[data-gb-nav="off"]')||t.target&&t.target!=="_self"||t.hasAttribute("download"))return null;var r;try{r=new URL(t.href,location.href)}catch{return null}return r.origin!==location.origin||!/^https?:$/.test(r.protocol)||r.pathname===location.pathname&&r.search===location.search&&(r.hash||(t.getAttribute("href")||"").indexOf("#")>-1)?null:t}function w(){clearTimeout(le),document.querySelectorAll("[data-gb-busy]").forEach(function(e){e.removeAttribute("data-gb-busy"),e.removeAttribute("aria-busy");var t=e.querySelector(":scope > .gb-pending-mark");t&&t.remove()})}function Be(e){if(w(),e.setAttribute("data-gb-busy",""),e.setAttribute("aria-busy","true"),e.hasAttribute("data-gb-pending")){var t=document.createElement("span");t.className="gb-pending-mark",t.setAttribute("role","status"),t.innerHTML='<span class="ui-sr-only">'+E(e.getAttribute("data-gb-pending-label")||"Loading")+"</span>",e.appendChild(t)}le=setTimeout(w,He)}function se(e){if(!(ce||h.next||h.__next_f||h.__NEXT_DATA__||e.closest('[data-gb-prefetch="off"]'))){var t=navigator.connection;if(!(t&&t.saveData)){var r=new URL(e.href,location.href);r.hash="";var n=r.href;if(!(ue[n]||r.pathname===location.pathname&&r.search===location.search)){ue[n]=!0;var a;Re?(a=document.createElement("script"),a.type="speculationrules",a.textContent=JSON.stringify({prefetch:[{source:"list",urls:[n]}]})):(a=document.createElement("link"),a.rel="prefetch",a.href=n),a.setAttribute("data-gb-prefetched",""),document.head.appendChild(a)}}}}function de(){if(!(oe||typeof document>"u")){oe=!0,addEventListener("click",function(r){if(!(r.button!==0||r.metaKey||r.ctrlKey||r.shiftKey||r.altKey)){var n=L(r.target);if(n){if(r.defaultPrevented){ce=!0;return}Be(n)}}});var e=function(r){r!==D&&(clearTimeout(I),D=r,r&&(I=setTimeout(function(){D===r&&se(r)},Ke)))},t=null;document.addEventListener("mousedown",function(r){t=L(r.target),t&&t===D&&clearTimeout(I)}),document.addEventListener("mouseover",function(r){e(L(r.target))}),document.addEventListener("focusin",function(r){var n=L(r.target);n&&n===t||e(n)}),document.addEventListener("touchstart",function(r){var n=L(r.target);n&&se(n)},{passive:!0}),addEventListener("pageshow",w),addEventListener("keydown",function(r){r.key==="Escape"&&w()}),h.navigation&&h.navigation.addEventListener&&h.navigation.addEventListener("navigateerror",w)}}de();var Fe='a[href], button, input, select, textarea, label, summary, details, dialog, [role="dialog"], [role="menu"], [role="button"], [role="menuitem"], [role="checkbox"], [contenteditable="true"], [contenteditable=""], [data-row-ignore], .ui-table__check',fe='details[open], dialog[open], [role="dialog"], [role="menu"]';function Ie(e,t){return t&&t.closest&&t.closest(fe)?!0:Array.prototype.some.call(e.querySelectorAll(fe),function(r){return r.getClientRects().length>0})}var be=!1,q=null,U=".ui-index, .ui-resource";function Ue(e){for(var t=e.getAttribute("data-href"),r=e.querySelectorAll("a[href]"),n=0;n<r.length;n++)if(r[n].getAttribute("href")===t)return r[n];return null}function ve(e){if(!(e.defaultPrevented||e.button>1||!e.target.closest)){var t=e.target.closest("[data-href]");if(t){var r=e.target.closest(Fe);if(!(r&&t.contains(r))){var n=h.getSelection?h.getSelection():null;if(!(n&&!n.isCollapsed&&n.anchorNode&&t.contains(n.anchorNode))){var a=Ue(t),i=a?a.href:new URL(t.getAttribute("data-href"),location.href).href;if(e.metaKey||e.ctrlKey||e.shiftKey||e.button===1){h.open(i,"_blank","noopener");return}a?a.click():location.assign(i)}}}}}function me(e){var t=[];return e.querySelectorAll("input[data-gb-select]").forEach(function(r){r.checked&&t.push(r.value)}),t}function C(e){var t=e.querySelectorAll("input[data-gb-select]"),r=0;t.forEach(function(i){var l=i.closest("tr, .ui-list__item, [data-href]");i.checked&&r++,l&&(l.classList.toggle("is-selected",i.checked),l.matches(".ui-list__item")||l.setAttribute("aria-selected",i.checked?"true":"false"))}),e.querySelectorAll("input[data-gb-select-all]").forEach(function(i){i.checked=r>0&&r===t.length,i.indeterminate=r>0&&r<t.length});var n=e.querySelector(".ui-bulkbar");n&&e.matches(".ui-resource")?n.querySelectorAll(".ui-bulkbar__actions button").forEach(function(i){i.disabled=r===0}):n&&(n.hidden=r===0);var a=e.querySelector("[data-gb-count]");a&&(a.textContent=(a.getAttribute("data-gb-count")||"{n} selected").replace("{n}",r)),e.dispatchEvent(new CustomEvent("gb:selection",{bubbles:!0,detail:{ids:me(e),total:t.length}}))}function pe(e){e.querySelectorAll("input[data-gb-select]").forEach(function(t){t.checked=!1}),C(e)}function ge(e){if(!e)return"";var t=e.getAttribute("data-sort-value");return t??e.textContent.trim()}function Ve(e){var t=e.closest("th"),r=e.closest("table");if(!(!t||!r)){var n=t.getAttribute("aria-sort")==="ascending"?"descending":"ascending";if(r.querySelectorAll("thead th[aria-sort]").forEach(function(c){c!==t&&c.setAttribute("aria-sort","none")}),t.setAttribute("aria-sort",n),r.getAttribute("data-gb-sort")!=="client"){r.dispatchEvent(new CustomEvent("gb:sort",{bubbles:!0,detail:{key:t.getAttribute("data-key"),direction:n}}));return}var a=Array.prototype.indexOf.call(t.parentElement.children,t),i=r.tBodies[0];if(i){var l=Array.prototype.slice.call(i.rows),u=n==="ascending"?1:-1,s=function(c){var d=String(c).replace(/[\s,%$€£¥]/g,"");return d!==""&&!isNaN(+d)?+d:null};l.sort(function(c,d){var v=ge(c.cells[a]),m=ge(d.cells[a]),g=s(v),S=s(m);return u*(g!=null&&S!=null?g-S:String(v).localeCompare(String(m),void 0,{numeric:!0,sensitivity:"base"}))}),l.forEach(function(c){i.appendChild(c)})}}}function We(e){return Array.prototype.slice.call(e.querySelectorAll(":scope > .ui-board__col[data-col]"))}function M(e){return Array.prototype.slice.call(e.querySelectorAll("li[data-id]")).filter(function(t){return t.closest(".ui-board__col")===e})}function V(e){var t=e.getAttribute("data-name")||(e.querySelector(".ui-card__link, h2, h3, h4")||e).textContent||"";return t.trim().replace(/\s+/g," ").slice(0,80)||"Card"}function P(e){var t=e.querySelector(".ui-board__name");return(t&&t.textContent||e.getAttribute("data-col")||"").trim()}function _(e,t){var r=e.querySelector(":scope > [data-gb-live]");r||(r=document.createElement("div"),r.className="ui-sr-only",r.setAttribute("aria-live","assertive"),r.setAttribute("data-gb-live",""),e.appendChild(r)),r.textContent="",setTimeout(function(){r.textContent=t},30)}function he(e,t){var r=e.querySelector(".ui-board__count"),n=r?parseInt(r.textContent,10):NaN;r&&String(n)===r.textContent.trim()&&(r.textContent=String(n+t))}function Qe(e,t,r,n){var a=t.closest(".ui-board__col"),i=M(r).filter(function(d){return d!==t});if(n<i.length)i[n].parentNode.insertBefore(t,i[n]);else if(i.length){var l=i[i.length-1];l.parentNode.insertBefore(t,l.nextSibling)}else{var u=r.querySelector("ol.ui-board__list");if(!u){u=document.createElement("ol"),u.className="ui-board__list";var s=r.querySelector(":scope > .ui-board__empty");s?s.replaceWith(u):r.querySelector(".ui-board__head").after(u)}u.appendChild(t)}if(a!==r&&(he(a,-1),he(r,1),!M(a).length&&!a.querySelector(".ui-board__next a[data-gb-more]"))){var c=document.createElement("p");c.className="ui-board__empty",c.textContent=e.getAttribute("data-empty-label")||"Nothing here",a.querySelectorAll(":scope > ol.ui-board__list, :scope > details.ui-board__more").forEach(function(d){d.remove()}),a.querySelector(".ui-board__head").after(c)}}var o=null;function T(e){return M(e).filter(function(t){return!o||t!==o.li})}function W(e){e.querySelectorAll("[data-gb-drop]").forEach(function(t){t.removeAttribute("data-gb-drop")}),e.querySelectorAll("[data-gb-over]").forEach(function(t){t.removeAttribute("data-gb-over")})}function Q(){if(o){W(o.b),o.to.setAttribute("data-gb-over","");var e=T(o.to),t=o.index<e.length?e[o.index]:e[e.length-1];if(t){t.setAttribute("data-gb-drop",o.index<e.length?"before":"after");var r=t.closest("details:not([open])");r&&o.b.contains(r)&&(r.open=!0),o.keys&&t.scrollIntoView&&t.scrollIntoView({block:"nearest",inline:"nearest"})}}}function K(){return o?P(o.to)+", position "+(o.index+1)+" of "+(T(o.to).length+1):""}function $(){o&&(o.li.removeAttribute("data-gb-lifted"),o.b.removeAttribute("data-gb-dragging"),W(o.b),o=null)}function ye(e,t,r){var n=t.closest(".ui-board__col");if(!(!n||!t.getAttribute("data-id"))){var a=M(n).indexOf(t);o={b:e,li:t,id:t.getAttribute("data-id"),from:n,to:n,index:a,origin:a,keys:r},t.setAttribute("data-gb-lifted",r?"key":"drag"),r&&(Q(),_(e,"Picked up "+V(t)+". "+K()+". Arrow keys move it, Space drops it, Escape cancels."))}}function Ae(){if(o){var e=o,t=V(e.li),r=e.to===e.from&&e.index===e.origin,n=K();if($(),r){_(e.b,t+" dropped where it was, in "+P(e.from)+".");return}var a=new CustomEvent("gb:move",{bubbles:!0,cancelable:!0,detail:{id:e.id,from:e.from.getAttribute("data-col"),to:e.to.getAttribute("data-col"),index:e.index}}),i=e.b.dispatchEvent(a);if(i&&Qe(e.b,e.li,e.to,e.index),_(e.b,"Moved "+t+" to "+n+"."),e.keys){var l=10,u=function(){var s=Array.prototype.slice.call(e.b.querySelectorAll("li[data-id]")).filter(function(c){return c.getAttribute("data-id")===e.id})[0];s&&document.activeElement!==s?s.focus():!s&&l-- >0&&requestAnimationFrame(u)};requestAnimationFrame(u)}}}function N(e){if(o){var t=o;$(),t.keys&&_(t.b,(e||"")+V(t.li)+" stays in "+P(t.from)+".")}}function Ee(e){var t=e&&e.closest?e.closest(".ui-board[data-gb-move]"):null;return t}function $e(e){var t=Ee(e.target),r=t&&e.target.closest("li[data-id]");if(!(!r||!t.contains(r)||t.__gbMoveOn)){if(!o){(e.key===" "||e.key==="Spacebar")&&e.target===r&&(e.preventDefault(),ye(t,r,!0));return}if(!(o.li!==r||!o.keys)){var n=We(t);if(e.key==="ArrowUp"||e.key==="ArrowDown")e.preventDefault(),o.index=Math.max(0,Math.min(T(o.to).length,o.index+(e.key==="ArrowUp"?-1:1)));else if(e.key==="ArrowLeft"||e.key==="ArrowRight"){e.preventDefault();var a=n.indexOf(o.to)+(e.key==="ArrowLeft"?-1:1);if(a<0||a>=n.length){_(t,K()+". No column further "+(e.key==="ArrowLeft"?"left":"right")+".");return}o.to=n[a],o.index=Math.min(o.index,T(o.to).length)}else if(e.key===" "||e.key==="Spacebar"||e.key==="Enter"){e.preventDefault(),Ae();return}else if(e.key==="Escape"){e.preventDefault(),e.stopPropagation(),N("Move cancelled. ");return}else if(e.key==="Tab"){N("Move cancelled. ");return}else return;Q(),_(t,K())}}}function Xe(e){var t=e.closest(".ui-board__col"),r=e.closest(".ui-board"),n=e.closest(".ui-board__next")||e.parentNode;if(!(!t||!r||n.getAttribute("aria-busy")==="true")){var a=t.getAttribute("data-col"),i=e.href;n.setAttribute("aria-busy","true"),n.innerHTML='<span class="ui-spinner" aria-hidden="true"></span><span role="status">Loading\u2026</span>',fetch(i,{headers:{Accept:"text/html"},credentials:"same-origin"}).then(function(l){if(!l.ok)throw new Error(String(l.status));return l.text()}).then(function(l){var u=new DOMParser().parseFromString(l,"text/html"),s=r.id?u.getElementById(r.id):u,c=Array.prototype.slice.call((s||u).querySelectorAll(".ui-board__col[data-col]")).filter(function(b){return b.getAttribute("data-col")===a})[0];if(!c)throw new Error("no column "+a);var d={};r.querySelectorAll("li[data-id]").forEach(function(b){d[b.getAttribute("data-id")]=1});var v=t.querySelector(":scope > ol.ui-board__list");if(!v){v=document.createElement("ol"),v.className="ui-board__list";var m=t.querySelector(":scope > .ui-board__empty");m?m.replaceWith(v):n.before(v)}var g=M(c).filter(function(b){return!d[b.getAttribute("data-id")]}).map(function(b){var A=document.importNode(b,!0);return v.appendChild(A),A}),S=c.querySelector(".ui-board__count"),O=t.querySelector(".ui-board__count");S&&O&&(O.textContent=S.textContent);var k=c.querySelector(".ui-board__next");k&&k.querySelector("a[data-gb-more]")?(n.innerHTML=k.innerHTML,n.removeAttribute("aria-busy")):n.remove();try{history.replaceState(history.state,"",i)}catch{}_(r,g.length+" more "+(g.length===1?"card":"cards")+" in "+P(t)+".");var y=g[0];if(y){var f=y.matches("[tabindex]")?y:y.querySelector("a[href], button, [tabindex]");f&&f.focus({preventScroll:!1})}}).catch(function(){n.removeAttribute("aria-busy"),n.innerHTML=`<span role="alert" class="ui-more__error">Couldn't load.</span>`;var l=document.createElement("a");l.className="ui-btn ui-btn--sm",l.href=i,l.setAttribute("data-gb-more",""),l.textContent="Try again",n.appendChild(l),l.focus()})}}function _e(){if(!(be||typeof document>"u")){be=!0,document.addEventListener("keydown",$e),document.addEventListener("focusout",function(t){o&&o.keys&&t.target===o.li&&!o.li.contains(t.relatedTarget)&&N("Move cancelled. ")}),document.addEventListener("dragstart",function(t){var r=Ee(t.target),n=r&&t.target.closest("li[data-id]");!n||!r.contains(n)||r.__gbMoveOn||!t.dataTransfer||(o&&$(),ye(r,n,!1),t.dataTransfer.effectAllowed="move",t.dataTransfer.setData("text/plain",n.getAttribute("data-id")||""),requestAnimationFrame(function(){o&&r.setAttribute("data-gb-dragging","")}))});var e=function(t){var r=t.target.closest?t.target.closest(".ui-board__col[data-col]"):null;if(!r||!o||!o.b.contains(r))return null;for(var n=T(r),a=n.length,i=0;i<n.length;i++){var l=n[i].getBoundingClientRect();if(l.height){if(t.clientY<l.top+l.height/2){a=i;break}a=i+1}}return{col:r,index:a}};document.addEventListener("dragover",function(t){if(!(!o||o.keys)){var r=e(t);r&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="move"),(r.col!==o.to||r.index!==o.index||!o.b.querySelector("[data-gb-over]"))&&(o.to=r.col,o.index=r.index,Q()))}}),document.addEventListener("dragleave",function(t){o&&!o.keys&&!o.b.contains(t.relatedTarget)&&W(o.b)}),document.addEventListener("drop",function(t){if(!(!o||o.keys)){t.preventDefault();var r=e(t);if(!r){N();return}o.to=r.col,o.index=r.index,Ae()}}),document.addEventListener("dragend",function(){o&&!o.keys&&N()}),document.addEventListener("click",function(t){var r=t.target;if(!(!r||!r.closest)){var n=r.closest(".ui-board a[data-gb-more][href]");if(n){!t.defaultPrevented&&t.button===0&&!t.metaKey&&!t.ctrlKey&&!t.shiftKey&&!t.altKey&&typeof fetch=="function"&&(t.preventDefault(),Xe(n));return}var a=r.closest("table[data-gb-sort] button.ui-table__sort");if(a){Ve(a);return}var i=r.closest("td.ui-table__check, th.ui-table__check");if(i&&r===i){var l=i.querySelector("input[data-gb-select], input[data-gb-select-all]");if(l){l.click();return}}var u=r.closest("input[data-gb-select]");if(u){var s=u.closest(U);if(s&&t.shiftKey&&q&&q!==u&&s.contains(q)){for(var c=Array.prototype.slice.call(s.querySelectorAll("input[data-gb-select]")),d=c.indexOf(q),v=c.indexOf(u),m=u.checked,g=Math.min(d,v);g<=Math.max(d,v);g++)c[g].checked=m;C(s)}q=u;return}ve(t)}}),document.addEventListener("auxclick",function(t){t.button===1&&ve(t)}),document.addEventListener("change",function(t){var r=t.target;if(!(!r||!r.matches)){var n=r.closest(U);n&&(r.matches("input[data-gb-select-all]")?(n.querySelectorAll("input[data-gb-select]").forEach(function(a){a.checked=r.checked}),C(n)):r.matches("input[data-gb-select]")&&C(n))}}),document.addEventListener("keydown",function(t){if(!(t.key!=="Escape"||t.defaultPrevented||p.length)){var r=document.activeElement&&document.activeElement.closest?document.activeElement.closest(U):null;r&&Ie(r,document.activeElement)||r&&r.querySelector("input[data-gb-select]:checked")&&pe(r)}})}}_e(),h.gembossUI={openModal:z,toast:Le,confirm:Te,initMenus:Ce,closeMenus:R,initSearch:Pe,initShell:Ne,initPasswordFields:Oe,resetPasswordFields:De,initNav:de,openModals:function(){return p.length},initCollections:_e,selection:me,clearSelection:pe,syncSelection:C,initMenuLayer:Z,floatMenu:F}})(globalThis);
|
|
1
|
+
(function(g){"use strict";if(g.gembossUI)return;var X='<svg viewBox="0 0 20 20" aria-hidden="true" focusable="false"><path d="M5 5l10 10M15 5L5 15" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" fill="none"/></svg>',ke='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), summary, iframe, [tabindex]:not([tabindex="-1"])',xe=function(e){return Array.prototype.slice.call(e.querySelectorAll(ke)).filter(function(t){return t.checkVisibility?t.checkVisibility({visibilityProperty:!0}):t.getClientRects().length>0})},E=function(e){return String(e).replace(/[&<>"']/g,function(t){return{"&":"&","<":"<",">":">",'"':""","'":"'"}[t]})},m=[],Le=0,H=null;function z(e){var t=e.title||"",r=e.label||"",n=e.closeLabel||"Close",a=document.activeElement,i=document.createElement("div");i.className="ui-overlay"+(e.overlayClass?" "+e.overlayClass:""),i.setAttribute("role","presentation");var l="gb-modal-title-"+ ++Le;i.innerHTML='<div class="ui-modal'+(e.className?" "+e.className:"")+'" role="dialog" aria-modal="true" '+(t?'aria-labelledby="'+l+'"':'aria-label="'+E(r)+'"')+' tabindex="-1">'+(t?'<div class="ui-modal__head"><div class="ui-modal__title" id="'+l+'">'+t+'</div><button type="button" class="ui-modal__close" aria-label="'+E(n)+'">'+X+"</button></div>":"")+(e.body||"")+(e.foot?'<div class="ui-modal__foot">'+e.foot+"</div>":"")+"</div>";var u=i.firstChild,s=!1,c={panel:u,overlay:i,close:function(d,b){var A=b&&b.force;return m.indexOf(c)<0?Promise.resolve():!A&&e.beforeClose?s?Promise.resolve():(s=!0,Promise.resolve().then(function(){return e.beforeClose(d)}).catch(function(x){return console.error(x),!1}).then(function(x){s=!1,x&&m.indexOf(c)>=0&&f(d)})):(f(d),Promise.resolve())}};function f(d){m.splice(m.indexOf(c),1),removeEventListener("keydown",v),i.remove();var b=m[m.length-1];b||(document.body.style.overflow=H||"",H=null),a&&a.isConnected&&a.focus&&(!b||b.panel.contains(a))?a.focus():b&&b.panel.focus(),e.onClose&&e.onClose(d)}function v(d){if(!(d===S||m[m.length-1]!==c)){if(d.key==="Escape"){if(d.isComposing||d.keyCode===229)return;d.preventDefault(),c.close(null);return}if(d.key==="Tab"){var b=xe(u);if(b.length){var A=b[0],x=b[b.length-1];u.contains(document.activeElement)?!d.shiftKey&&document.activeElement===x?(d.preventDefault(),A.focus()):d.shiftKey&&document.activeElement===A&&(d.preventDefault(),x.focus()):(d.preventDefault(),A.focus())}}}}var h=!1;i.addEventListener("mousedown",function(d){h=d.target===i}),i.addEventListener("click",function(d){d.target===i&&h&&c.close(null),h=!1});var p=u.querySelector(".ui-modal__head .ui-modal__close");p&&(p.onclick=function(){c.close(null)});var S=window.event;addEventListener("keydown",v),m.length||(H=document.body.style.overflow),m.push(c);var O=document.body;try{for(var k=document.querySelectorAll("dialog[open]"),y=k.length-1;y>=0;y--)if(k[y].matches(":modal")){O=k[y];break}}catch{}return O.append(i),document.body.style.overflow="hidden",setTimeout(function(){(u.querySelector("[autofocus]")||u).focus()},0),c}function we(e,t){t=t||{};var r=document.querySelector(".gemboss-toast-viewport"),n=!r;r||(r=document.createElement("div"),r.className="gemboss-toast-viewport",r.setAttribute("role","status"),r.setAttribute("aria-live","polite"),document.body.append(r));var a=document.createElement("div");a.className="gemboss-toast"+(t.error?" is-error":""),t.error&&a.setAttribute("role","alert");var i=document.createElement("span");i.className="gemboss-toast-text",i.textContent=String(e),a.append(i);var l=t.duration===0;if(l){var u=document.createElement("button");u.type="button",u.className="gemboss-toast-dismiss",u.setAttribute("aria-label",t.dismissLabel||"Dismiss"),u.innerHTML=X,u.onclick=function(){a.remove()},a.append(u)}n&&(r.dataset.readyAt=String(Date.now()+50));var s=Math.max(0,Number(r.dataset.readyAt||0)-Date.now()),c=function(){r.append(a)};return s||r._gbQueue?((r._gbQueue=r._gbQueue||[]).push(c),r._gbFlush||(r._gbFlush=setTimeout(function(){var f=r._gbQueue;r._gbQueue=null,r._gbFlush=null,f.forEach(function(v){v()})},s))):c(),l||setTimeout(function(){a.remove()},s+(t.duration||(t.error?6e3:3500))),a}var G=!1,qe="details.ui-menu, details.gb-account",Ce=".ui-menu__item, .gemboss-account-menu-item";function F(e){document.querySelectorAll("details.ui-menu[open], details.gb-account[open]").forEach(function(t){t!==e&&(t.open=!1)})}function Me(){G||(G=!0,document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest(qe);F(t),t&&e.target.closest(Ce)&&(t.open=!1)}),addEventListener("blur",function(){F()}),addEventListener("keydown",function(e){var t=e.key==="Escape"&&!e.isComposing&&document.querySelector("details.ui-menu[open], details.gb-account[open]");if(t){e.preventDefault(),e.stopImmediatePropagation(),t.open=!1;var r=t.querySelector("summary");r&&r.focus()}},!0))}var J=!1,Y=typeof HTMLElement<"u"&&Object.prototype.hasOwnProperty.call(HTMLElement.prototype,"popover");function R(e){return{list:e.querySelector(":scope > .ui-menu__list"),button:e.querySelector(":scope > summary")}}function j(e,t,r){e.style.maxHeight="",e.style.left="0px",e.style.top="0px";var n=t.getBoundingClientRect(),a=document.documentElement.clientWidth,i=g.innerHeight,l=e.offsetWidth,u=e.offsetHeight,s=i-n.bottom-4-8,c=n.top-4-8,f;u<=s||s>=c?(f=n.bottom+4,u>s&&(e.style.maxHeight=Math.max(s,0)+"px"),e.setAttribute("data-side","bottom")):(u>c&&(e.style.maxHeight=Math.max(c,0)+"px"),f=n.top-4-Math.min(u,c),e.setAttribute("data-side","top"));var v=r?n.right-l:n.left;v=Math.max(8,Math.min(v,a-l-8)),e.style.left=Math.round(v)+"px",e.style.top=Math.round(f)+"px"}function B(e){var t=R(e),r=t.list,n=t.button;!r||!n||!e.open||!Y||(r.getAttribute("popover")!=="manual"&&r.setAttribute("popover","manual"),r.matches(":popover-open")||r.showPopover(),j(r,n,e.classList.contains("ui-menu--end")))}function Te(e){var t=R(e).list;t&&t.hasAttribute("popover")&&t.matches(":popover-open")&&t.hidePopover()}function Z(e){e&&e.closest&&e.closest(".ui-menu__list")||document.querySelectorAll("details.ui-menu[open]").forEach(function(t){var r=R(t).list;!r||!r.matches(":popover-open")||(!e||e.nodeType===9||e.contains&&e.contains(t))&&(t.open=!1)})}function ee(){J||!Y||typeof document>"u"||(J=!0,document.documentElement.setAttribute("data-gb-menus","float"),document.querySelectorAll("details.ui-menu[open]").forEach(B),document.addEventListener("toggle",function(e){var t=e.target;!t||!t.matches||!t.matches("details.ui-menu")||(t.open?B(t):Te(t))},!0),document.addEventListener("scroll",function(e){Z(e.target)},!0),addEventListener("resize",function(){Z(null)}))}ee();function Ne(e){e=e||{};var t=e.tone==="critical";return new Promise(function(r){var n=z({title:E(e.title||""),label:e.title?"":e.label||"Confirm",closeLabel:e.closeLabel||e.cancelLabel,body:e.body?'<div class="ui-modal__body">'+E(e.body)+"</div>":"",foot:'<button type="button" class="ui-btn" data-gb-confirm="0"'+(t?" autofocus":"")+">"+E(e.cancelLabel||"Cancel")+'</button><button type="button" class="ui-btn ui-btn--primary'+(t?" ui-btn--critical":"")+'" data-gb-confirm="1"'+(t?"":" autofocus")+">"+E(e.confirmLabel||"OK")+"</button>",onClose:function(a){r(a===!0)}});n.panel.querySelectorAll("[data-gb-confirm]").forEach(function(a){a.onclick=function(){n.close(a.getAttribute("data-gb-confirm")==="1")}})})}var te=!1;function Oe(){if(!te){te=!0;var e=function(){return document.querySelector(".gemboss-platform-shell")},t=function(n){var a=e();if(a){a.classList.toggle("is-mobile-nav-open",n);var i=a.querySelector(".gemboss-mobile-nav-backdrop");i&&(i.tabIndex=n?0:-1);var l=a.querySelector(".gemboss-mobile-menu-btn");if(l){var u=a.querySelector(".icon-nav[id]");u&&!l.hasAttribute("aria-controls")&&l.setAttribute("aria-controls",u.id),l.setAttribute("aria-expanded",String(n));var s=l.getAttribute(n?"data-label-close":"data-label-open");s&&l.setAttribute("aria-label",s)}}},r=function(){var n=e();return!!n&&n.classList.contains("is-mobile-nav-open")};document.addEventListener("click",function(n){var a=n.target;a.closest&&(a.closest(".gemboss-mobile-menu-btn")?t(!r()):(a.closest(".gemboss-mobile-nav-backdrop")||a.closest(".icon-nav .gnav-item, .icon-nav .gnav-subitem"))&&t(!1))}),addEventListener("keydown",function(n){n.key==="Escape"&&!n.isComposing&&n.keyCode!==229&&r()&&!m.length&&t(!1)}),addEventListener("gemboss:assistant-docked",function(){t(!1)}),t(r())}}var re=!1,ne="M3 17 17 3";function ae(e){return document.getElementById(e.getAttribute("aria-controls")||"")||e.parentNode&&e.parentNode.querySelector("input")}function ie(e,t){var r=ae(e);if(r){r.type=t?"text":"password";var n=t?e.getAttribute("data-label-hide")||"Hide password":e.getAttribute("data-label-show")||"Show password";e.setAttribute("aria-label",n),e.setAttribute("title",n);var a=e.querySelector("svg"),i=a&&a.querySelector('path[d="'+ne+'"]');if(a&&t&&!i){var l=document.createElementNS("http://www.w3.org/2000/svg","path");l.setAttribute("d",ne),a.append(l)}i&&!t&&i.remove()}}function De(){re||(re=!0,document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest(".gb-auth-pw-toggle"),r=t&&ae(t);r&&ie(t,r.type==="password")}))}function Pe(){document.querySelectorAll(".gb-auth-pw-toggle").forEach(function(e){ie(e,!1)})}var oe=!1;function Ke(){oe||(oe=!0,document.addEventListener("keydown",function(e){var t=document.querySelector(".gemboss-topbar-search-input");if(t){var r=e.target,n=r&&(r.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(r.tagName));(e.key==="k"||e.key==="K")&&(e.metaKey||e.ctrlKey)&&!e.altKey?(e.preventDefault(),t.focus(),t.select()):e.key==="/"&&!n&&!e.metaKey&&!e.ctrlKey&&!e.altKey?(e.preventDefault(),t.focus()):e.key==="Escape"&&r===t&&t.blur()}}))}var He=120,Fe=15e3,Re=typeof HTMLScriptElement<"u"&&!!HTMLScriptElement.supports&&HTMLScriptElement.supports("speculationrules"),le=!1,I=0,ue=0,D=null,ce={},se=!1;function L(e){var t=e&&e.closest?e.closest("a[href]"):null;if(!t||!(t.matches(".gnav-item, .gnav-subitem")||t.hasAttribute("data-gb-pending"))||t.getAttribute("data-gb-nav")==="next"||t.closest('[data-gb-nav="off"]')||t.target&&t.target!=="_self"||t.hasAttribute("download"))return null;var r;try{r=new URL(t.href,location.href)}catch{return null}return r.origin!==location.origin||!/^https?:$/.test(r.protocol)||r.pathname===location.pathname&&r.search===location.search&&(r.hash||(t.getAttribute("href")||"").indexOf("#")>-1)?null:t}function w(){clearTimeout(ue),document.querySelectorAll("[data-gb-busy]").forEach(function(e){e.removeAttribute("data-gb-busy"),e.removeAttribute("aria-busy");var t=e.querySelector(":scope > .gb-pending-mark");t&&t.remove()})}function Be(e){if(w(),e.setAttribute("data-gb-busy",""),e.setAttribute("aria-busy","true"),e.hasAttribute("data-gb-pending")){var t=document.createElement("span");t.className="gb-pending-mark",t.setAttribute("role","status"),t.innerHTML='<span class="ui-sr-only">'+E(e.getAttribute("data-gb-pending-label")||"Loading")+"</span>",e.appendChild(t)}ue=setTimeout(w,Fe)}function de(e){if(!(se||g.next||g.__next_f||g.__NEXT_DATA__||e.closest('[data-gb-prefetch="off"]'))){var t=navigator.connection;if(!(t&&t.saveData)){var r=new URL(e.href,location.href);r.hash="";var n=r.href;if(!(ce[n]||r.pathname===location.pathname&&r.search===location.search)){ce[n]=!0;var a;Re?(a=document.createElement("script"),a.type="speculationrules",a.textContent=JSON.stringify({prefetch:[{source:"list",urls:[n]}]})):(a=document.createElement("link"),a.rel="prefetch",a.href=n),a.setAttribute("data-gb-prefetched",""),document.head.appendChild(a)}}}}function fe(){if(!(le||typeof document>"u")){le=!0,addEventListener("click",function(r){if(!(r.button!==0||r.metaKey||r.ctrlKey||r.shiftKey||r.altKey)){var n=L(r.target);if(n){if(r.defaultPrevented){se=!0;return}Be(n)}}});var e=function(r){r!==D&&(clearTimeout(I),D=r,r&&(I=setTimeout(function(){D===r&&de(r)},He)))},t=null;document.addEventListener("mousedown",function(r){t=L(r.target),t&&t===D&&clearTimeout(I)}),document.addEventListener("mouseover",function(r){e(L(r.target))}),document.addEventListener("focusin",function(r){var n=L(r.target);n&&n===t||e(n)}),document.addEventListener("touchstart",function(r){var n=L(r.target);n&&de(n)},{passive:!0}),addEventListener("pageshow",w),addEventListener("keydown",function(r){r.key==="Escape"&&w()}),g.navigation&&g.navigation.addEventListener&&g.navigation.addEventListener("navigateerror",w)}}fe();var Ie='a[href], button, input, select, textarea, label, summary, details, dialog, [role="dialog"], [role="menu"], [role="button"], [role="menuitem"], [role="checkbox"], [contenteditable="true"], [contenteditable=""], [data-row-ignore], .ui-table__check',be='details[open], dialog[open], [role="dialog"], [role="menu"]';function Ue(e,t){return t&&t.closest&&t.closest(be)?!0:Array.prototype.some.call(e.querySelectorAll(be),function(r){return r.getClientRects().length>0})}var ve=!1,q=null,U=".ui-index, .ui-resource";function Ve(e){for(var t=e.getAttribute("data-href"),r=e.querySelectorAll("a[href]"),n=0;n<r.length;n++)if(r[n].getAttribute("href")===t)return r[n];return null}function me(e){if(!(e.defaultPrevented||e.button>1||!e.target.closest)){var t=e.target.closest("[data-href]");if(t){var r=e.target.closest(Ie);if(!(r&&t.contains(r))){var n=g.getSelection?g.getSelection():null;if(!(n&&!n.isCollapsed&&n.anchorNode&&t.contains(n.anchorNode))){var a=Ve(t),i=a?a.href:new URL(t.getAttribute("data-href"),location.href).href;if(e.metaKey||e.ctrlKey||e.shiftKey||e.button===1){g.open(i,"_blank","noopener");return}a?a.click():location.assign(i)}}}}}function pe(e){var t=[];return e.querySelectorAll("input[data-gb-select]").forEach(function(r){r.checked&&t.push(r.value)}),t}function C(e){var t=e.querySelectorAll("input[data-gb-select]"),r=0;t.forEach(function(i){var l=i.closest("tr, .ui-list__item, [data-href]");i.checked&&r++,l&&(l.classList.toggle("is-selected",i.checked),l.matches(".ui-list__item")||l.setAttribute("aria-selected",i.checked?"true":"false"))}),e.querySelectorAll("input[data-gb-select-all]").forEach(function(i){i.checked=r>0&&r===t.length,i.indeterminate=r>0&&r<t.length});var n=e.querySelector(".ui-bulkbar");n&&e.matches(".ui-resource")?n.querySelectorAll(".ui-bulkbar__actions button").forEach(function(i){i.disabled=r===0}):n&&(n.hidden=r===0);var a=e.querySelector("[data-gb-count]");a&&(a.textContent=(a.getAttribute("data-gb-count")||"{n} selected").replace("{n}",r)),e.dispatchEvent(new CustomEvent("gb:selection",{bubbles:!0,detail:{ids:pe(e),total:t.length}}))}function ge(e){e.querySelectorAll("input[data-gb-select]").forEach(function(t){t.checked=!1}),C(e)}function he(e){if(!e)return"";var t=e.getAttribute("data-sort-value");return t??e.textContent.trim()}function We(e){var t=e.closest("th"),r=e.closest("table");if(!(!t||!r)){var n=t.getAttribute("aria-sort")==="ascending"?"descending":"ascending";if(r.querySelectorAll("thead th[aria-sort]").forEach(function(c){c!==t&&c.setAttribute("aria-sort","none")}),t.setAttribute("aria-sort",n),r.getAttribute("data-gb-sort")!=="client"){r.dispatchEvent(new CustomEvent("gb:sort",{bubbles:!0,detail:{key:t.getAttribute("data-key"),direction:n}}));return}var a=Array.prototype.indexOf.call(t.parentElement.children,t),i=r.tBodies[0];if(i){var l=Array.prototype.slice.call(i.rows),u=n==="ascending"?1:-1,s=function(c){var f=String(c).replace(/[\s,%$€£¥]/g,"");return f!==""&&!isNaN(+f)?+f:null};l.sort(function(c,f){var v=he(c.cells[a]),h=he(f.cells[a]),p=s(v),S=s(h);return u*(p!=null&&S!=null?p-S:String(v).localeCompare(String(h),void 0,{numeric:!0,sensitivity:"base"}))}),l.forEach(function(c){i.appendChild(c)})}}}function Qe(e){return Array.prototype.slice.call(e.querySelectorAll(":scope > .ui-board__col[data-col]"))}function M(e){return Array.prototype.slice.call(e.querySelectorAll("li[data-id]")).filter(function(t){return t.closest(".ui-board__col")===e})}function V(e){var t=e.getAttribute("data-name")||(e.querySelector(".ui-card__link, h2, h3, h4")||e).textContent||"";return t.trim().replace(/\s+/g," ").slice(0,80)||"Card"}function P(e){var t=e.querySelector(".ui-board__name");return(t&&t.textContent||e.getAttribute("data-col")||"").trim()}function _(e,t){var r=e.querySelector(":scope > [data-gb-live]");r||(r=document.createElement("div"),r.className="ui-sr-only",r.setAttribute("aria-live","assertive"),r.setAttribute("data-gb-live",""),e.appendChild(r)),r.textContent="",setTimeout(function(){r.textContent=t},30)}function ye(e,t){var r=e.querySelector(".ui-board__count"),n=r?parseInt(r.textContent,10):NaN;r&&String(n)===r.textContent.trim()&&(r.textContent=String(n+t))}function $e(e,t,r,n){var a=t.closest(".ui-board__col"),i=M(r).filter(function(f){return f!==t});if(n<i.length)i[n].parentNode.insertBefore(t,i[n]);else if(i.length){var l=i[i.length-1];l.parentNode.insertBefore(t,l.nextSibling)}else{var u=r.querySelector("ol.ui-board__list");if(!u){u=document.createElement("ol"),u.className="ui-board__list";var s=r.querySelector(":scope > .ui-board__empty");s?s.replaceWith(u):r.querySelector(".ui-board__head").after(u)}u.appendChild(t)}if(a!==r&&(ye(a,-1),ye(r,1),!M(a).length&&!a.querySelector(".ui-board__next a[data-gb-more]"))){var c=document.createElement("p");c.className="ui-board__empty",c.textContent=e.getAttribute("data-empty-label")||"Nothing here",a.querySelectorAll(":scope > ol.ui-board__list, :scope > details.ui-board__more").forEach(function(f){f.remove()}),a.querySelector(".ui-board__head").after(c)}}var o=null;function T(e){return M(e).filter(function(t){return!o||t!==o.li})}function W(e){e.querySelectorAll("[data-gb-drop]").forEach(function(t){t.removeAttribute("data-gb-drop")}),e.querySelectorAll("[data-gb-over]").forEach(function(t){t.removeAttribute("data-gb-over")})}function Q(){if(o){W(o.b),o.to.setAttribute("data-gb-over","");var e=T(o.to),t=o.index<e.length?e[o.index]:e[e.length-1];if(t){t.setAttribute("data-gb-drop",o.index<e.length?"before":"after");var r=t.closest("details:not([open])");r&&o.b.contains(r)&&(r.open=!0),o.keys&&t.scrollIntoView&&t.scrollIntoView({block:"nearest",inline:"nearest"})}}}function K(){return o?P(o.to)+", position "+(o.index+1)+" of "+(T(o.to).length+1):""}function $(){o&&(o.li.removeAttribute("data-gb-lifted"),o.b.removeAttribute("data-gb-dragging"),W(o.b),o=null)}function Ae(e,t,r){var n=t.closest(".ui-board__col");if(!(!n||!t.getAttribute("data-id"))){var a=M(n).indexOf(t);o={b:e,li:t,id:t.getAttribute("data-id"),from:n,to:n,index:a,origin:a,keys:r},t.setAttribute("data-gb-lifted",r?"key":"drag"),r&&(Q(),_(e,"Picked up "+V(t)+". "+K()+". Arrow keys move it, Space drops it, Escape cancels."))}}function Ee(){if(o){var e=o,t=V(e.li),r=e.to===e.from&&e.index===e.origin,n=K();if($(),r){_(e.b,t+" dropped where it was, in "+P(e.from)+".");return}var a=new CustomEvent("gb:move",{bubbles:!0,cancelable:!0,detail:{id:e.id,from:e.from.getAttribute("data-col"),to:e.to.getAttribute("data-col"),index:e.index}}),i=e.b.dispatchEvent(a);if(i&&$e(e.b,e.li,e.to,e.index),_(e.b,"Moved "+t+" to "+n+"."),e.keys){var l=10,u=function(){var s=Array.prototype.slice.call(e.b.querySelectorAll("li[data-id]")).filter(function(c){return c.getAttribute("data-id")===e.id})[0];s&&document.activeElement!==s?s.focus():!s&&l-- >0&&requestAnimationFrame(u)};requestAnimationFrame(u)}}}function N(e){if(o){var t=o;$(),t.keys&&_(t.b,(e||"")+V(t.li)+" stays in "+P(t.from)+".")}}function _e(e){var t=e&&e.closest?e.closest(".ui-board[data-gb-move]"):null;return t}function Xe(e){var t=_e(e.target),r=t&&e.target.closest("li[data-id]");if(!(!r||!t.contains(r)||t.__gbMoveOn)){if(!o){(e.key===" "||e.key==="Spacebar")&&e.target===r&&(e.preventDefault(),Ae(t,r,!0));return}if(!(o.li!==r||!o.keys)){var n=Qe(t);if(e.key==="ArrowUp"||e.key==="ArrowDown")e.preventDefault(),o.index=Math.max(0,Math.min(T(o.to).length,o.index+(e.key==="ArrowUp"?-1:1)));else if(e.key==="ArrowLeft"||e.key==="ArrowRight"){e.preventDefault();var a=n.indexOf(o.to)+(e.key==="ArrowLeft"?-1:1);if(a<0||a>=n.length){_(t,K()+". No column further "+(e.key==="ArrowLeft"?"left":"right")+".");return}o.to=n[a],o.index=Math.min(o.index,T(o.to).length)}else if(e.key===" "||e.key==="Spacebar"||e.key==="Enter"){e.preventDefault(),Ee();return}else if(e.key==="Escape"){e.preventDefault(),e.stopPropagation(),N("Move cancelled. ");return}else if(e.key==="Tab"){N("Move cancelled. ");return}else return;Q(),_(t,K())}}}function ze(e){var t=e.closest(".ui-board__col"),r=e.closest(".ui-board"),n=e.closest(".ui-board__next")||e.parentNode;if(!(!t||!r||n.getAttribute("aria-busy")==="true")){var a=t.getAttribute("data-col"),i=e.href;n.setAttribute("aria-busy","true"),n.innerHTML='<span class="ui-spinner" aria-hidden="true"></span><span role="status">Loading\u2026</span>',fetch(i,{headers:{Accept:"text/html"},credentials:"same-origin"}).then(function(l){if(!l.ok)throw new Error(String(l.status));return l.text()}).then(function(l){var u=new DOMParser().parseFromString(l,"text/html"),s=r.id?u.getElementById(r.id):u,c=Array.prototype.slice.call((s||u).querySelectorAll(".ui-board__col[data-col]")).filter(function(b){return b.getAttribute("data-col")===a})[0];if(!c)throw new Error("no column "+a);var f={};r.querySelectorAll("li[data-id]").forEach(function(b){f[b.getAttribute("data-id")]=1});var v=t.querySelector(":scope > ol.ui-board__list");if(!v){v=document.createElement("ol"),v.className="ui-board__list";var h=t.querySelector(":scope > .ui-board__empty");h?h.replaceWith(v):n.before(v)}var p=M(c).filter(function(b){return!f[b.getAttribute("data-id")]}).map(function(b){var A=document.importNode(b,!0);return v.appendChild(A),A}),S=c.querySelector(".ui-board__count"),O=t.querySelector(".ui-board__count");S&&O&&(O.textContent=S.textContent);var k=c.querySelector(".ui-board__next");k&&k.querySelector("a[data-gb-more]")?(n.innerHTML=k.innerHTML,n.removeAttribute("aria-busy")):n.remove();try{history.replaceState(history.state,"",i)}catch{}_(r,p.length+" more "+(p.length===1?"card":"cards")+" in "+P(t)+".");var y=p[0];if(y){var d=y.matches("[tabindex]")?y:y.querySelector("a[href], button, [tabindex]");d&&d.focus({preventScroll:!1})}}).catch(function(){n.removeAttribute("aria-busy"),n.innerHTML=`<span role="alert" class="ui-more__error">Couldn't load.</span>`;var l=document.createElement("a");l.className="ui-btn ui-btn--sm",l.href=i,l.setAttribute("data-gb-more",""),l.textContent="Try again",n.appendChild(l),l.focus()})}}function Se(){if(!(ve||typeof document>"u")){ve=!0,document.addEventListener("keydown",Xe),document.addEventListener("focusout",function(t){o&&o.keys&&t.target===o.li&&!o.li.contains(t.relatedTarget)&&N("Move cancelled. ")}),document.addEventListener("dragstart",function(t){var r=_e(t.target),n=r&&t.target.closest("li[data-id]");!n||!r.contains(n)||r.__gbMoveOn||!t.dataTransfer||(o&&$(),Ae(r,n,!1),t.dataTransfer.effectAllowed="move",t.dataTransfer.setData("text/plain",n.getAttribute("data-id")||""),requestAnimationFrame(function(){o&&r.setAttribute("data-gb-dragging","")}))});var e=function(t){var r=t.target.closest?t.target.closest(".ui-board__col[data-col]"):null;if(!r||!o||!o.b.contains(r))return null;for(var n=T(r),a=n.length,i=0;i<n.length;i++){var l=n[i].getBoundingClientRect();if(l.height){if(t.clientY<l.top+l.height/2){a=i;break}a=i+1}}return{col:r,index:a}};document.addEventListener("dragover",function(t){if(!(!o||o.keys)){var r=e(t);r&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="move"),(r.col!==o.to||r.index!==o.index||!o.b.querySelector("[data-gb-over]"))&&(o.to=r.col,o.index=r.index,Q()))}}),document.addEventListener("dragleave",function(t){o&&!o.keys&&!o.b.contains(t.relatedTarget)&&W(o.b)}),document.addEventListener("drop",function(t){if(!(!o||o.keys)){t.preventDefault();var r=e(t);if(!r){N();return}o.to=r.col,o.index=r.index,Ee()}}),document.addEventListener("dragend",function(){o&&!o.keys&&N()}),document.addEventListener("click",function(t){var r=t.target;if(!(!r||!r.closest)){var n=r.closest(".ui-board a[data-gb-more][href]");if(n){!t.defaultPrevented&&t.button===0&&!t.metaKey&&!t.ctrlKey&&!t.shiftKey&&!t.altKey&&typeof fetch=="function"&&(t.preventDefault(),ze(n));return}var a=r.closest("table[data-gb-sort] button.ui-table__sort");if(a){We(a);return}var i=r.closest("td.ui-table__check, th.ui-table__check");if(i&&r===i){var l=i.querySelector("input[data-gb-select], input[data-gb-select-all]");if(l){l.click();return}}var u=r.closest("input[data-gb-select]");if(u){var s=u.closest(U);if(s&&t.shiftKey&&q&&q!==u&&s.contains(q)){for(var c=Array.prototype.slice.call(s.querySelectorAll("input[data-gb-select]")),f=c.indexOf(q),v=c.indexOf(u),h=u.checked,p=Math.min(f,v);p<=Math.max(f,v);p++)c[p].checked=h;C(s)}q=u;return}me(t)}}),document.addEventListener("auxclick",function(t){t.button===1&&me(t)}),document.addEventListener("change",function(t){var r=t.target;if(!(!r||!r.matches)){var n=r.closest(U);n&&(r.matches("input[data-gb-select-all]")?(n.querySelectorAll("input[data-gb-select]").forEach(function(a){a.checked=r.checked}),C(n)):r.matches("input[data-gb-select]")&&C(n))}}),document.addEventListener("keydown",function(t){if(!(t.key!=="Escape"||t.defaultPrevented||m.length)){var r=document.activeElement&&document.activeElement.closest?document.activeElement.closest(U):null;r&&Ue(r,document.activeElement)||r&&r.querySelector("input[data-gb-select]:checked")&&ge(r)}})}}Se(),g.gembossUI={openModal:z,toast:we,confirm:Ne,initMenus:Me,closeMenus:F,initSearch:Ke,initShell:Oe,initPasswordFields:De,resetPasswordFields:Pe,initNav:fe,openModals:function(){return m.length},initCollections:Se,selection:pe,clearSelection:ge,syncSelection:C,initMenuLayer:ee,floatMenu:B,placeFloating:j}})(globalThis);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ui-spark{--ui-spark-c: var(--ui-text-muted, #686b71);display:block;max-width:100%;height:auto;overflow:visible}.ui-spark--series{--ui-spark-c: var(--ui-series-1, #5661f5)}.ui-spark--success{--ui-spark-c: var(--ui-success-fg, #007f5f)}.ui-spark--critical{--ui-spark-c: var(--ui-danger-fg, #b42318)}.ui-spark__line{fill:none;stroke:var(--ui-spark-c);stroke-width:1.5;stroke-linejoin:round;stroke-linecap:round;vector-effect:non-scaling-stroke}.ui-spark__area{fill:color-mix(in srgb,var(--ui-spark-c) 14%,transparent)}.ui-spark__pt{fill:var(--ui-spark-c)}.ui-spark__end{fill:var(--ui-spark-end, var(--ui-series-1, #5661f5))}.ui-sharebar{display:flex;gap:1px;height:6px;border-radius:999px;overflow:hidden;background:var(--ui-surface-2, #eceef2)}.ui-sharebar__seg{display:block;flex:0 0 0;min-width:2px;background:var(--c, var(--ui-series-1, #5661f5))}.ui-sharebar__seg--neutral{--c: var(--ui-text-muted, #686b71)}.ui-sharebar__seg--info{--c: var(--gemboss-accent, #5661f5)}.ui-sharebar__seg--success{--c: var(--gemboss-success, #007f5f)}.ui-sharebar__seg--warning{--c: var(--gemboss-warning, #9a6700)}.ui-sharebar__seg--critical{--c: var(--gemboss-danger, #d72c0d)}.ui-sharebar__seg--series-1{--c: var(--ui-series-1, #5661f5)}.ui-sharebar__seg--series-2{--c: var(--ui-series-2, #0f9f8f)}.ui-sharebar__seg--series-3{--c: var(--ui-series-3, #d9822b)}.ui-sharebar__seg--series-4{--c: var(--ui-series-4, #c2417a)}.ui-sharebar__seg--series-5{--c: var(--ui-series-5, #6b7280)}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two charts small enough to sit inside a card or a table cell — @gemboss/ui 0.30.0.
|
|
3
|
+
*
|
|
4
|
+
* `Sparkline`: the trend line every surface was drawing by hand. Counted 08/10/2026: the admin (intelligence `Spark`,
|
|
5
|
+
* analytics KPIs, operator), talent-radar trends, search-radar `Spark.jsx`, gemwatcher's pulse, content-radar's archive,
|
|
6
|
+
* gemform's form cards: six hand copies, three ways of choosing the baseline, one with gaps for a missing day.
|
|
7
|
+
* `ShareBar`: one bar split by share, e.g. a form's registrations by status (gemform). The kit's `ui-progress` is one
|
|
8
|
+
* value, `ui-barlist` one bar per row; neither says "how these N parts divide one whole" in one line.
|
|
9
|
+
*
|
|
10
|
+
* Server-renderable (no state, no effect). Colours are tokens (`--ui-spark-c`, `--c`), so the dark palette follows.
|
|
11
|
+
* ShareBar sizes its segments with an inline `flex-grow`: a plain-HTML page under a CSP that forbids inline style
|
|
12
|
+
* (gemcare: `style-src 'self'`) has to size them from its own stylesheet or script.
|
|
13
|
+
* A page that writes the markup itself (no React) computes the path with `sparklinePaths` (pure, `@gemboss/ui` index)
|
|
14
|
+
* or by hand, and links `minichart.css`.
|
|
15
|
+
*/
|
|
16
|
+
import "./minichart.css"; // its own entry (0.30.0): a surface that draws no mini chart never downloads it
|
|
17
|
+
import React from "react";
|
|
18
|
+
|
|
19
|
+
const cx = (...p: Array<string | false | null | undefined>) => p.filter(Boolean).join(" ");
|
|
20
|
+
const r1 = (n: number) => Math.round(n * 10) / 10;
|
|
21
|
+
|
|
22
|
+
/** A value, or a gap (`null` / `undefined` / NaN): a day with no reading breaks the line instead of drawing a zero. */
|
|
23
|
+
export type SparkPoint = number | null | undefined;
|
|
24
|
+
|
|
25
|
+
export interface SparklineGeometry {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
/** One `d` per unbroken run of two or more points. */
|
|
29
|
+
lines: string[];
|
|
30
|
+
/** One closed `d` per run, down to the baseline (empty when `area` is off). */
|
|
31
|
+
areas: string[];
|
|
32
|
+
/** Points with no neighbour on either side: drawn as dots, a line of one point is invisible. */
|
|
33
|
+
dots: Array<[number, number]>;
|
|
34
|
+
/** The newest point, when the newest reading is a number (the "now" dot). */
|
|
35
|
+
last: [number, number] | null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const isNum = (v: SparkPoint): v is number => typeof v === "number" && Number.isFinite(v);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The geometry of a sparkline, oldest point first, as SVG path data in a `width` x `height` box.
|
|
42
|
+
*
|
|
43
|
+
* The scale is honest by default: from 0 when every value is >= 0 (a count drawn from its own minimum turns 5, 4, 5
|
|
44
|
+
* into a cliff), otherwise from the smallest value. `min` / `max` fix it, e.g. a 30-day window that must not rescale.
|
|
45
|
+
* `invert` puts small values at the top (a rank: #1 is best).
|
|
46
|
+
*/
|
|
47
|
+
export function sparklinePaths(points: readonly SparkPoint[], opts: {
|
|
48
|
+
width?: number; height?: number; pad?: number; min?: number; max?: number; invert?: boolean; area?: boolean;
|
|
49
|
+
} = {}): SparklineGeometry | null {
|
|
50
|
+
const { width = 120, height = 28, pad = 3, invert = false, area = true } = opts;
|
|
51
|
+
const vals = points.filter(isNum);
|
|
52
|
+
if (!vals.length) return null;
|
|
53
|
+
const lo = opts.min ?? (Math.min(...vals) >= 0 ? 0 : Math.min(...vals));
|
|
54
|
+
const hi = Math.max(opts.max ?? Math.max(...vals), lo + 1e-9);
|
|
55
|
+
const span = hi - lo || 1;
|
|
56
|
+
const n = points.length;
|
|
57
|
+
const x = (i: number) => r1(n === 1 ? width / 2 : pad + (i * (width - 2 * pad)) / (n - 1));
|
|
58
|
+
const y = (v: number) => {
|
|
59
|
+
const t = (Math.min(Math.max(v, lo), hi) - lo) / span;
|
|
60
|
+
return r1(invert ? pad + t * (height - 2 * pad) : height - pad - t * (height - 2 * pad));
|
|
61
|
+
};
|
|
62
|
+
// The area always fills DOWN to the bottom edge: under an inverted scale too, so the better (higher) a rank, the more
|
|
63
|
+
// ground under it; filled up to the top it read as shading above the line.
|
|
64
|
+
const base = height - pad;
|
|
65
|
+
const runs: Array<Array<[number, number]>> = [];
|
|
66
|
+
let cur: Array<[number, number]> | null = null;
|
|
67
|
+
// An index loop, not forEach: forEach skips the holes of a sparse array (`new Array(7)` with two days filled), and a
|
|
68
|
+
// hole is a day with no reading, which must break the line like `null` does.
|
|
69
|
+
for (let i = 0; i < n; i++) {
|
|
70
|
+
const v = points[i];
|
|
71
|
+
if (!isNum(v)) { cur = null; continue; }
|
|
72
|
+
if (!cur) { cur = []; runs.push(cur); }
|
|
73
|
+
cur.push([x(i), y(v)]);
|
|
74
|
+
}
|
|
75
|
+
const lines: string[] = [];
|
|
76
|
+
const areas: string[] = [];
|
|
77
|
+
const dots: Array<[number, number]> = [];
|
|
78
|
+
for (const run of runs) {
|
|
79
|
+
if (run.length === 1) { dots.push(run[0]); continue; }
|
|
80
|
+
const d = run.map(([px, py], j) => `${j ? "L" : "M"}${px} ${py}`).join(" ");
|
|
81
|
+
lines.push(d);
|
|
82
|
+
if (area) areas.push(`${d} L${run[run.length - 1][0]} ${base} L${run[0][0]} ${base} Z`);
|
|
83
|
+
}
|
|
84
|
+
const lastV = points[n - 1];
|
|
85
|
+
return { width, height, lines, areas, dots, last: isNum(lastV) ? [x(n - 1), y(lastV)] : null };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type SparkTone = "neutral" | "series" | "success" | "critical";
|
|
89
|
+
// Whole class names, never built from a template: a class written out is a class grep (and the admin's orphan-rule gate,
|
|
90
|
+
// a-tap-target-rule-outlived-its-markup) can find.
|
|
91
|
+
const SPARK_TONE: Record<SparkTone, string> = { neutral: "", series: "ui-spark--series", success: "ui-spark--success", critical: "ui-spark--critical" };
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* A trend line. The line is muted ink and the newest point is one iris dot: the accent marks "now" and nothing else.
|
|
95
|
+
* `tone` colours the line for a series that means something (`success` / `critical`), `series` for iris.
|
|
96
|
+
* With `label` it is an image with that name (say what it shows: "Registrations, last 7 days: 3 then 5"); without it,
|
|
97
|
+
* it is decoration beside a number that already says it (aria-hidden).
|
|
98
|
+
*/
|
|
99
|
+
export function Sparkline({ points, width = 120, height = 28, label, tone = "neutral", area = true, endDot = true, min, max, invert, className }: {
|
|
100
|
+
points: readonly SparkPoint[];
|
|
101
|
+
width?: number;
|
|
102
|
+
height?: number;
|
|
103
|
+
label?: string;
|
|
104
|
+
tone?: SparkTone;
|
|
105
|
+
area?: boolean;
|
|
106
|
+
endDot?: boolean;
|
|
107
|
+
min?: number;
|
|
108
|
+
max?: number;
|
|
109
|
+
invert?: boolean;
|
|
110
|
+
className?: string;
|
|
111
|
+
}) {
|
|
112
|
+
const g = sparklinePaths(points, { width, height, min, max, invert, area });
|
|
113
|
+
if (!g) return null;
|
|
114
|
+
const a11y = label ? { role: "img", "aria-label": label } : { "aria-hidden": true as const, focusable: "false" as const };
|
|
115
|
+
return (
|
|
116
|
+
<svg className={cx("ui-spark", SPARK_TONE[tone], className)} width={width} height={height}
|
|
117
|
+
viewBox={`0 0 ${width} ${height}`} {...a11y}>
|
|
118
|
+
{label ? <title>{label}</title> : null}
|
|
119
|
+
{g.areas.map((d) => <path key={`a${d}`} className="ui-spark__area" d={d} />)}
|
|
120
|
+
{g.lines.map((d) => <path key={`l${d}`} className="ui-spark__line" d={d} />)}
|
|
121
|
+
{g.dots.map(([cx_, cy]) => <circle key={`p${cx_}`} className="ui-spark__pt" cx={cx_} cy={cy} r={1.5} />)}
|
|
122
|
+
{endDot && g.last ? <circle className="ui-spark__end" cx={g.last[0]} cy={g.last[1]} r={2.5} /> : null}
|
|
123
|
+
</svg>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** A part's colour: a status tone (the same five the kit's badges use) or a chart series. */
|
|
128
|
+
export type ShareTone = "neutral" | "info" | "success" | "warning" | "critical" | "series-1" | "series-2" | "series-3" | "series-4" | "series-5";
|
|
129
|
+
|
|
130
|
+
const SEG: Record<ShareTone, string> = {
|
|
131
|
+
neutral: "ui-sharebar__seg--neutral", info: "ui-sharebar__seg--info", success: "ui-sharebar__seg--success",
|
|
132
|
+
warning: "ui-sharebar__seg--warning", critical: "ui-sharebar__seg--critical", "series-1": "ui-sharebar__seg--series-1",
|
|
133
|
+
"series-2": "ui-sharebar__seg--series-2", "series-3": "ui-sharebar__seg--series-3", "series-4": "ui-sharebar__seg--series-4",
|
|
134
|
+
"series-5": "ui-sharebar__seg--series-5",
|
|
135
|
+
};
|
|
136
|
+
const SERIES: ShareTone[] = ["series-1", "series-2", "series-3", "series-4", "series-5"];
|
|
137
|
+
|
|
138
|
+
export interface SharePart {
|
|
139
|
+
label: string;
|
|
140
|
+
value: number;
|
|
141
|
+
/** Defaults to the series colours in order. */
|
|
142
|
+
tone?: ShareTone;
|
|
143
|
+
key?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* One bar, split by share. Parts at 0 take no room; an all-zero bar is the empty track. The bar is one image whose
|
|
148
|
+
* name lists every part ("Status: New 25, Contacted 2, Qualified 4"), so a screen reader hears the numbers the
|
|
149
|
+
* colours stand for; each segment's `title` says its own on hover.
|
|
150
|
+
*/
|
|
151
|
+
export function ShareBar({ parts, label, className }: { parts: readonly SharePart[]; label?: string; className?: string }) {
|
|
152
|
+
const shown = parts.map((p, i) => ({ ...p, tone: p.tone ?? SERIES[i % 5] })).filter((p) => p.value > 0);
|
|
153
|
+
const total = shown.reduce((a, p) => a + p.value, 0);
|
|
154
|
+
const said = parts.map((p) => `${p.label} ${p.value}`).join(", ");
|
|
155
|
+
return (
|
|
156
|
+
<div className={cx("ui-sharebar", className)} role="img" aria-label={label ? `${label}: ${said}` : said}>
|
|
157
|
+
{shown.map((p) => (
|
|
158
|
+
// The SHARE, not the raw value: flex-grow values that add up to less than 1 hand out only that fraction of the
|
|
159
|
+
// track (0.2 + 0.3 filled half the bar). Shares always add up to 1.
|
|
160
|
+
<span key={p.key ?? p.label} className={cx("ui-sharebar__seg", SEG[p.tone])} style={{ flexGrow: +(p.value / total).toFixed(4) }}
|
|
161
|
+
title={`${p.label} ${p.value}`} />
|
|
162
|
+
))}
|
|
163
|
+
</div>
|
|
164
|
+
);
|
|
165
|
+
}
|
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}}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;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/search-dialog.tsx
CHANGED
|
@@ -15,14 +15,16 @@ import { Icon } from "./icons";
|
|
|
15
15
|
|
|
16
16
|
const cx = (...p: Array<string | false | null | undefined>) => p.filter(Boolean).join(" ");
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
/** `external` (0.31.0): a page outside the surface (content-radar's collected posts): it opens in a new tab, so the
|
|
19
|
+
* person keeps the surface and the dialog closes behind it. */
|
|
20
|
+
export type SearchItem = { href: string; title: string; meta?: React.ReactNode; external?: boolean };
|
|
19
21
|
export type SearchSection = { title: string; items: SearchItem[] };
|
|
20
22
|
|
|
21
23
|
// One constant, not a default `= []`: a fresh array each render, read by an effect, re-ran it forever
|
|
22
24
|
// ("Maximum update depth exceeded", review of 0.7.0 in Chromium).
|
|
23
25
|
const NO_SECTIONS: SearchSection[] = [];
|
|
24
26
|
|
|
25
|
-
export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Search…", label = "Search", fallbackHref, shortcut = true, renderItem }: {
|
|
27
|
+
export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Search…", label = "Search", fallbackHref, shortcut = true, renderItem, trigger = "icon", hint = "⌘K", onNavigate, minChars = 1 }: {
|
|
26
28
|
/** Results for a query. Called at most every 150 ms; an answer to an older query is dropped. */
|
|
27
29
|
search: (q: string) => Promise<SearchSection[]>;
|
|
28
30
|
/** What the popup shows before anything is typed (Featurebase: "Trending requests", "Latest updates"). */
|
|
@@ -34,12 +36,29 @@ export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Sea
|
|
|
34
36
|
/** ⌘K / Ctrl+K and "/" open it. */
|
|
35
37
|
shortcut?: boolean;
|
|
36
38
|
renderItem?: (item: SearchItem) => React.ReactNode;
|
|
39
|
+
/**
|
|
40
|
+
* What opens it (0.31.0). `icon`: the 36px magnifier (GemFeedback). `field`: the topbar's search BOX — the admin's
|
|
41
|
+
* "Search ⌘K" look, the same `gemboss-topbar-search` box TopbarSearch draws — for a surface whose centre column is
|
|
42
|
+
* the search (content-radar). It is a link that opens the popup, not a text box: typing happens in the popup.
|
|
43
|
+
*/
|
|
44
|
+
trigger?: "icon" | "field";
|
|
45
|
+
/** The hint at the right edge of the `field` trigger; null hides it. */
|
|
46
|
+
hint?: string | null;
|
|
47
|
+
/**
|
|
48
|
+
* A result inside the surface, picked with Enter or a plain click (0.31.0). Without it the page reloads at `href`; a
|
|
49
|
+
* Next surface passes `router.push`, so a running assistant answer or a draft is not thrown away by a full reload.
|
|
50
|
+
*/
|
|
51
|
+
onNavigate?: (href: string) => void;
|
|
52
|
+
/** Fewer characters than this are not searched (0.31.0): the popup says how many to type, not "Nothing matches.". */
|
|
53
|
+
minChars?: number;
|
|
37
54
|
}) {
|
|
38
55
|
const [open, setOpen] = useState(false);
|
|
39
56
|
const [q, setQ] = useState("");
|
|
40
57
|
const [sections, setSections] = useState<SearchSection[]>(initial);
|
|
41
58
|
const [active, setActive] = useState(0);
|
|
42
59
|
const [busy, setBusy] = useState(false);
|
|
60
|
+
// A search that THREW is not "nothing matches" (0.31.0): the person reads the reason, not an empty list.
|
|
61
|
+
const [failed, setFailed] = useState<string | null>(null);
|
|
43
62
|
const ref = useRef<HTMLDialogElement>(null);
|
|
44
63
|
const input = useRef<HTMLInputElement>(null);
|
|
45
64
|
const seq = useRef(0);
|
|
@@ -74,20 +93,22 @@ export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Sea
|
|
|
74
93
|
// Every change takes a new number: an answer still on its way for an older query is dropped,
|
|
75
94
|
// including when the box was just cleared (it used to land under an empty box).
|
|
76
95
|
const mine = ++seq.current;
|
|
96
|
+
setFailed(null);
|
|
77
97
|
if (!query) { setSections(initialRef.current); setActive(0); setBusy(false); return undefined; }
|
|
98
|
+
if (query.length < minChars) { setSections(NO_SECTIONS); setActive(0); setBusy(false); return undefined; }
|
|
78
99
|
setBusy(true);
|
|
79
100
|
const t = setTimeout(async () => {
|
|
80
101
|
try {
|
|
81
102
|
const res = await searchRef.current(query);
|
|
82
103
|
if (mine === seq.current) { setSections(res); setActive(0); }
|
|
83
|
-
} catch {
|
|
84
|
-
if (mine === seq.current) setSections(NO_SECTIONS);
|
|
104
|
+
} catch (e) {
|
|
105
|
+
if (mine === seq.current) { setSections(NO_SECTIONS); setFailed(e instanceof Error && e.message ? e.message : "error"); }
|
|
85
106
|
} finally {
|
|
86
107
|
if (mine === seq.current) setBusy(false);
|
|
87
108
|
}
|
|
88
109
|
}, 150);
|
|
89
110
|
return () => { clearTimeout(t); if (mine === seq.current) setBusy(false); };
|
|
90
|
-
}, [q, open]);
|
|
111
|
+
}, [q, open, minChars]);
|
|
91
112
|
// Before anything is typed, show the latest suggestions the page passed.
|
|
92
113
|
useEffect(() => { if (open && !q.trim()) setSections(initial); }, [initial, open, q]);
|
|
93
114
|
// The highlighted result stays in view as the arrows move it.
|
|
@@ -96,16 +117,37 @@ export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Sea
|
|
|
96
117
|
document.getElementById(`${listId}-${active}`)?.scrollIntoView({ block: "nearest" });
|
|
97
118
|
}, [active, open, listId]);
|
|
98
119
|
|
|
99
|
-
const go = (item: SearchItem | undefined) => {
|
|
120
|
+
const go = (item: SearchItem | undefined) => {
|
|
121
|
+
if (!item) return;
|
|
122
|
+
if (item.external) { window.open(item.href, "_blank", "noopener,noreferrer"); ref.current?.close(); }
|
|
123
|
+
else if (onNavigate) { ref.current?.close(); onNavigate(item.href); }
|
|
124
|
+
else window.location.assign(item.href);
|
|
125
|
+
};
|
|
126
|
+
// A plain click (no ⌘ / Ctrl / Shift / Alt, main button): ⌘-click on a result is "open it in a tab and keep looking".
|
|
127
|
+
const plain = (e: React.MouseEvent) => !(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0);
|
|
128
|
+
const short = q.trim().length > 0 && q.trim().length < minChars;
|
|
100
129
|
let n = -1;
|
|
101
130
|
return (
|
|
102
131
|
<>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
|
|
132
|
+
{trigger === "field" ? (
|
|
133
|
+
// No aria-label: the name is the words on the box (WCAG 2.5.3 label in name; review #3945).
|
|
134
|
+
<a className="gemboss-topbar-search gb-search-field" href={fallbackHref ?? "#"} aria-haspopup="dialog"
|
|
135
|
+
onClick={(e) => { e.preventDefault(); show(); }}>
|
|
136
|
+
<Icon name="search" size={18} className="gemboss-topbar-search-icon" />
|
|
137
|
+
<span className="gb-search-field-text">{placeholder}</span>
|
|
138
|
+
{hint ? <kbd className="gemboss-topbar-search-kbd" aria-hidden="true">{hint}</kbd> : null}
|
|
139
|
+
</a>
|
|
140
|
+
) : (
|
|
141
|
+
<a className="gb-search-trigger" href={fallbackHref ?? "#"} aria-label={label} aria-haspopup="dialog"
|
|
142
|
+
onClick={(e) => { e.preventDefault(); show(); }}>
|
|
143
|
+
<Icon name="search" size={18} />
|
|
144
|
+
</a>
|
|
145
|
+
)}
|
|
107
146
|
<dialog ref={ref} className="ui-modal gb-search" aria-label={label}
|
|
108
|
-
|
|
147
|
+
// Closing forgets the last answer too (0.31.0): reopened, the popup drew the previous results and highlight for a
|
|
148
|
+
// frame, and an Enter in that frame opened the previous highlight (measured in the browser test).
|
|
149
|
+
// `seq` moves on too: an answer still on its way when the popup closed is dropped, not painted into the next opening.
|
|
150
|
+
onClose={() => { seq.current += 1; setOpen(false); setQ(""); setSections(initialRef.current); setActive(0); setFailed(null); }}
|
|
109
151
|
onClick={(e) => { if (e.target === e.currentTarget) e.currentTarget.close(); }}>
|
|
110
152
|
<div className="gb-search-box">
|
|
111
153
|
<Icon name="search" size={18} className="gb-search-icon" />
|
|
@@ -117,10 +159,16 @@ export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Sea
|
|
|
117
159
|
else if (e.key === "ArrowUp") { e.preventDefault(); setActive((a) => Math.max(a - 1, 0)); }
|
|
118
160
|
// Enter that confirms an IME composition (Vietnamese, Chinese) is not "open".
|
|
119
161
|
else if (e.key === "Enter" && !e.nativeEvent.isComposing && e.keyCode !== 229) { e.preventDefault(); go(flat[active]); }
|
|
162
|
+
// Escape closes the popup in one press and is marked handled (0.31.0, review #3945): unmarked, a surface's own
|
|
163
|
+
// window listener ("Escape hides the assistant", "Escape closes the composer") fired on the same key. The
|
|
164
|
+
// search box's own "clear the words" Escape went first, so it also took two presses.
|
|
165
|
+
else if (e.key === "Escape" && !e.nativeEvent.isComposing && e.keyCode !== 229) { e.preventDefault(); e.stopPropagation(); ref.current?.close(); }
|
|
120
166
|
}} />
|
|
121
167
|
</div>
|
|
122
168
|
<p className="gb-search-empty" aria-live="polite">
|
|
123
|
-
{
|
|
169
|
+
{short ? `Type at least ${minChars} characters.`
|
|
170
|
+
: failed && q.trim() && !busy ? `Search failed: ${failed}`
|
|
171
|
+
: sections.every((s) => !s.items.length) && q.trim() ? (busy ? "Searching…" : "Nothing matches.") : ""}
|
|
124
172
|
</p>
|
|
125
173
|
<div className="gb-search-results" id={listId} role="listbox" aria-busy={busy}>
|
|
126
174
|
{sections.filter((s) => s.items.length).map((s) => (
|
|
@@ -131,8 +179,14 @@ export function SearchDialog({ search, initial = NO_SECTIONS, placeholder = "Sea
|
|
|
131
179
|
const i = n;
|
|
132
180
|
return (
|
|
133
181
|
<a key={`${s.title}-${it.href}`} id={`${listId}-${i}`} href={it.href} role="option" aria-selected={i === active}
|
|
182
|
+
{...(it.external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
|
|
183
|
+
onClick={(e) => {
|
|
184
|
+
if (!plain(e)) return; // ⌘-click: a background tab, keep looking
|
|
185
|
+
if (it.external) { ref.current?.close(); return; } // the browser opens the tab
|
|
186
|
+
if (onNavigate) { e.preventDefault(); ref.current?.close(); onNavigate(it.href); }
|
|
187
|
+
}}
|
|
134
188
|
className={cx("gb-search-item", i === active && "is-active")} onMouseMove={() => setActive(i)}>
|
|
135
|
-
{renderItem ? renderItem(it) : (<><span className="gb-search-item-title">{it.title}</span>{it.meta ? <span className="gb-search-item-meta">{it.meta}</span> : null}</>)}
|
|
189
|
+
{renderItem ? renderItem(it) : (<><span className="gb-search-item-title">{it.title}{it.external ? <span aria-hidden="true"> ↗</span> : null}</span>{it.meta ? <span className="gb-search-item-meta">{it.meta}</span> : null}</>)}
|
|
136
190
|
</a>
|
|
137
191
|
);
|
|
138
192
|
})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ui-setup,.ui-setup__inner{display:grid;gap:var(--ui-space-3, 12px)}.ui-setup__head,.ui-setup__row{display:flex;align-items:center;gap:var(--ui-space-3, 12px);list-style:none;cursor:pointer;border-radius:var(--ui-radius-md, 8px);color:inherit;transition:background-color .12s ease}.ui-setup__head::-webkit-details-marker,.ui-setup__row::-webkit-details-marker{display:none}div.ui-setup__head{cursor:auto}summary.ui-setup__head{padding:6px 8px;margin:-6px -8px 0}.ui-setup__title{margin:0;font-size:var(--ui-fs-body, 13px);line-height:20px;font-weight:650;color:var(--ui-text-strong, var(--ui-text))}.ui-setup__desc{margin:0;font-size:var(--ui-fs-body, 13px);line-height:20px;color:var(--ui-text-muted)}.ui-setup__row{padding:8px;margin:0 -8px}summary.ui-setup__head:hover,summary.ui-setup__row:hover{background:var(--ui-surface-2, #eceef2)}.ui-setup__row--static{cursor:auto}.ui-setup__row.ui-setup__row--static:after{content:none}summary.ui-setup__head:active,summary.ui-setup__row:active{background:var(--ui-border, #e5e7ea)}summary.ui-setup__head:focus-visible,summary.ui-setup__row:focus-visible{outline:2px solid var(--ui-focus, #5661f5);outline-offset:2px}summary.ui-setup__head:after,.ui-setup__row:after{content:"\25be";margin-left:auto;font-size:11px;color:var(--ui-text-muted);transition:transform .12s ease}.ui-setup:not([open])>summary.ui-setup__head:after,.ui-setup__step:not([open])>.ui-setup__row:after{transform:rotate(-90deg)}.ui-setup__bar{appearance:none;-webkit-appearance:none;display:block;width:100%;height:6px;border:0;border-radius:999px;overflow:hidden;background:var(--ui-border, #e5e7ea);color:var(--ui-accent, #1b1c1e)}.ui-setup__bar::-webkit-progress-bar{background:var(--ui-border, #e5e7ea);border-radius:inherit}.ui-setup__bar::-webkit-progress-value{background:currentColor;border-radius:inherit;transition:width .15s ease}.ui-setup__bar::-moz-progress-bar{background:currentColor;border-radius:inherit}.ui-setup__bar--done{color:var(--ui-success-fg, #007f5f)}.ui-setup__steps{display:grid;gap:2px}.ui-setup__mark{flex:0 0 16px;text-align:center;line-height:20px;color:var(--ui-text-muted)}.ui-setup__step[data-state=done] .ui-setup__mark{color:var(--ui-success-fg, #007f5f)}.ui-setup__label{min-width:0;overflow-wrap:anywhere;font-size:var(--ui-fs-body, 13px);line-height:20px;font-weight:550;color:var(--ui-text)}.ui-setup__step[data-state=done] .ui-setup__label{font-weight:450;color:var(--ui-text-muted)}.ui-setup__body{padding:4px 0 12px 28px;font-size:var(--ui-fs-body, 13px);line-height:20px;color:var(--ui-text)}.ui-setup__body>:first-child{margin-top:0}.ui-setup__body>:last-child{margin-bottom:0}@media (pointer: coarse),(max-width: 47.9975em){summary.ui-setup__head,.ui-setup__row{min-height:44px;box-sizing:border-box}}@media (prefers-reduced-motion: reduce){.ui-setup__head,.ui-setup__row,summary.ui-setup__head:after,.ui-setup__row:after,.ui-setup__bar::-webkit-progress-value{transition:none}}
|