@gemboss/ui 0.36.1 → 0.40.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 +441 -0
- package/README.md +617 -14
- package/catalog/editor.html +45 -25
- package/catalog/index.html +5522 -1448
- package/gemboss-ui.css +3 -3
- package/package.json +11 -2
- package/parts/components.css +2 -2
- package/parts/core.css +1 -1
- package/parts/shell.css +2 -2
- package/src/assistant/chat-markdown.ts +7 -4
- package/src/assistant.css +1 -1
- package/src/auth-field.css +1 -0
- package/src/auth-field.tsx +74 -0
- package/src/auth-sso-plain.js +1 -0
- package/src/auth.css +1 -1
- package/src/auth.tsx +64 -1
- package/src/brand-gem.tsx +19 -0
- package/src/brand.tsx +4 -7
- package/src/chat-plain.js +2 -2
- package/src/editor/controls.tsx +148 -11
- package/src/editor/frame.tsx +8 -4
- package/src/editor/index.ts +8 -4
- package/src/editor/panel.tsx +44 -14
- package/src/editor/repeater.tsx +322 -0
- package/src/editor/sortable.tsx +50 -24
- package/src/editor/swatch.ts +20 -0
- package/src/editor/tiles.tsx +51 -0
- package/src/editor-plain.js +1 -1
- package/src/editor-repeater.css +1 -0
- package/src/editor-tiles.css +1 -0
- package/src/editor.css +1 -1
- package/src/gemboss-field.css +1 -1
- package/src/icons.tsx +11 -0
- package/src/index.ts +14 -2
- package/src/kit-plain.js +1 -1
- package/src/service-switcher-plain.js +1 -1
- package/src/service-switcher.css +1 -1
- package/src/service-switcher.tsx +119 -35
- package/src/services.ts +4 -2
- package/src/shell.css +1 -1
- package/src/site.css +1 -0
- package/src/site.tsx +50 -0
- package/src/team-chat-data.ts +79 -0
- package/src/team-chat.css +1 -0
- package/src/team-chat.tsx +825 -0
- package/src/toggle-bar.tsx +60 -0
- package/src/ui.css +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(M){"use strict";var b=M.gembossUI||(M.gembossUI={});if(b.initServiceSwitcher)return;var K=[["gemboss","GemBoss"],["build","Build the store"],["market","Read the market"],["content","Content and community"],["customers","Customers"],["team","Team and partners"]],O=[["gemboss","GemBoss","https://admin.gemboss.ai","The seller app and the ops console.","gemboss","dashboard","iris"],["gemfactory","GemFactory","https://gemfactory.ops.gemboss.ai","Review sections, elements and templates.","build","layers","blue"],["gemmedia","GemMedia","https://media.gemboss.ai","Images and videos made for stores, and their cost.","build","image","rose"],["gemform","GemForm","https://gemform.ops.gemboss.ai","Form submissions from stores.","build","document","teal"],["gemwatcher","GemWatcher","https://gemwatcher.ops.gemboss.ai","Store and market intelligence.","market","eye","violet"],["gemmarket","GemMarket","https://market.gemboss.ai","Each store's market read and its competitors.","market","chart","green"],["gemcapture","GemCapture","https://capture.gemboss.ai/admin","Page captures and visual checks.","market","page","slate"],["search-radar","Search Radar","https://search-radar.ops.gemboss.ai","Rankings on the App Store, Google and AI answers.","market","radar","amber"],["gempress","GemPress","https://press.gemboss.ai/admin","Articles and the content store.","content","article","orange"],["content-radar","Content Radar","https://content-radar.ops.gemboss.ai","From the topics worth writing to articles.","content","radar","teal"],["gemcommunity","GemCommunity","https://community.gemboss.ai/admin","The seller community.","content","users","blue"],["gemnews","GemCommunity News","https://news.gemboss.ai/admin","News posts and how they are read.","content","megaphone","rose"],["gemcare","GemCare","https://care.gemboss.ai/inbox","The customer care inbox.","customers","chat","green"],["gemfeedback","GemFeedback","https://feedback.gemboss.ai/admin","The feedback backlog.","customers","inbox","violet"],["partner-radar","Partner Radar","https://partner-radar.ops.gemboss.ai","Partners and agencies, as a CRM.","team","link","orange"],["taskdesk","Taskdesk","https://gemlabs-taskdesk-production.up.railway.app","Every job the fleet is running.","team","list","slate"]],U={apps:'<circle cx="4.5" cy="4.5" r="1"/><circle cx="10" cy="4.5" r="1"/><circle cx="15.5" cy="4.5" r="1"/><circle cx="4.5" cy="10" r="1"/><circle cx="10" cy="10" r="1"/><circle cx="15.5" cy="10" r="1"/><circle cx="4.5" cy="15.5" r="1"/><circle cx="10" cy="15.5" r="1"/><circle cx="15.5" cy="15.5" r="1"/>',close:'<path d="M5 5l10 10M15 5 5 15"/>',search:'<circle cx="8.8" cy="8.8" r="5.3"/><path d="M12.8 12.8 17 17"/>',dashboard:'<rect x="3" y="3" width="6" height="6" rx="1.3"/><rect x="11" y="3" width="6" height="6" rx="1.3"/><rect x="3" y="11" width="6" height="6" rx="1.3"/><rect x="11" y="11" width="6" height="6" rx="1.3"/>',layers:'<path d="M10 3 17 6.8 10 10.6 3 6.8z"/><path d="M3 10.1l7 3.8 7-3.8"/><path d="M3 13.4l7 3.8 7-3.8"/>',image:'<rect x="3" y="3.5" width="14" height="13" rx="1.8"/><circle cx="7.3" cy="7.8" r="1.3"/><path d="M3.5 15l4.2-4.2 3 3 2.2-2.2 3.6 3.6"/>',document:'<path d="M5 2.8h6.8l3.2 3.2v11.2H5z"/><path d="M11.8 2.8V6H15M7.5 10h5M7.5 13h5"/>',eye:'<path d="M1.8 10S4.7 4.8 10 4.8 18.2 10 18.2 10 15.3 15.2 10 15.2 1.8 10 1.8 10z"/><circle cx="10" cy="10" r="2.5"/>',chart:'<path d="M3 16.5h14"/><rect x="4.5" y="9" width="2.8" height="5.5" rx=".7"/><rect x="8.6" y="5" width="2.8" height="9.5" rx=".7"/><rect x="12.7" y="11" width="2.8" height="3.5" rx=".7"/>',page:'<rect x="2.5" y="3.5" width="15" height="13" rx="2"/><path d="M2.5 7.5h15M6 11h8M6 13.5h5"/>',radar:'<circle cx="10" cy="10" r="7"/><circle cx="10" cy="10" r="3.5"/><path d="M10 10l5-5"/>',article:'<rect x="3" y="3.5" width="14" height="13" rx="1.5"/><path d="M6 7h8M6 10h8M6 13h5"/>',users:'<circle cx="7.5" cy="7.3" r="2.8"/><path d="M2.5 16.3c.6-2.5 2.5-4 5-4s4.4 1.5 5 4"/><path d="M12.3 4.8a2.8 2.8 0 0 1 0 5.2M14.3 12.5c1.6.4 2.7 1.7 3.2 3.8"/>',megaphone:'<path d="M3 8v4h3l6 4V4L6 8H3z"/><path d="M15 7.5a3.5 3.5 0 0 1 0 5"/>',chat:'<path d="M3 4.5h14v9H8.5L5 16.5v-3H3z"/>',inbox:'<path d="M3 11l2-7h10l2 7v5H3z"/><path d="M3 11h4l1 2h4l1-2h4"/>',link:'<path d="M8.6 11.4a3 3 0 0 0 4.2 0l2.6-2.6a3 3 0 0 0-4.2-4.2l-1 1"/><path d="M11.4 8.6a3 3 0 0 0-4.2 0l-2.6 2.6a3 3 0 0 0 4.2 4.2l1-1"/>',list:'<path d="M8 5h9M8 10h9M8 15h9"/><circle cx="4" cy="5" r=".9"/><circle cx="4" cy="10" r=".9"/><circle cx="4" cy="15" r=".9"/>'},D={trigger:"Switch service",title:"Gem services",close:"Close",search:"Find a service",noMatch:"No service matches \u201C{query}\u201D.",all:"All services and their health"},F="https://gemfactory.ops.gemboss.ai/services",B=O.map(function(a){return{id:a[0],name:a[1],url:a[2],purpose:a[3],group:a[4],icon:a[5],tint:a[6]}}),c=function(a){return String(a).replace(/[&<>"']/g,function(r){return{"&":"&","<":"<",">":">",'"':""","'":"'"}[r]})},k=function(a,r){return'<svg viewBox="0 0 20 20" width="'+r+'" height="'+r+'" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">'+(U[a]||"")+"</g></svg>"},V=0;function j(a){return K.map(function(r){return{id:r[0],title:r[1],services:a.filter(function(l){return l.group===r[0]})}}).filter(function(r){return r.services.length>0})}function W(a,r,l){var o=a.map(function(d){return d.getBoundingClientRect()}),h=o[r],_=h.left+h.width/2,f=-1,m=0,y=0;return o.forEach(function(d,E){if(!(l>0?d.top<=h.top+1:d.top>=h.top-1)){var u=Math.abs(d.left+d.width/2-_),s=f<0||(l>0?d.top<m-1:d.top>m+1),p=f>=0&&Math.abs(d.top-m)<=1;(s||p&&u<y)&&(f=E,m=d.top,y=u)}}),f}function N(a,r){var l=a.children;l.length===r.length&&r.every(function(o,h){return l[h]===o})||a.replaceChildren.apply(a,r)}function J(a,r){var l=r.current||a.getAttribute("data-gb-service-switcher")||"",o={},h;for(h in D)o[h]=r.labels&&r.labels[h]!=null?r.labels[h]:D[h];var _=r.allHref===void 0?F:r.allHref,f=j(r.services||B),m="gb-svc"+ ++V+"-",y=m+"svc",d=m+"svc-t",E=document.createElement("template");E.innerHTML='<button type="button" class="gb-svc-trigger'+(r.className?" "+c(r.className):"")+'" aria-haspopup="dialog" aria-expanded="false" aria-controls="'+y+'" aria-label="'+c(o.trigger)+'" title="'+c(o.trigger)+'">'+k("apps",20)+'</button><dialog id="'+y+'" class="gb-svc" aria-labelledby="'+d+'"><div class="gb-svc__head"><h2 class="gb-svc__title" id="'+d+'">'+c(o.title)+'</h2><button type="button" class="ui-modal__close" aria-label="'+c(o.close)+'">'+k("close",20)+"</button></div>"+(r.search===!1?"":'<div class="gb-svc__search"><label class="gemboss-field gemboss-field--group">'+k("search",16)+'<input class="gemboss-field__bare" type="search" name="service-search" autocomplete="off" value="" placeholder="'+c(o.search)+'" aria-label="'+c(o.search)+'"></label></div>')+'<div class="gb-svc__body">'+f.map(function(e){return'<div class="gb-svc__group" role="group" aria-labelledby="'+m+"svc-"+c(e.id)+'"><h3 class="gb-svc__heading" id="'+m+"svc-"+c(e.id)+'">'+c(e.title)+'</h3><ul class="gb-svc__grid" role="list">'+e.services.map(function(t){return'<li><a class="gb-svc__tile" href="'+c(t.url)+'" data-tint="'+c(t.tint)+'"'+(t.id===l?' aria-current="page"':"")+' tabindex="-1"><span class="gb-svc__mark" aria-hidden="true">'+k(t.icon,22)+'</span><span class="gb-svc__name">'+c(t.name)+'</span><span class="gb-svc__purpose">'+c(t.purpose)+"</span></a></li>"}).join("")+"</ul></div>"}).join("")+"</div>"+(_?'<div class="gb-svc__foot"><a class="gb-svc__all" href="'+c(_)+'">'+c(o.all)+'<span aria-hidden="true">\u2192</span></a></div>':"")+"</dialog>";var u=E.content.firstChild,s=u.nextSibling,p=s.querySelector(".gb-svc__search input"),S=s.querySelector(".gb-svc__body"),G=function(){return Array.prototype.slice.call(s.querySelectorAll(".gb-svc__tile"))},Q=G(),X=0,C=[];f.forEach(function(e,t){e.el=S.children[t],e.ul=e.el.querySelector("ul"),e.items=e.services.map(function(n){var i=Q[X++],v={s:n,a:i,li:i.parentNode};return C.push(v),v})});var A=document.createElement("p");A.className="gb-svc__empty",A.setAttribute("role","status");var L=l,R=null,q=!1;function x(){var e=p?p.value:"",t=e.trim().toLowerCase(),n=[],i=[];f.forEach(function(g){var T=g.items.filter(function(w){return!t||(w.s.name+" "+w.s.purpose+" "+w.s.id+" "+g.title).toLowerCase().indexOf(t)>-1});T.length&&(N(g.ul,T.map(function(w){return w.li})),n.push(g.el),i=i.concat(T))}),n.length||(A.textContent=o.noMatch.replace("{query}",e.trim()),n.push(A)),N(S,n);var v=i.map(function(g){return g.s.id}),I=v.indexOf(L)>-1?L:v.indexOf(l)>-1?l:v[0];i.forEach(function(g){g.a.setAttribute("tabindex",g.s.id===I?"0":"-1")})}function H(){var e=u.previousElementSibling,t=(e&&e.tagName==="A"?e:u).getBoundingClientRect(),n=u.closest(".gemboss-platform-topbar"),i=n?n.getBoundingClientRect().bottom:u.getBoundingClientRect().bottom,v=document.documentElement.clientWidth,I=Math.min(760,v-24);s.style.setProperty("--gb-svc-x",Math.round(Math.max(12,Math.min(t.left,v-I-12)))+"px"),s.style.setProperty("--gb-svc-y",Math.round(i+6)+"px")}function z(){if(!(s.open||!s.isConnected)){H(),b.closeMenus&&b.closeMenus(),R=document.activeElement,s.showModal(),u.setAttribute("aria-expanded","true"),L=l,x();var e=s.querySelector(".gb-svc__tile[aria-current]")||s.querySelector(".gb-svc__tile");e&&e.focus(),addEventListener("resize",H)}}return s.addEventListener("close",function(){removeEventListener("resize",H),u.setAttribute("aria-expanded","false"),p&&(p.value=""),x();var e=R;R=null,e&&e.focus&&e.focus({preventScroll:!0})}),u.addEventListener("click",z),s.addEventListener("pointerdown",function(e){q=e.target===s}),s.addEventListener("click",function(e){var t=e.target,n=q;if(q=!1,t===s){n&&s.close();return}(t.closest(".ui-modal__close")||t.closest(".gb-svc__tile, .gb-svc__all")&&e.button===0&&!e.metaKey&&!e.ctrlKey&&!e.shiftKey&&!e.altKey)&&s.close()}),p&&(p.addEventListener("input",x),p.addEventListener("keydown",function(e){if(!e.isComposing){var t=G()[0];e.key==="Escape"?(e.preventDefault(),s.close()):e.key==="ArrowDown"?(e.preventDefault(),t&&t.focus()):e.key==="Enter"&&p.value.trim()&&(e.preventDefault(),t&&t.click())}})),S.addEventListener("keydown",function(e){var t=G(),n=t.indexOf(document.activeElement),i;if(!(n<0||e.altKey||e.ctrlKey||e.metaKey)){if(e.key==="ArrowRight")i=Math.min(n+1,t.length-1);else if(e.key==="ArrowLeft")i=Math.max(n-1,0);else if(e.key==="Home")i=0;else if(e.key==="End")i=t.length-1;else if(e.key==="ArrowDown"||e.key==="ArrowUp"){if(i=W(t,n,e.key==="ArrowDown"?1:-1),i<0&&e.key==="ArrowUp"&&p){e.preventDefault(),p.focus();return}i<0&&(i=n)}else return;e.preventDefault(),t[i].focus()}}),S.addEventListener("focusin",function(e){for(var t=0;t<C.length;t++)if(C[t].a===e.target){L=C[t].s.id,x();return}}),x(),a.replaceWith(u,s),{button:u,dialog:s,open:z,close:function(){s.close()}}}function P(a){return a=a||{},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){P(a)},{once:!0}):!b.openModal&&M.console&&document.querySelector('script[src*="kit-plain"]')&&M.console.error("@gemboss/ui service-switcher-plain.js: load it after kit-plain.js (kit-plain.js defines nothing when gembossUI exists)"),Array.prototype.map.call((a.root||document).querySelectorAll("[data-gb-service-switcher]"),function(r){return J(r,a)})}b.initServiceSwitcher=P,b.GEM_SERVICES=B})(typeof globalThis<"u"?globalThis:this);
|
|
1
|
+
(function(M){"use strict";var b=M.gembossUI||(M.gembossUI={});if(b.initServiceSwitcher)return;var K=[["gemboss","GemBoss"],["build","Build the store"],["market","Read the market"],["content","Content and community"],["customers","Customers"],["team","Team and partners"]],O=[["gemboss","GemBoss","https://admin.gemboss.ai","The seller app and the ops console.","gemboss","dashboard","iris"],["gemfactory","GemFactory","https://gemfactory.ops.gemboss.ai","Review sections, elements and templates.","build","layers","blue"],["gemmedia","GemMedia","https://media.gemboss.ai","Images and videos made for stores, and their cost.","build","image","rose"],["gemform","GemForm","https://gemform.ops.gemboss.ai","Form submissions from stores.","build","document","teal"],["gemx","GemX","https://x.gemboss.ai","Tests and personalization across every store.","build","sliders","amber"],["gemwatcher","GemWatcher","https://gemwatcher.ops.gemboss.ai","Store and market intelligence.","market","eye","violet"],["gemmarket","GemMarket","https://market.gemboss.ai","Each store's market read and its competitors.","market","chart","green"],["gempixel","GemPixel","https://pixel.gemboss.ai","Events every store sends, and whether they add up.","market","activity","blue"],["gemcapture","GemCapture","https://capture.gemboss.ai/admin","Page captures and visual checks.","market","page","slate"],["search-radar","Search Radar","https://search-radar.ops.gemboss.ai","Rankings on the App Store, Google and AI answers.","market","radar","amber"],["gempress","GemPress","https://press.gemboss.ai/admin","Articles and the content store.","content","article","orange"],["content-radar","Content Radar","https://content-radar.ops.gemboss.ai","From the topics worth writing to articles.","content","radar","teal"],["gemcommunity","GemCommunity","https://community.gemboss.ai/admin","The seller community.","content","users","blue"],["gemnews","GemCommunity News","https://news.gemboss.ai/admin","News posts and how they are read.","content","megaphone","rose"],["gemcare","GemCare","https://care.gemboss.ai/inbox","The customer care inbox.","customers","chat","green"],["gemfeedback","GemFeedback","https://feedback.gemboss.ai/admin","The feedback backlog.","customers","inbox","violet"],["partner-radar","Partner Radar","https://partner-radar.ops.gemboss.ai","Partners and agencies, as a CRM.","team","link","orange"],["taskdesk","Taskdesk","https://gemlabs-taskdesk-production.up.railway.app","Every job the fleet is running.","team","list","slate"]],U={apps:'<circle cx="4.5" cy="4.5" r="1"/><circle cx="10" cy="4.5" r="1"/><circle cx="15.5" cy="4.5" r="1"/><circle cx="4.5" cy="10" r="1"/><circle cx="10" cy="10" r="1"/><circle cx="15.5" cy="10" r="1"/><circle cx="4.5" cy="15.5" r="1"/><circle cx="10" cy="15.5" r="1"/><circle cx="15.5" cy="15.5" r="1"/>',close:'<path d="M5 5l10 10M15 5 5 15"/>',search:'<circle cx="8.8" cy="8.8" r="5.3"/><path d="M12.8 12.8 17 17"/>',dashboard:'<rect x="3" y="3" width="6" height="6" rx="1.3"/><rect x="11" y="3" width="6" height="6" rx="1.3"/><rect x="3" y="11" width="6" height="6" rx="1.3"/><rect x="11" y="11" width="6" height="6" rx="1.3"/>',layers:'<path d="M10 3 17 6.8 10 10.6 3 6.8z"/><path d="M3 10.1l7 3.8 7-3.8"/><path d="M3 13.4l7 3.8 7-3.8"/>',image:'<rect x="3" y="3.5" width="14" height="13" rx="1.8"/><circle cx="7.3" cy="7.8" r="1.3"/><path d="M3.5 15l4.2-4.2 3 3 2.2-2.2 3.6 3.6"/>',document:'<path d="M5 2.8h6.8l3.2 3.2v11.2H5z"/><path d="M11.8 2.8V6H15M7.5 10h5M7.5 13h5"/>',sliders:'<path d="M3 5h14M3 10h14M3 15h14"/><circle cx="7" cy="5" r="1.6"/><circle cx="13" cy="10" r="1.6"/><circle cx="9" cy="15" r="1.6"/>',eye:'<path d="M1.8 10S4.7 4.8 10 4.8 18.2 10 18.2 10 15.3 15.2 10 15.2 1.8 10 1.8 10z"/><circle cx="10" cy="10" r="2.5"/>',chart:'<path d="M3 16.5h14"/><rect x="4.5" y="9" width="2.8" height="5.5" rx=".7"/><rect x="8.6" y="5" width="2.8" height="9.5" rx=".7"/><rect x="12.7" y="11" width="2.8" height="3.5" rx=".7"/>',activity:'<path d="M2.5 10h3l2-5 3 10 2-5h5"/>',page:'<rect x="2.5" y="3.5" width="15" height="13" rx="2"/><path d="M2.5 7.5h15M6 11h8M6 13.5h5"/>',radar:'<circle cx="10" cy="10" r="7"/><circle cx="10" cy="10" r="3.5"/><path d="M10 10l5-5"/>',article:'<rect x="3" y="3.5" width="14" height="13" rx="1.5"/><path d="M6 7h8M6 10h8M6 13h5"/>',users:'<circle cx="7.5" cy="7.3" r="2.8"/><path d="M2.5 16.3c.6-2.5 2.5-4 5-4s4.4 1.5 5 4"/><path d="M12.3 4.8a2.8 2.8 0 0 1 0 5.2M14.3 12.5c1.6.4 2.7 1.7 3.2 3.8"/>',megaphone:'<path d="M3 8v4h3l6 4V4L6 8H3z"/><path d="M15 7.5a3.5 3.5 0 0 1 0 5"/>',chat:'<path d="M3 4.5h14v9H8.5L5 16.5v-3H3z"/>',inbox:'<path d="M3 11l2-7h10l2 7v5H3z"/><path d="M3 11h4l1 2h4l1-2h4"/>',link:'<path d="M8.6 11.4a3 3 0 0 0 4.2 0l2.6-2.6a3 3 0 0 0-4.2-4.2l-1 1"/><path d="M11.4 8.6a3 3 0 0 0-4.2 0l-2.6 2.6a3 3 0 0 0 4.2 4.2l1-1"/>',list:'<path d="M8 5h9M8 10h9M8 15h9"/><circle cx="4" cy="5" r=".9"/><circle cx="4" cy="10" r=".9"/><circle cx="4" cy="15" r=".9"/>'},B={trigger:"Switch service",title:"Gem services",close:"Close",search:"Find a service",noMatch:"No service matches \u201C{query}\u201D.",all:"All services and their health"},F="https://gemfactory.ops.gemboss.ai/services",V=".gemboss-platform-topbar, header, [role='banner']",D=O.map(function(a){return{id:a[0],name:a[1],url:a[2],purpose:a[3],group:a[4],icon:a[5],tint:a[6]}}),c=function(a){return String(a).replace(/[&<>"']/g,function(r){return{"&":"&","<":"<",">":">",'"':""","'":"'"}[r]})},k=function(a,r){return'<svg viewBox="0 0 20 20" width="'+r+'" height="'+r+'" aria-hidden="true" focusable="false"><g fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">'+(U[a]||"")+"</g></svg>"},j=0;function W(a){return K.map(function(r){return{id:r[0],title:r[1],services:a.filter(function(l){return l.group===r[0]})}}).filter(function(r){return r.services.length>0})}function X(a,r,l){var o=a.map(function(d){return d.getBoundingClientRect()}),u=o[r],_=u.left+u.width/2,f=-1,m=0,y=0;return o.forEach(function(d,E){if(!(l>0?d.top<=u.top+1:d.top>=u.top-1)){var h=Math.abs(d.left+d.width/2-_),s=f<0||(l>0?d.top<m-1:d.top>m+1),p=f>=0&&Math.abs(d.top-m)<=1;(s||p&&h<y)&&(f=E,m=d.top,y=h)}}),f}function N(a,r){var l=a.children;l.length===r.length&&r.every(function(o,u){return l[u]===o})||a.replaceChildren.apply(a,r)}function J(a,r){var l=r.current||a.getAttribute("data-gb-service-switcher")||"",o={},u;for(u in B)o[u]=r.labels&&r.labels[u]!=null?r.labels[u]:B[u];var _=r.allHref===void 0?F:r.allHref,f=W(r.services||D),m="gb-svc"+ ++j+"-",y=m+"svc",d=m+"svc-t",E=document.createElement("template");E.innerHTML='<button type="button" class="gb-svc-trigger'+(r.className?" "+c(r.className):"")+'" aria-haspopup="dialog" aria-expanded="false" aria-controls="'+y+'" aria-label="'+c(o.trigger)+'" title="'+c(o.trigger)+'">'+k("apps",20)+'</button><dialog id="'+y+'" class="gb-svc" aria-labelledby="'+d+'"><div class="gb-svc__head"><h2 class="gb-svc__title" id="'+d+'">'+c(o.title)+'</h2><button type="button" class="ui-modal__close" aria-label="'+c(o.close)+'">'+k("close",20)+"</button></div>"+(r.search===!1?"":'<div class="gb-svc__search"><label class="gemboss-field gemboss-field--group">'+k("search",16)+'<input class="gemboss-field__bare" type="search" name="service-search" autocomplete="off" value="" placeholder="'+c(o.search)+'" aria-label="'+c(o.search)+'"></label></div>')+'<div class="gb-svc__body">'+f.map(function(e){return'<div class="gb-svc__group" role="group" aria-labelledby="'+m+"svc-"+c(e.id)+'"><h3 class="gb-svc__heading" id="'+m+"svc-"+c(e.id)+'">'+c(e.title)+'</h3><ul class="gb-svc__grid" role="list">'+e.services.map(function(t){return'<li><a class="gb-svc__tile" href="'+c(t.url)+'" data-tint="'+c(t.tint)+'"'+(t.id===l?' aria-current="page"':"")+' tabindex="-1"><span class="gb-svc__mark" aria-hidden="true">'+k(t.icon,22)+'</span><span class="gb-svc__name">'+c(t.name)+'</span><span class="gb-svc__purpose">'+c(t.purpose)+"</span></a></li>"}).join("")+"</ul></div>"}).join("")+"</div>"+(_?'<div class="gb-svc__foot"><a class="gb-svc__all" href="'+c(_)+'">'+c(o.all)+'<span aria-hidden="true">\u2192</span></a></div>':"")+"</dialog>";var h=E.content.firstChild,s=h.nextSibling,p=s.querySelector(".gb-svc__search input"),S=s.querySelector(".gb-svc__body"),G=function(){return Array.prototype.slice.call(s.querySelectorAll(".gb-svc__tile"))},Q=G(),Y=0,C=[];f.forEach(function(e,t){e.el=S.children[t],e.ul=e.el.querySelector("ul"),e.items=e.services.map(function(n){var i=Q[Y++],v={s:n,a:i,li:i.parentNode};return C.push(v),v})});var A=document.createElement("p");A.className="gb-svc__empty",A.setAttribute("role","status");var L=l,R=null,q=!1;function x(){var e=p?p.value:"",t=e.trim().toLowerCase(),n=[],i=[];f.forEach(function(g){var T=g.items.filter(function(w){return!t||(w.s.name+" "+w.s.purpose+" "+w.s.id+" "+g.title).toLowerCase().indexOf(t)>-1});T.length&&(N(g.ul,T.map(function(w){return w.li})),n.push(g.el),i=i.concat(T))}),n.length||(A.textContent=o.noMatch.replace("{query}",e.trim()),n.push(A)),N(S,n);var v=i.map(function(g){return g.s.id}),I=v.indexOf(L)>-1?L:v.indexOf(l)>-1?l:v[0];i.forEach(function(g){g.a.setAttribute("tabindex",g.s.id===I?"0":"-1")})}function H(){var e=h.previousElementSibling,t=(e&&e.tagName==="A"?e:h).getBoundingClientRect(),n=h.closest(V),i=Math.max(h.getBoundingClientRect().bottom,n?n.getBoundingClientRect().bottom:0),v=document.documentElement.clientWidth,I=Math.min(760,v-24);s.style.setProperty("--gb-svc-x",Math.round(Math.max(12,Math.min(t.left,v-I-12)))+"px"),s.style.setProperty("--gb-svc-y",Math.round(i+6)+"px")}function z(){if(!(s.open||!s.isConnected)){H(),b.closeMenus&&b.closeMenus(),R=document.activeElement,s.showModal(),h.setAttribute("aria-expanded","true"),L=l,x();var e=s.querySelector(".gb-svc__tile[aria-current]")||s.querySelector(".gb-svc__tile");e&&e.focus(),addEventListener("resize",H)}}return s.addEventListener("close",function(){removeEventListener("resize",H),h.setAttribute("aria-expanded","false"),p&&(p.value=""),x();var e=R;R=null,e&&e.focus&&e.focus({preventScroll:!0})}),h.addEventListener("click",z),s.addEventListener("pointerdown",function(e){q=e.target===s}),s.addEventListener("click",function(e){var t=e.target,n=q;if(q=!1,t===s){n&&s.close();return}(t.closest(".ui-modal__close")||t.closest(".gb-svc__tile, .gb-svc__all")&&e.button===0&&!e.metaKey&&!e.ctrlKey&&!e.shiftKey&&!e.altKey)&&s.close()}),p&&(p.addEventListener("input",x),p.addEventListener("keydown",function(e){if(!e.isComposing){var t=G()[0];e.key==="Escape"?(e.preventDefault(),s.close()):e.key==="ArrowDown"?(e.preventDefault(),t&&t.focus()):e.key==="Enter"&&p.value.trim()&&(e.preventDefault(),t&&t.click())}})),S.addEventListener("keydown",function(e){var t=G(),n=t.indexOf(document.activeElement),i;if(!(n<0||e.altKey||e.ctrlKey||e.metaKey)){if(e.key==="ArrowRight")i=Math.min(n+1,t.length-1);else if(e.key==="ArrowLeft")i=Math.max(n-1,0);else if(e.key==="Home")i=0;else if(e.key==="End")i=t.length-1;else if(e.key==="ArrowDown"||e.key==="ArrowUp"){if(i=X(t,n,e.key==="ArrowDown"?1:-1),i<0&&e.key==="ArrowUp"&&p){e.preventDefault(),p.focus();return}i<0&&(i=n)}else return;e.preventDefault(),t[i].focus()}}),S.addEventListener("focusin",function(e){for(var t=0;t<C.length;t++)if(C[t].a===e.target){L=C[t].s.id,x();return}}),x(),a.replaceWith(h,s),{button:h,dialog:s,open:z,close:function(){s.close()}}}function P(a){return a=a||{},document.readyState==="loading"?document.addEventListener("DOMContentLoaded",function(){P(a)},{once:!0}):!b.openModal&&M.console&&document.querySelector('script[src*="kit-plain"]')&&M.console.error("@gemboss/ui service-switcher-plain.js: load it after kit-plain.js (kit-plain.js defines nothing when gembossUI exists)"),Array.prototype.map.call((a.root||document).querySelectorAll("[data-gb-service-switcher]"),function(r){return J(r,a)})}b.initServiceSwitcher=P,b.GEM_SERVICES=D})(typeof globalThis<"u"?globalThis:this);
|
package/src/service-switcher.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--gb-svc-iris: var(--gemboss-accent, #5661f5);--gb-svc-blue: #2563eb;--gb-svc-teal: #0d9488;--gb-svc-green: #16a34a;--gb-svc-amber: #d97706;--gb-svc-orange: #ea580c;--gb-svc-rose: #e11d48;--gb-svc-violet: #9333ea;--gb-svc-slate: #64748b;--gb-svc-wash: 14%}:root[data-theme=dark]{--gb-svc-blue: #60a5fa;--gb-svc-teal: #2dd4bf;--gb-svc-green: #4ade80;--gb-svc-amber: #fbbf24;--gb-svc-orange: #fb923c;--gb-svc-rose: #fb7185;--gb-svc-violet: #c084fc;--gb-svc-slate: #94a3b8;--gb-svc-wash: 22%}.gb-svc-trigger{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin:0;padding:0;box-sizing:border-box;border:0;border-radius:var(--gemboss-radius-md, 8px);background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background-color var(--gemboss-transition-base, .15s) ease}.gb-brand+.gb-svc-trigger{margin-left:-4px}.gb-svc-trigger:hover,.gb-svc-trigger[aria-expanded=true]{background:var(--gemboss-hover);color:var(--gemboss-text)}.gb-svc-trigger:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}@media (pointer: coarse),(max-width: 47.9975em){.gb-svc-trigger{width:44px;height:44px}}@media (max-width: 460px){.gb-brand+.gb-svc-trigger{width:40px;margin-left:-8px}}@media (max-width: 359.98px){.gemboss-platform-topbar:has(.gb-svc-trigger) .gemboss-topbar-center:not(:empty){min-width:56px}}dialog.gb-svc{position:fixed;inset:var(--gb-svc-y, 62px) auto auto var(--gb-svc-x, 16px);margin:0;padding:0;box-sizing:border-box;width:min(760px,calc(100vw - 24px));max-width:none;max-height:min(80vh,calc(100dvh - var(--gb-svc-y, 62px) - 12px));border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg, 12px);background:var(--gemboss-surface);color:var(--gemboss-text);box-shadow:var(--gemboss-shadow-overlay);overflow:hidden;z-index:400}dialog.gb-svc[open]{display:flex;flex-direction:column;animation:gb-svc-in .12s ease-out}dialog.gb-svc::backdrop{background:#00000029}@keyframes gb-svc-in{0%{opacity:0;transform:translateY(-4px)}}@keyframes gb-svc-up{0%{opacity:0;transform:translateY(16px)}}html:has(dialog.gb-svc:modal){overflow:hidden}.gb-svc__head{flex:none;display:flex;align-items:center;gap:12px;padding:10px 12px 4px 16px}.gb-svc__title{flex:1 1 auto;min-width:0;margin:0;font-size:14px;line-height:20px;font-weight:650;color:var(--gemboss-text-strong)}.gb-svc__search{flex:none;padding:4px 16px 8px}.gb-svc__search svg{flex:none;width:16px;height:16px;color:var(--gemboss-text-muted)}.gb-svc__body{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 16px}.gb-svc__group+.gb-svc__group{margin-top:16px}.gb-svc__heading{margin:0 0 8px;font-size:11px;line-height:16px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--gemboss-text-muted)}.gb-svc__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(156px,1fr));gap:8px;margin:0;padding:0;list-style:none}.gb-svc__grid>li{display:flex;min-width:0}.gb-svc__tile{--gb-svc-tint: var(--gb-svc-slate);flex:1 1 auto;min-width:0;box-sizing:border-box;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:12px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg, 12px);background:var(--gemboss-surface);color:var(--gemboss-text);text-decoration:none;transition:background-color var(--gemboss-transition-fast, .12s) ease,border-color var(--gemboss-transition-fast, .12s) ease}.gb-svc__tile:hover{background:var(--gemboss-hover)}.gb-svc__tile:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:2px}.gb-svc__tile[aria-current=page]{border-color:var(--gemboss-accent);box-shadow:inset 0 0 0 1px var(--gemboss-accent)}.gb-svc__tile[data-tint=iris]{--gb-svc-tint: var(--gb-svc-iris)}.gb-svc__tile[data-tint=blue]{--gb-svc-tint: var(--gb-svc-blue)}.gb-svc__tile[data-tint=teal]{--gb-svc-tint: var(--gb-svc-teal)}.gb-svc__tile[data-tint=green]{--gb-svc-tint: var(--gb-svc-green)}.gb-svc__tile[data-tint=amber]{--gb-svc-tint: var(--gb-svc-amber)}.gb-svc__tile[data-tint=orange]{--gb-svc-tint: var(--gb-svc-orange)}.gb-svc__tile[data-tint=rose]{--gb-svc-tint: var(--gb-svc-rose)}.gb-svc__tile[data-tint=violet]{--gb-svc-tint: var(--gb-svc-violet)}.gb-svc__tile[data-tint=slate]{--gb-svc-tint: var(--gb-svc-slate)}.gb-svc__mark{flex:none;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;margin-bottom:8px;border-radius:var(--gemboss-radius-lg, 12px);background:color-mix(in srgb,var(--gb-svc-tint) var(--gb-svc-wash),var(--gemboss-surface));color:color-mix(in srgb,var(--gb-svc-tint) 78%,var(--gemboss-text-strong))}.gb-svc__name{max-width:100%;font-size:13px;line-height:18px;font-weight:600;color:var(--gemboss-text-strong);overflow-wrap:anywhere}.gb-svc__purpose{max-width:100%;font-size:12px;line-height:16px;color:var(--gemboss-text-muted);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}.gb-svc__empty{margin:0;padding:24px 0;font-size:13px;color:var(--gemboss-text-muted);text-align:center}.gb-svc__foot{flex:none;padding:4px 16px;border-top:1px solid var(--gemboss-divider-soft)}.gb-svc__all{display:inline-flex;align-items:center;gap:4px;min-height:36px;font-size:13px;font-weight:500;color:var(--gemboss-accent-strong);text-decoration:none}.gb-svc__all:hover{text-decoration:underline}.gb-svc__all:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:2px;border-radius:4px}@media (pointer: coarse){.gb-svc__all{min-height:44px}}@media (max-width: 640px){dialog.gb-svc{inset:0;width:100%;height:100dvh;max-height:100dvh;border:0;border-radius:0;padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)}dialog.gb-svc[open]{animation-name:gb-svc-up}.gb-svc__head{padding:8px 8px 4px 16px;border-bottom:0}.gb-svc__search,.gb-svc__body{padding-inline:12px}.gb-svc__grid{grid-template-columns:repeat(2,minmax(0,1fr))}.gb-svc__foot{padding-inline:12px}.gb-svc__all{min-height:44px}}@media (prefers-reduced-motion: reduce){dialog.gb-svc[open]{animation:none}}
|
|
1
|
+
:root{--gb-svc-iris: var(--gemboss-accent, #5661f5);--gb-svc-blue: #2563eb;--gb-svc-teal: #0d9488;--gb-svc-green: #16a34a;--gb-svc-amber: #d97706;--gb-svc-orange: #ea580c;--gb-svc-rose: #e11d48;--gb-svc-violet: #9333ea;--gb-svc-slate: #64748b;--gb-svc-wash: 14%}:root[data-theme=dark]{--gb-svc-blue: #60a5fa;--gb-svc-teal: #2dd4bf;--gb-svc-green: #4ade80;--gb-svc-amber: #fbbf24;--gb-svc-orange: #fb923c;--gb-svc-rose: #fb7185;--gb-svc-violet: #c084fc;--gb-svc-slate: #94a3b8;--gb-svc-wash: 22%}.gb-svc-trigger{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin:0;padding:0;box-sizing:border-box;border:0;border-radius:var(--gemboss-radius-md, 8px);background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background-color var(--gemboss-transition-base, .15s) ease}.gb-brand+.gb-svc-trigger{margin-left:-4px}.gb-svc-trigger:hover,.gb-svc-trigger[aria-expanded=true]{background:var(--gemboss-hover);color:var(--gemboss-text)}.gb-svc-trigger:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}@media (pointer: coarse),(max-width: 47.9975em){.gb-svc-trigger{width:44px;height:44px}}@media (max-width: 460px){.gb-brand+.gb-svc-trigger{width:40px;margin-left:-8px}}@media (max-width: 359.98px){.gemboss-platform-topbar:has(.gb-svc-trigger) .gemboss-topbar-center:not(:empty){min-width:56px;container:gb-svc-search / inline-size}}@container gb-svc-search (max-width: 95.98px){.gemboss-topbar-center .gemboss-topbar-search{grid-template-columns:minmax(0,1fr);padding:0}.gemboss-topbar-center .gemboss-topbar-search>*{grid-area:1 / 1}.gemboss-topbar-center .gemboss-topbar-search-icon{justify-self:center;pointer-events:none}.gemboss-topbar-center .gemboss-topbar-search-input{justify-self:stretch;width:auto;padding:0 8px}.gemboss-topbar-center .gemboss-topbar-search-input::placeholder{color:transparent}.gemboss-topbar-center .gemboss-topbar-search:is(:focus-within,:has(>.gemboss-topbar-search-input:not(:placeholder-shown)))>.gemboss-topbar-search-icon{visibility:hidden}.gemboss-topbar-center .gb-search-field-text{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}}dialog.gb-svc{position:fixed;inset:var(--gb-svc-y, 62px) auto auto var(--gb-svc-x, 16px);margin:0;padding:0;box-sizing:border-box;width:min(760px,calc(100vw - 24px));max-width:none;max-height:min(80vh,calc(100dvh - var(--gb-svc-y, 62px) - 12px));border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg, 12px);background:var(--gemboss-surface);color:var(--gemboss-text);box-shadow:var(--gemboss-shadow-overlay);overflow:hidden;z-index:400}dialog.gb-svc[open]{display:flex;flex-direction:column;animation:gb-svc-in .12s ease-out}dialog.gb-svc::backdrop{background:#00000029}@keyframes gb-svc-in{0%{opacity:0;transform:translateY(-4px)}}@keyframes gb-svc-up{0%{opacity:0;transform:translateY(16px)}}html:has(dialog.gb-svc:modal){overflow:hidden}.gb-svc__head{flex:none;display:flex;align-items:center;gap:12px;padding:10px 12px 4px 16px}.gb-svc__title{flex:1 1 auto;min-width:0;margin:0;font-size:14px;line-height:20px;font-weight:650;color:var(--gemboss-text-strong)}.gb-svc__search{flex:none;padding:4px 16px 8px}.gb-svc__search svg{flex:none;width:16px;height:16px;color:var(--gemboss-text-muted)}.gb-svc__body{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 16px}.gb-svc__group+.gb-svc__group{margin-top:16px}.gb-svc__heading{margin:0 0 8px;font-size:11px;line-height:16px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--gemboss-text-muted)}.gb-svc__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(156px,1fr));gap:8px;margin:0;padding:0;list-style:none}.gb-svc__grid>li{display:flex;min-width:0}.gb-svc__tile{--gb-svc-tint: var(--gb-svc-slate);flex:1 1 auto;min-width:0;box-sizing:border-box;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:12px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg, 12px);background:var(--gemboss-surface);color:var(--gemboss-text);text-decoration:none;transition:background-color var(--gemboss-transition-fast, .12s) ease,border-color var(--gemboss-transition-fast, .12s) ease}.gb-svc__tile:hover{background:var(--gemboss-hover)}.gb-svc__tile:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:2px}.gb-svc__tile[aria-current=page]{border-color:var(--gemboss-accent);box-shadow:inset 0 0 0 1px var(--gemboss-accent)}.gb-svc__tile[data-tint=iris]{--gb-svc-tint: var(--gb-svc-iris)}.gb-svc__tile[data-tint=blue]{--gb-svc-tint: var(--gb-svc-blue)}.gb-svc__tile[data-tint=teal]{--gb-svc-tint: var(--gb-svc-teal)}.gb-svc__tile[data-tint=green]{--gb-svc-tint: var(--gb-svc-green)}.gb-svc__tile[data-tint=amber]{--gb-svc-tint: var(--gb-svc-amber)}.gb-svc__tile[data-tint=orange]{--gb-svc-tint: var(--gb-svc-orange)}.gb-svc__tile[data-tint=rose]{--gb-svc-tint: var(--gb-svc-rose)}.gb-svc__tile[data-tint=violet]{--gb-svc-tint: var(--gb-svc-violet)}.gb-svc__tile[data-tint=slate]{--gb-svc-tint: var(--gb-svc-slate)}.gb-svc__mark{flex:none;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;margin-bottom:8px;border-radius:var(--gemboss-radius-lg, 12px);background:color-mix(in srgb,var(--gb-svc-tint) var(--gb-svc-wash),var(--gemboss-surface));color:color-mix(in srgb,var(--gb-svc-tint) 78%,var(--gemboss-text-strong))}.gb-svc__name{max-width:100%;font-size:13px;line-height:18px;font-weight:600;color:var(--gemboss-text-strong);overflow-wrap:anywhere}.gb-svc__purpose{max-width:100%;font-size:12px;line-height:16px;color:var(--gemboss-text-muted);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}.gb-svc__grid--media{grid-template-columns:repeat(auto-fill,minmax(208px,1fr));gap:12px}.gb-svc__tile--media{padding:8px 8px 12px}.gb-svc__tile--media>.gb-svc__name,.gb-svc__tile--media>.gb-svc__purpose{padding-inline:4px}.gb-svc__media{display:block;width:100%;aspect-ratio:16 / 9;margin-bottom:8px;overflow:hidden;border-radius:var(--gemboss-radius-md, 8px);background:radial-gradient(120% 100% at 85% 0%,color-mix(in srgb,var(--gb-svc-tint) calc(var(--gb-svc-wash) * 2),var(--gemboss-surface)),transparent 70%),color-mix(in srgb,var(--gb-svc-tint) var(--gb-svc-wash),var(--gemboss-surface))}.gb-svc__media img{display:block;width:100%;height:100%;object-fit:cover}.gb-svc__media-glyph{display:grid;place-items:center;width:100%;height:100%;font-size:44px;line-height:1;font-weight:700;color:color-mix(in srgb,var(--gb-svc-tint) 78%,var(--gemboss-text-strong))}.gb-svc__glyph{font-size:20px;line-height:1;font-weight:700}.gb-svc__badge{display:inline-block;margin-left:6px;padding:0 6px;border-radius:999px;vertical-align:1px;font-size:11px;line-height:16px;font-weight:600;white-space:nowrap;background:color-mix(in srgb,var(--gemboss-accent) 12%,var(--gemboss-surface));color:var(--gemboss-accent-strong)}.gb-svc__empty{margin:0;padding:24px 0;font-size:13px;color:var(--gemboss-text-muted);text-align:center}.gb-svc__foot{flex:none;padding:4px 16px;border-top:1px solid var(--gemboss-divider-soft)}.gb-svc__all{display:inline-flex;align-items:center;gap:4px;min-height:36px;font-size:13px;font-weight:500;color:var(--gemboss-accent-strong);text-decoration:none}.gb-svc__all:hover{text-decoration:underline}.gb-svc__all:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:2px;border-radius:4px}@media (pointer: coarse){.gb-svc__all{min-height:44px}}@media (max-width: 640px){dialog.gb-svc{inset:0;width:100%;height:100dvh;max-height:100dvh;border:0;border-radius:0;padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)}dialog.gb-svc[open]{animation-name:gb-svc-up}.gb-svc__head{padding:8px 8px 4px 16px;border-bottom:0}.gb-svc__search,.gb-svc__body{padding-inline:12px}.gb-svc__grid{grid-template-columns:repeat(2,minmax(0,1fr))}.gb-svc__grid--media{gap:8px}.gb-svc__media-glyph{font-size:36px}.gb-svc__foot{padding-inline:12px}.gb-svc__all{min-height:44px}}@media (prefers-reduced-motion: reduce){dialog.gb-svc[open]{animation:none}}
|
package/src/service-switcher.tsx
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
import "./service-switcher.css";
|
|
23
23
|
import React, { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
24
24
|
import { useModalDialog } from "./dialog";
|
|
25
|
-
import { Icon } from "./icons";
|
|
26
|
-
import { GEM_SERVICES,
|
|
25
|
+
import { Icon, type IconName } from "./icons";
|
|
26
|
+
import { GEM_SERVICES, SERVICE_GROUPS, type GemService, type ServiceId, type ServiceTint } from "./services";
|
|
27
27
|
|
|
28
28
|
/** GemFactory's services page: every service and its health. */
|
|
29
29
|
export const SERVICES_HEALTH_URL = "https://gemfactory.ops.gemboss.ai/services";
|
|
@@ -56,6 +56,50 @@ export interface ServiceSwitcherProps {
|
|
|
56
56
|
className?: string;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* One tile of a `Switcher` (0.40.0). The service tiles are a mark (an icon) + a name + a line; a tile with `media` is a
|
|
61
|
+
* card with an illustration on top (a community, a workspace: Chris 20/10/2026, "kèm hình ảnh minh hoạ, tên và
|
|
62
|
+
* description … full popup như các dịch vụ gemboss").
|
|
63
|
+
*/
|
|
64
|
+
export interface SwitcherItem {
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
/** One short plain sentence under the name (two lines at most are shown). */
|
|
68
|
+
description?: string;
|
|
69
|
+
/** Opened in the same tab. */
|
|
70
|
+
href: string;
|
|
71
|
+
/** A `groups` id; an item whose group is not listed goes in a last group without a heading. */
|
|
72
|
+
group?: string;
|
|
73
|
+
/** An illustration on top of the tile: an image (`src`), or, without one, `glyph` (an emoji, two letters) drawn big
|
|
74
|
+
* on a panel tinted with `tint`. */
|
|
75
|
+
media?: { src?: string | null; glyph?: string };
|
|
76
|
+
/** The small mark of a tile without `media`: a kit icon … */
|
|
77
|
+
icon?: IconName;
|
|
78
|
+
/** … or a short text / emoji. */
|
|
79
|
+
glyph?: string;
|
|
80
|
+
/** The hue of the mark or the illustration panel (SERVICE_TINTS). Default slate. */
|
|
81
|
+
tint?: ServiceTint;
|
|
82
|
+
/** A chip after the name: "Apply", "New". */
|
|
83
|
+
badge?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface SwitcherProps {
|
|
87
|
+
items: readonly SwitcherItem[];
|
|
88
|
+
/** The groups, in their order. Absent: one group without a heading. */
|
|
89
|
+
groups?: ReadonlyArray<{ id: string; title: string }>;
|
|
90
|
+
/** The item this page belongs to: `aria-current="page"` and the accent ring. */
|
|
91
|
+
current?: string;
|
|
92
|
+
labels?: ServiceSwitcherLabels;
|
|
93
|
+
/** The foot: a link (`allHref`, worded `labels.all`) … */
|
|
94
|
+
allHref?: string | null;
|
|
95
|
+
/** … or the app's own foot (actions: "Create a community"). Wins over `allHref`. */
|
|
96
|
+
foot?: React.ReactNode;
|
|
97
|
+
search?: boolean;
|
|
98
|
+
/** The button's glyph. Default the nine-dot "apps". */
|
|
99
|
+
triggerIcon?: IconName;
|
|
100
|
+
className?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
59
103
|
const LABELS: Required<ServiceSwitcherLabels> = {
|
|
60
104
|
trigger: "Switch service", title: "Gem services", close: "Close", search: "Find a service",
|
|
61
105
|
noMatch: "No service matches “{query}”.", all: "All services and their health",
|
|
@@ -63,6 +107,11 @@ const LABELS: Required<ServiceSwitcherLabels> = {
|
|
|
63
107
|
|
|
64
108
|
const cx = (...p: Array<string | false | null | undefined>) => p.filter(Boolean).join(" ");
|
|
65
109
|
|
|
110
|
+
/** The bar the panel hangs under (0.37.1): the kit's topbar, or a surface's own header (GemNews's admin draws a 56px
|
|
111
|
+
* `<header>` of its own; with the kit's topbar alone the panel was placed from the 32px button and covered its last 6px).
|
|
112
|
+
* The same selector in service-switcher-plain.js. */
|
|
113
|
+
const BAR = ".gemboss-platform-topbar, header, [role='banner']";
|
|
114
|
+
|
|
66
115
|
/** The tile one row down (`dir` 1) or up (-1) from tile `i`, nearest by its centre: rows are read off the screen, so it
|
|
67
116
|
* holds for any column count and across groups. -1 when there is no such row. */
|
|
68
117
|
function rowStep(tiles: HTMLElement[], i: number, dir: 1 | -1): number {
|
|
@@ -80,34 +129,50 @@ function rowStep(tiles: HTMLElement[], i: number, dir: 1 | -1): number {
|
|
|
80
129
|
return best;
|
|
81
130
|
}
|
|
82
131
|
|
|
83
|
-
|
|
132
|
+
/** The groups to draw, in order, after a search: each with the items it holds (an unlisted group's items last, untitled). */
|
|
133
|
+
function groupItems(items: readonly SwitcherItem[], groups: SwitcherProps["groups"], q: string) {
|
|
134
|
+
const order = groups ?? [];
|
|
135
|
+
const known = new Set(order.map((g) => g.id));
|
|
136
|
+
const all = [...order.map((g) => ({ id: g.id, title: g.title, items: items.filter((s) => s.group === g.id) })),
|
|
137
|
+
{ id: "", title: "", items: items.filter((s) => !s.group || !known.has(s.group)) }];
|
|
138
|
+
return all
|
|
139
|
+
.map((g) => ({ ...g, items: q ? g.items.filter((s) => `${s.name} ${s.description ?? ""} ${s.id} ${g.title}`.toLowerCase().includes(q)) : g.items }))
|
|
140
|
+
.filter((g) => g.items.length > 0);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Switcher (0.40.0): the nine-dot button and its panel, for any list — ServiceSwitcher is this with the Gem services.
|
|
145
|
+
* Same dialog, search, groups, keyboard and phone sheet; a tile is either the service kind (mark + name + line) or, with
|
|
146
|
+
* `media`, a card with an illustration on top. GemCommunity opens its groups with it.
|
|
147
|
+
*/
|
|
148
|
+
export function Switcher({ items, groups, current, labels, allHref = null, foot, search = true, triggerIcon = "apps", className }: SwitcherProps) {
|
|
84
149
|
const L = { ...LABELS, ...labels };
|
|
85
150
|
const [open, setOpen] = useState(false);
|
|
86
151
|
const [query, setQuery] = useState("");
|
|
87
|
-
const [roving, setRoving] = useState<
|
|
152
|
+
const [roving, setRoving] = useState<string | undefined>(current);
|
|
88
153
|
const button = useRef<HTMLButtonElement>(null);
|
|
89
154
|
const field = useRef<HTMLInputElement>(null);
|
|
90
|
-
// Each opening starts with every
|
|
155
|
+
// Each opening starts with every item shown (cleared on close: SettingsDialog's review #4073).
|
|
91
156
|
const { ref, onClick, onPointerDown } = useModalDialog(open, () => { setOpen(false); setQuery(""); });
|
|
92
157
|
const id = useId();
|
|
93
158
|
const panelId = `${id}svc`, titleId = `${id}svc-t`;
|
|
94
159
|
|
|
95
160
|
const q = query.trim().toLowerCase();
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
161
|
+
const shownGroups = useMemo(() => groupItems(items, groups, q), [items, groups, q]);
|
|
162
|
+
const shown = shownGroups.flatMap((g) => g.items.map((s) => s.id));
|
|
163
|
+
// The one tile in the Tab order: the last one focused, else the current item, else the first shown.
|
|
164
|
+
const tabStop = roving && shown.includes(roving) ? roving : current && shown.includes(current) ? current : shown[0];
|
|
165
|
+
|
|
166
|
+
/** Under the bar that holds the button, from the brand's left edge (the logo link before the button; the button itself
|
|
167
|
+
* without one). The bar is the closest `BAR` around the button (0.37.1: a surface's own `<header>` too, not only the
|
|
168
|
+
* kit's topbar), and never above the button's own bottom edge; with none, the button's bottom edge. */
|
|
104
169
|
const place = () => {
|
|
105
170
|
const d = ref.current, b = button.current;
|
|
106
171
|
if (!d || !b) return;
|
|
107
172
|
const prev = b.previousElementSibling;
|
|
108
173
|
const anchor = (prev && prev.tagName === "A" ? prev : b).getBoundingClientRect();
|
|
109
|
-
const bar = b.closest(
|
|
110
|
-
const top = bar ? bar.getBoundingClientRect().bottom :
|
|
174
|
+
const bar = b.closest(BAR);
|
|
175
|
+
const top = Math.max(b.getBoundingClientRect().bottom, bar ? bar.getBoundingClientRect().bottom : 0);
|
|
111
176
|
const vw = document.documentElement.clientWidth;
|
|
112
177
|
const w = Math.min(760, vw - 24);
|
|
113
178
|
d.style.setProperty("--gb-svc-x", `${Math.round(Math.max(12, Math.min(anchor.left, vw - w - 12)))}px`);
|
|
@@ -115,7 +180,7 @@ export function ServiceSwitcher({ current, services = GEM_SERVICES, labels, allH
|
|
|
115
180
|
};
|
|
116
181
|
useEffect(() => {
|
|
117
182
|
if (!open) return undefined;
|
|
118
|
-
// After useModalDialog's showModal (effects run in order): the current
|
|
183
|
+
// After useModalDialog's showModal (effects run in order): the current item's tile (the first one when the list
|
|
119
184
|
// has no current), not the corner ✕ the browser picks, and not the search box (on a phone it would pull up the
|
|
120
185
|
// keyboard over the grid).
|
|
121
186
|
setRoving(current);
|
|
@@ -165,7 +230,7 @@ export function ServiceSwitcher({ current, services = GEM_SERVICES, labels, allH
|
|
|
165
230
|
<>
|
|
166
231
|
<button ref={button} type="button" className={cx("gb-svc-trigger", className)} aria-haspopup="dialog" aria-expanded={open}
|
|
167
232
|
aria-controls={panelId} aria-label={L.trigger} title={L.trigger} onClick={() => { place(); setOpen(true); }}>
|
|
168
|
-
<Icon name=
|
|
233
|
+
<Icon name={triggerIcon} size={20} />
|
|
169
234
|
</button>
|
|
170
235
|
<dialog ref={ref} id={panelId} className="gb-svc" aria-labelledby={titleId} onClick={onClick} onPointerDown={onPointerDown}>
|
|
171
236
|
<div className="gb-svc__head">
|
|
@@ -186,25 +251,36 @@ export function ServiceSwitcher({ current, services = GEM_SERVICES, labels, allH
|
|
|
186
251
|
</div>
|
|
187
252
|
) : null}
|
|
188
253
|
<div className="gb-svc__body" onKeyDown={onGridKey}>
|
|
189
|
-
{
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
254
|
+
{shownGroups.length === 0 ? <p className="gb-svc__empty" role="status">{L.noMatch.replace("{query}", query.trim())}</p> : shownGroups.map((g) => {
|
|
255
|
+
const hid = `${id}svc-${g.id || "rest"}`;
|
|
256
|
+
const media = g.items.some((s) => s.media);
|
|
257
|
+
return (
|
|
258
|
+
<div key={g.id || "rest"} className="gb-svc__group" role="group" {...(g.title ? { "aria-labelledby": hid } : { "aria-label": L.title })}>
|
|
259
|
+
{g.title ? <h3 className="gb-svc__heading" id={hid}>{g.title}</h3> : null}
|
|
260
|
+
<ul className={cx("gb-svc__grid", media && "gb-svc__grid--media")} role="list">
|
|
261
|
+
{g.items.map((s) => (
|
|
262
|
+
<li key={s.id}>
|
|
263
|
+
<a className={cx("gb-svc__tile", s.media && "gb-svc__tile--media")} href={s.href} data-tint={s.tint}
|
|
264
|
+
aria-current={s.id === current ? "page" : undefined}
|
|
265
|
+
tabIndex={s.id === tabStop ? 0 : -1} onFocus={() => setRoving(s.id)} onClick={onTileClick}>
|
|
266
|
+
{s.media ? (
|
|
267
|
+
<span className="gb-svc__media" aria-hidden="true">
|
|
268
|
+
{s.media.src ? <img src={s.media.src} alt="" loading="lazy" decoding="async" /> : <span className="gb-svc__media-glyph">{s.media.glyph}</span>}
|
|
269
|
+
</span>
|
|
270
|
+
) : (
|
|
271
|
+
<span className="gb-svc__mark" aria-hidden="true">{s.icon ? <Icon name={s.icon} size={22} /> : <span className="gb-svc__glyph">{s.glyph}</span>}</span>
|
|
272
|
+
)}
|
|
273
|
+
<span className="gb-svc__name">{s.name}{s.badge ? <span className="gb-svc__badge">{s.badge}</span> : null}</span>
|
|
274
|
+
{s.description ? <span className="gb-svc__purpose">{s.description}</span> : null}
|
|
275
|
+
</a>
|
|
276
|
+
</li>
|
|
277
|
+
))}
|
|
278
|
+
</ul>
|
|
279
|
+
</div>
|
|
280
|
+
);
|
|
281
|
+
})}
|
|
206
282
|
</div>
|
|
207
|
-
{allHref ? (
|
|
283
|
+
{foot ? <div className="gb-svc__foot">{foot}</div> : allHref ? (
|
|
208
284
|
<div className="gb-svc__foot">
|
|
209
285
|
<a className="gb-svc__all" href={allHref} onClick={onTileClick}>{L.all}<span aria-hidden="true">→</span></a>
|
|
210
286
|
</div>
|
|
@@ -213,3 +289,11 @@ export function ServiceSwitcher({ current, services = GEM_SERVICES, labels, allH
|
|
|
213
289
|
</>
|
|
214
290
|
);
|
|
215
291
|
}
|
|
292
|
+
|
|
293
|
+
/** The Gem services: `Switcher` with GEM_SERVICES in the groups of SERVICE_GROUPS, the service's own mark and tint. */
|
|
294
|
+
export function ServiceSwitcher({ current, services = GEM_SERVICES, labels, allHref = SERVICES_HEALTH_URL, search = true, className }: ServiceSwitcherProps) {
|
|
295
|
+
const items = useMemo(() => services.map((s): SwitcherItem => ({
|
|
296
|
+
id: s.id, name: s.name, description: s.purpose, href: s.url, group: s.group, icon: s.icon, tint: s.tint,
|
|
297
|
+
})), [services]);
|
|
298
|
+
return <Switcher items={items} groups={SERVICE_GROUPS} current={current} labels={labels} allHref={allHref} search={search} className={className} />;
|
|
299
|
+
}
|
package/src/services.ts
CHANGED
|
@@ -32,8 +32,8 @@ export type ServiceTint = (typeof SERVICE_TINTS)[number];
|
|
|
32
32
|
|
|
33
33
|
export type ServiceId =
|
|
34
34
|
| "gemboss"
|
|
35
|
-
| "gemfactory" | "gemmedia" | "gemform"
|
|
36
|
-
| "gemwatcher" | "gemmarket" | "gemcapture" | "search-radar"
|
|
35
|
+
| "gemfactory" | "gemmedia" | "gemform" | "gemx"
|
|
36
|
+
| "gemwatcher" | "gemmarket" | "gempixel" | "gemcapture" | "search-radar"
|
|
37
37
|
| "gempress" | "content-radar" | "gemcommunity" | "gemnews"
|
|
38
38
|
| "gemcare" | "gemfeedback"
|
|
39
39
|
| "partner-radar" | "taskdesk";
|
|
@@ -56,9 +56,11 @@ export const GEM_SERVICES: readonly GemService[] = [
|
|
|
56
56
|
{ id: "gemfactory", name: "GemFactory", url: "https://gemfactory.ops.gemboss.ai", purpose: "Review sections, elements and templates.", group: "build", icon: "layers", tint: "blue" },
|
|
57
57
|
{ id: "gemmedia", name: "GemMedia", url: "https://media.gemboss.ai", purpose: "Images and videos made for stores, and their cost.", group: "build", icon: "image", tint: "rose" },
|
|
58
58
|
{ id: "gemform", name: "GemForm", url: "https://gemform.ops.gemboss.ai", purpose: "Form submissions from stores.", group: "build", icon: "document", tint: "teal" },
|
|
59
|
+
{ id: "gemx", name: "GemX", url: "https://x.gemboss.ai", purpose: "Tests and personalization across every store.", group: "build", icon: "sliders", tint: "amber" },
|
|
59
60
|
|
|
60
61
|
{ id: "gemwatcher", name: "GemWatcher", url: "https://gemwatcher.ops.gemboss.ai", purpose: "Store and market intelligence.", group: "market", icon: "eye", tint: "violet" },
|
|
61
62
|
{ id: "gemmarket", name: "GemMarket", url: "https://market.gemboss.ai", purpose: "Each store's market read and its competitors.", group: "market", icon: "chart", tint: "green" },
|
|
63
|
+
{ id: "gempixel", name: "GemPixel", url: "https://pixel.gemboss.ai", purpose: "Events every store sends, and whether they add up.", group: "market", icon: "activity", tint: "blue" },
|
|
62
64
|
{ id: "gemcapture", name: "GemCapture", url: "https://capture.gemboss.ai/admin", purpose: "Page captures and visual checks.", group: "market", icon: "page", tint: "slate" },
|
|
63
65
|
{ id: "search-radar", name: "Search Radar", url: "https://search-radar.ops.gemboss.ai", purpose: "Rankings on the App Store, Google and AI answers.", group: "market", icon: "radar", tint: "amber" },
|
|
64
66
|
|
package/src/shell.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.gemboss-popover-surface{background:var(--gemboss-surface);background:color-mix(in srgb,var(--gemboss-surface) 93%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg);box-shadow:var(--gemboss-shadow-raised)}@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){.gemboss-popover-surface{background:var(--gemboss-surface)}}.icon-nav{position:fixed;top:56px;left:0;z-index:200;width:72px;height:calc(100dvh - 56px);background:var(--gemboss-rail-bg);border-right:1px solid var(--gemboss-divider);display:flex;flex-direction:column;padding-top:8px;overflow:hidden}.gemboss-account-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:220px;z-index:320;overflow:hidden}.gemboss-account-menu-item,.ui-menu__item{display:block;width:100%;min-height:44px;padding:12px 16px;border:0;background:transparent;font:inherit;font-size:13px;color:var(--gemboss-text);text-align:left;text-decoration:none;cursor:pointer;transition:background var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gemboss-account-menu-item:hover,.ui-menu__item:hover{background:var(--gemboss-hover)}.gemboss-account-menu-item:focus-visible,.ui-menu__item:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px;background:var(--gemboss-hover)}.gemboss-account-menu-item.danger,.ui-menu__item--danger{color:var(--gemboss-danger-strong)}.gemboss-account-chip{width:30px;height:30px;border:1px solid #cfd6ce;border-radius:var(--gemboss-radius-full);background:#f5f7f4;color:#303633;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer}.gemboss-platform-main{box-sizing:border-box;min-height:100dvh;margin-left:72px;padding-top:56px;background:var(--gemboss-app-bg)}.icon-nav{top:56px;height:calc(100dvh - 56px);background:var(--gemboss-nav-bg);border-right-color:var(--gemboss-divider)}@media (max-width: 1040px){.gemboss-platform-topbar{grid-template-columns:minmax(120px,1fr) minmax(220px,520px) minmax(120px,1fr)}}@media (max-width: 760px){.gemboss-platform-main{margin-left:0}}.gemboss-account-chip{width:32px;height:32px;border-radius:50%;background:var(--gemboss-primary);color:#fff;font-weight:600;font-size:12px;display:inline-flex;align-items:center;justify-content:center;border:none;cursor:pointer;transition:transform var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{transform:scale(1.05)}.gemboss-account-chip:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gemboss-platform-main{margin-top:56px;margin-left:72px;min-height:calc(100vh - 56px);padding:24px;background:#fafafb}@media (max-width: 768px){.gemboss-platform-main{margin-left:0;padding:16px}}.gemboss-platform-shell{display:block;min-height:100vh;background:var(--gemboss-app-bg)}.gemboss-platform-topbar{position:fixed;inset:0 0 auto;z-index:300;height:56px;border-bottom:1px solid var(--gemboss-divider);background:var(--gemboss-topbar-bg);display:grid;grid-template-columns:minmax(200px,1fr) minmax(280px,560px) minmax(200px,1fr);align-items:center;gap:16px;padding:0 16px;box-shadow:var(--gemboss-shadow-resting)}:root:has(.gemboss-platform-topbar){scroll-padding-top:64px}.gemboss-account-chip{width:32px;height:32px;border:1px solid var(--gemboss-chip-line);border-radius:var(--gemboss-radius-full);background:var(--gemboss-surface);color:var(--gemboss-chip-ink);display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer;transition:border-color var(--gemboss-transition-base) ease,background-color var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{border-color:var(--gemboss-chip-line-hover);background:var(--gemboss-chip-bg-hover);transform:none}.icon-nav{position:fixed;top:56px;left:0;z-index:200;width:72px;height:calc(100dvh - 56px);border-right:1px solid var(--gemboss-divider);background:var(--gemboss-nav-bg);padding-top:12px}.gemboss-platform-main{min-height:calc(100vh - 56px);margin-top:56px;margin-left:72px;background:var(--gemboss-app-bg);padding:24px}@media (max-width: 1120px){.gemboss-platform-topbar{grid-template-columns:220px minmax(220px,1fr) auto;gap:12px}}@media (max-width: 760px){.gemboss-platform-topbar{height:auto;min-height:56px;grid-template-columns:minmax(0,1fr) auto;padding:12px}.gemboss-account-chip,.icon-nav{display:none}.gemboss-platform-main{margin-left:0;padding:104px 16px 16px}}.gnav-scroll{scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-assistant-railfoot.is-button{width:100%;border:none;background:none;cursor:pointer;text-align:left;font:inherit;border-radius:8px;transition:background .12s ease,color .12s ease}.gemboss-assistant-railfoot.is-button:hover{background:var(--gemboss-primary-soft);color:var(--gemboss-primary-dark)}.gemboss-assistant-empty{padding:24px 20px;color:var(--gemboss-text-muted);font-size:13px}@media (max-width: 760px){.gemboss-platform-topbar{display:flex;align-items:center;gap:8px;height:56px;min-height:56px;padding:0 12px}.gemboss-account-chip{display:inline-flex}.gemboss-platform-main{padding-top:56px;padding-bottom:calc(56px + env(safe-area-inset-bottom))}}@media (pointer: coarse){.gemboss-account-chip{width:44px;height:44px}.gnav-item{min-height:44px}.gemboss-assistant-collapse,.gemboss-assistant-newchat{min-height:44px;min-width:44px}}.icon-nav{width:240px;padding:12px 0 0;overflow:hidden;background:var(--gemboss-nav-bg);display:flex;flex-direction:column}.gnav-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding-inline:12px}.gnav-bottom{padding:0 12px 12px}.gnav-item{display:flex;align-items:center;gap:12px;width:100%;padding:8px 12px;margin:1px 0;border:0;background:transparent;cursor:pointer;text-align:left;border-radius:var(--gemboss-radius-md);text-decoration:none;font-family:inherit;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:500;line-height:1.2;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gnav-item:hover{background:var(--gemboss-nav-hover)}.gnav-item:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gnav-item.active{color:var(--gemboss-active-fg);font-weight:600}.gnav-group:not(.has-active-child)>.gnav-item.active{background:var(--gemboss-active-bg)}.gnav-group:not(.has-active-child)>.gnav-item.active:hover{background:var(--gemboss-active-bg)}.gnav-group.has-active-child>.gnav-item.active:hover{background:var(--gemboss-nav-hover)}.gnav-ico{flex:0 0 20px;width:20px;height:20px;display:grid;place-items:center}.gnav-ico svg{width:20px;height:20px;fill:currentColor}.gnav-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gnav-sub{list-style:none;margin:1px 0 6px;padding:0}.gnav-subitem{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 12px 6px 44px;margin:1px 0;border-radius:var(--gemboss-radius-sm);color:var(--gemboss-text-muted);font-size:13px;line-height:1.2;text-decoration:none;white-space:nowrap;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}@media (pointer: coarse){.gnav-subitem{min-height:44px}}.gnav-subitem:hover{background:var(--gemboss-nav-hover);color:var(--gemboss-text)}.gnav-subitem.active{color:var(--gemboss-active-fg);font-weight:600;background:var(--gemboss-active-bg)}.gnav-subitem.active:hover{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-subitem.active:before{content:"";position:absolute;left:20px;top:50%;transform:translateY(-50%);width:3px;height:15px;border-radius:2px;background:var(--gemboss-primary)}.gnav-subitem.is-soon{opacity:.5;cursor:default}.gnav-subitem em{font-style:normal;font-size:var(--gemboss-fs-micro);font-weight:600;letter-spacing:.04em;text-transform:uppercase;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-sm);padding:1px 6px}.gnav-sep{height:1px;background:var(--gemboss-divider);margin:8px 6px}.gnav-item.gnav-assistant{color:var(--gemboss-accent-strong);font-weight:600;background:var(--gemboss-accent-soft)}.gnav-item.gnav-assistant .gnav-ico svg{fill:var(--gemboss-accent)}.gnav-item.gnav-assistant:hover{background:color-mix(in srgb,var(--gemboss-accent) 16%,var(--gemboss-surface))}.gnav-item.gnav-assistant.active{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-item.gnav-assistant.active .gnav-ico svg{fill:var(--gemboss-active-fg)}.gemboss-platform-main{margin-left:240px}.gemboss-mobile-menu-btn,.gemboss-mobile-nav-backdrop{display:none}@media (max-width: 760px){.gemboss-platform-main{margin-left:0;padding-bottom:env(safe-area-inset-bottom)}.gemboss-mobile-menu-btn{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:38px;height:38px;margin-left:-2px;border:0;border-radius:8px;background:transparent;cursor:pointer;color:var(--gemboss-text)}.gemboss-mobile-menu-btn:active{background:var(--gemboss-hover)}.icon-nav{display:flex;width:min(82vw,300px);transform:translate(-100%);transition:transform .26s cubic-bezier(.4,0,.2,1),box-shadow .26s cubic-bezier(.4,0,.2,1);z-index:1000;box-shadow:none}.gemboss-platform-shell.is-mobile-nav-open .icon-nav{transform:translate(0);box-shadow:2px 0 26px #1f1e1d33}.gemboss-mobile-nav-backdrop{display:block;position:fixed;inset:56px 0 0;width:100%;border:0;padding:0;background:#14131261;opacity:0;pointer-events:none;transition:opacity .22s ease;z-index:999}.gemboss-platform-shell.is-mobile-nav-open .gemboss-mobile-nav-backdrop{opacity:1;pointer-events:auto}}@media (max-width: 305.98px){.gemboss-platform-topbar{padding:0 8px}}@media (min-width: 306px) and (max-width: 460px){.gemboss-platform-topbar{padding:0 8px}.gemboss-mobile-menu-btn,.gemboss-account-chip{width:44px;height:44px}}.gemboss-assistant-chatslot{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;min-width:0}.gemboss-assistant-chatslot[hidden]{display:none}.gemboss-assistant-page>.gemboss-assistant-tabs{flex:0 0 auto;display:flex;align-items:center;gap:4px;padding:4px 8px 0;overflow-x:auto;scrollbar-width:none}.gemboss-assistant-tabs::-webkit-scrollbar{display:none}.gemboss-assistant-tab{display:flex;align-items:center;flex:0 1 auto;min-width:0;max-width:190px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-md);background:transparent}.gemboss-assistant-tab.active{background:var(--gemboss-active-bg);border-color:var(--gemboss-active-bg)}.gemboss-assistant-tab-main{display:flex;align-items:center;gap:6px;min-width:0;min-height:44px;padding:0 4px 0 8px;border:0;background:transparent;font:inherit;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-tab.active .gemboss-assistant-tab-main{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gemboss-assistant-tab-dot{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-divider)}.gemboss-assistant-tab-dot.is-running{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}.gemboss-assistant-tab-close{flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;padding:0}.gemboss-assistant-tab-close:hover{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-close svg{width:14px;height:14px}.gemboss-assistant-sronly{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gemboss-assistant-thread-running{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}@media (prefers-reduced-motion: reduce){.gemboss-assistant-tab-dot.is-running,.gemboss-assistant-thread-running{animation:none}}.gemboss-assistant-route-claim{display:block;height:100%}.gemboss-assistant-layout.is-dock{height:auto;min-height:0}.gemboss-assistant-layout.is-dock .gemboss-assistant-page{height:auto;max-width:none;padding:4px 0 8px}.gnav-item.gnav-assistant{position:relative}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after,body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{content:"";position:absolute;top:6px;left:26px;width:8px;height:8px;border-radius:50%;border:2px solid var(--gemboss-surface)}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{background:var(--gemboss-success-strong)}@media (prefers-reduced-motion: reduce){body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{animation:none}}.gemboss-assistant-layout{display:flex;height:calc(100dvh - 56px);width:100%;min-height:0}.gemboss-assistant-rail{flex:0 0 264px;width:264px;display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--gemboss-divider);background:transparent;padding:16px 12px 12px;gap:12px;transition:flex-basis .18s ease,width .18s ease}.gemboss-assistant-rail-top{display:flex;align-items:center;gap:6px}.gemboss-assistant-newchat{display:flex;align-items:center;gap:8px;flex:1 1 auto;min-width:0;padding:12px;border:1px solid var(--gemboss-divider);border-radius:12px;background:transparent;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:600;cursor:pointer;transition:background .12s ease,border-color .12s ease}.gemboss-assistant-newchat:hover{background:#00000009;border-color:var(--gemboss-text-muted)}.gemboss-assistant-newchat svg{width:17px;height:17px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-newchat span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}.gemboss-assistant-kbd{flex:0 0 auto;font-size:var(--gemboss-fs-micro);font-weight:600;line-height:1;padding:4px 6px;border:1px solid var(--gemboss-divider);border-radius:6px;background:transparent;color:var(--gemboss-text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gemboss-assistant-search:focus-within .gemboss-assistant-kbd{display:none}.gemboss-assistant-collapse{flex:0 0 auto;display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-collapse:hover{background:#0000000d;color:var(--gemboss-text)}.gemboss-assistant-collapse svg{width:16px;height:16px;fill:currentColor}.gemboss-assistant-search{gap:6px}.gemboss-assistant-search>svg{width:15px;height:15px;fill:var(--gemboss-text-muted);flex:0 0 auto}.gemboss-assistant-search-clear{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:6px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-search-clear:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-search-clear svg{width:13px;height:13px;fill:currentColor}.gemboss-assistant-railfoot{flex:0 0 auto;display:flex;align-items:center;gap:6px;padding:8px 12px 2px;border-top:1px solid var(--gemboss-divider);margin-top:4px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption);line-height:1.35}.gemboss-assistant-railfoot svg{width:13px;height:13px;flex:0 0 auto;fill:currentColor;opacity:.8}.gemboss-assistant-threads{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:2px}.gemboss-assistant-threads-empty{padding:16px 8px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption)}.gemboss-assistant-group{display:flex;flex-direction:column;gap:2px}.gemboss-assistant-group+.gemboss-assistant-group{margin-top:12px}.gemboss-assistant-group-label{padding:4px 12px;font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--gemboss-text-muted);text-transform:uppercase}.gemboss-assistant-thread{position:relative;display:flex;align-items:center;border-radius:8px;transition:background .12s ease}.gemboss-assistant-thread:hover{background:var(--gemboss-hover, rgba(0,0,0,.04))}.gemboss-assistant-thread.active{background:#00000012}.gemboss-assistant-thread-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:8px 12px;border:0;background:transparent;text-align:left;cursor:pointer}.gemboss-assistant-thread-titlerow{display:flex;align-items:center;gap:6px;width:100%;min-width:0}.gemboss-assistant-pin-dot{width:12px;height:12px;flex:0 0 auto;fill:var(--gemboss-text-muted)}.gemboss-assistant-thread-title{flex:1 1 auto;min-width:0;font-size:13px;font-weight:500;color:var(--gemboss-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gemboss-assistant-thread-meta{font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-assistant-thread.menu-open{background:#00000012}.gemboss-assistant-thread.menu-open .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-menu{z-index:60;width:184px;padding:6px;display:flex;flex-direction:column}.gemboss-assistant-menu-confirm{padding:8px 12px 6px;font-size:var(--gemboss-fs-caption);font-weight:600;color:var(--gemboss-text)}.gemboss-assistant-menu button{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:0;border-radius:8px;background:transparent;text-align:left;font-size:13px;color:var(--gemboss-text);cursor:pointer}.gemboss-assistant-menu button:hover{background:var(--gemboss-hover, rgba(0,0,0,.05))}.gemboss-assistant-menu button.danger{color:var(--gemboss-danger-strong)}.gemboss-assistant-menu button svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-thread-actions{position:absolute;right:6px;display:flex;gap:2px;opacity:0;transition:opacity .12s ease}.gemboss-assistant-thread:hover .gemboss-assistant-thread-actions,.gemboss-assistant-thread:focus-within .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-thread-act{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-thread-act:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-thread-act.danger:hover{color:var(--gemboss-danger-strong)}.gemboss-assistant-thread-act svg{width:15px;height:15px;fill:currentColor}.gemboss-assistant-thread.editing{background:#00000012}.gemboss-assistant-thread-edit{display:flex;align-items:center;gap:2px;width:100%;padding:6px}.gemboss-assistant-thread-edit input{flex:1 1 auto;min-width:0}.gemboss-assistant-layout .gemboss-assistant-page{height:100%;max-width:820px;flex:1 1 auto;min-width:0;padding-top:16px}.gemboss-assistant-layout .gemboss-assistant-page.is-switching{opacity:.55;transition:opacity .12s ease;pointer-events:none}.gemboss-assistant-rail.is-collapsed{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat span,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-search,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-railfoot,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-threads{display:none}@media (max-width: 760px){.gemboss-assistant-rail{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-newchat span,.gemboss-assistant-search,.gemboss-assistant-railfoot,.gemboss-assistant-threads,.gemboss-assistant-collapse{display:none}}.gemboss-assistant-page{height:calc(100dvh - 56px);width:100%;max-width:760px;margin:0 auto;padding:24px 0 16px;display:flex;flex-direction:column;min-height:0}.gemboss-assistant-page>*{flex:1 1 auto;min-height:0}.gemboss-assistant-empty{flex:1;display:grid;place-items:center;color:var(--gemboss-text-muted);font-size:14px}.gemboss-platform-shell{display:flow-root}.gemboss-platform-main{padding-bottom:calc(24px + var(--gemboss-invite-h, 0px))}@keyframes gemboss-assistant-pulse{0%,to{opacity:1}50%{opacity:.35}}.gb-account{position:relative}.gb-account>summary{list-style:none}.gb-account>summary::-webkit-details-marker{display:none}.gb-account-head{padding:12px 16px;border-bottom:1px solid var(--gemboss-divider)}.gb-account-name{font-size:13px;font-weight:600;color:var(--gemboss-text-strong)}.gb-account-email{font-size:12px;color:var(--gemboss-text-muted)}.gb-account-role{display:inline-block;margin-top:4px;padding:1px 6px;border-radius:4px;font-size:11px;font-weight:600;color:var(--gemboss-active-fg);background:var(--gemboss-active-bg)}.gb-account-form{margin:0}.gnav-scroll::-webkit-scrollbar{width:9px}.gnav-scroll::-webkit-scrollbar-track{background:transparent}.gnav-scroll::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:6px;border:2px solid transparent;background-clip:content-box}
|
|
1
|
+
.gemboss-popover-surface{background:var(--gemboss-surface);background:color-mix(in srgb,var(--gemboss-surface) 93%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-lg);box-shadow:var(--gemboss-shadow-raised)}@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){.gemboss-popover-surface{background:var(--gemboss-surface)}}.icon-nav{position:fixed;top:56px;left:0;z-index:200;width:72px;height:calc(100dvh - 56px);background:var(--gemboss-rail-bg);border-right:1px solid var(--gemboss-divider);display:flex;flex-direction:column;padding-top:8px;overflow:hidden}.gemboss-account-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:220px;z-index:320;overflow:hidden}.gemboss-account-menu-item,.ui-menu__item{display:block;width:100%;min-height:44px;padding:12px 16px;border:0;background:transparent;font:inherit;font-size:13px;color:var(--gemboss-text);text-align:left;text-decoration:none;cursor:pointer;transition:background var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gemboss-account-menu-item:hover,.ui-menu__item:hover{background:var(--gemboss-hover)}.gemboss-account-menu-item:focus-visible,.ui-menu__item:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px;background:var(--gemboss-hover)}.gemboss-account-menu-item.danger,.ui-menu__item--danger{color:var(--gemboss-danger-strong)}.gemboss-account-chip{width:30px;height:30px;border:1px solid #cfd6ce;border-radius:var(--gemboss-radius-full);background:#f5f7f4;color:#303633;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer}.gemboss-platform-main{box-sizing:border-box;min-height:100dvh;margin-left:72px;padding-top:56px;background:var(--gemboss-app-bg)}.icon-nav{top:56px;height:calc(100dvh - 56px);background:var(--gemboss-nav-bg);border-right-color:var(--gemboss-divider)}@media (max-width: 1040px){.gemboss-platform-topbar{grid-template-columns:minmax(120px,1fr) minmax(220px,520px) minmax(120px,1fr)}}@media (max-width: 760px){.gemboss-platform-main{margin-left:0}}.gemboss-account-chip{width:32px;height:32px;border-radius:50%;background:var(--gemboss-primary);color:#fff;font-weight:600;font-size:12px;display:inline-flex;align-items:center;justify-content:center;border:none;cursor:pointer;transition:transform var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{transform:scale(1.05)}.gemboss-account-chip:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gemboss-platform-main{margin-top:56px;margin-left:72px;min-height:calc(100vh - 56px);padding:24px;background:#fafafb}@media (max-width: 768px){.gemboss-platform-main{margin-left:0;padding:16px}}.gemboss-platform-shell{display:block;min-height:100vh;background:var(--gemboss-app-bg)}.gemboss-platform-topbar{position:fixed;inset:0 0 auto;z-index:300;height:56px;border-bottom:1px solid var(--gemboss-divider);background:var(--gemboss-topbar-bg);display:grid;grid-template-columns:minmax(200px,1fr) minmax(280px,560px) minmax(200px,1fr);align-items:center;gap:16px;padding:0 16px;box-shadow:var(--gemboss-shadow-resting)}:root:has(.gemboss-platform-topbar){scroll-padding-top:64px}.gemboss-account-chip{width:32px;height:32px;border:1px solid var(--gemboss-chip-line);border-radius:var(--gemboss-radius-full);background:var(--gemboss-surface);color:var(--gemboss-chip-ink);display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:11px;font-weight:700;cursor:pointer;transition:border-color var(--gemboss-transition-base) ease,background-color var(--gemboss-transition-base) ease}.gemboss-account-chip:hover{border-color:var(--gemboss-chip-line-hover);background:var(--gemboss-chip-bg-hover);transform:none}.icon-nav{position:fixed;top:56px;left:0;z-index:200;width:72px;height:calc(100dvh - 56px);border-right:1px solid var(--gemboss-divider);background:var(--gemboss-nav-bg);padding-top:12px}.gemboss-platform-main{min-height:calc(100vh - 56px);margin-top:56px;margin-left:72px;background:var(--gemboss-app-bg);padding:24px}@media (max-width: 1120px){.gemboss-platform-topbar{grid-template-columns:220px minmax(220px,1fr) auto;gap:12px}}@media (max-width: 760px){.gemboss-platform-topbar{height:auto;min-height:56px;grid-template-columns:minmax(0,1fr) auto;padding:12px}.gemboss-account-chip,.icon-nav{display:none}.gemboss-platform-main{margin-left:0;padding:16px}}.gnav-scroll{scrollbar-width:thin;scrollbar-color:rgba(31,30,29,.22) transparent}.gemboss-assistant-railfoot.is-button{width:100%;border:none;background:none;cursor:pointer;text-align:left;font:inherit;border-radius:8px;transition:background .12s ease,color .12s ease}.gemboss-assistant-railfoot.is-button:hover{background:var(--gemboss-primary-soft);color:var(--gemboss-primary-dark)}.gemboss-assistant-empty{padding:24px 20px;color:var(--gemboss-text-muted);font-size:13px}@media (max-width: 760px){.gemboss-platform-topbar{display:flex;align-items:center;gap:8px;height:56px;min-height:56px;padding:0 12px}.gemboss-account-chip{display:inline-flex}.gemboss-platform-main{padding-top:16px;padding-bottom:calc(56px + env(safe-area-inset-bottom))}}@media (pointer: coarse){.gemboss-account-chip{width:44px;height:44px}.gnav-item{min-height:44px}.gemboss-assistant-collapse,.gemboss-assistant-newchat{min-height:44px;min-width:44px}}.icon-nav{width:240px;padding:12px 0 0;overflow:hidden;background:var(--gemboss-nav-bg);display:flex;flex-direction:column}.gnav-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding-inline:12px}.gnav-bottom{padding:0 12px 12px}.gnav-item{display:flex;align-items:center;gap:12px;width:100%;padding:8px 12px;margin:1px 0;border:0;background:transparent;cursor:pointer;text-align:left;border-radius:var(--gemboss-radius-md);text-decoration:none;font-family:inherit;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:500;line-height:1.2;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gnav-item:hover{background:var(--gemboss-nav-hover)}.gnav-item:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:-2px}.gnav-item.active{color:var(--gemboss-active-fg);font-weight:600}.gnav-group:not(.has-active-child)>.gnav-item.active{background:var(--gemboss-active-bg)}.gnav-group:not(.has-active-child)>.gnav-item.active:hover{background:var(--gemboss-active-bg)}.gnav-group.has-active-child>.gnav-item.active:hover{background:var(--gemboss-nav-hover)}.gnav-ico{flex:0 0 20px;width:20px;height:20px;display:grid;place-items:center}.gnav-ico svg{width:20px;height:20px;fill:currentColor}.gnav-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gnav-sub{list-style:none;margin:1px 0 6px;padding:0}.gnav-subitem{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 12px 6px 44px;margin:1px 0;border-radius:var(--gemboss-radius-sm);color:var(--gemboss-text-muted);font-size:13px;line-height:1.2;text-decoration:none;white-space:nowrap;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}@media (pointer: coarse){.gnav-subitem{min-height:44px}}.gnav-subitem:hover{background:var(--gemboss-nav-hover);color:var(--gemboss-text)}.gnav-subitem.active{color:var(--gemboss-active-fg);font-weight:600;background:var(--gemboss-active-bg)}.gnav-subitem.active:hover{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-subitem.active:before{content:"";position:absolute;left:20px;top:50%;transform:translateY(-50%);width:3px;height:15px;border-radius:2px;background:var(--gemboss-primary)}.gnav-subitem.is-soon{opacity:.5;cursor:default}.gnav-subitem em{font-style:normal;font-size:var(--gemboss-fs-micro);font-weight:600;letter-spacing:.04em;text-transform:uppercase;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-sm);padding:1px 6px}.gnav-sep{height:1px;background:var(--gemboss-divider);margin:8px 6px}.gnav-item.gnav-assistant{color:var(--gemboss-accent-strong);font-weight:600;background:var(--gemboss-accent-soft)}.gnav-item.gnav-assistant .gnav-ico svg{fill:var(--gemboss-accent)}.gnav-item.gnav-assistant:hover{background:color-mix(in srgb,var(--gemboss-accent) 16%,var(--gemboss-surface))}.gnav-item.gnav-assistant.active{background:var(--gemboss-active-bg);color:var(--gemboss-active-fg)}.gnav-item.gnav-assistant.active .gnav-ico svg{fill:var(--gemboss-active-fg)}.gemboss-platform-main{margin-left:240px}.gemboss-mobile-menu-btn,.gemboss-mobile-nav-backdrop{display:none}@media (max-width: 760px){.gemboss-platform-main{margin-left:0;padding-bottom:env(safe-area-inset-bottom)}.gemboss-mobile-menu-btn{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:38px;height:38px;margin-left:-2px;border:0;border-radius:8px;background:transparent;cursor:pointer;color:var(--gemboss-text)}.gemboss-mobile-menu-btn:active{background:var(--gemboss-hover)}.icon-nav{display:flex;width:min(82vw,300px);transform:translate(-100%);transition:transform .26s cubic-bezier(.4,0,.2,1),box-shadow .26s cubic-bezier(.4,0,.2,1);z-index:1000;box-shadow:none}.gemboss-platform-shell.is-mobile-nav-open .icon-nav{transform:translate(0);box-shadow:2px 0 26px #1f1e1d33}.gemboss-mobile-nav-backdrop{display:block;position:fixed;inset:56px 0 0;width:100%;border:0;padding:0;background:#14131261;opacity:0;pointer-events:none;transition:opacity .22s ease;z-index:999}.gemboss-platform-shell.is-mobile-nav-open .gemboss-mobile-nav-backdrop{opacity:1;pointer-events:auto}}@media (max-width: 305.98px){.gemboss-platform-topbar{padding:0 8px}}@media (min-width: 306px) and (max-width: 460px){.gemboss-platform-topbar{padding:0 8px}.gemboss-mobile-menu-btn,.gemboss-account-chip{width:44px;height:44px}}.gemboss-assistant-chatslot{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;min-width:0}.gemboss-assistant-chatslot[hidden]{display:none}.gemboss-assistant-page>.gemboss-assistant-tabs{flex:0 0 auto;display:flex;align-items:center;gap:4px;padding:4px 8px 0;overflow-x:auto;scrollbar-width:none}.gemboss-assistant-tabs::-webkit-scrollbar{display:none}.gemboss-assistant-tab{display:flex;align-items:center;flex:0 1 auto;min-width:0;max-width:190px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-md);background:transparent}.gemboss-assistant-tab.active{background:var(--gemboss-active-bg);border-color:var(--gemboss-active-bg)}.gemboss-assistant-tab-main{display:flex;align-items:center;gap:6px;min-width:0;min-height:44px;padding:0 4px 0 8px;border:0;background:transparent;font:inherit;font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-tab.active .gemboss-assistant-tab-main{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gemboss-assistant-tab-dot{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-divider)}.gemboss-assistant-tab-dot.is-running{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}.gemboss-assistant-tab-close{flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;border:0;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;padding:0}.gemboss-assistant-tab-close:hover{color:var(--gemboss-text-strong)}.gemboss-assistant-tab-close svg{width:14px;height:14px}.gemboss-assistant-sronly{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gemboss-assistant-thread-running{flex:0 0 auto;width:6px;height:6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}@media (prefers-reduced-motion: reduce){.gemboss-assistant-tab-dot.is-running,.gemboss-assistant-thread-running{animation:none}}.gemboss-assistant-route-claim{display:block;height:100%}.gemboss-assistant-layout.is-dock{height:auto;min-height:0}.gemboss-assistant-layout.is-dock .gemboss-assistant-page{height:auto;max-width:none;padding:4px 0 8px}.gnav-item.gnav-assistant{position:relative}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after,body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{content:"";position:absolute;top:6px;left:26px;width:8px;height:8px;border-radius:50%;border:2px solid var(--gemboss-surface)}body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{background:var(--gemboss-primary);animation:gemboss-assistant-pulse 1.4s ease-in-out infinite}body.gemboss-assistant-unread .gnav-item.gnav-assistant:after{background:var(--gemboss-success-strong)}@media (prefers-reduced-motion: reduce){body.gemboss-assistant-busy .gnav-item.gnav-assistant:after{animation:none}}.gemboss-assistant-layout{display:flex;height:calc(100dvh - 56px);width:100%;min-height:0}.gemboss-assistant-rail{flex:0 0 264px;width:264px;display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--gemboss-divider);background:transparent;padding:16px 12px 12px;gap:12px;transition:flex-basis .18s ease,width .18s ease}.gemboss-assistant-rail-top{display:flex;align-items:center;gap:6px}.gemboss-assistant-newchat{display:flex;align-items:center;gap:8px;flex:1 1 auto;min-width:0;padding:12px;border:1px solid var(--gemboss-divider);border-radius:12px;background:transparent;color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:600;cursor:pointer;transition:background .12s ease,border-color .12s ease}.gemboss-assistant-newchat:hover{background:#00000009;border-color:var(--gemboss-text-muted)}.gemboss-assistant-newchat svg{width:17px;height:17px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-newchat span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}.gemboss-assistant-kbd{flex:0 0 auto;font-size:var(--gemboss-fs-micro);font-weight:600;line-height:1;padding:4px 6px;border:1px solid var(--gemboss-divider);border-radius:6px;background:transparent;color:var(--gemboss-text-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gemboss-assistant-search:focus-within .gemboss-assistant-kbd{display:none}.gemboss-assistant-collapse{flex:0 0 auto;display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-collapse:hover{background:#0000000d;color:var(--gemboss-text)}.gemboss-assistant-collapse svg{width:16px;height:16px;fill:currentColor}.gemboss-assistant-search{gap:6px}.gemboss-assistant-search>svg{width:15px;height:15px;fill:var(--gemboss-text-muted);flex:0 0 auto}.gemboss-assistant-search-clear{display:grid;place-items:center;width:20px;height:20px;border:0;border-radius:6px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer}.gemboss-assistant-search-clear:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-search-clear svg{width:13px;height:13px;fill:currentColor}.gemboss-assistant-railfoot{flex:0 0 auto;display:flex;align-items:center;gap:6px;padding:8px 12px 2px;border-top:1px solid var(--gemboss-divider);margin-top:4px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption);line-height:1.35}.gemboss-assistant-railfoot svg{width:13px;height:13px;flex:0 0 auto;fill:currentColor;opacity:.8}.gemboss-assistant-threads{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:2px}.gemboss-assistant-threads-empty{padding:16px 8px;color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-caption)}.gemboss-assistant-group{display:flex;flex-direction:column;gap:2px}.gemboss-assistant-group+.gemboss-assistant-group{margin-top:12px}.gemboss-assistant-group-label{padding:4px 12px;font-size:11px;font-weight:600;letter-spacing:.02em;color:var(--gemboss-text-muted);text-transform:uppercase}.gemboss-assistant-thread{position:relative;display:flex;align-items:center;border-radius:8px;transition:background .12s ease}.gemboss-assistant-thread:hover{background:var(--gemboss-hover, rgba(0,0,0,.04))}.gemboss-assistant-thread.active{background:#00000012}.gemboss-assistant-thread-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:8px 12px;border:0;background:transparent;text-align:left;cursor:pointer}.gemboss-assistant-thread-titlerow{display:flex;align-items:center;gap:6px;width:100%;min-width:0}.gemboss-assistant-pin-dot{width:12px;height:12px;flex:0 0 auto;fill:var(--gemboss-text-muted)}.gemboss-assistant-thread-title{flex:1 1 auto;min-width:0;font-size:13px;font-weight:500;color:var(--gemboss-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.gemboss-assistant-thread-meta{font-size:var(--gemboss-fs-caption);color:var(--gemboss-text-muted)}.gemboss-assistant-thread.menu-open{background:#00000012}.gemboss-assistant-thread.menu-open .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-menu{z-index:60;width:184px;padding:6px;display:flex;flex-direction:column}.gemboss-assistant-menu-confirm{padding:8px 12px 6px;font-size:var(--gemboss-fs-caption);font-weight:600;color:var(--gemboss-text)}.gemboss-assistant-menu button{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:0;border-radius:8px;background:transparent;text-align:left;font-size:13px;color:var(--gemboss-text);cursor:pointer}.gemboss-assistant-menu button:hover{background:var(--gemboss-hover, rgba(0,0,0,.05))}.gemboss-assistant-menu button.danger{color:var(--gemboss-danger-strong)}.gemboss-assistant-menu button svg{width:15px;height:15px;fill:currentColor;flex:0 0 auto}.gemboss-assistant-thread-actions{position:absolute;right:6px;display:flex;gap:2px;opacity:0;transition:opacity .12s ease}.gemboss-assistant-thread:hover .gemboss-assistant-thread-actions,.gemboss-assistant-thread:focus-within .gemboss-assistant-thread-actions{opacity:1}.gemboss-assistant-thread-act{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;transition:background .12s ease,color .12s ease}.gemboss-assistant-thread-act:hover{background:#00000012;color:var(--gemboss-text)}.gemboss-assistant-thread-act.danger:hover{color:var(--gemboss-danger-strong)}.gemboss-assistant-thread-act svg{width:15px;height:15px;fill:currentColor}.gemboss-assistant-thread.editing{background:#00000012}.gemboss-assistant-thread-edit{display:flex;align-items:center;gap:2px;width:100%;padding:6px}.gemboss-assistant-thread-edit input{flex:1 1 auto;min-width:0}.gemboss-assistant-layout .gemboss-assistant-page{height:100%;max-width:820px;flex:1 1 auto;min-width:0;padding-top:16px}.gemboss-assistant-layout .gemboss-assistant-page.is-switching{opacity:.55;transition:opacity .12s ease;pointer-events:none}.gemboss-assistant-rail.is-collapsed{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-rail.is-collapsed .gemboss-assistant-newchat span,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-search,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-railfoot,.gemboss-assistant-rail.is-collapsed .gemboss-assistant-threads{display:none}@media (max-width: 760px){.gemboss-assistant-rail{flex-basis:60px;width:60px;padding:16px 8px 12px}.gemboss-assistant-rail .gemboss-assistant-rail-top{flex-direction:column;gap:8px}.gemboss-assistant-newchat{justify-content:center;padding:8px;flex:0 0 auto}.gemboss-assistant-newchat span,.gemboss-assistant-search,.gemboss-assistant-railfoot,.gemboss-assistant-threads,.gemboss-assistant-collapse{display:none}}.gemboss-assistant-page{height:calc(100dvh - 56px);width:100%;max-width:760px;margin:0 auto;padding:24px 0 16px;display:flex;flex-direction:column;min-height:0}.gemboss-assistant-page>*{flex:1 1 auto;min-height:0}.gemboss-assistant-empty{flex:1;display:grid;place-items:center;color:var(--gemboss-text-muted);font-size:14px}.gemboss-platform-shell{display:flow-root}.gemboss-platform-main{padding-bottom:calc(24px + var(--gemboss-invite-h, 0px))}@keyframes gemboss-assistant-pulse{0%,to{opacity:1}50%{opacity:.35}}.gb-account{position:relative}.gb-account>summary{list-style:none}.gb-account>summary::-webkit-details-marker{display:none}.gb-account-head{padding:12px 16px;border-bottom:1px solid var(--gemboss-divider)}.gb-account-name{font-size:13px;font-weight:600;color:var(--gemboss-text-strong)}.gb-account-email{font-size:12px;color:var(--gemboss-text-muted)}.gb-account-role{display:inline-block;margin-top:4px;padding:1px 6px;border-radius:4px;font-size:11px;font-weight:600;color:var(--gemboss-active-fg);background:var(--gemboss-active-bg)}.gb-account-form{margin:0}.gnav-scroll::-webkit-scrollbar{width:9px}.gnav-scroll::-webkit-scrollbar-track{background:transparent}.gnav-scroll::-webkit-scrollbar-thumb{background:#1f1e1d33;border-radius:6px;border:2px solid transparent;background-clip:content-box}
|
package/src/site.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.gb-site-wrap{width:min(100% - 32px,1132px);margin-inline:auto}.gb-site-header{position:sticky;top:0;z-index:50;background:var(--gemboss-surface);border-bottom:1px solid var(--gemboss-divider)}.gb-site-header__in{display:flex;align-items:center;gap:32px;height:64px;width:min(100% - 32px,1132px);margin-inline:auto;padding:0 24px}.gb-brand.gb-brand--site{display:inline-flex;align-items:center;gap:8px;height:44px;flex:0 0 auto;min-width:0;margin:0;padding:0 8px;border-radius:var(--gemboss-radius-md);color:var(--gb-brand-ink, var(--gemboss-text-strong));text-decoration:none;transition:background-color var(--gemboss-transition-fast) ease}.gb-brand.gb-brand--site:hover{background:var(--gemboss-hover);text-decoration:none}.gb-brand.gb-brand--site:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gb-brand--site .gb-brand-gem{display:block;flex:0 0 auto}.gb-brand--site .gb-brand-name{min-width:0;font-family:Inter,var(--gemboss-font-sans);font-size:18px;font-weight:700;letter-spacing:-.02em;line-height:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}@media (max-width: 460px){.gb-brand.gb-brand--site{justify-content:flex-start}.gb-brand--site .gb-brand-name{display:inline}}.gb-site-nav{display:flex;align-items:center;gap:4px;min-width:0}.gb-site-link{display:inline-flex;align-items:center;min-height:36px;padding:8px 12px;border-radius:var(--gemboss-radius-md);color:var(--gemboss-text);font-size:var(--gemboss-fs-body);font-weight:500;line-height:20px;text-decoration:none;white-space:nowrap;transition:background-color var(--gemboss-transition-fast) ease,color var(--gemboss-transition-fast) ease}.gb-site-link:hover{background:var(--gemboss-hover);color:var(--gemboss-text-strong);text-decoration:none}.gb-site-link[aria-current=page]{color:var(--gemboss-text-strong);font-weight:600}.gb-site-link:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:2px}.gb-site-actions{display:flex;align-items:center;gap:4px;margin-left:auto}.gb-site-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;height:40px;padding:0 20px;border:1px solid transparent;border-radius:var(--gemboss-radius-md);font-family:var(--gemboss-font-sans);font-size:var(--gemboss-fs-body);font-weight:600;line-height:1;letter-spacing:0;text-decoration:none;white-space:nowrap;cursor:pointer;transition:transform var(--gemboss-transition-fast) ease,box-shadow var(--gemboss-transition-fast) ease,border-color var(--gemboss-transition-fast) ease}.gb-site-btn:hover{text-decoration:none}.gb-site-btn:focus-visible{outline:2px solid var(--gemboss-accent);outline-offset:2px}.gb-site-btn--primary{background:var(--gemboss-primary);color:var(--gemboss-on-primary)}.gb-site-btn--primary:hover{transform:translateY(-1px);box-shadow:var(--gemboss-shadow-resting)}.gb-site-btn--secondary{background:transparent;color:var(--gemboss-text-strong);border-color:var(--gemboss-chip-line)}.gb-site-btn--secondary:hover{border-color:var(--gemboss-text-strong)}.gb-site-header .gb-site-btn{height:36px;padding:0 16px;margin-left:8px}@media (pointer: coarse),(max-width: 768px){.gb-site-btn,.gb-site-header .gb-site-btn,.gb-site-link{min-height:44px}}@media (max-width: 900px){.gb-site-header__in{gap:12px;padding:0 16px}.gb-site-nav{display:none}}@media (max-width: 640px){.gb-site-header__in{width:100%;padding:0 12px}}@media (max-width: 380px){.gb-site-actions .gb-site-link{display:none}}.gb-site-footer{padding:64px 0 32px;border-top:1px solid var(--gemboss-divider);color:var(--gemboss-text-muted);font-size:var(--gemboss-fs-body)}.gb-site-footer__grid{display:grid;grid-template-columns:minmax(0,1.5fr) repeat(auto-fit,minmax(140px,1fr));gap:32px}.gb-site-footer__col h4{margin:0 0 12px;font-size:13px;font-weight:600;color:var(--gemboss-text-strong)}.gb-site-footer__col a{display:block;padding:6px 0;color:var(--gemboss-text-muted);line-height:20px;text-decoration:none}.gb-site-footer__col a:hover{color:var(--gemboss-text-strong)}.gb-site-footer__bottom{display:flex;flex-wrap:wrap;justify-content:space-between;gap:12px 24px;margin-top:32px;padding-top:24px;border-top:1px solid var(--gemboss-divider);font-size:13px}.gb-site-footer__bottom a{color:inherit;text-decoration:none}.gb-site-footer__bottom a:hover{color:var(--gemboss-text-strong)}@media (max-width: 560px){.gb-site-footer__grid{grid-template-columns:1fr}}
|
package/src/site.tsx
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The public site layer (0.40.0): the top bar and the lockup of a PUBLIC page (gemboss.ai, the docs, news, a product's
|
|
3
|
+
* home page), as opposed to an app surface (the admin, a portal behind sign-in), which keeps `Topbar` + `BrandLockup`.
|
|
4
|
+
*
|
|
5
|
+
* Why it exists (Chris 20/10/2026, "có gemboss ui thì có gemboss website ui"): every public page drew its own bar, and
|
|
6
|
+
* the same detail drifted across them. Measured 20/10/2026: the logo name was 18px on gemboss.ai and the docs, 16px on
|
|
7
|
+
* news, 13.3px on the community home; the bar 65 / 57 / 69 / 56px tall. Chris's call the same day: TWO lockup sizes,
|
|
8
|
+
* site 18px and app 13.3px. This module is the site size, plus the bar, its links and buttons, and the footer.
|
|
9
|
+
*
|
|
10
|
+
* The values are gemboss.ai's own (website/assets/styles.css): bar 64px with a 1132px column, name 18px/700 with the
|
|
11
|
+
* docs' tracking, nav links 14px/500, "Start free" 36px in the bar and 40px elsewhere, footer columns 13px headings and
|
|
12
|
+
* 14px links. A plain-HTML page writes the same markup and links site.css (README "The public site layer").
|
|
13
|
+
*
|
|
14
|
+
* `SiteBrand` draws the gem from brand-gem.tsx and NOT through BrandLockup: brand.tsx brings the ServiceSwitcher, whose
|
|
15
|
+
* panel names internal tools and their admin URLs, and a public page must not carry it.
|
|
16
|
+
*/
|
|
17
|
+
import React from "react";
|
|
18
|
+
import "./site.css";
|
|
19
|
+
import { BrandGem } from "./brand-gem";
|
|
20
|
+
|
|
21
|
+
type AnchorProps = React.AnchorHTMLAttributes<HTMLAnchorElement>;
|
|
22
|
+
const cx = (...c: (string | false | null | undefined)[]) => c.filter(Boolean).join(" ");
|
|
23
|
+
|
|
24
|
+
/** The lockup at the site size: the same gem as BrandLockup, the name at 18px. */
|
|
25
|
+
export function SiteBrand({ name, href = "/", label, className, ...rest }: { name: string; label?: string } & AnchorProps) {
|
|
26
|
+
return (
|
|
27
|
+
<a className={cx("gb-brand gb-brand--site", className)} href={href} aria-label={label ?? `${name} home`} {...rest}>
|
|
28
|
+
<BrandGem />
|
|
29
|
+
<span className="gb-brand-name">{name}</span>
|
|
30
|
+
</a>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The public site's top bar. `brand`: a `SiteBrand`. `nav`: links (`<a className="gb-site-link">`), hidden at ≤900px.
|
|
36
|
+
* `actions`: the right side, e.g. a "Sign in" `gb-site-link` and a `gb-site-btn gb-site-btn--primary`.
|
|
37
|
+
*/
|
|
38
|
+
export function SiteHeader({ brand, nav, navLabel = "Main", actions, className, children }:
|
|
39
|
+
{ brand: React.ReactNode; nav?: React.ReactNode; navLabel?: string; actions?: React.ReactNode; className?: string; children?: React.ReactNode }) {
|
|
40
|
+
return (
|
|
41
|
+
<header className={cx("gb-site-header", className)}>
|
|
42
|
+
<div className="gb-site-header__in">
|
|
43
|
+
{brand}
|
|
44
|
+
{nav ? <nav className="gb-site-nav" aria-label={navLabel}>{nav}</nav> : null}
|
|
45
|
+
{actions ? <div className="gb-site-actions">{actions}</div> : null}
|
|
46
|
+
{children}
|
|
47
|
+
</div>
|
|
48
|
+
</header>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The team chat's row rules, as plain data (no React, no DOM): which messages start a new turn, where a day separator
|
|
3
|
+
* goes, where the "New messages" line goes. GemCare's chat had these rules in `renderChatMessages`
|
|
4
|
+
* (public/assets/inbox.js); they live here so GemCare and GemCommunity break a conversation into turns the same way,
|
|
5
|
+
* and an upgrade to them happens in one place. The components (team-chat.tsx) only draw what this returns.
|
|
6
|
+
*
|
|
7
|
+
* The rules (GemCare origin/main, 20/10/2026):
|
|
8
|
+
* - A message is GROUPED under the one before it (no avatar, no name line) when the same person wrote both, on the same
|
|
9
|
+
* day, less than 5 minutes apart, and it is not a reply (a reply starts a turn of its own: it answers someone else).
|
|
10
|
+
* - A day separator comes before the first message and before the first message of each new day (local time of the
|
|
11
|
+
* viewer). A new day also breaks a group: two lines either side of midnight are two turns.
|
|
12
|
+
* - The "New messages" line comes before the first message someone ELSE wrote that the viewer has not read. The
|
|
13
|
+
* viewer's own messages after the mark are not "new". The line also breaks a group, so the first new message
|
|
14
|
+
* always shows who wrote it.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export type ChatRowMessage = {
|
|
18
|
+
id: string | number;
|
|
19
|
+
/** Who wrote it. Null/undefined: someone who has left (never grouped). */
|
|
20
|
+
authorId?: string | number | null;
|
|
21
|
+
/** When it was written: an ISO string, epoch ms, or a Date. */
|
|
22
|
+
at: string | number | Date;
|
|
23
|
+
/** The message it answers, if any. A reply is never grouped. */
|
|
24
|
+
replyToId?: string | number | null;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type ChatRow<M> =
|
|
28
|
+
| { kind: "day"; key: string; date: Date }
|
|
29
|
+
| { kind: "new" }
|
|
30
|
+
| { kind: "message"; message: M; grouped: boolean };
|
|
31
|
+
|
|
32
|
+
export type ChatRowOptions<M> = {
|
|
33
|
+
/** The viewer: their own messages never get the "New messages" line. */
|
|
34
|
+
meId?: string | number | null;
|
|
35
|
+
/** True for a message the viewer has not read yet (e.g. `m.id > readUpTo`). No predicate, no line. */
|
|
36
|
+
isUnread?: (message: M) => boolean;
|
|
37
|
+
/** Messages closer than this are one turn. Default 5 minutes, as GemCare. */
|
|
38
|
+
groupWithinMs?: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const toDate = (at: string | number | Date) => (at instanceof Date ? at : new Date(at));
|
|
42
|
+
|
|
43
|
+
/** The viewer's local calendar day, as a key: two dates with the same key are the same day. */
|
|
44
|
+
export function chatDayKey(at: string | number | Date): string {
|
|
45
|
+
const d = toDate(at);
|
|
46
|
+
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** "Today", "Yesterday", or null (the caller formats older days with its own locale, e.g. "Mon, Sep 28"). */
|
|
50
|
+
export function chatDayWord(at: string | number | Date, now: Date = new Date()): "Today" | "Yesterday" | null {
|
|
51
|
+
const key = chatDayKey(at);
|
|
52
|
+
if (key === chatDayKey(now)) return "Today";
|
|
53
|
+
const y = new Date(now);
|
|
54
|
+
y.setDate(y.getDate() - 1);
|
|
55
|
+
return key === chatDayKey(y) ? "Yesterday" : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The rows to draw, in order: day separators, the "New messages" line, and each message with its `grouped` flag. */
|
|
59
|
+
export function teamChatRows<M extends ChatRowMessage>(messages: readonly M[], opts: ChatRowOptions<M> = {}): ChatRow<M>[] {
|
|
60
|
+
const within = opts.groupWithinMs ?? 5 * 60 * 1000;
|
|
61
|
+
const firstNew = opts.isUnread
|
|
62
|
+
? messages.findIndex((m) => opts.isUnread!(m) && (opts.meId == null || m.authorId !== opts.meId))
|
|
63
|
+
: -1;
|
|
64
|
+
const rows: ChatRow<M>[] = [];
|
|
65
|
+
messages.forEach((m, i) => {
|
|
66
|
+
const prev = i > 0 ? messages[i - 1] : undefined;
|
|
67
|
+
const at = toDate(m.at);
|
|
68
|
+
const newDay = !prev || chatDayKey(prev.at) !== chatDayKey(at);
|
|
69
|
+
if (newDay) rows.push({ kind: "day", key: chatDayKey(at), date: at });
|
|
70
|
+
const isFirstNew = i === firstNew;
|
|
71
|
+
if (isFirstNew) rows.push({ kind: "new" });
|
|
72
|
+
const grouped = Boolean(
|
|
73
|
+
prev && !newDay && !isFirstNew && m.authorId != null && prev.authorId === m.authorId && m.replyToId == null
|
|
74
|
+
&& at.getTime() - toDate(prev.at).getTime() < within,
|
|
75
|
+
);
|
|
76
|
+
rows.push({ kind: "message", message: m, grouped });
|
|
77
|
+
});
|
|
78
|
+
return rows;
|
|
79
|
+
}
|