domma-cms 1.6.15 → 1.6.17
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/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/js/app.js +1 -1
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +2 -2
- package/admin/js/lib/layouts-arrange.js +1 -1
- package/admin/js/lib/page-editor-reference.js +3 -3
- package/admin/js/lib/project-page-arrange.js +1 -1
- package/admin/js/lib/scribe-composer.js +1 -4
- package/admin/js/lib/scribe-model.js +4 -0
- package/admin/js/lib/sidebar-grouping.js +1 -1
- package/admin/js/lib/sidebar-renderer.js +2 -2
- package/admin/js/templates/docs/usage-navigation.html +4 -2
- package/admin/js/templates/effects.html +10 -4
- package/admin/js/templates/layouts.html +1 -1
- package/admin/js/views/layouts.js +8 -8
- package/package.json +2 -2
- package/public/css/site.css +1 -1
- package/public/js/effects.js +1 -1
- package/server/services/markdown.js +12 -6
- package/server/services/permissionRegistry.js +1 -1
- package/server/services/sidebar-migration.js +14 -1
- package/server/templates/page.html +2 -2
|
@@ -1,4 +1 @@
|
|
|
1
|
-
import{insertAtCursor as se}from"./markdown-toolbar.js";const le=20,V={render:{label:"Render",icon:"edit-3",color:"var(--dm-info,#3b82f6)"},wait:{label:"Wait",icon:"clock",color:"var(--dm-warning,#f59e0b)"},undo:{label:"Undo",icon:"corner-up-left",color:"var(--dm-secondary,#a855f7)"},redraw:{label:"Redraw",icon:"refresh-cw",color:"var(--dm-success,#22c55e)"}},T="padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;box-sizing:border-box;width:100%;",ce="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem;",ae="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.85em;";export function openScribeComposer(n){const r=de(),e=[];let o=null;const u=E.slideover({title:"Scribe Composer",size:"lg",position:"right"});be();const b=document.createElement("div");b.className="scribe-composer",b.style.cssText="display:flex;flex-direction:column;height:100%;";const y=document.createElement("div");y.style.cssText="padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);";const g=document.createElement("div");g.style.cssText="min-height:3.5rem;padding:.85rem 1rem;background:var(--dm-surface,#1a1a1a);border:1px dashed var(--dm-border,#333);border-radius:6px;font-size:1.25rem;line-height:1.5;overflow-wrap:anywhere;",y.appendChild(g);const w=document.createElement("div");w.style.cssText="display:flex;gap:.5rem;margin-top:.75rem;align-items:center;";const $=ee("rotate-cw","Replay"),B=ee("code","Show code"),k=document.createElement("span");k.style.cssText="font-size:.8em;color:var(--dm-text-muted,#aaa);flex:1;text-align:right;margin-right:.5rem;",w.appendChild($),w.appendChild(k),w.appendChild(B),y.appendChild(w);const p=document.createElement("pre");p.style.cssText="display:none;margin:.75rem 0 0;padding:.6rem .75rem;background:var(--dm-surface,#0a0a0a);border:1px solid var(--dm-border,#333);border-radius:4px;font-family:monospace;font-size:.78em;white-space:pre-wrap;word-break:break-all;color:var(--dm-text-muted,#bbb);max-height:200px;overflow:auto;",y.appendChild(p),B.addEventListener("click",()=>{const t=p.style.display!=="none";p.style.display=t?"none":"block"}),$.addEventListener("click",()=>X()),b.appendChild(y);const R=document.createElement("div");R.style.cssText="display:flex;flex:1;min-height:0;overflow:hidden;";const F=ue(r,()=>{v(),x()});R.appendChild(F.el);const M=document.createElement("main");M.style.cssText="flex:1;overflow-y:auto;padding:1rem 1.25rem;display:flex;flex-direction:column;";const W=document.createElement("h4");W.textContent="Actions",W.style.cssText="margin:0 0 .75rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",M.appendChild(W);const z=document.createElement("div");z.style.cssText="display:flex;flex-direction:column;gap:.6rem;",M.appendChild(z);const H=document.createElement("div");H.style.cssText="display:flex;gap:.4rem;margin-top:.9rem;flex-wrap:wrap;",Object.entries(V).forEach(([t,s])=>{const l=document.createElement("button");l.type="button",l.style.cssText=`padding:.4rem .8rem;background:transparent;border:1px dashed color-mix(in srgb, ${s.color} 40%, transparent);border-radius:4px;color:${s.color};cursor:pointer;font-size:.85em;display:inline-flex;align-items:center;gap:.35rem;`;const d=document.createElement("span");d.setAttribute("data-icon",s.icon),l.appendChild(d),l.appendChild(document.createTextNode(` + ${s.label}`)),l.addEventListener("click",()=>{v(),r.actions.push(ie(t)),j(),x()}),H.appendChild(l)}),M.appendChild(H),R.appendChild(M),b.appendChild(R);const L=document.createElement("div");L.style.cssText="display:flex;padding:.75rem 1rem;border-top:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);gap:.5rem;align-items:center;";const S=document.createElement("button");S.type="button",S.className="btn btn-ghost btn-sm",S.textContent="Undo (Ctrl+Z)",S.addEventListener("click",()=>J()),L.appendChild(S);const U=document.createElement("span");U.style.cssText="font-size:.75em;color:var(--dm-text-muted,#aaa);",L.appendChild(U);const G=document.createElement("div");G.style.flex="1",L.appendChild(G);const A=document.createElement("button");A.type="button",A.className="btn btn-ghost",A.textContent="Cancel",A.addEventListener("click",()=>u.close()),L.appendChild(A);const D=document.createElement("button");D.type="button",D.className="btn btn-primary",D.textContent="Insert Scribe",D.addEventListener("click",()=>{se(n,Q()),u.close()}),L.appendChild(D),b.appendChild(L),u.setContent(b),b.addEventListener("keydown",t=>{const s=(t.key||"").toLowerCase();(t.ctrlKey||t.metaKey)&&s==="z"&&!t.shiftKey&&e.length>0&&(t.preventDefault(),t.stopPropagation(),J())}),j(),x(),P(),requestAnimationFrame(()=>{Domma.icons.scan()}),u.open();function v(){e.push(JSON.stringify(r)),e.length>le&&e.shift(),P()}function J(){if(e.length===0){E.toast("Nothing to undo",{type:"info",duration:700});return}const t=JSON.parse(e.pop());Object.assign(r.globals,t.globals),r.actions.length=0,t.actions.forEach(s=>r.actions.push(s)),F.sync(),j(),x(),P(),E.toast("Undone",{type:"info",duration:500})}function P(){U.textContent=e.length===0?"":`${e.length} step${e.length===1?"":"s"} stored`,S.disabled=e.length===0,S.style.opacity=e.length===0?".4":"1"}function x(t=150){clearTimeout(o),o=setTimeout(X,t)}function X(){te(g),g.style.color="",g.style.fontStyle="",p.textContent=Q();const t=r.actions.filter(c=>c.type==="render"||c.type==="redraw"?(c.text||"").length>0:!0);if(t.length===0){g.textContent="(add an action to preview)",g.style.color="var(--dm-text-muted,#666)",g.style.fontStyle="italic",k.textContent="";return}const s=document.createElement("span");s.className="dm-fx-scribe",g.appendChild(s);const l=r.globals,d={speed:l.speed,deleteSpeed:l.deleteSpeed,cursor:l.cursor,cursorType:l.cursorType,loop:l.loop,loopDelay:l.loopDelay,pauseOnHover:l.pauseOnHover,actions:pe(t)};l.cursorChar&&(d.cursorChar=l.cursorChar);try{E.scribe(s,d),k.textContent=`${t.length} action${t.length===1?"":"s"}`}catch{k.textContent="Preview error"}}function j(){if(te(z),r.actions.length===0){const t=document.createElement("p");t.textContent="No actions yet - add one from the buttons below.",t.style.cssText="font-size:.85em;color:var(--dm-text-muted,#888);font-style:italic;margin:.5rem 0;",z.appendChild(t);return}r.actions.forEach((t,s)=>{z.appendChild(oe(t,s))}),requestAnimationFrame(()=>Domma.icons.scan())}function oe(t,s){const l=V[t.type],d=document.createElement("div");d.style.cssText=`border:1px solid var(--dm-border,#333);border-left:3px solid ${l.color};border-radius:4px;padding:.6rem .75rem;background:var(--dm-surface,#15151a);`;const c=document.createElement("div");c.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const N=document.createElement("span");N.style.cssText=`display:inline-flex;align-items:center;gap:.3rem;font-size:.72rem;font-weight:700;color:${l.color};text-transform:uppercase;letter-spacing:.06em;`;const a=document.createElement("span");a.setAttribute("data-icon",l.icon),N.appendChild(a),N.appendChild(document.createTextNode(l.label)),c.appendChild(N);const f=document.createElement("span");f.textContent=`#${s+1}`,f.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);",c.appendChild(f);const m=document.createElement("div");m.style.flex="1",c.appendChild(m);const i=q("chevron-up","Move up");s===0&&(i.disabled=!0,i.style.opacity=".3"),i.addEventListener("click",()=>Z(s,-1)),c.appendChild(i);const h=q("chevron-down","Move down");s===r.actions.length-1&&(h.disabled=!0,h.style.opacity=".3"),h.addEventListener("click",()=>Z(s,1)),c.appendChild(h);const C=q("x","Remove");return C.addEventListener("click",()=>{v(),r.actions.splice(s,1),j(),x()}),c.appendChild(C),d.appendChild(c),d.appendChild(re(t)),d}function Z(t,s){const l=t+s;if(l<0||l>=r.actions.length)return;v();const[d]=r.actions.splice(t,1);r.actions.splice(l,0,d),j(),x()}function re(t){const s=document.createElement("div");if(s.style.cssText="display:flex;flex-direction:column;gap:.5rem;",t.type==="render"||t.type==="redraw"){const a=document.createElement("textarea");a.value=t.text||"",a.placeholder=t.type==="redraw"?"New text - clears everything first, then types this":"Text to type out",a.rows=2,a.style.cssText=T+"resize:vertical;font-family:inherit;min-height:2.2rem;";let f=a.value;a.addEventListener("input",()=>{t.text=a.value,x()}),a.addEventListener("blur",()=>{a.value!==f&&(v(),f=a.value)}),s.appendChild(a);const m=document.createElement("div");m.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8em;";const i=document.createElement("label");i.textContent="Effect:",i.style.color="var(--dm-text-muted,#aaa)";const h=document.createElement("select");return h.style.cssText=T+"width:auto;padding:.25rem .4rem;",["none","fade","bounce","glow"].forEach(C=>{const _=document.createElement("option");_.value=C,_.textContent=C.charAt(0).toUpperCase()+C.slice(1),h.appendChild(_)}),h.value=t.effect||"none",h.addEventListener("change",()=>{v(),t.effect=h.value,x()}),m.appendChild(i),m.appendChild(h),s.appendChild(m),s}if(t.type==="wait"){const a=document.createElement("div");a.style.cssText="display:flex;gap:.4rem;align-items:center;";const f=document.createElement("input");f.type="number",f.min="0",f.value=String(t.duration??1e3),f.style.cssText=T+"flex:1;",f.addEventListener("input",()=>{const i=parseInt(f.value,10);!Number.isNaN(i)&&i>=0&&(t.duration=i,x())}),f.addEventListener("blur",()=>v()),a.appendChild(f);const m=document.createElement("select");return m.style.cssText=T+"width:auto;",[["ms","ms"],["s","seconds"]].forEach(([i,h])=>{const C=document.createElement("option");C.value=i,C.textContent=h,m.appendChild(C)}),m.value=t.unit||"ms",m.addEventListener("change",()=>{v(),t.unit=m.value,x()}),a.appendChild(m),s.appendChild(a),s}const l=document.createElement("div");l.style.cssText="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap;font-size:.85em;";const d=document.createElement("input");d.type="number",d.min="1",d.value=String(t.count||5),d.style.cssText=T+"width:5rem;",d.addEventListener("input",()=>{const a=parseInt(d.value,10);!Number.isNaN(a)&&a>0&&(t.count=a,x())}),d.addEventListener("blur",()=>v());const c=`undo-mode-${Math.random().toString(36).slice(2)}`;return[["last","Last render"],["all","All text"],["count","Exactly N chars"]].forEach(([a,f])=>{const m=document.createElement("label");m.style.cssText="display:inline-flex;align-items:center;gap:.3rem;cursor:pointer;";const i=document.createElement("input");i.type="radio",i.name=c,i.value=a,i.checked=(t.mode||"last")===a,i.addEventListener("change",()=>{i.checked&&(v(),t.mode=a,d.style.display=a==="count"?"":"none",x())}),m.appendChild(i),m.appendChild(document.createTextNode(f)),l.appendChild(m),a==="count"&&(l.appendChild(d),d.style.display=(t.mode||"last")==="count"?"":"none")}),s.appendChild(l),s}function Q(){const t=r.globals,s=[];t.speed!==50&&s.push(`speed="${t.speed}"`),t.deleteSpeed!==30&&s.push(`delete-speed="${t.deleteSpeed}"`),t.cursor?(t.cursorType!=="caret"&&s.push(`cursor-type="${t.cursorType}"`),t.cursorChar&&s.push(`cursor-char="${he(t.cursorChar)}"`)):s.push('cursor="false"'),t.loop&&(s.push('loop="true"'),t.loopDelay!==1e3&&s.push(`loop-delay="${t.loopDelay}"`)),t.pauseOnHover&&s.push('pause-on-hover="true"');const l=s.length?" "+s.join(" "):"",d=r.actions.map(c=>c.type==="render"?`[render${c.effect&&c.effect!=="none"?` effect="${c.effect}"`:""}]${c.text||""}[/render]`:c.type==="redraw"?`[redraw${c.effect&&c.effect!=="none"?` effect="${c.effect}"`:""}]${c.text||""}[/redraw]`:c.type==="wait"?`[wait]${c.duration}${c.unit==="s"?"s":""}[/wait]`:c.mode==="all"?'[undo all="true" /]':c.mode==="count"?`[undo count="${c.count}" /]`:"[undo /]");return`[scribe${l}]
|
|
2
|
-
${d.join(`
|
|
3
|
-
`)}
|
|
4
|
-
[/scribe]`}}function de(){return{globals:{speed:50,deleteSpeed:30,cursor:!0,cursorType:"caret",cursorChar:"",loop:!1,loopDelay:1e3,pauseOnHover:!1},actions:[{type:"render",text:"We build things that matter.",effect:"none"},{type:"wait",duration:1500,unit:"ms"},{type:"redraw",text:"We create solutions that last.",effect:"none"},{type:"wait",duration:1500,unit:"ms"}]}}function ie(n){switch(n){case"render":return{type:"render",text:"",effect:"none"};case"wait":return{type:"wait",duration:1e3,unit:"ms"};case"undo":return{type:"undo",mode:"last",count:5};case"redraw":return{type:"redraw",text:"",effect:"none"}}return{type:"render",text:"",effect:"none"}}function pe(n){const r=[];return n.forEach(e=>{if(e.type==="render"){const o={render:e.text||""};e.effect&&e.effect!=="none"&&(o.effect=e.effect),r.push(o)}else if(e.type==="redraw"){r.push({undoRender:"all"});const o={render:e.text||""};e.effect&&e.effect!=="none"&&(o.effect=e.effect),r.push(o)}else e.type==="wait"?r.push({wait:e.unit==="s"?(e.duration||0)*1e3:e.duration||0}):e.type==="undo"&&(e.mode==="all"?r.push({undoRender:"all"}):e.mode==="count"?r.push({undoRender:e.count}):r.push({undoRender:!0}))}),r}function ue(n,r){const e=document.createElement("aside");e.style.cssText="width:240px;flex-shrink:0;padding:1rem 1.25rem;border-right:1px solid var(--dm-border,#333);overflow-y:auto;display:flex;flex-direction:column;gap:.75rem;background:var(--dm-background-alt,#0c0c12);";const o=document.createElement("h4");o.textContent="Global settings",o.style.cssText="margin:0 0 .25rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",e.appendChild(o);const u=K(n.globals.speed,p=>{n.globals.speed=p,r()}),b=K(n.globals.deleteSpeed,p=>{n.globals.deleteSpeed=p,r()}),y=Y(n.globals.cursor,p=>{n.globals.cursor=p,r()},"Show cursor"),g=fe([["caret","Caret (|)"],["block","Block (\u2588)"],["underline","Underline (_)"]],n.globals.cursorType,p=>{n.globals.cursorType=p,r()}),w=me(n.globals.cursorChar,"\u258C (optional override)",p=>{n.globals.cursorChar=p,r()}),$=Y(n.globals.loop,p=>{n.globals.loop=p,r()},"Loop forever"),B=K(n.globals.loopDelay,p=>{n.globals.loopDelay=p,r()},0),k=Y(n.globals.pauseOnHover,p=>{n.globals.pauseOnHover=p,r()},"Pause on hover");return e.appendChild(O("Speed (ms / char)",u)),e.appendChild(O("Delete speed (ms / char)",b)),e.appendChild(y.wrap),e.appendChild(O("Cursor style",g)),e.appendChild(O("Custom cursor char",w)),e.appendChild($.wrap),e.appendChild(O("Loop delay (ms)",B)),e.appendChild(k.wrap),{el:e,sync(){u.value=String(n.globals.speed),b.value=String(n.globals.deleteSpeed),y.input.checked=n.globals.cursor,g.value=n.globals.cursorType,w.value=n.globals.cursorChar,$.input.checked=n.globals.loop,B.value=String(n.globals.loopDelay),k.input.checked=n.globals.pauseOnHover}}}function O(n,r){const e=document.createElement("div"),o=document.createElement("label");return o.style.cssText=ce,o.textContent=n,e.appendChild(o),e.appendChild(r),e}function K(n,r,e=1){const o=document.createElement("input");return o.type="number",o.min=String(e),o.value=String(n),o.style.cssText=T,o.addEventListener("input",()=>{const u=parseInt(o.value,10);!Number.isNaN(u)&&u>=e&&r(u)}),o}function me(n,r,e){const o=document.createElement("input");return o.type="text",o.value=n,o.placeholder=r,o.style.cssText=T,o.addEventListener("input",()=>e(o.value)),o}function fe(n,r,e){const o=document.createElement("select");return o.style.cssText=T,n.forEach(([u,b])=>{const y=document.createElement("option");y.value=u,y.textContent=b,o.appendChild(y)}),o.value=r,o.addEventListener("change",()=>e(o.value)),o}function Y(n,r,e){const o=document.createElement("label");o.style.cssText=ae;const u=document.createElement("input");return u.type="checkbox",u.checked=n,u.addEventListener("change",()=>r(u.checked)),o.appendChild(u),o.appendChild(document.createTextNode(e)),{wrap:o,input:u}}function ee(n,r){const e=document.createElement("button");e.type="button",e.className="btn btn-ghost btn-sm",e.style.cssText="display:inline-flex;align-items:center;gap:.35rem;";const o=document.createElement("span");return o.setAttribute("data-icon",n),e.appendChild(o),e.appendChild(document.createTextNode(r)),e}function q(n,r){const e=document.createElement("button");e.type="button",e.title=r,e.style.cssText="padding:.25rem .4rem;background:transparent;border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text-muted,#aaa);cursor:pointer;display:inline-flex;align-items:center;";const o=document.createElement("span");return o.setAttribute("data-icon",n),e.appendChild(o),e}function te(n){for(;n.firstChild;)n.removeChild(n.firstChild)}function he(n){return String(n).replace(/&/g,"&").replace(/"/g,""")}let ne=!1;function be(){ne||(ne=!0,I.register("edit-3",{viewBox:"0 0 24 24",paths:["M12 20h9","M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("clock",{viewBox:"0 0 24 24",paths:["M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z","M12 6v6l4 2"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("corner-up-left",{viewBox:"0 0 24 24",paths:["M9 14 4 9l5-5","M20 20v-7a4 4 0 0 0-4-4H4"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("refresh-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M1 20v-6h6","M3.51 9a9 9 0 0 1 14.85-3.36L23 10","M20.49 15a9 9 0 0 1-14.85 3.36L1 14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("rotate-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M20.49 15a9 9 0 1 1-2.12-9.36L23 10"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("code",{viewBox:"0 0 24 24",paths:["M16 18l6-6-6-6","M8 6l-6 6 6 6"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-up",{viewBox:"0 0 24 24",path:"M18 15l-6-6-6 6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-down",{viewBox:"0 0 24 24",path:"M6 9l6 6 6-6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("x",{viewBox:"0 0 24 24",paths:["M18 6L6 18","M6 6l12 12"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}
|
|
1
|
+
import{insertAtCursor as re}from"./markdown-toolbar.js";import{SCRIBE_FIELDS as ae,scribeDefaults as se,scribeLoop as ce,stateToScribeActions as ie,buildScribeShortcode as le}from"./scribe-model.js";const de=20,Q={render:{label:"Render",icon:"edit-3",color:"var(--dm-info,#3b82f6)"},wait:{label:"Wait",icon:"clock",color:"var(--dm-warning,#f59e0b)"},undo:{label:"Undo",icon:"corner-up-left",color:"var(--dm-secondary,#a855f7)"},redraw:{label:"Redraw",icon:"refresh-cw",color:"var(--dm-success,#22c55e)"}},L="padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;box-sizing:border-box;width:100%;",pe="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem;",ue="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.85em;";export function openScribeComposer(s){const r=me(),n=[];let t=null,p=null;function c(){clearTimeout(t),p?.destroy(),p=null}const h=E.slideover({title:"Scribe Composer",size:"lg",position:"right",onClose:c});Ce();const b=document.createElement("div");b.className="scribe-composer",b.style.cssText="display:flex;flex-direction:column;height:100%;";const y=document.createElement("div");y.style.cssText="padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);";const k=document.createElement("div");k.style.cssText="min-height:3.5rem;padding:.85rem 1rem;background:var(--dm-surface,#1a1a1a);border:1px dashed var(--dm-border,#333);border-radius:6px;font-size:1.25rem;line-height:1.5;overflow-wrap:anywhere;",y.appendChild(k);const B=document.createElement("div");B.style.cssText="display:flex;gap:.5rem;margin-top:.75rem;align-items:center;";const Y=V("rotate-cw","Replay"),q=V("code","Show code"),N=document.createElement("span");N.style.cssText="font-size:.8em;color:var(--dm-text-muted,#aaa);flex:1;text-align:right;margin-right:.5rem;",B.appendChild(Y),B.appendChild(N),B.appendChild(q),y.appendChild(B);const M=document.createElement("pre");M.style.cssText="display:none;margin:.75rem 0 0;padding:.6rem .75rem;background:var(--dm-surface,#0a0a0a);border:1px solid var(--dm-border,#333);border-radius:4px;font-family:monospace;font-size:.78em;white-space:pre-wrap;word-break:break-all;color:var(--dm-text-muted,#bbb);max-height:200px;overflow:auto;",y.appendChild(M),q.addEventListener("click",()=>{const e=M.style.display!=="none";M.style.display=e?"none":"block"}),Y.addEventListener("click",()=>{J(),p?.resume(),p&&(N.textContent="Playing preview")}),b.appendChild(y);const R=document.createElement("div");R.style.cssText="display:flex;flex:1;min-height:0;overflow:hidden;";const F=fe(r,()=>{C(),x()});R.appendChild(F.el);const z=document.createElement("main");z.style.cssText="flex:1;overflow-y:auto;padding:1rem 1.25rem;display:flex;flex-direction:column;";const D=document.createElement("h4");D.textContent="Actions",D.style.cssText="margin:0 0 .75rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",z.appendChild(D);const A=document.createElement("div");A.style.cssText="display:flex;flex-direction:column;gap:.6rem;",z.appendChild(A);const P=document.createElement("div");P.style.cssText="display:flex;gap:.4rem;margin-top:.9rem;flex-wrap:wrap;",Object.entries(Q).forEach(([e,a])=>{const i=document.createElement("button");i.type="button",i.style.cssText=`padding:.4rem .8rem;background:transparent;border:1px dashed color-mix(in srgb, ${a.color} 40%, transparent);border-radius:4px;color:${a.color};cursor:pointer;font-size:.85em;display:inline-flex;align-items:center;gap:.35rem;`;const l=document.createElement("span");l.setAttribute("data-icon",a.icon),i.appendChild(l),i.appendChild(document.createTextNode(` + ${a.label}`)),i.addEventListener("click",()=>{C(),r.actions.push(he(e)),$(),x()}),P.appendChild(i)}),z.appendChild(P),R.appendChild(z),b.appendChild(R);const T=document.createElement("div");T.style.cssText="display:flex;padding:.75rem 1rem;border-top:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);gap:.5rem;align-items:center;";const S=document.createElement("button");S.type="button",S.className="btn btn-ghost btn-sm",S.textContent="Undo (Ctrl+Z)",S.addEventListener("click",()=>H()),T.appendChild(S);const U=document.createElement("span");U.style.cssText="font-size:.75em;color:var(--dm-text-muted,#aaa);",T.appendChild(U);const G=document.createElement("div");G.style.flex="1",T.appendChild(G);const W=document.createElement("button");W.type="button",W.className="btn btn-ghost",W.textContent="Cancel",W.addEventListener("click",()=>h.close()),T.appendChild(W);const j=document.createElement("button");j.type="button",j.className="btn btn-primary",j.textContent="Insert Scribe",j.addEventListener("click",()=>{re(s,Z()),h.close()}),T.appendChild(j),b.appendChild(T),h.setContent(b),b.addEventListener("keydown",e=>{const a=(e.key||"").toLowerCase();(e.ctrlKey||e.metaKey)&&a==="z"&&!e.shiftKey&&n.length>0&&(e.preventDefault(),e.stopPropagation(),H())}),$(),x(),O(),requestAnimationFrame(()=>{Domma.icons.scan()}),h.open();function C(){n.push(JSON.stringify(r)),n.length>de&&n.shift(),O()}function H(){if(n.length===0){E.toast("Nothing to undo",{type:"info",duration:700});return}const e=JSON.parse(n.pop());Object.assign(r.globals,e.globals),r.actions.length=0,e.actions.forEach(a=>r.actions.push(a)),F.sync(),$(),x(),O(),E.toast("Undone",{type:"info",duration:500})}function O(){U.textContent=n.length===0?"":`${n.length} step${n.length===1?"":"s"} stored`,S.disabled=n.length===0,S.style.opacity=n.length===0?".4":"1"}function x(e=150){clearTimeout(t),t=setTimeout(J,e)}function J(){c(),ee(k),k.style.color="",k.style.fontStyle="",M.textContent=Z();const e=r.actions.filter(o=>o.type==="render"||o.type==="redraw"?(o.text||"").length>0:!0);if(e.length===0){k.textContent="(add an action to preview)",k.style.color="var(--dm-text-muted,#666)",k.style.fontStyle="italic",N.textContent="";return}const a=document.createElement("span");a.className="dm-fx-scribe",k.appendChild(a);const i=r.globals,{effect:l,controls:g,...w}=i;w.actions=ie(e,l);try{p=Domma.effects.scribe(a,w),N.textContent=i.autoStart?`${e.length} action${e.length===1?"":"s"}`:"Press Replay to start"}catch{N.textContent="Preview error"}}function $(){if(ee(A),r.actions.length===0){const e=document.createElement("p");e.textContent="No actions yet - add one from the buttons below.",e.style.cssText="font-size:.85em;color:var(--dm-text-muted,#888);font-style:italic;margin:.5rem 0;",A.appendChild(e);return}r.actions.forEach((e,a)=>{A.appendChild(ne(e,a))}),requestAnimationFrame(()=>Domma.icons.scan())}function ne(e,a){const i=Q[e.type],l=document.createElement("div");l.style.cssText=`border:1px solid var(--dm-border,#333);border-left:3px solid ${i.color};border-radius:4px;padding:.6rem .75rem;background:var(--dm-surface,#15151a);`;const g=document.createElement("div");g.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const w=document.createElement("span");w.style.cssText=`display:inline-flex;align-items:center;gap:.3rem;font-size:.72rem;font-weight:700;color:${i.color};text-transform:uppercase;letter-spacing:.06em;`;const o=document.createElement("span");o.setAttribute("data-icon",i.icon),w.appendChild(o),w.appendChild(document.createTextNode(i.label)),g.appendChild(w);const m=document.createElement("span");m.textContent=`#${a+1}`,m.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);",g.appendChild(m);const u=document.createElement("div");u.style.flex="1",g.appendChild(u);const d=K("chevron-up","Move up");a===0&&(d.disabled=!0,d.style.opacity=".3"),d.addEventListener("click",()=>X(a,-1)),g.appendChild(d);const f=K("chevron-down","Move down");a===r.actions.length-1&&(f.disabled=!0,f.style.opacity=".3"),f.addEventListener("click",()=>X(a,1)),g.appendChild(f);const v=K("x","Remove");return v.addEventListener("click",()=>{C(),r.actions.splice(a,1),$(),x()}),g.appendChild(v),l.appendChild(g),l.appendChild(oe(e)),l}function X(e,a){const i=e+a;if(i<0||i>=r.actions.length)return;C();const[l]=r.actions.splice(e,1);r.actions.splice(i,0,l),$(),x()}function oe(e){const a=document.createElement("div");if(a.style.cssText="display:flex;flex-direction:column;gap:.5rem;",e.type==="render"||e.type==="redraw"){const o=document.createElement("textarea");o.value=e.text||"",o.placeholder=e.type==="redraw"?"New text - clears everything first, then types this":"Text to type out",o.rows=2,o.style.cssText=L+"resize:vertical;font-family:inherit;min-height:2.2rem;";let m=o.value;o.addEventListener("input",()=>{e.text=o.value,x()}),o.addEventListener("blur",()=>{o.value!==m&&(C(),m=o.value)}),a.appendChild(o);const u=document.createElement("div");u.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8em;";const d=document.createElement("label");d.textContent="Effect:",d.style.color="var(--dm-text-muted,#aaa)";const f=document.createElement("select");return f.style.cssText=L+"width:auto;padding:.25rem .4rem;",["inherit","none","fade","bounce","glow"].forEach(v=>{const _=document.createElement("option");_.value=v,_.textContent=v==="inherit"?"Default effect":v.charAt(0).toUpperCase()+v.slice(1),f.appendChild(_)}),f.value=e.effect||"none",f.addEventListener("change",()=>{C(),e.effect=f.value,x()}),u.appendChild(d),u.appendChild(f),a.appendChild(u),a}if(e.type==="wait"){const o=document.createElement("div");o.style.cssText="display:flex;gap:.4rem;align-items:center;";const m=document.createElement("input");m.type="number",m.min="0",m.step="any",m.value=String(e.duration??1e3),m.style.cssText=L+"flex:1;",m.addEventListener("input",()=>{const d=Number(m.value);!Number.isNaN(d)&&d>=0&&(e.duration=d,x())}),m.addEventListener("blur",()=>C()),o.appendChild(m);const u=document.createElement("select");return u.style.cssText=L+"width:auto;",[["ms","ms"],["s","seconds"]].forEach(([d,f])=>{const v=document.createElement("option");v.value=d,v.textContent=f,u.appendChild(v)}),u.value=e.unit||"ms",u.addEventListener("change",()=>{C(),e.unit=u.value,x()}),o.appendChild(u),a.appendChild(o),a}const i=document.createElement("div");i.style.cssText="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap;font-size:.85em;";const l=document.createElement("input");l.type="number",l.min="1",l.value=String(e.count||5),l.style.cssText=L+"width:5rem;",l.addEventListener("input",()=>{const o=parseInt(l.value,10);!Number.isNaN(o)&&o>0&&(e.count=o,x())}),l.addEventListener("blur",()=>C());const g=`undo-mode-${Math.random().toString(36).slice(2)}`;return[["last","Last render"],["all","All text"],["count","Exactly N units"]].forEach(([o,m])=>{const u=document.createElement("label");u.style.cssText="display:inline-flex;align-items:center;gap:.3rem;cursor:pointer;";const d=document.createElement("input");d.type="radio",d.name=g,d.value=o,d.checked=(e.mode||"last")===o,d.addEventListener("change",()=>{d.checked&&(C(),e.mode=o,l.style.display=o==="count"?"":"none",x())}),u.appendChild(d),u.appendChild(document.createTextNode(m)),i.appendChild(u),o==="count"&&(i.appendChild(l),l.style.display=(e.mode||"last")==="count"?"":"none")}),a.appendChild(i),a}function Z(){return le(r.globals,r.actions)}}function me(){return{globals:se(),actions:[{type:"render",text:"We build things that matter.",effect:"inherit"},{type:"wait",duration:1500,unit:"ms"},{type:"redraw",text:"We create solutions that last.",effect:"inherit"},{type:"wait",duration:1500,unit:"ms"}]}}function he(s){switch(s){case"render":return{type:"render",text:"",effect:"inherit"};case"wait":return{type:"wait",duration:1e3,unit:"ms"};case"undo":return{type:"undo",mode:"last",count:5};case"redraw":return{type:"redraw",text:"",effect:"inherit"}}return{type:"render",text:"",effect:"inherit"}}function fe(s,r){const n=document.createElement("aside");n.style.cssText="width:240px;flex-shrink:0;padding:1rem 1.25rem;border-right:1px solid var(--dm-border,#333);overflow-y:auto;display:flex;flex-direction:column;gap:.75rem;background:var(--dm-background-alt,#0c0c12);";const t=document.createElement("h4");t.textContent="Global settings",t.style.cssText="margin:0 0 .25rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",n.appendChild(t);const p=ae.map(c=>{const h=y=>{r(),s.globals[c.key]=c.key==="loop"?ce(y):y};let b;if(c.type==="checkbox"){const y=ve(s.globals[c.key],h,c.label);n.appendChild(y.wrap),b=y.input}else b=c.type==="select"?ge(c.options,s.globals[c.key],h):c.type==="number"?xe(s.globals[c.key],h,c.min):ye(s.globals[c.key],"",h),n.appendChild(be(c.label,b));return{field:c,input:b}});return{el:n,sync(){p.forEach(({field:c,input:h})=>{c.type==="checkbox"?h.checked=s.globals[c.key]:h.value=String(s.globals[c.key])})}}}function be(s,r){const n=document.createElement("div"),t=document.createElement("label");return t.style.cssText=pe,t.textContent=s,n.appendChild(t),n.appendChild(r),n}function xe(s,r,n=1){const t=document.createElement("input");return t.type="number",t.min=String(n),t.value=String(s),t.style.cssText=L,t.addEventListener("input",()=>{const p=Number(t.value);!Number.isNaN(p)&&p>=n&&r(p)}),t}function ye(s,r,n){const t=document.createElement("input");return t.type="text",t.value=s,t.placeholder=r,t.style.cssText=L,t.addEventListener("input",()=>n(t.value)),t}function ge(s,r,n){const t=document.createElement("select");return t.style.cssText=L,s.forEach(([p,c])=>{const h=document.createElement("option");h.value=p,h.textContent=c,t.appendChild(h)}),t.value=r,t.addEventListener("change",()=>n(t.value)),t}function ve(s,r,n){const t=document.createElement("label");t.style.cssText=ue;const p=document.createElement("input");return p.type="checkbox",p.checked=s,p.addEventListener("change",()=>r(p.checked)),t.appendChild(p),t.appendChild(document.createTextNode(n)),{wrap:t,input:p}}function V(s,r){const n=document.createElement("button");n.type="button",n.className="btn btn-ghost btn-sm",n.style.cssText="display:inline-flex;align-items:center;gap:.35rem;";const t=document.createElement("span");return t.setAttribute("data-icon",s),n.appendChild(t),n.appendChild(document.createTextNode(r)),n}function K(s,r){const n=document.createElement("button");n.type="button",n.title=r,n.style.cssText="padding:.25rem .4rem;background:transparent;border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text-muted,#aaa);cursor:pointer;display:inline-flex;align-items:center;";const t=document.createElement("span");return t.setAttribute("data-icon",s),n.appendChild(t),n}function ee(s){for(;s.firstChild;)s.removeChild(s.firstChild)}function we(s){return String(s).replace(/&/g,"&").replace(/"/g,""")}let te=!1;function Ce(){te||(te=!0,I.register("edit-3",{viewBox:"0 0 24 24",paths:["M12 20h9","M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("clock",{viewBox:"0 0 24 24",paths:["M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z","M12 6v6l4 2"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("corner-up-left",{viewBox:"0 0 24 24",paths:["M9 14 4 9l5-5","M20 20v-7a4 4 0 0 0-4-4H4"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("refresh-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M1 20v-6h6","M3.51 9a9 9 0 0 1 14.85-3.36L23 10","M20.49 15a9 9 0 0 1-14.85 3.36L1 14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("rotate-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M20.49 15a9 9 0 1 1-2.12-9.36L23 10"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("code",{viewBox:"0 0 24 24",paths:["M16 18l6-6-6-6","M8 6l-6 6 6 6"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-up",{viewBox:"0 0 24 24",path:"M18 15l-6-6-6 6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-down",{viewBox:"0 0 24 24",path:"M6 9l6 6 6-6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("x",{viewBox:"0 0 24 24",paths:["M18 6L6 18","M6 6l12 12"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const SCRIBE_FIELDS=[{name:"mode",key:"mode",label:"Render mode",type:"select",default:"typewriter",options:[["typewriter","Characters"],["word","Words"],["sentence","Sentences"]]},{name:"effect",key:"effect",label:"Default entrance effect",type:"select",default:"none",options:["none","fade","bounce","glow"].map(r=>[r,r])},{name:"speed",key:"speed",label:"Typing speed (ms/unit)",type:"number",default:50,min:0},{name:"delete-speed",key:"deleteSpeed",label:"Delete speed (ms/unit)",type:"number",default:30,min:0},{name:"cursor",key:"cursor",label:"Show cursor",type:"checkbox",default:!0},{name:"cursor-char",key:"cursorChar",label:"Cursor character",type:"text",default:"|"},{name:"cursor-type",key:"cursorType",label:"Cursor style",type:"select",default:"caret",options:[["caret","Caret"],["block","Block"],["underline","Underline"]]},{name:"cursor-blink",key:"cursorBlink",label:"Blink cursor while idle",type:"checkbox",default:!0},{name:"loop",key:"loop",label:"Loop (false, true, or total plays)",type:"text",default:!1},{name:"loop-delay",key:"loopDelay",label:"Loop delay (ms)",type:"number",default:1e3,min:0},{name:"pause-on-hover",key:"pauseOnHover",label:"Pause on hover",type:"checkbox",default:!1},{name:"auto-start",key:"autoStart",label:"Start automatically",type:"checkbox",default:!0},{name:"respect-motion-preference",key:"respectMotionPreference",label:"Respect reduced motion",type:"checkbox",default:!0,always:!0},{name:"controls",key:"controls",label:"Show playback controls",type:"checkbox",default:!1}];export function scribeDefaults(){return Object.fromEntries(SCRIBE_FIELDS.map(r=>[r.key,r.default]))}export function scribeLoop(r){if(r===!0||r==="true")return!0;if(r===!1||r==="false"||r==="")return!1;const o=Number(r);return Number.isInteger(o)&&o>=1?o:!1}export function stateToScribeActions(r,o="none"){const n=[];return r.forEach(t=>{t.type==="render"||t.type==="redraw"?(t.type==="redraw"&&n.push({undoRender:"all"}),n.push({render:t.text||"",effect:!t.effect||t.effect==="inherit"?o:t.effect})):t.type==="wait"?n.push({wait:t.unit==="s"?(t.duration||0)*1e3:t.duration||0}):t.type==="undo"&&n.push({undoRender:t.mode==="all"?"all":t.mode==="count"?t.count:!0})}),n}export function buildScribeShortcode(r,o){const n=e=>String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">"),t=SCRIBE_FIELDS.filter(e=>e.always||r[e.key]!==e.default).map(e=>`${e.name}="${n(r[e.key])}"`),l=o.map(e=>{if(e.type==="render"||e.type==="redraw"){const c=e.effect&&e.effect!=="inherit"?` effect="${n(e.effect)}"`:"";return`[${e.type}${c}]${e.text||""}[/${e.type}]`}return e.type==="wait"?`[wait]${e.duration}${e.unit==="s"?"s":""}[/wait]`:e.mode==="all"?'[undo all="true" /]':e.mode==="count"?`[undo count="${e.count}" /]`:"[undo /]"});return`[scribe${t.length?" "+t.join(" "):""}]
|
|
2
|
+
${l.join(`
|
|
3
|
+
`)}
|
|
4
|
+
[/scribe]`}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isPathAllowed as F}from"./admin-scope.js";export const TOOLS_FOLDER_TEXT="Tools",MANAGE_PLUGINS_URL="#/plugins",MANAGE_PLUGINS_ITEM={text:"Marketplace",url:MANAGE_PLUGINS_URL,icon:"store",permission:"plugins"};export function stripItemByUrl(e,t){const n=[];for(const r of e||[]){if(!r||r.url===t)continue;const s={...r};Array.isArray(r.items)&&r.items.length&&(s.items=stripItemByUrl(r.items,t)),n.push(s)}return n}export function managePluginsItem(){return{...MANAGE_PLUGINS_ITEM}}export const TOOLS_FOLDER_KEY="tools";const
|
|
1
|
+
import{isPathAllowed as F}from"./admin-scope.js";export const TOOLS_FOLDER_TEXT="Tools",MANAGE_PLUGINS_URL="#/plugins",MANAGE_PLUGINS_ITEM={text:"Marketplace",url:MANAGE_PLUGINS_URL,icon:"store",permission:"plugins"};export function stripItemByUrl(e,t){const n=[];for(const r of e||[]){if(!r||r.url===t)continue;const s={...r};Array.isArray(r.items)&&r.items.length&&(s.items=stripItemByUrl(r.items,t)),n.push(s)}return n}export function managePluginsItem(){return{...MANAGE_PLUGINS_ITEM}}export const TOOLS_FOLDER_KEY="tools";const E=["countUrl","core","permission"],c=e=>String(e??"").toLowerCase();export function slugify(e){return c(e).trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}export function groupKeyFor(e,t){return`${c(e)}.${slugify(t)}`}export const GROUP_ICON="folder";const P=e=>e&&(e.type==="separator"||e.type==="spacer"||e.type==="theme-switcher"),A=e=>e&&!P(e)&&!e.url;function w(e){return(e||[]).filter(Boolean).map(t=>Array.isArray(t.items)?{...t,items:w(t.items)}:{...t})}function M(e,t,n=[]){for(const r of e||[]){if(!r)continue;if(t(r))return[...n,r];const s=M(r.items,t,[...n,r]);if(s)return s}return null}function I(e,t,n=[],r=[]){for(const s of e||[])s&&(t(s)&&r.push([...n,s]),I(s.items,t,[...n,s],r));return r}const U=e=>!e.some(t=>t.hidden||t.restricted);function $(e,t){for(const n of e||[]){if(t(n))return n;const r=$(n?.items,t);if(r)return r}return null}export function findFolder(e,t){if(!t)return null;const n=c(t);return $(e,r=>A(r)&&c(r.key)===n)||$(e,r=>A(r)&&!r.key&&c(r.text)===n)}function b(e,t){const n={...t,...e};for(const r of E)t[r]!==void 0&&(n[r]=t[r]);return!(Array.isArray(e.items)&&e.items.length)&&Array.isArray(t.items)&&(n.items=t.items),e.text||(n.text=t.text),!e.icon&&t.icon&&(n.icon=t.icon),delete n.ref,delete n.folder,delete n.group,n}function O(e,{persisted:t,orphan:n=!1,node:r=null}){const s=e?.item||{};return{persisted:t,orphan:n,source:s.source||(s.core?"Built in":""),folder:e?.folder||TOOLS_FOLDER_KEY,defaults:n?{text:null,icon:null}:{text:s.text||"",icon:s.icon||""},...n&&r&&{label:r.text||r.url},...(e?.group||e?.item?.group)&&{group:e.group||e.item.group}}}export function placeTools(e,t,{forEditor:n=!1}={}){const r=w(e),s=(t||[]).filter(o=>o&&o.item&&typeof o.item.text=="string"),m=new Map;for(const o of s)o.item.url&&!m.has(o.item.url)&&m.set(o.item.url,o);const y=new Set,d=o=>{const i=[];for(const u of o){const h=u.url?m.get(u.url):null;if(h&&!y.has(u.url)){y.add(u.url);const g=b(u,h.item);Array.isArray(u.items)&&u.items.length?g.items=d(u.items):n&&(g.items=[]),n&&(g.$tool=O(h,{persisted:!0})),i.push(g);continue}if(u.ref){if(!n)continue;const{ref:g,...f}=u;i.push({...f,items:d(u.items||[]),$tool:O(null,{persisted:!0,orphan:!0,node:u})});continue}Array.isArray(u.items)&&(u.items=d(u.items)),i.push(u)}return i},a=d(r),T=new Set,S=o=>{for(const i of o||[])i.hidden&&i.text&&!i.url&&!(Array.isArray(i.items)&&i.items.length)&&T.add(c(i.text)),S(i.items)};S(a);let x=null;const L=()=>{const o=findFolder(a,TOOLS_FOLDER_KEY);if(o)return o;if(!x){x={text:TOOLS_FOLDER_TEXT,key:TOOLS_FOLDER_KEY,icon:"tool",items:[],synthesised:!0};const i=a.findIndex(u=>["system","documentation"].includes(c(u?.key||u?.text)));a.splice(i===-1?a.length:i,0,x)}return x},l=new Set,k=(o,i)=>{const u=groupKeyFor(o.key||slugify(o.text),i),h=$(a,p=>A(p)&&c(p.key)===u)||(o.items||[]).find(p=>A(p)&&(!p.key||c(p.key)===u)&&c(p.text)===c(i));if(h)return h;const g={text:String(i),key:u,icon:GROUP_ICON,items:[],synthesised:!0},f=o.items.findIndex(p=>l.has(p));return o.items.splice(f===-1?o.items.length:f,0,g),g};for(const o of s){const{item:i}=o;if(i.url&&y.has(i.url))continue;i.url&&y.add(i.url);const u=T.has(c(i.text));if(u&&!n)continue;const h=b({},i);n&&(h.items=[],h.$tool=O(o,{persisted:!1}),u&&(h.hidden=!0));let f=(o.parent?findFolder(a,o.parent)||$(a,_=>!P(_)&&c(_.text)===c(o.parent)):null)||findFolder(a,o.folder||i.folder)||L();f.items=Array.isArray(f.items)?f.items:[];const p=typeof(o.group||i.group)=="string"?(o.group||i.group).trim():"";p&&slugify(p)&&(f=k(f,p),f.items=Array.isArray(f.items)?f.items:[]),f.items.push(h),l.add(h)}return a}export const LOCKED_TOOLS=[{folder:"overview",item:{text:"Dashboard",url:"#/",icon:"home"}},{folder:"content",item:{text:"Site menus",url:"#/menus",icon:"menu",permission:"menus"}},{folder:"system",item:{text:"Users",url:"#/users",icon:"users",permission:"users"}},{folder:"system",item:{text:"My Profile",url:"#/my-profile",icon:"user"}}];export function isLockedUrl(e){return LOCKED_TOOLS.some(t=>t.item.url===e)}export function ensureLockedTools(e,{leaveInHiddenFolders:t=!1}={}){const n=w(e);for(const{folder:r,item:s}of LOCKED_TOOLS){const m=I(n,l=>l?.url===s.url),y=m.find(l=>!l.some(k=>k.restricted));if(!y&&m.length)continue;const d=y?.at(-1);if(d){if(d.hidden&&delete d.hidden,!y.slice(0,-1).some(o=>o.hidden)||t)continue;const k=y.at(-2);k.items=k.items.filter(o=>o!==d)}const a=c(r),T=I(n,l=>A(l)&&c(l.key)===a).filter(U),S=I(n,l=>A(l)&&!l.key&&c(l.text)===a).filter(U),x=(T[0]||S[0])?.at(-1)||null,L=d||{...s};x?(x.items=Array.isArray(x.items)?x.items:[],x.items.push(L)):n.push(L)}return n}export function insertFoldersBeforeSystem(e,t){const n=(t||[]).filter(Boolean);if(!n.length)return e;const r=["system","documentation"],s=e.findIndex(m=>r.includes(c(m?.key||m?.text)));return s===-1?[...e,...n]:[...e.slice(0,s),...n,...e.slice(s)]}export function canAny(e,t){return t?!e||!e.length?!1:e.includes(t)?!0:["read","create","update","delete"].some(n=>e.includes(`${t}.${n}`)):!0}export function filterByPermission(e,t,n=null){const r=[];for(const s of e){if(s.hidden||s.permission&&!canAny(t,s.permission))continue;const m=typeof s.url=="string"?s.url:"";if(n&&m.startsWith("#/")&&!F(n,m.slice(1)))continue;const y=Array.isArray(s.items)&&s.items.length>0,d=y?filterByPermission(s.items,t,n):[];y&&!d.length&&!m||r.push({...s,items:d})}return r}export function sidebarStateKey(e,t=null){const n=String(e?.text||"").replace(/\s*\(\d+\)\s*$/,"").toLowerCase().replace(/\s+/g,"-"),r=String(e?.url||"").match(/^#\/projects\/([^/]+)/);let s="";if(r)try{s=`project-${decodeURIComponent(r[1])}.`}catch{s=`project-${r[1]}.`}return t?e?.key?`sidebar.expanded.key.${c(e.key)}`:`${t}/${s}${n}`:`sidebar.expanded.${s}${n}`}export function pruneEmptyToolsFolder(e){return(e||[]).filter(t=>A(t)?!(c(t.key)===TOOLS_FOLDER_KEY||!t.key&&t.text===TOOLS_FOLDER_TEXT)||Array.isArray(t.items)&&t.items.length>0:!0)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{api as g,getUser as L}from"../api.js";import{isPathAllowed as ue}from"./admin-scope.js";import{colourToCss as V,applyFloat as fe,applyHighlight as me,itemHighlightAttrs as pe}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{placeTools as he,ensureLockedTools as ge,managePluginsItem as be,stripItemByUrl as ye,insertFoldersBeforeSystem as ve,pruneEmptyToolsFolder as xe,sidebarStateKey as X,canAny as O,filterByPermission as $e,MANAGE_PLUGINS_URL as Z}from"./sidebar-grouping.js";import{arrangeButtonMarkup as we,canArrange as ke,startArrange as Se}from"./sidebar-arrange.js";import{collapseButtonMarkup as qe,wireSidebarSize as Ce,COLLAPSED_WIDTH as Ae}from"./sidebar-size.js";import{FREQUENT_MAX as Y,addFrequent as Fe,frequentFolder as Le,moveFrequent as J,readFrequent as z,readFrequentHidden as Ee,removeFrequent as Te,saveFrequent as
|
|
1
|
+
import{api as g,getUser as L}from"../api.js";import{isPathAllowed as ue}from"./admin-scope.js";import{colourToCss as V,applyFloat as fe,applyHighlight as me,itemHighlightAttrs as pe}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{placeTools as he,ensureLockedTools as ge,managePluginsItem as be,stripItemByUrl as ye,insertFoldersBeforeSystem as ve,pruneEmptyToolsFolder as xe,sidebarStateKey as X,canAny as O,filterByPermission as $e,MANAGE_PLUGINS_URL as Z}from"./sidebar-grouping.js";import{arrangeButtonMarkup as we,canArrange as ke,startArrange as Se}from"./sidebar-arrange.js";import{collapseButtonMarkup as qe,wireSidebarSize as Ce,COLLAPSED_WIDTH as Ae}from"./sidebar-size.js";import{FREQUENT_MAX as Y,addFrequent as Fe,frequentFolder as Le,moveFrequent as J,readFrequent as z,readFrequentHidden as Ee,removeFrequent as Te,saveFrequent as He,syncFrequent as Me,writeFrequent as Ne,writeFrequentHidden as Q}from"./sidebar-frequent.js";import{hotkeyFor as ee,hotkeyTitle as je,setHotkeyTree as Be}from"./hotkeys-ui.js";import{hotkeyLabel as Pe}from"./hotkeys.js";function m(e){return String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const Re=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Site menus",url:"#/menus",icon:"menu",permission:"menus"}];async function _e(e){if(!O(e,"projects"))return[];let n=[];try{n=await g.projects.listWithCounts()}catch{return[]}if(!Array.isArray(n))return[];const s=[{key:"pages",text:"Pages",icon:"file-text",path:"/pages"},{key:"collections",text:"Collections",icon:"database",path:"/collections"},{key:"forms",text:"Forms",icon:"layout",path:"/forms"},{key:"actions",text:"Actions",icon:"zap",path:"/actions"},{key:"menus",text:"Site menus",icon:"menu",path:"/menus"},{key:"blocks",text:"Blocks",icon:"box",path:"/blocks"},{key:"components",text:"Components",icon:"component",path:"/components"},{key:"views",text:"Views",icon:"eye",path:"/views"},{key:"roles",text:"Roles",icon:"shield",path:"/roles"},{key:"users",text:"Users",icon:"users",path:"/users"},{key:"apis",text:"APIs",icon:"code",path:"/apis"}];return n.map(t=>{const o="#/projects/"+encodeURIComponent(t.slug),a=t.counts||{},d=[{text:"Overview",url:o,icon:t.icon||"folder"}];for(const c of s){const r=Number(a[c.key])||0;r<=0||d.push({text:`${c.text} (${r})`,url:o+c.path,icon:c.icon})}d.push({text:"Settings",url:o+"/settings",icon:"settings"});const u=t.enabled===!1;return{text:t.name||t.slug,key:`project.${t.slug}`,icon:t.icon||"folder",items:d,...u&&{colour:"neutral",badge:{text:"off"}}}})}function Ie(e,n){for(const s of e)if(!s.hidden&&(s.key==="projects"||!s.key&&(s.text||"").toLowerCase()==="projects")){s.items=Array.isArray(s.items)?s.items.slice():[],s.items.push(...n);return}}function te(e,n){const s=se.includes(n.tone)?n.tone:"info",t=n.label||String(n.count);n.details?j.set(e,n.details):j.delete(e);const i=!n.inventory&&A.some(o=>o.url===e&&!o.inventory)?" data-live":"";return`<span class="sidebar-badge sidebar-badge--${s}" data-count-for="${m(e)}"${i} data-badge-label="${m(t)}" aria-label="${m(t)}">${m(String(n.count))}</span>`}function ne(e){for(const n of e.querySelectorAll("details")){const s=n.querySelector(":scope > summary");if(!s)continue;let t=0,i=!1;const o=[];for(const r of n.querySelectorAll(":scope > .sidebar-children .sidebar-badge[data-live]")){const f=Number(r.textContent)||0;f&&(t+=f,i||(i=r.classList.contains("sidebar-badge--danger")),o.push({text:r.closest("a")?.querySelector(".sidebar-text")?.textContent.trim()??"",meta:r.dataset.badgeLabel,tone:r.classList.contains("sidebar-badge--danger")?"danger":void 0}))}const a=`folder:${n.dataset.stateKey||s.textContent.trim()}`;let d=s.querySelector(":scope > .sidebar-badge--sum");if(!t){d?.remove(),j.delete(a);continue}d||(d=document.createElement("span"),s.querySelector(".sidebar-text")?.after(d));const u=s.querySelector(".sidebar-text")?.textContent.trim()||"This folder",c=o.map(r=>`${r.text}: ${r.meta}`).join(" \xB7 ");d.className=`sidebar-badge sidebar-badge--sum sidebar-badge--${i?"danger":"info"}`,d.dataset.countFor=a,d.dataset.badgeLabel=c,d.setAttribute("aria-label",c),d.textContent=String(t),j.set(a,{title:u,items:o})}}const j=new Map;function Oe(e,n){if(!e.url||!n)return"";const s=n[e.url];return!s||!(s.count>0)&&!s.showZero?"":te(e.url,s)}const se=["info","attention","danger","live"],Ue={"#/pages":["page","pages"],"#/media":["file in the media library","files in the media library"],"#/menus":["menu","menus"],"#/context-menus":["context menu","context menus"],"#/theme":["element override in the theme","element overrides in the theme"],"#/collections":["collection","collections"],"#/forms":["form","forms"],"#/views":["view","views"],"#/actions":["action","actions"],"#/blocks":["block","blocks"],"#/components":["component","components"],"#/users":["user","users"],"#/plugins":["plugin installed","plugins installed"],"#/system/notifications":["unread notification","unread notifications"]};function W(e,{fallbackLabel:n="",tone:s="info"}={}){const t=Number(typeof e=="object"&&e!==null?e.count:e);if(!Number.isFinite(t)||t<0)return null;const i=typeof e?.label=="string"&&e.label||(n?`${t} - ${n}`:String(t)),o={count:Math.round(t),label:i,tone:se.includes(e?.tone)?e.tone:s};return e?.details&&typeof e.details=="object"&&(o.details=e.details),e?.inventory===!0&&(o.inventory=!0),e?.showZero===!0&&(o.showZero=!0),o}function oe(e,n,s=null,{inFrequent:t=!1}={}){if(e&&e.type==="separator")return'<hr class="sidebar-divider">';if(e&&e.type==="theme-switcher")return"";if(e&&e.type==="spacer"){const y=["xs","sm","md","lg","xl","flex"].includes(e.size)?e.size:"md";return`<div class="sidebar-spacer sidebar-spacer--${m(y)}" aria-hidden="true"></div>`}const i=String(e.text||"?").trim().charAt(0).toUpperCase()||"?",o=e.icon?`<span data-icon="${m(e.icon)}"></span>`:`<span class="sidebar-initial" aria-hidden="true">${m(i)}</span>`,a=m(e.text||""),d=e.url?m(e.url):"",u=Array.isArray(e.items)&&e.items.length>0,c=e.colour?V(e.colour):"",r=pe(e),f=[r.hover&&` data-menu-item-hover="${m(r.hover)}"`,r.active&&` data-menu-item-active="${m(r.active)}"`].filter(Boolean).join(""),x=[c&&`color:${m(c)}`,r.accent&&`--dm-menu-highlight:${m(r.accent)}`].filter(Boolean).join(";"),w=x?` style="${x}"`:"",k=e.url?je(e.url,e.text||"",{inFrequent:t}):"",q=k?` title="${m(k)}"`:"";let F="";if(e.badge&&e.badge.text!=null&&e.badge.text!==""){const y=e.badge.variant?V(e.badge.variant):"";F=`<span class="dm-menu-badge"${y?` style="background:${m(y)};color:var(--dm-text-inverse,#fff)"`:""}>${m(String(e.badge.text))}</span>`}if(e.frequent&&e.empty){const y=X(e,s),C=S.get(y)!==!1;return`<details data-state-key="${m(y)}"${C?" open":""} data-frequent data-frequent-empty>
|
|
2
2
|
<summary${w}>${o} <span class="sidebar-text">${a}</span></summary>
|
|
3
3
|
<div class="sidebar-children"><p class="sidebar-frequent-empty">Right-click any Tool and choose <strong>Add to Frequent</strong> to keep it here.</p></div>
|
|
4
4
|
</details>`}if(u){const y=X(e,s),C=S.get(y)!==!1,B=e.items.map(T=>oe(T,n,y,{inFrequent:!!e.frequent})).join(""),P=e.frequent?' data-frequent title="Your Frequent Tools - right-click any Tool to add or remove it"':"";return`<details data-state-key="${m(y)}"${C?" open":""}${P}>
|
|
5
5
|
<summary${w}${q}>${o} <span class="sidebar-text">${a}</span>${F}</summary>
|
|
6
6
|
<div class="sidebar-children">${B}</div>
|
|
7
|
-
</details>`}return`<a href="${d}" class="sidebar-link" data-url="${d}"${w}${f}${q}>${o} <span class="sidebar-text">${a}</span>${Oe(e,n)}${F}</a>`}async function ze(e=[],n=[],s=null){const t=p=>p.then(b=>Array.isArray(b)?b.length:Array.isArray(b?.entries)?b.entries.length:0).catch(()=>0);A=Ge(e,s);const i=new Set(A.map(p=>p.url)),o={pages:"#/pages",media:"#/media",menus:"#/menus","context-menus":"#/context-menus",theme:"#/theme",collections:"#/collections",forms:"#/forms",views:"#/views",actions:"#/actions",blocks:"#/blocks",components:"#/components",users:"#/users",plugins:"#/plugins",notifications:"#/system/notifications"},a=(p,b)=>O(n,p)&&!i.has(o[p])?b():Promise.resolve(0),[d,u,c,r,f,x,w,k,q,F,y,C,B,P]=await Promise.all([a("pages",()=>t(g.pages.list())),a("media",()=>t(g.media.list())),a("menus",()=>t(g.menus.list())),a("context-menus",()=>t(g.contextMenus.list())),a("theme",()=>g.theme.get().then(p=>(p?.overrides||[]).length).catch(()=>0)),a("collections",()=>t(g.collections.list())),a("forms",()=>t(g.forms.list())),a("views",()=>t(g.views.list())),a("actions",()=>t(g.actions.list())),a("blocks",()=>t(g.blocks.list())),a("components",()=>t(g.components.list())),a("users",()=>t(g.users.list())),a("plugins",()=>t(g.plugins.list())),a("notifications",()=>g.system?.notifications?.unreadCount?.().then(p=>p?.count??0).catch(()=>0)??Promise.resolve(0))]),T={};await Promise.all(A.map(async p=>{const b=await ie(p);b&&(T[p.url]=b)}));const U={"#/pages":d,"#/media":u,"#/menus":c,"#/context-menus":r,"#/theme":f,"#/collections":x,"#/forms":w,"#/views":k,"#/actions":q,"#/blocks":F,"#/components":y,"#/users":C,"#/plugins":B,"#/system/notifications":P},R={};for(const[p,b]of Object.entries(U)){if(i.has(p))continue;const[I,l]=Ue[p]??["item","items"],v=W(b);v&&(R[p]={...v,label:`${v.count} ${v.count===1?I:l}`})}return{...R,...T}}let A=[];const We="dm:sidebar-count",De=6e4;function Ge(e=[],n=null){const s=[],t=i=>{if(i&&!(n&&typeof i.url=="string"&&i.url.startsWith("#/")&&!ue(n,i.url.slice(1)))){i.url&&typeof i.countUrl=="string"&&i.countUrl&&s.push({url:i.url,countUrl:i.countUrl,text:i.text||"",countLabel:i.countLabel||"",inventory:i.inventory===!0});for(const o of[...i.children||[],...i.items||[]])t(o)}};for(const i of e??[])t(i?.item??i);return s}async function ie(e){try{const n=new Date,s=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`,t=e.countUrl+(e.countUrl.includes("?")?"&":"?")+`today=${s}`;return W(await H.get(t),{fallbackLabel:e.countLabel||e.text})}catch{return null}}function ae(e,n,s){const t=[...e.querySelectorAll("a.sidebar-link")].filter(i=>i.dataset.url===n);if(t.length){for(const i of t){const o=i.querySelector(".sidebar-badge[data-count-for]");if(!s||!(s.count>0)&&!s.showZero)o?.remove();else{const a=document.createRange();a.selectNodeContents(i);const d=a.createContextualFragment(te(n,s)).firstElementChild;o?o.replaceWith(d):i.querySelector(".sidebar-text")?.after(d)}}D.set(n,s),ne(e)}}const D=new Map;async function G(e,n=null){const s=n?A.filter(t=>t.url===n):A;await Promise.all(s.map(async t=>{const i=await ie(t),o=D.get(t.url);JSON.stringify(o??null)!==JSON.stringify(i)&&ae(e,t.url,i)}))}function Ke(e){e.dataset.liveCounts||(e.dataset.liveCounts="1",window.addEventListener(We,n=>{const s=n.detail||{};if(s.url)if(s.count!==void 0){const t=A.find(i=>i.url===s.url);ae(e,s.url,W(s,{fallbackLabel:t?.countLabel||t?.text||""}))}else G(e,s.url)}),setInterval(()=>{!document.hidden&&document.body.contains(e)&&G(e)},De),document.addEventListener("visibilitychange",()=>{document.hidden||G(e)}),Ve(e))}function re(e,n,s){const t=(a,d,u)=>{const c=document.createElement(a);return d&&(c.className=d),u!=null&&(c.textContent=String(u)),c};if(!s){e.textContent=n;return}e.appendChild(t("strong","dm-badge-pop-title",s.title||n)),(s.rows?.length||!s.items?.length)&&e.appendChild(t("p","dm-badge-pop-sub",n));const i=Array.isArray(s.rows)?s.rows.slice(0,6):[];if(i.length){const a=t("dl","dm-badge-pop-rows");for(const d of i)a.appendChild(t("dt",null,d.label)),a.appendChild(t("dd",d.tone==="danger"?"is-danger":null,d.value));e.appendChild(a)}const o=Array.isArray(s.items)?s.items.slice(0,6):[];if(o.length){const a=t("ul","dm-badge-pop-items");for(const d of o){const u=t("li",d.tone==="danger"?"is-danger":null);u.appendChild(t("span","dm-badge-pop-text",d.text)),d.meta&&u.appendChild(t("span","dm-badge-pop-meta",d.meta)),a.appendChild(u)}e.appendChild(a)}else s.empty&&e.appendChild(t("p","dm-badge-pop-empty",s.empty))}function Ve(e){let n=null,s=null;const t=()=>e.classList.contains("is-collapsed"),i=()=>{clearTimeout(s),n?.remove(),n=null},o=(c,r)=>{i(),s=setTimeout(()=>{n=document.createElement("div"),n.className="dm-help-pop dm-badge-pop",n.setAttribute("role","tooltip"),r(n),document.body.appendChild(n);const f=c.getBoundingClientRect(),x=n.getBoundingClientRect(),w=Math.min(f.right+10,innerWidth-x.width-8);n.style.left=`${Math.max(8,w)}px`,n.style.top=`${Math.max(8,Math.min(f.top+f.height/2-x.height/2,innerHeight-x.height-8))}px`},150)},a=c=>{const r=c?.dataset.badgeLabel;if(!r)return i();o(c,f=>re(f,r,j.get(c.dataset.countFor)))},d=c=>{const r=c.querySelector(":scope > .sidebar-text")?.textContent.trim()||"",f=c.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");o(c,x=>{const w=f&&j.get(f.dataset.countFor);if(w)return re(x,f.dataset.badgeLabel,{...w,title:w.title||r});if(!f){x.textContent=r;return}const k=document.createElement("strong");k.className="dm-badge-pop-title",k.textContent=r;const q=document.createElement("p");q.className="dm-badge-pop-sub",q.textContent=f.dataset.badgeLabel,x.append(k,q)})},u=c=>{const r=c.closest?.("a.sidebar-link, summary");return r&&e.contains(r)?r:null};e.addEventListener("mouseover",c=>{if(t()){const f=u(c.target);f&&!f.contains(c.relatedTarget)&&d(f);return}const r=c.target.closest?.(".sidebar-badge[data-badge-label]");r&&a(r)}),e.addEventListener("mouseout",c=>{if(t()){const r=u(c.target);r&&!r.contains(c.relatedTarget)&&i();return}c.target.closest?.(".sidebar-badge[data-badge-label]")&&i()}),e.addEventListener("focusin",c=>{const r=c.target.closest?.("a, summary");if(t()&&r&&e.contains(r)&&r.querySelector(":scope > .sidebar-text"))return d(r);const f=r?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");f?a(f):i()}),e.addEventListener("focusout",i),e.addEventListener("click",i),window.addEventListener("scroll",i,!0),window.addEventListener("hashchange",i)}async function Xe(e=[]){if(!O(e,"settings"))return"Admin";try{const n=await g.settings.get();return n?.adminBrand?.title||n?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:e,permissions:n,adminScope:s=null}){const t=$(e).get(0);if(!t)return;const i=He(g,L()).catch(()=>{});let o,a=null,d=null,u=null,c=null,r=null;try{const l=await g.get("/sidebar/menu");o=Array.isArray(l?.items)?l.items:null,a=l?.variant||null,d=l?.position||null,u=l?.style||null,c=l?.float||null,r=l?.highlight||null}catch{o=null}(!o||!o.some(l=>l&&(!l.hidden||l.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),o=Re.slice());let f=[];try{f=await H.get("/api/sidebar/registered-items")||[]}catch{}o=ye(o,Z),o=he(o,f.filter(l=>(l?.item??l)?.url!==Z)),o=ge(o),o=ve(o,[be()]);const x=await _e(n);x.length&&Ie(o,x),o=$e(o,n,s),o=xe(o),await i;const w=Le(o,z(L()),{hidden:Ee(L())});w&&(o=[w,...o]),Be(o);const[k,q]=await Promise.all([ze(f.filter(l=>O(n,l?.item?.permission)),n,s).catch(()=>({})),Xe(n)]),F=a?` dm-admin-sidebar--${m(a)}`:"";function y(l,v="px"){if(l==null)return l;const h=String(l).trim();return/^\d+(\.\d+)?$/.test(h)?`${h}${v}`:h}let C="";if(u){const l=[];u.fontFamily&&l.push(`font-family: ${u.fontFamily}, sans-serif`),u.fontSize&&l.push(`font-size: ${y(u.fontSize)}`),u.fontWeight&&l.push(`font-weight: ${u.fontWeight}`),u.letterSpacing&&l.push(`letter-spacing: ${y(u.letterSpacing,"em")}`);const v=[];if(l.length&&v.push(`#admin-sidebar .dm-admin-sidebar, #admin-sidebar .dm-admin-sidebar .sidebar-link, #admin-sidebar .dm-admin-sidebar summary, #admin-sidebar .dm-admin-sidebar .sidebar-text { ${l.join("; ")} }`),u.iconSize){const h=y(u.iconSize);v.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${h} !important; height: ${h} !important; }`)}v.length&&(C=`<style data-admin-sidebar-style>${v.join(" ")}</style>`)}const B=ke(n)?we():"",P=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span><span class="dm-admin-sidebar-title">${m(q)}</span>${B}${qe()}</div>`,T=o.some(l=>l&&l.type==="spacer"&&l.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",U=`${C}<nav class="dm-admin-sidebar${F}${T}">${P}${o.map(l=>oe(l,k)).join("")}</nav>`,R=document.createRange();R.selectNodeContents(t);const p=R.createContextualFragment(U);t.replaceChildren(p),Domma.icons.scan(t),t.querySelector(".dm-admin-sidebar-arrange")?.addEventListener("click",()=>Se(t));for(const l of A)D.set(l.url,k[l.url]??null);ne(t),Ke(t),t.removeAttribute("data-menu-hover"),t.removeAttribute("data-menu-active"),t.style.removeProperty("--dm-menu-highlight"),me(t,{highlight:r});const b=document.querySelector(".dashboard-wrapper");["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(l=>{t.style[l]=""}),t.classList.remove("dm-menu-floating"),b&&(b.style.paddingLeft="",b.style.paddingRight=""),t.__dmGutter=()=>{if(d!=="floating"||!b)return;const l=c&&c.anchor||"TL",v=Number.isFinite(Number(c?.offsetX))?Number(c.offsetX):16,h=t.classList.contains("is-collapsed")?Ae:parseInt(t.style.width,10)||t.getBoundingClientRect().width||260,N=Math.round(h+v*2)+"px";l==="R"||l==="TR"||l==="BR"?b.style.paddingRight=N:b.style.paddingLeft=N},d==="floating"&&fe(t,{position:"floating",float:c||{}}),t.querySelectorAll("details").forEach(l=>{l.addEventListener("toggle",function(){const v=this.getAttribute("data-state-key");v&&S.set(v,this.open);const h=this.querySelector(":scope > .sidebar-children");if(h)if(this.open){const N=h.scrollHeight;h.style.maxHeight="0",requestAnimationFrame(()=>{h.style.maxHeight=N+"px",h.addEventListener("transitionend",function de(){h.style.maxHeight="none",h.removeEventListener("transitionend",de)})})}else{const N=h.scrollHeight;h.style.maxHeight=N+"px",requestAnimationFrame(()=>{h.style.maxHeight="0"})}})}),Ce(t),Qe(t),t.dataset.routeWired||(t.dataset.routeWired="1",M.subscribe("router:afterChange",()=>t.__dmSetActive?.()));function I(){const l=/^#\/(dashboards|my-dashboard)\b/.test(location.hash)?"#/":location.hash||"#/";$(t).find(".sidebar-link").removeClass("active"),$(t).find(`.sidebar-link[data-url="${l}"]`).addClass("active")}I(),t.__dmSetActive=I}function le(){try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}function K(e){return`${location.origin}${location.pathname}${e}`}function _(e,n){const s=L(),t=e(z(s));if(!Ne(s,t)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}t.length&&Q(s,!1),ce(s),n&&E.toast(n,{type:"success",duration:2500}),le()}function ce(e){Me(g,e).catch(()=>E.toast("Frequent is saved in this browser only - the server could not keep it.",{type:"warning"}))}function Ze(e){if(!Q(L(),e)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}ce(L()),E.toast(e?"Frequent hidden. Add a Tool to it from its right-click menu to bring it back.":"Frequent shown.",{type:"success",duration:3500}),le()}function Ye(e){const n=e.dataset.url;if(!n)return[];const s=e.querySelector(".sidebar-text")?.textContent.trim()||n,t=z(L()),i=t.includes(n),o=!!e.closest("details[data-frequent]"),a=t.indexOf(n),d=!i&&t.length>=Y;return[{header:s},{label:"Open",icon:"arrow-right",...ee(n)&&{shortcut:Pe(ee(n))},action:()=>{location.hash=n}},{label:"Open in a new tab",icon:"external-link",action:()=>window.open(K(n),"_blank","noopener")},{type:"divider"},i?{label:"Remove from Frequent",icon:"star",action:()=>_(u=>Te(u,n),`${s} removed from Frequent.`)}:{label:d?`Frequent is full (${Y})`:"Add to Frequent",icon:"star",disabled:d,action:()=>_(u=>Fe(u,n),`${s} added to Frequent.`)},...o?[{label:"Move up",icon:"arrow-up",disabled:a<=0,action:()=>_(u=>J(u,n,-1))},{label:"Move down",icon:"arrow-down",disabled:a<0||a>=t.length-1,action:()=>_(u=>J(u,n,1))}]:[],{type:"divider"},{label:"Copy link",icon:"link",action:async()=>{try{await navigator.clipboard.writeText(K(n)),E.toast("Link copied.",{type:"success",duration:2e3})}catch{E.toast(K(n),{type:"info",duration:8e3})}}}]}function Je(e,n){const s=e.closest("details"),t=e.querySelector(".sidebar-text")?.textContent.trim()||"Folder",i=o=>n.querySelectorAll("details").forEach(a=>{a.open!==o&&(a.open=o)});return[{header:t},{label:s?.open?"Close":"Open",icon:s?.open?"chevron-up":"chevron-down",action:()=>{s&&(s.open=!s.open)}},{label:"Open every folder",icon:"chevrons-down",action:()=>i(!0)},{label:"Close every folder",icon:"chevrons-up",action:()=>i(!1)},...s?.hasAttribute("data-frequent-empty")?[{type:"divider"},{label:"Hide Frequent until I add a Tool",icon:"eye-off",action:()=>Ze(!0)}]:s?.hasAttribute("data-frequent")?[{type:"divider"},{label:"Clear Frequent",icon:"x",action:()=>_(()=>[],"Frequent cleared.")}]:[]]}function Qe(e){e.dataset.ctxWired||typeof E>"u"||!E.contextMenu||(e.dataset.ctxWired="1",E.contextMenu(e,{match:"a.sidebar-link, details > summary",inherit:!1,density:"compact",items:n=>n.matches("summary")?Je(n,e):Ye(n)}))}
|
|
7
|
+
</details>`}return`<a href="${d}" class="sidebar-link" data-url="${d}"${w}${f}${q}>${o} <span class="sidebar-text">${a}</span>${Oe(e,n)}${F}</a>`}async function ze(e=[],n=[],s=null){const t=p=>p.then(b=>Array.isArray(b)?b.length:Array.isArray(b?.entries)?b.entries.length:0).catch(()=>0);A=Ge(e,s);const i=new Set(A.map(p=>p.url)),o={pages:"#/pages",media:"#/media",menus:"#/menus","context-menus":"#/context-menus",theme:"#/theme",collections:"#/collections",forms:"#/forms",views:"#/views",actions:"#/actions",blocks:"#/blocks",components:"#/components",users:"#/users",plugins:"#/plugins",notifications:"#/system/notifications"},a=(p,b)=>O(n,p)&&!i.has(o[p])?b():Promise.resolve(0),[d,u,c,r,f,x,w,k,q,F,y,C,B,P]=await Promise.all([a("pages",()=>t(g.pages.list())),a("media",()=>t(g.media.list())),a("menus",()=>t(g.menus.list())),a("context-menus",()=>t(g.contextMenus.list())),a("theme",()=>g.theme.get().then(p=>(p?.overrides||[]).length).catch(()=>0)),a("collections",()=>t(g.collections.list())),a("forms",()=>t(g.forms.list())),a("views",()=>t(g.views.list())),a("actions",()=>t(g.actions.list())),a("blocks",()=>t(g.blocks.list())),a("components",()=>t(g.components.list())),a("users",()=>t(g.users.list())),a("plugins",()=>t(g.plugins.list())),a("notifications",()=>g.system?.notifications?.unreadCount?.().then(p=>p?.count??0).catch(()=>0)??Promise.resolve(0))]),T={};await Promise.all(A.map(async p=>{const b=await ie(p);b&&(T[p.url]=b)}));const U={"#/pages":d,"#/media":u,"#/menus":c,"#/context-menus":r,"#/theme":f,"#/collections":x,"#/forms":w,"#/views":k,"#/actions":q,"#/blocks":F,"#/components":y,"#/users":C,"#/plugins":B,"#/system/notifications":P},R={};for(const[p,b]of Object.entries(U)){if(i.has(p))continue;const[I,l]=Ue[p]??["item","items"],v=W(b);v&&(R[p]={...v,label:`${v.count} ${v.count===1?I:l}`})}return{...R,...T}}let A=[];const We="dm:sidebar-count",De=6e4;function Ge(e=[],n=null){const s=[],t=i=>{if(i&&!(n&&typeof i.url=="string"&&i.url.startsWith("#/")&&!ue(n,i.url.slice(1)))){i.url&&typeof i.countUrl=="string"&&i.countUrl&&s.push({url:i.url,countUrl:i.countUrl,text:i.text||"",countLabel:i.countLabel||"",inventory:i.inventory===!0});for(const o of[...i.children||[],...i.items||[]])t(o)}};for(const i of e??[])t(i?.item??i);return s}async function ie(e){try{const n=new Date,s=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`,t=e.countUrl+(e.countUrl.includes("?")?"&":"?")+`today=${s}`;return W(await H.get(t),{fallbackLabel:e.countLabel||e.text})}catch{return null}}function ae(e,n,s){const t=[...e.querySelectorAll("a.sidebar-link")].filter(i=>i.dataset.url===n);if(t.length){for(const i of t){const o=i.querySelector(".sidebar-badge[data-count-for]");if(!s||!(s.count>0)&&!s.showZero)o?.remove();else{const a=document.createRange();a.selectNodeContents(i);const d=a.createContextualFragment(te(n,s)).firstElementChild;o?o.replaceWith(d):i.querySelector(".sidebar-text")?.after(d)}}D.set(n,s),ne(e)}}const D=new Map;async function G(e,n=null){const s=n?A.filter(t=>t.url===n):A;await Promise.all(s.map(async t=>{const i=await ie(t),o=D.get(t.url);JSON.stringify(o??null)!==JSON.stringify(i)&&ae(e,t.url,i)}))}function Ke(e){e.dataset.liveCounts||(e.dataset.liveCounts="1",window.addEventListener(We,n=>{const s=n.detail||{};if(s.url)if(s.count!==void 0){const t=A.find(i=>i.url===s.url);ae(e,s.url,W(s,{fallbackLabel:t?.countLabel||t?.text||""}))}else G(e,s.url)}),setInterval(()=>{!document.hidden&&document.body.contains(e)&&G(e)},De),document.addEventListener("visibilitychange",()=>{document.hidden||G(e)}),Ve(e))}function re(e,n,s){const t=(a,d,u)=>{const c=document.createElement(a);return d&&(c.className=d),u!=null&&(c.textContent=String(u)),c};if(!s){e.textContent=n;return}e.appendChild(t("strong","dm-badge-pop-title",s.title||n)),(s.rows?.length||!s.items?.length)&&e.appendChild(t("p","dm-badge-pop-sub",n));const i=Array.isArray(s.rows)?s.rows.slice(0,6):[];if(i.length){const a=t("dl","dm-badge-pop-rows");for(const d of i)a.appendChild(t("dt",null,d.label)),a.appendChild(t("dd",d.tone==="danger"?"is-danger":null,d.value));e.appendChild(a)}const o=Array.isArray(s.items)?s.items.slice(0,6):[];if(o.length){const a=t("ul","dm-badge-pop-items");for(const d of o){const u=t("li",d.tone==="danger"?"is-danger":null);u.appendChild(t("span","dm-badge-pop-text",d.text)),d.meta&&u.appendChild(t("span","dm-badge-pop-meta",d.meta)),a.appendChild(u)}e.appendChild(a)}else s.empty&&e.appendChild(t("p","dm-badge-pop-empty",s.empty))}function Ve(e){let n=null,s=null;const t=()=>e.classList.contains("is-collapsed"),i=()=>{clearTimeout(s),n?.remove(),n=null},o=(c,r)=>{i(),s=setTimeout(()=>{n=document.createElement("div"),n.className="dm-help-pop dm-badge-pop",n.setAttribute("role","tooltip"),r(n),document.body.appendChild(n);const f=c.getBoundingClientRect(),x=n.getBoundingClientRect(),w=Math.min(f.right+10,innerWidth-x.width-8);n.style.left=`${Math.max(8,w)}px`,n.style.top=`${Math.max(8,Math.min(f.top+f.height/2-x.height/2,innerHeight-x.height-8))}px`},150)},a=c=>{const r=c?.dataset.badgeLabel;if(!r)return i();o(c,f=>re(f,r,j.get(c.dataset.countFor)))},d=c=>{const r=c.querySelector(":scope > .sidebar-text")?.textContent.trim()||"",f=c.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");o(c,x=>{const w=f&&j.get(f.dataset.countFor);if(w)return re(x,f.dataset.badgeLabel,{...w,title:w.title||r});if(!f){x.textContent=r;return}const k=document.createElement("strong");k.className="dm-badge-pop-title",k.textContent=r;const q=document.createElement("p");q.className="dm-badge-pop-sub",q.textContent=f.dataset.badgeLabel,x.append(k,q)})},u=c=>{const r=c.closest?.("a.sidebar-link, summary");return r&&e.contains(r)?r:null};e.addEventListener("mouseover",c=>{if(t()){const f=u(c.target);f&&!f.contains(c.relatedTarget)&&d(f);return}const r=c.target.closest?.(".sidebar-badge[data-badge-label]");r&&a(r)}),e.addEventListener("mouseout",c=>{if(t()){const r=u(c.target);r&&!r.contains(c.relatedTarget)&&i();return}c.target.closest?.(".sidebar-badge[data-badge-label]")&&i()}),e.addEventListener("focusin",c=>{const r=c.target.closest?.("a, summary");if(t()&&r&&e.contains(r)&&r.querySelector(":scope > .sidebar-text"))return d(r);const f=r?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");f?a(f):i()}),e.addEventListener("focusout",i),e.addEventListener("click",i),window.addEventListener("scroll",i,!0),window.addEventListener("hashchange",i)}async function Xe(e=[]){if(!O(e,"settings"))return"Admin";try{const n=await g.settings.get();return n?.adminBrand?.title||n?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:e,permissions:n,adminScope:s=null}){const t=$(e).get(0);if(!t)return;const i=Me(g,L()).catch(()=>{});let o,a=null,d=null,u=null,c=null,r=null;try{const l=await g.get("/sidebar/menu");o=Array.isArray(l?.items)?l.items:null,a=l?.variant||null,d=l?.position||null,u=l?.style||null,c=l?.float||null,r=l?.highlight||null}catch{o=null}(!o||!o.some(l=>l&&(!l.hidden||l.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),o=Re.slice());let f=[];try{f=await H.get("/api/sidebar/registered-items")||[]}catch{}o=ye(o,Z),o=he(o,f.filter(l=>(l?.item??l)?.url!==Z)),o=ge(o),o=ve(o,[be()]);const x=await _e(n);x.length&&Ie(o,x),o=$e(o,n,s),o=xe(o),await i;const w=Le(o,z(L()),{hidden:Ee(L())});w&&(o=[w,...o]),Be(o);const[k,q]=await Promise.all([ze(f.filter(l=>O(n,l?.item?.permission)),n,s).catch(()=>({})),Xe(n)]),F=a?` dm-admin-sidebar--${m(a)}`:"";function y(l,v="px"){if(l==null)return l;const h=String(l).trim();return/^\d+(\.\d+)?$/.test(h)?`${h}${v}`:h}let C="";if(u){const l=[];u.fontFamily&&l.push(`font-family: ${u.fontFamily}, sans-serif`),u.fontSize&&l.push(`font-size: ${y(u.fontSize)}`),u.fontWeight&&l.push(`font-weight: ${u.fontWeight}`),u.letterSpacing&&l.push(`letter-spacing: ${y(u.letterSpacing,"em")}`);const v=[];if(l.length&&v.push(`#admin-sidebar .dm-admin-sidebar, #admin-sidebar .dm-admin-sidebar .sidebar-link, #admin-sidebar .dm-admin-sidebar summary, #admin-sidebar .dm-admin-sidebar .sidebar-text { ${l.join("; ")} }`),u.iconSize){const h=y(u.iconSize);v.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${h} !important; height: ${h} !important; }`)}v.length&&(C=`<style data-admin-sidebar-style>${v.join(" ")}</style>`)}const B=ke(n)?we():"",P=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span><span class="dm-admin-sidebar-title">${m(q)}</span>${B}${qe()}</div>`,T=o.some(l=>l&&l.type==="spacer"&&l.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",U=`${C}<nav class="dm-admin-sidebar${F}${T}">${P}${o.map(l=>oe(l,k)).join("")}</nav>`,R=document.createRange();R.selectNodeContents(t);const p=R.createContextualFragment(U);t.replaceChildren(p),Domma.icons.scan(t),t.querySelector(".dm-admin-sidebar-arrange")?.addEventListener("click",()=>Se(t));for(const l of A)D.set(l.url,k[l.url]??null);ne(t),Ke(t),t.removeAttribute("data-menu-hover"),t.removeAttribute("data-menu-active"),t.style.removeProperty("--dm-menu-highlight"),me(t,{highlight:r});const b=document.querySelector(".dashboard-wrapper");["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(l=>{t.style[l]=""}),t.classList.remove("dm-menu-floating"),b&&(b.style.paddingLeft="",b.style.paddingRight=""),t.__dmGutter=()=>{if(d!=="floating"||!b)return;const l=c&&c.anchor||"TL",v=Number.isFinite(Number(c?.offsetX))?Number(c.offsetX):16,h=t.classList.contains("is-collapsed")?Ae:parseInt(t.style.width,10)||t.getBoundingClientRect().width||260,N=Math.round(h+v*2)+"px";l==="R"||l==="TR"||l==="BR"?b.style.paddingRight=N:b.style.paddingLeft=N},d==="floating"&&fe(t,{position:"floating",float:c||{}}),t.querySelectorAll("details").forEach(l=>{l.addEventListener("toggle",function(){const v=this.getAttribute("data-state-key");v&&S.set(v,this.open);const h=this.querySelector(":scope > .sidebar-children");if(h)if(this.open){const N=h.scrollHeight;h.style.maxHeight="0",requestAnimationFrame(()=>{h.style.maxHeight=N+"px",h.addEventListener("transitionend",function de(){h.style.maxHeight="none",h.removeEventListener("transitionend",de)})})}else{const N=h.scrollHeight;h.style.maxHeight=N+"px",requestAnimationFrame(()=>{h.style.maxHeight="0"})}})}),Ce(t),Qe(t),t.dataset.routeWired||(t.dataset.routeWired="1",M.subscribe("router:afterChange",()=>t.__dmSetActive?.()));function I(){const l=/^#\/(dashboards|my-dashboard)\b/.test(location.hash)?"#/":location.hash||"#/";$(t).find(".sidebar-link").removeClass("active"),$(t).find(`.sidebar-link[data-url="${l}"]`).addClass("active")}I(),t.__dmSetActive=I}function le(){try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}function K(e){return`${location.origin}${location.pathname}${e}`}function _(e,n){const s=L(),t=e(z(s));if(!Ne(s,t)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}t.length&&Q(s,!1),ce(s),n&&E.toast(n,{type:"success",duration:2500}),le()}function ce(e){He(g,e).catch(()=>E.toast("Frequent is saved in this browser only - the server could not keep it.",{type:"warning"}))}function Ze(e){if(!Q(L(),e)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}ce(L()),E.toast(e?"Frequent hidden. Add a Tool to it from its right-click menu to bring it back.":"Frequent shown.",{type:"success",duration:3500}),le()}function Ye(e){const n=e.dataset.url;if(!n)return[];const s=e.querySelector(".sidebar-text")?.textContent.trim()||n,t=z(L()),i=t.includes(n),o=!!e.closest("details[data-frequent]"),a=t.indexOf(n),d=!i&&t.length>=Y;return[{header:s},{label:"Open",icon:"arrow-right",...ee(n)&&{shortcut:Pe(ee(n))},action:()=>{location.hash=n}},{label:"Open in a new tab",icon:"external-link",action:()=>window.open(K(n),"_blank","noopener")},{type:"divider"},i?{label:"Remove from Frequent",icon:"star",action:()=>_(u=>Te(u,n),`${s} removed from Frequent.`)}:{label:d?`Frequent is full (${Y})`:"Add to Frequent",icon:"star",disabled:d,action:()=>_(u=>Fe(u,n),`${s} added to Frequent.`)},...o?[{label:"Move up",icon:"arrow-up",disabled:a<=0,action:()=>_(u=>J(u,n,-1))},{label:"Move down",icon:"arrow-down",disabled:a<0||a>=t.length-1,action:()=>_(u=>J(u,n,1))}]:[],{type:"divider"},{label:"Copy link",icon:"link",action:async()=>{try{await navigator.clipboard.writeText(K(n)),E.toast("Link copied.",{type:"success",duration:2e3})}catch{E.toast(K(n),{type:"info",duration:8e3})}}}]}function Je(e,n){const s=e.closest("details"),t=e.querySelector(".sidebar-text")?.textContent.trim()||"Folder",i=o=>n.querySelectorAll("details").forEach(a=>{a.open!==o&&(a.open=o)});return[{header:t},{label:s?.open?"Close":"Open",icon:s?.open?"chevron-up":"chevron-down",action:()=>{s&&(s.open=!s.open)}},{label:"Open every folder",icon:"chevrons-down",action:()=>i(!0)},{label:"Close every folder",icon:"chevrons-up",action:()=>i(!1)},...s?.hasAttribute("data-frequent-empty")?[{type:"divider"},{label:"Hide Frequent until I add a Tool",icon:"eye-off",action:()=>Ze(!0)}]:s?.hasAttribute("data-frequent")?[{type:"divider"},{label:"Clear Frequent",icon:"x",action:()=>_(()=>[],"Frequent cleared.")}]:[]]}function Qe(e){e.dataset.ctxWired||typeof E>"u"||!E.contextMenu||(e.dataset.ctxWired="1",E.contextMenu(e,{match:"a.sidebar-link, details > summary",inherit:!1,density:"compact",items:n=>n.matches("summary")?Je(n,e):Ye(n)}))}
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
<div class="col-12">
|
|
8
8
|
<div class="docs-body">
|
|
9
9
|
|
|
10
|
-
<p>The site's navigation is made of <strong>menus</strong>, edited at <strong>Content >
|
|
11
|
-
|
|
10
|
+
<p>The site's navigation is made of <strong>site menus</strong>, edited at <strong>Content >
|
|
11
|
+
Site menus</strong>. (Not to be confused with <strong>page contents</strong> - the list a layout
|
|
12
|
+
with a sidebar builds from a page's own headings, set up in <strong>Layouts</strong> and per page
|
|
13
|
+
with <code>[contents]</code>.) A menu is a list of links; a <strong>location</strong> (a slot) is where one is
|
|
12
14
|
shown. Each menu is a file in <code>config/menus/</code>, and the slot map is
|
|
13
15
|
<code>config/menu-locations.json</code>. Pages have no "show in navigation" switch - a page
|
|
14
16
|
appears in the navbar when a menu links to it.</p>
|
|
@@ -310,7 +310,7 @@ Your text appears letter by letter.
|
|
|
310
310
|
<tr>
|
|
311
311
|
<td><code>[render]</code></td>
|
|
312
312
|
<td><code>[render effect="fade"]Text[/render]</code></td>
|
|
313
|
-
<td>Type the text. Optional <code>effect</code>: fade,
|
|
313
|
+
<td>Type the text. Optional <code>effect</code>: none, fade, bounce, glow (inherits the Scribe default)</td>
|
|
314
314
|
</tr>
|
|
315
315
|
<tr>
|
|
316
316
|
<td><code>[wait]</code></td>
|
|
@@ -321,7 +321,7 @@ Your text appears letter by letter.
|
|
|
321
321
|
<td><code>[undo]</code></td>
|
|
322
322
|
<td><code>[undo /]</code> or <code>[undo count="3" /]</code> or <code>[undo all="true" /]</code>
|
|
323
323
|
</td>
|
|
324
|
-
<td>Delete the last render action, N
|
|
324
|
+
<td>Delete the last render action, N units in the chosen mode, or all text</td>
|
|
325
325
|
</tr>
|
|
326
326
|
</tbody>
|
|
327
327
|
</table>
|
|
@@ -357,12 +357,12 @@ Your text appears letter by letter.
|
|
|
357
357
|
<tr>
|
|
358
358
|
<td><code>cursor-type</code></td>
|
|
359
359
|
<td>-</td>
|
|
360
|
-
<td>Cursor style (block, underline
|
|
360
|
+
<td>Cursor style (caret, block, underline)</td>
|
|
361
361
|
</tr>
|
|
362
362
|
<tr>
|
|
363
363
|
<td><code>loop</code></td>
|
|
364
364
|
<td>false</td>
|
|
365
|
-
<td>
|
|
365
|
+
<td>false: once; true: forever; positive integer: total plays</td>
|
|
366
366
|
</tr>
|
|
367
367
|
<tr>
|
|
368
368
|
<td><code>loop-delay</code></td>
|
|
@@ -374,6 +374,12 @@ Your text appears letter by letter.
|
|
|
374
374
|
<td>false</td>
|
|
375
375
|
<td>Pause animation while hovered (true/false)</td>
|
|
376
376
|
</tr>
|
|
377
|
+
<tr><td><code>mode</code></td><td>typewriter</td><td>Characters (typewriter), word, or sentence</td></tr>
|
|
378
|
+
<tr><td><code>effect</code></td><td>none</td><td>Default entrance: none, fade, bounce, glow</td></tr>
|
|
379
|
+
<tr><td><code>cursor-blink</code></td><td>true</td><td>Blink while idle; steady while typing and deleting</td></tr>
|
|
380
|
+
<tr><td><code>auto-start</code></td><td>true</td><td>false waits for Play; playback controls appear automatically</td></tr>
|
|
381
|
+
<tr><td><code>respect-motion-preference</code></td><td>Site setting</td><td>Honor the visitor’s reduced motion preference</td></tr>
|
|
382
|
+
<tr><td><code>controls</code></td><td>false</td><td>Show Play, Pause, and Replay</td></tr>
|
|
377
383
|
</tbody>
|
|
378
384
|
</table>
|
|
379
385
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<!-- Layouts -->
|
|
12
12
|
<div class="tab-panel active">
|
|
13
|
-
<p class="lyx-note">A layout sets a page's width, background, and whether it has the navbar, footer and
|
|
13
|
+
<p class="lyx-note">A layout sets a page's width, background, and whether it has the navbar, footer and page contents (the list of the page's sections).
|
|
14
14
|
Pages choose one in the page editor; a page that names none uses Default.
|
|
15
15
|
<span data-help-title="Layouts" data-help="The built-in layouts can be edited but not deleted. A layout you make gets a key from its name (Dark Landing becomes dark-landing) - that key is what a page's layout: line names, and it does not change if you rename the layout later. Deleting a layout that pages use leaves those pages on Default."></span></p>
|
|
16
16
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{api as O,apiRequest as Qe}from"../api.js";import{HIGHLIGHT_HOVER as Xe,HIGHLIGHT_ACTIVE as Ze,HIGHLIGHT_HOVER_LABELS as et,HIGHLIGHT_ACTIVE_LABELS as tt}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{addBannerAction as at}from"../lib/plugin-chrome.js";import{helpPopovers as Me}from"../lib/help-popover.js";import{onceClosed as Te,openMenuAt as He,sidebarCount as lt}from"../lib/tool-kit.js";import{FILTERS as st,WIDTHS as ot,WIDTH_HINTS as nt,WIDTH_LABELS as it,WIDTH_SHARE as $e,arrangeLayouts as ct,checkLayout as rt,checkOptions as dt,formFromPreset as ut}from"../lib/layouts-arrange.js";const ae=/^\/layouts\/?(\?.*)?$/,Le="#/layouts",le="layouts.draft",
|
|
1
|
+
import{api as O,apiRequest as Qe}from"../api.js";import{HIGHLIGHT_HOVER as Xe,HIGHLIGHT_ACTIVE as Ze,HIGHLIGHT_HOVER_LABELS as et,HIGHLIGHT_ACTIVE_LABELS as tt}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{addBannerAction as at}from"../lib/plugin-chrome.js";import{helpPopovers as Me}from"../lib/help-popover.js";import{onceClosed as Te,openMenuAt as He,sidebarCount as lt}from"../lib/tool-kit.js";import{FILTERS as st,WIDTHS as ot,WIDTH_HINTS as nt,WIDTH_LABELS as it,WIDTH_SHARE as $e,arrangeLayouts as ct,checkLayout as rt,checkOptions as dt,formFromPreset as ut}from"../lib/layouts-arrange.js";const ae=/^\/layouts\/?(\?.*)?$/,Le="#/layouts",le="layouts.draft",z="layouts.options.draft",se="layouts.filter",Oe=(l="")=>`
|
|
2
2
|
<span class="lyx-shape" aria-hidden="true" data-bind-style-background-color="bg${l}">
|
|
3
3
|
<span class="lyx-shape-nav" data-bind-hidden="!hasNav${l}"></span>
|
|
4
4
|
<span class="lyx-shape-body"><span class="lyx-shape-col" data-bind-style-width="share${l}"></span><span class="lyx-shape-side" data-bind-hidden="!hasSide${l}" data-bind-class="sideRight${l} && 'is-right'"></span></span>
|
|
@@ -13,11 +13,11 @@ import{api as O,apiRequest as Qe}from"../api.js";import{HIGHLIGHT_HOVER as Xe,HI
|
|
|
13
13
|
<span class="lyx-chip" data-bind-class="usedTone" title="Pages that use this layout">{{usedText}}</span>
|
|
14
14
|
</span>
|
|
15
15
|
<button type="button" class="lyx-kebab" aria-label="Actions for {{label}}" title="Actions">\u22EE</button>
|
|
16
|
-
</div>`,G=l=>String(l??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Be(l){const c=document.createElement("template");return c.innerHTML=l.trim(),c.content.firstElementChild}const De=(l,c,i=`${c}s`)=>`${l} ${l===1?c:i}`,bt=l=>`#/pages/edit${l}`;let m=null,Ae=!1;function ht(){Ae||!window.R?.use||(Ae=!0,R.use((l,c,i)=>!(ae.test(c?.path||"")&&!ae.test(l?.path||""))||!m?.dirty()?i():E.confirm("You have unsaved layout changes. Leave anyway? They are kept as a draft for your next visit.").then(u=>{u?i():history.replaceState(null,"",Le)})),M.subscribe("router:afterChange",({to:l}={})=>{if(m&&!ae.test(l?.path||"")){const c=m;m=null,c.dispose()}}))}export const layoutsView={templateUrl:"/admin/js/templates/layouts.html",async onMount(l){if(ht(),m){const e=m;m=null,e.dispose()}const c=[],i=e=>(c.push(e),e);let V=!1;const u=l.get(0).querySelector(".lyx")||l.get(0),p=()=>!V&&u.isConnected,b=M.observable({}),
|
|
16
|
+
</div>`,G=l=>String(l??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Be(l){const c=document.createElement("template");return c.innerHTML=l.trim(),c.content.firstElementChild}const De=(l,c,i=`${c}s`)=>`${l} ${l===1?c:i}`,bt=l=>`#/pages/edit${l}`;let m=null,Ae=!1;function ht(){Ae||!window.R?.use||(Ae=!0,R.use((l,c,i)=>!(ae.test(c?.path||"")&&!ae.test(l?.path||""))||!m?.dirty()?i():E.confirm("You have unsaved layout changes. Leave anyway? They are kept as a draft for your next visit.").then(u=>{u?i():history.replaceState(null,"",Le)})),M.subscribe("router:afterChange",({to:l}={})=>{if(m&&!ae.test(l?.path||"")){const c=m;m=null,c.dispose()}}))}export const layoutsView={templateUrl:"/admin/js/templates/layouts.html",async onMount(l){if(ht(),m){const e=m;m=null,e.dispose()}const c=[],i=e=>(c.push(e),e);let V=!1;const u=l.get(0).querySelector(".lyx")||l.get(0),p=()=>!V&&u.isConnected,b=M.observable({}),F=M.observable({byKey:{},missing:[]}),oe=M.observable(!0),Y=M.observable("");let ne="all";try{ne=st.includes(S.get(se))?S.get(se):"all"}catch{}const k=M.observable(ne),ie=M.observable("");i(M.effect(()=>{const e=k.value;try{S.set(se,e)}catch{}}));const ce=M.observable([]);i(M.effect(()=>{ce.value=ct(b.value,F.value,{filter:k.value,query:ie.value})}));const Ie=M.computed(()=>{const e=Object.values(b.value),t=e.filter(o=>o.builtin).length;return{all:e.length,builtin:t,custom:e.length-t}}),U=M.computed(()=>F.value.missing||[]),Pe=M.computed(()=>{const e=U.value.length;return`${De(e,"page")} name${e===1?"s":""} a layout that no longer exists and show${e===1?"s":""} as Default.`}),j=M.observable({spacerSize:"8",spacerClass:""}),f=M.observable("8"),g=M.observable(""),J=M.observable(!1),re=()=>({spacerSize:String(f.value??""),spacerClass:String(g.value??"")}),N=M.computed(()=>dt(re())),x=M.computed(()=>{const e=j.value;return String(f.value??"")!==e.spacerSize||String(g.value??"")!==e.spacerClass}),de=M.computed(()=>J.value||!x.value||Object.keys(N.value.errors).length>0),ze=M.computed(()=>x.value?"Unsaved changes - Ctrl+S saves.":"Saved."),B=e=>({...b.peek()[e]||{},key:e}),Q=e=>(F.peek().byKey||{})[e]||[];async function X(){try{const[e,t]=await Promise.all([O.layouts.get(),Qe("/layouts/_usage",{method:"GET"}).catch(()=>({byKey:{},missing:[]}))]);if(!p())return;b.value=e&&typeof e=="object"?e:{},F.value=t&&typeof t=="object"?t:{byKey:{},missing:[]},Y.value=""}catch(e){Y.value=`Could not load the layouts: ${e.message||e}`}finally{oe.value=!1}}async function Fe(){const e=await O.layouts.getOptions().catch(()=>({spacerSize:8,spacerClass:""}));if(!p())return;const t={spacerSize:String(e?.spacerSize??8),spacerClass:String(e?.spacerClass??"")};j.value=t,f.value=t.spacerSize,g.value=t.spacerClass}async function ue(){if(de.peek())return;J.value=!0;const{payload:e}=N.peek();try{await O.layouts.saveOptions(e),j.value={spacerSize:String(e.spacerSize),spacerClass:e.spacerClass},f.value=String(e.spacerSize),g.value=e.spacerClass;try{S.remove?S.remove(z):S.set(z,null)}catch{}E.toast("Layout options saved.",{type:"success"})}catch(t){E.toast(`Not saved: ${t.message||t}`,{type:"error"})}finally{J.value=!1}}function Re(){const e=j.peek();f.value=e.spacerSize,g.value=e.spacerClass}const pe=()=>lt(Le);async function je(e){const t=B(e);if(t.builtin)return;const o=Q(e).length,r=o?` ${De(o,"page")} use${o===1?"s":""} it and will show as Default.`:" No page uses it.";if(await E.confirm(`Delete the layout "${G(t.label||e)}"?${r}`))try{await O.layouts.remove(e),E.toast(`Deleted "${t.label||e}".`,{type:"success"}),pe(),p()&&await X()}catch(n){E.toast(`Not deleted: ${n.message||n}`,{type:"error"})}}async function Ne(e){const t=`layout: ${e}`;try{await navigator.clipboard.writeText(t),E.toast(`Copied "${t}" - paste it into a page's frontmatter.`,{type:"success"})}catch{E.toast(`Copy this into a page's frontmatter: ${t}`,{type:"info",duration:7e3})}}const C=new Set;let h=null,be=!1;function he(e){const t=e===null,o=t?U.peek():Q(e),r=t?null:B(e),n=E.slideover({title:t?"Pages on a missing layout":`Pages using ${G(r.label||e)}`,size:"sm",position:"right"}),D=Be(`
|
|
17
17
|
<div class="lyx-form">
|
|
18
18
|
<p class="lyx-note"></p>
|
|
19
19
|
<div class="lyx-pages"></div>
|
|
20
|
-
</div>`);D.querySelector(".lyx-note").textContent=t?"These pages name a layout that no longer exists, so they show as Default. Open one and choose a layout for it.":o.length?"Click a page to open it in the editor.":"No page uses this layout.";const W=D.querySelector(".lyx-pages");for(const s of o){const w=document.createElement("a");w.href=bt(s.urlPath);const A=document.createElement("span");A.textContent=s.title||s.urlPath;const _=document.createElement("small");_.textContent=[s.urlPath,t?`"${s.layout}"`:"",s.status==="draft"?"draft":""].filter(Boolean).join(" \xB7 "),w.append(A,_),w.addEventListener("click",()=>n.close()),W.appendChild(w)}n.element.appendChild(D),C.add(n),Te(n,()=>C.delete(n)),n.open()}function T(e=null,{from:t=null,draft:o=null}={}){const r=e?B(e):null;if(e&&!b.peek()[e]){E.toast(`There is no layout "${e}".`,{type:"warning"});return}const n=!r,D=r||(t?{...B(t),label:`${B(t).label||t} copy`,builtin:!1}:{}),W={...ut(D),...o||{}},s=Object.fromEntries(Object.entries(W).map(([a,y])=>[a,M.observable(y)])),w=()=>Object.fromEntries(Object.keys(s).map(a=>[a,s[a].peek()])),A=a=>JSON.stringify(Object.fromEntries(Object.entries(a).map(([y,te])=>[y,typeof te=="boolean"?te:String(te??"")]))),_=A(W),Se=()=>A(w())!==_||!!o||!!(t&&n),K=M.observable(!1),
|
|
20
|
+
</div>`);D.querySelector(".lyx-note").textContent=t?"These pages name a layout that no longer exists, so they show as Default. Open one and choose a layout for it.":o.length?"Click a page to open it in the editor.":"No page uses this layout.";const W=D.querySelector(".lyx-pages");for(const s of o){const w=document.createElement("a");w.href=bt(s.urlPath);const A=document.createElement("span");A.textContent=s.title||s.urlPath;const _=document.createElement("small");_.textContent=[s.urlPath,t?`"${s.layout}"`:"",s.status==="draft"?"draft":""].filter(Boolean).join(" \xB7 "),w.append(A,_),w.addEventListener("click",()=>n.close()),W.appendChild(w)}n.element.appendChild(D),C.add(n),Te(n,()=>C.delete(n)),n.open()}function T(e=null,{from:t=null,draft:o=null}={}){const r=e?B(e):null;if(e&&!b.peek()[e]){E.toast(`There is no layout "${e}".`,{type:"warning"});return}const n=!r,D=r||(t?{...B(t),label:`${B(t).label||t} copy`,builtin:!1}:{}),W={...ut(D),...o||{}},s=Object.fromEntries(Object.entries(W).map(([a,y])=>[a,M.observable(y)])),w=()=>Object.fromEntries(Object.keys(s).map(a=>[a,s[a].peek()])),A=a=>JSON.stringify(Object.fromEntries(Object.entries(a).map(([y,te])=>[y,typeof te=="boolean"?te:String(te??"")]))),_=A(W),Se=()=>A(w())!==_||!!o||!!(t&&n),K=M.observable(!1),P=M.computed(()=>rt(Object.fromEntries(Object.keys(s).map(a=>[a,s[a].value])),{isNew:n,taken:Object.keys(b.value)})),q=a=>M.computed(()=>P.value.errors[a]||""),qe={hasNav:M.computed(()=>s.navbar.value!==!1),hasFoot:M.computed(()=>s.footer.value!==!1),hasSide:M.computed(()=>s.sidebar.value===!0),sideRight:M.computed(()=>s.sidebar.value===!0&&s.sidebarSide.value==="right"),share:M.computed(()=>$e[s.width.value]||$e.normal),bg:M.computed(()=>s.useBg.value?s.bgColor.value:"")},Ee={...s,...qe,saving:K,labelErr:q("label"),bgErr:q("bgColor"),classErr:q("cssClass"),cWidthErr:q("cWidth"),hoverOptions:[{value:"",label:"The theme's"},...Xe.map(a=>({value:a,label:et[a]||a}))],selectedOptions:[{value:"",label:"The theme's"},...Ze.map(a=>({value:a,label:tt[a]||a}))],keyHint:M.computed(()=>n?P.value.key?`Pages will name it "layout: ${P.value.key}".`:"":`Pages name it "layout: ${r.key}" - renaming does not change that.`),widthHint:M.computed(()=>nt[s.width.value]||""),builtinNote:!n&&r.builtin===!0,noBg:M.computed(()=>!s.useBg.value),cannot:M.computed(()=>K.value||Object.keys(P.value.errors).length>0),saveText:n?"Create layout":"Save"},Ge=n?t?"Duplicate layout":"New layout":`Edit ${G(r.label||r.key)}`,d=E.slideover({title:Ge,size:"md",position:"right"}),L=Be(`
|
|
21
21
|
<div class="lyx-form">
|
|
22
22
|
<div class="lyx-preview">${Oe(".value")}
|
|
23
23
|
<small class="lyx-hint" data-bind-text="keyHint.value"></small></div>
|
|
@@ -42,18 +42,18 @@ import{api as O,apiRequest as Qe}from"../api.js";import{HIGHLIGHT_HOVER as Xe,HI
|
|
|
42
42
|
</div>
|
|
43
43
|
<div class="lyx-wide">
|
|
44
44
|
<span class="form-label">Around the content
|
|
45
|
-
<span data-help="Whether pages on this layout show the site's navbar and footer, and the
|
|
45
|
+
<span data-help="Whether pages on this layout show the site's navbar and footer, and the page contents - a list of the page's own sections, built from its headings."></span></span>
|
|
46
46
|
<div class="lyx-switches">
|
|
47
47
|
<label><input type="checkbox" class="form-switch" data-model="navbar.value"> Navbar</label>
|
|
48
48
|
<label><input type="checkbox" class="form-switch" data-model="footer.value"> Footer</label>
|
|
49
|
-
<label><input type="checkbox" class="form-switch" data-model="sidebar.value">
|
|
49
|
+
<label><input type="checkbox" class="form-switch" data-model="sidebar.value"> Page contents</label>
|
|
50
50
|
</div>
|
|
51
51
|
<div class="lyx-switches" data-if="sidebar.value">
|
|
52
|
-
<label><input type="radio" name="lyx-side" value="left" data-model="sidebarSide.value">
|
|
52
|
+
<label><input type="radio" name="lyx-side" value="left" data-model="sidebarSide.value"> Page contents on the left</label>
|
|
53
53
|
<label><input type="radio" name="lyx-side" value="right" data-model="sidebarSide.value"> on the right</label>
|
|
54
54
|
</div>
|
|
55
55
|
<details class="lyx-contents" data-if="sidebar.value">
|
|
56
|
-
<summary>Page contents settings <span data-help="
|
|
56
|
+
<summary>Page contents settings <span data-help="Page contents lists the page's own headings. These are the defaults for every page on the layout; a page can change any of them for itself with the [contents] tag."></span></summary>
|
|
57
57
|
<div class="lyx-contents-grid">
|
|
58
58
|
<label>Width (px) <input type="number" class="form-input" min="160" max="480" step="10" placeholder="260" data-model="cWidth.value"></label>
|
|
59
59
|
<label>Headings
|
|
@@ -124,4 +124,4 @@ import{api as O,apiRequest as Qe}from"../api.js";import{HIGHLIGHT_HOVER as Xe,HI
|
|
|
124
124
|
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="cannot.value">
|
|
125
125
|
<span data-icon="check" data-icon-size="13"></span> <span data-bind-text="saveText"></span></button>
|
|
126
126
|
</div>
|
|
127
|
-
</div>`);async function ke(){if(Ee.cannot.peek())return;K.value=!0;const{payload:a}=
|
|
127
|
+
</div>`);async function ke(){if(Ee.cannot.peek())return;K.value=!0;const{payload:a}=P.peek();try{n?await O.layouts.create(a):await O.layouts.update(r.key,a),E.toast(n?`Created "${a.label}".`:"Saved.",{type:"success"}),Z=!0,d.close(),pe(),p()&&await X()}catch(y){E.toast(`Not saved: ${y.message||y}`,{type:"error"})}finally{K.value=!1}}d.element.appendChild(L);const Ve=Me(L),Ye=M.applyBindings(Ee,L,{methods:{save:ke,cancel:()=>d.close()}}),Ue=a=>{(a.ctrlKey||a.metaKey)&&a.key==="Enter"&&(a.preventDefault(),ke())};L.addEventListener("keydown",Ue);const Ce={key:r?.key??null,dirty:Se,values:w};h=Ce,C.add(d),Te(d,()=>{Ye.dispose(),Ve(),C.delete(d),h===Ce&&(h=null)});const Je=d.close.bind(d);let Z=!1,ee=!1;d.close=async a=>{if(!Z&&!be&&a!==!0&&Se()){if(ee)return;ee=!0;const y=await E.confirm("Discard the changes you have not saved?");if(ee=!1,!y)return}return Z=!0,Je()},I.scan(L),d.open(),L.querySelector("#lyx-f-label")?.focus()}function We(e){const t=b.peek()[e];if(!t)return[];const o=Q(e).length;return[{header:t.label||e},{label:"Edit\u2026",icon:"edit",action:()=>T(e)},{label:o?`Pages using it (${o})\u2026`:"Pages using it",icon:"file-text",disabled:!o,action:()=>he(e)},{label:"Duplicate\u2026",icon:"copy",action:()=>T(null,{from:e})},{label:"Copy frontmatter line",icon:"clipboard",action:()=>Ne(e)},...t.builtin?[]:[{type:"divider"},{label:"Delete\u2026",icon:"trash",danger:!0,action:()=>je(e)}]]}const H=u.querySelector(".lyx-list");H.innerHTML=pt;const ve=E.tabs(u.querySelector(".lyx-tabs"),{tabSelector:".tab-item",panelSelector:".tab-panel"}),_e=M.applyBindings({loading:oe,loadError:Y,filter:k,query:ie,rows:ce,counts:Ie,missing:U,missingText:Pe,spacerSize:f,spacerClass:g,optDirty:x,optCannot:de,optStatus:ze,optErrSize:M.computed(()=>N.value.errors.spacerSize||""),optErrClass:M.computed(()=>N.value.errors.spacerClass||"")},u,{methods:{showAll:()=>{k.value="all"},showBuiltin:()=>{k.value="builtin"},showCustom:()=>{k.value="custom"},showMissing:()=>he(null),saveOptions:()=>ue(),resetOptions:()=>Re()}});i(()=>_e.dispose()),i(Me(u,{position:"bottom"}));const Ke=E.contextMenu(H,{cursor:"glyph",match:".lyx-row",inherit:!1,density:"compact",items:e=>We(e.dataset.key)});i(()=>Ke?.destroy?.());const ye=e=>{const t=e.target.closest(".lyx-row");if(!t)return;const o=e.target.closest(".lyx-kebab");if(o){He(o);return}T(t.dataset.key)},me=e=>{const t=e.target.closest(".lyx-row");t&&(e.key==="F10"&&e.shiftKey?(e.preventDefault(),He(t)):e.key==="Enter"&&e.target===t&&T(t.dataset.key))};H.addEventListener("click",ye),H.addEventListener("keydown",me),i(()=>{H.removeEventListener("click",ye),H.removeEventListener("keydown",me)});const fe=e=>{!(e.ctrlKey||e.metaKey)||e.key!=="s"||!p()||C.size||(e.preventDefault(),x.peek()&&ue())};document.addEventListener("keydown",fe,!0),i(()=>document.removeEventListener("keydown",fe,!0)),at(l,{id:"layouts-new",icon:"plus",title:"New layout",onClick:()=>{ve.activate?.(0),T()}});const ge=e=>{(x.peek()||h?.dirty())&&(xe(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",ge),i(()=>window.removeEventListener("beforeunload",ge));function xe(){try{h?.dirty()&&S.set(le,{key:h.key,values:h.values(),at:new Date().toISOString()}),x.peek()&&S.set(z,{...re(),at:new Date().toISOString()})}catch{}}if(m={dirty:()=>x.peek()||!!h?.dirty(),dispose(){V=!0,xe(),be=!0,[...C].forEach(e=>{try{e.close(!0)}catch{}}),c.splice(0).forEach(e=>{try{e()}catch{}})}},I.scan(u),await Promise.all([X(),Fe()]),!p())return;I.scan(u);let $=null,v=null;try{$=S.get(z),v=S.get(le)}catch{}const we=e=>{try{S.remove?S.remove(e):S.set(e,null)}catch{}};if($&&typeof $=="object"&&"spacerSize"in $&&(we(z),await E.confirm("You left unsaved spacer options. Put them back?")&&p()&&(f.value=String($.spacerSize??""),g.value=String($.spacerClass??""),ve.activate?.(1))),v?.values&&p()){we(le);const e=v.key&&b.peek()[v.key],t=e?`your changes to "${G(b.peek()[v.key].label||v.key)}"`:"the new layout you started";await E.confirm(`You left ${t} unsaved. Pick up where you left off?`)&&p()&&T(e?v.key:null,{draft:v.values})}}};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domma-cms",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.17",
|
|
4
4
|
"description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/server.js",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"@fastify/rate-limit": "^10.3.0",
|
|
85
85
|
"@fastify/static": "9.1.1",
|
|
86
86
|
"bcryptjs": "^3.0.3",
|
|
87
|
-
"domma-js": "0.51.
|
|
87
|
+
"domma-js": "0.51.9",
|
|
88
88
|
"dotenv": "^17.2.3",
|
|
89
89
|
"fastify": "5.8.5",
|
|
90
90
|
"gray-matter": "^4.0.3",
|