domma-cms 0.13.5 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/admin/css/admin.css +1 -1
  2. package/admin/js/api.js +1 -1
  3. package/admin/js/app.js +2 -2
  4. package/admin/js/config/sidebar-config.js +1 -1
  5. package/admin/js/lib/markdown-toolbar.js +24 -18
  6. package/admin/js/lib/scribe-composer.js +4 -0
  7. package/admin/js/lib/simple-editor.js +49 -0
  8. package/admin/js/templates/block-editor.html +76 -18
  9. package/admin/js/templates/blocks.html +18 -8
  10. package/admin/js/templates/component-editor.html +141 -0
  11. package/admin/js/templates/components.html +18 -0
  12. package/admin/js/views/block-editor-enhance.js +1 -0
  13. package/admin/js/views/block-editor.js +8 -8
  14. package/admin/js/views/blocks.js +11 -4
  15. package/admin/js/views/component-editor.js +28 -0
  16. package/admin/js/views/components.js +11 -0
  17. package/admin/js/views/index.js +1 -1
  18. package/admin/js/views/layouts.js +1 -1
  19. package/admin/js/views/page-editor.js +6 -6
  20. package/admin/js/views/pages.js +5 -2
  21. package/config/navigation.json +5 -0
  22. package/config/plugins.json +5 -5
  23. package/config/presets.json +92 -40
  24. package/config/site.json +75 -8
  25. package/package.json +2 -2
  26. package/public/css/site.css +1 -1
  27. package/server/routes/api/blocks.js +128 -60
  28. package/server/routes/api/components.js +115 -0
  29. package/server/routes/api/layouts.js +24 -0
  30. package/server/routes/api/pages.js +135 -132
  31. package/server/routes/api/versions.js +16 -0
  32. package/server/server.js +6 -0
  33. package/server/services/blocks.js +387 -284
  34. package/server/services/components.js +653 -0
  35. package/server/services/content.js +334 -334
  36. package/server/services/hooks.js +28 -0
  37. package/server/services/markdown.js +2836 -2629
  38. package/server/services/permissionRegistry.js +13 -0
  39. package/server/services/renderer.js +13 -3
  40. package/server/services/versions.js +37 -0
@@ -1,4 +1,4 @@
1
- import{api as j}from"../api.js";import{CardBuilder as Ke}from"../lib/card-builder.js?v=4";import{attachEditorKeybindings as Ze,createToolbar as Xe,insertAtCursor as ye}from"../lib/markdown-toolbar.js?v=9";import{populateThemeSelect as et}from"../lib/themes.js";import{createFoldingManager as tt}from"../lib/editor-folding.js";import{makeField as pe,makeSelect as qe,makeTextInput as Me,makeCheckbox as We,makeLivePreview as He,makeIconInput as _e}from"../lib/shortcode-modal.js";function nt(){const l=E.slideover({title:"Editor Reference",size:"md",position:"right"}),se="background:var(--dm-surface-subtle,#1a1a2e);padding:.2rem .4rem;border-radius:3px;font-size:.85em;font-family:monospace;",de="margin:1rem 0 .5rem;font-size:1rem;";function G(b){const w=document.createElement("code");return w.style.cssText=se,w.textContent=b,w}function J(b){const w=document.createElement("h3");return w.style.cssText=de,w.textContent=b,w}const Ne=document.createElement("div");Ne.style.cssText="padding:1rem;";const Ie=document.createElement("div");Ie.className="tabs";const Pe=document.createElement("div");Pe.className="tab-list",["Basics","Layout","Components","Data","Advanced"].forEach((b,w)=>{const i=document.createElement("button");i.className="tab-item"+(w===0?" active":""),i.textContent=b,Pe.appendChild(i)});const W=document.createElement("div");W.className="tab-content";const Se="display:flex;flex-direction:column;gap:1rem;",$e=document.createElement("div");$e.className="tab-panel active",$e.style.cssText=Se;const fe=document.createElement("div");fe.className="tab-panel",fe.style.cssText=Se;const ie=document.createElement("div");ie.className="tab-panel",ie.style.cssText=Se;const ve=document.createElement("div");ve.className="tab-panel",ve.style.cssText=Se;const Ee=document.createElement("div");Ee.className="tab-panel",Ee.style.cssText=Se,W.appendChild($e),W.appendChild(fe),W.appendChild(ie),W.appendChild(ve),W.appendChild(Ee),Ie.appendChild(Pe),Ie.appendChild(W),Ne.appendChild(Ie);const Re=document.createElement("div");Re.appendChild(J("Markdown Basics"));const me=document.createElement("table");me.style.cssText="width:100%;border-collapse:collapse;font-size:.9em;";const Q=document.createElement("thead"),ne=document.createElement("tr");["Syntax","Result"].forEach(b=>{const w=document.createElement("th");w.style.cssText="text-align:left;padding:.4rem .5rem;border-bottom:1px solid var(--dm-border,#333);",w.textContent=b,ne.appendChild(w)}),Q.appendChild(ne),me.appendChild(Q);const he=document.createElement("tbody");[["**bold**","bold (rendered bold)"],["_italic_","italic (rendered italic)"],["## Heading","Heading (h2)"],["[text](url)","Link"],["![alt](url)","Image"],["- item","Bullet list"],["`code`","Inline code"],["---","Divider"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.35rem .5rem;vertical-align:top;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.35rem .5rem;vertical-align:top;color:var(--dm-text-muted,#aaa);font-size:.85em;",o.textContent=w,i.appendChild(s),i.appendChild(o),he.appendChild(i)}),me.appendChild(he),Re.appendChild(me),$e.appendChild(Re);const ee=document.createElement("div");ee.appendChild(J("Grid & Columns"));function U(b){const w=document.createElement("p");return w.style.cssText="margin:.3rem 0 .6rem;font-size:.82em;color:var(--dm-text-muted,#aaa);",w.textContent=b,w}function B(b,w,i){const s=document.createElement("p");s.style.cssText="margin:.75rem 0 .25rem;font-size:.85em;font-weight:600;",s.textContent=b;const o=document.createElement("div");o.style.cssText="position:relative;";const _=document.createElement("pre");_.style.cssText=se+"display:block;padding:.5rem 2rem .5rem .75rem;white-space:pre;overflow-x:auto;margin:0;",_.textContent=w;const K=document.createElement("button");K.type="button",K.title="Copy code",K.style.cssText="position:absolute;top:.3rem;right:.3rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.15rem;line-height:1;color:inherit;",K.addEventListener("mouseenter",()=>{K.style.opacity="1"}),K.addEventListener("mouseleave",()=>{K.style.opacity=".45"});const ae=document.createElement("span");ae.setAttribute("data-icon","copy"),K.appendChild(ae),K.addEventListener("click",()=>{const P=document.createElement("textarea");P.value=w,P.style.cssText="position:fixed;opacity:0;",document.body.appendChild(P),P.select(),document.execCommand("copy"),P.remove(),E.toast("Copied!",{type:"success",duration:1200})}),o.appendChild(_),o.appendChild(K);const X=document.createDocumentFragment();return X.appendChild(s),X.appendChild(o),i&&X.appendChild(U(i)),X}const te=document.createElement("table");te.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['cols="N"',"[grid] only","Number of columns (1\u201312)"],['gap="N"',"[grid], [row]","Gap between columns/rows (1\u20136)"],['span="N"',"[col] only","How many columns this cell spans"],['fullwidth="true"',"[grid] only","Break out of page container to span full viewport"],['class="x"',"all","Add extra CSS classes"]].forEach(([b,w,i])=>{const s=document.createElement("tr");[b,w,i].forEach((o,_)=>{const K=document.createElement("td");K.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",_===0?K.appendChild(G(b)):(K.style.color="var(--dm-text-muted,#aaa)",K.textContent=o),s.appendChild(K)}),te.appendChild(s)}),ee.appendChild(te),ee.appendChild(B("Equal columns",`[grid cols="3" gap="4"]
1
+ import{api as j}from"../api.js";import{CardBuilder as Ke}from"../lib/card-builder.js?v=4";import{attachEditorKeybindings as Ze,createToolbar as Xe,insertAtCursor as ye}from"../lib/markdown-toolbar.js?v=9";import{populateThemeSelect as et}from"../lib/themes.js";import{createFoldingManager as tt}from"../lib/editor-folding.js";import{makeCheckbox as We,makeField as pe,makeIconInput as _e,makeLivePreview as He,makeSelect as qe,makeTextInput as Me}from"../lib/shortcode-modal.js";import{openScribeComposer as nt}from"../lib/scribe-composer.js?v=1";function at(){const l=E.slideover({title:"Editor Reference",size:"md",position:"right"}),se="background:var(--dm-surface-subtle,#1a1a2e);padding:.2rem .4rem;border-radius:3px;font-size:.85em;font-family:monospace;",de="margin:1rem 0 .5rem;font-size:1rem;";function G(b){const w=document.createElement("code");return w.style.cssText=se,w.textContent=b,w}function J(b){const w=document.createElement("h3");return w.style.cssText=de,w.textContent=b,w}const Ne=document.createElement("div");Ne.style.cssText="padding:1rem;";const Ie=document.createElement("div");Ie.className="tabs";const Pe=document.createElement("div");Pe.className="tab-list",["Basics","Layout","Components","Data","Advanced"].forEach((b,w)=>{const i=document.createElement("button");i.className="tab-item"+(w===0?" active":""),i.textContent=b,Pe.appendChild(i)});const W=document.createElement("div");W.className="tab-content";const Se="display:flex;flex-direction:column;gap:1rem;",$e=document.createElement("div");$e.className="tab-panel active",$e.style.cssText=Se;const fe=document.createElement("div");fe.className="tab-panel",fe.style.cssText=Se;const ie=document.createElement("div");ie.className="tab-panel",ie.style.cssText=Se;const ve=document.createElement("div");ve.className="tab-panel",ve.style.cssText=Se;const Ee=document.createElement("div");Ee.className="tab-panel",Ee.style.cssText=Se,W.appendChild($e),W.appendChild(fe),W.appendChild(ie),W.appendChild(ve),W.appendChild(Ee),Ie.appendChild(Pe),Ie.appendChild(W),Ne.appendChild(Ie);const Re=document.createElement("div");Re.appendChild(J("Markdown Basics"));const me=document.createElement("table");me.style.cssText="width:100%;border-collapse:collapse;font-size:.9em;";const Q=document.createElement("thead"),ne=document.createElement("tr");["Syntax","Result"].forEach(b=>{const w=document.createElement("th");w.style.cssText="text-align:left;padding:.4rem .5rem;border-bottom:1px solid var(--dm-border,#333);",w.textContent=b,ne.appendChild(w)}),Q.appendChild(ne),me.appendChild(Q);const he=document.createElement("tbody");[["**bold**","bold (rendered bold)"],["_italic_","italic (rendered italic)"],["## Heading","Heading (h2)"],["[text](url)","Link"],["![alt](url)","Image"],["- item","Bullet list"],["`code`","Inline code"],["---","Divider"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.35rem .5rem;vertical-align:top;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.35rem .5rem;vertical-align:top;color:var(--dm-text-muted,#aaa);font-size:.85em;",o.textContent=w,i.appendChild(s),i.appendChild(o),he.appendChild(i)}),me.appendChild(he),Re.appendChild(me),$e.appendChild(Re);const ee=document.createElement("div");ee.appendChild(J("Grid & Columns"));function U(b){const w=document.createElement("p");return w.style.cssText="margin:.3rem 0 .6rem;font-size:.82em;color:var(--dm-text-muted,#aaa);",w.textContent=b,w}function B(b,w,i){const s=document.createElement("p");s.style.cssText="margin:.75rem 0 .25rem;font-size:.85em;font-weight:600;",s.textContent=b;const o=document.createElement("div");o.style.cssText="position:relative;";const _=document.createElement("pre");_.style.cssText=se+"display:block;padding:.5rem 2rem .5rem .75rem;white-space:pre;overflow-x:auto;margin:0;",_.textContent=w;const K=document.createElement("button");K.type="button",K.title="Copy code",K.style.cssText="position:absolute;top:.3rem;right:.3rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.15rem;line-height:1;color:inherit;",K.addEventListener("mouseenter",()=>{K.style.opacity="1"}),K.addEventListener("mouseleave",()=>{K.style.opacity=".45"});const ae=document.createElement("span");ae.setAttribute("data-icon","copy"),K.appendChild(ae),K.addEventListener("click",()=>{const P=document.createElement("textarea");P.value=w,P.style.cssText="position:fixed;opacity:0;",document.body.appendChild(P),P.select(),document.execCommand("copy"),P.remove(),E.toast("Copied!",{type:"success",duration:1200})}),o.appendChild(_),o.appendChild(K);const X=document.createDocumentFragment();return X.appendChild(s),X.appendChild(o),i&&X.appendChild(U(i)),X}const te=document.createElement("table");te.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['cols="N"',"[grid] only","Number of columns (1\u201312)"],['gap="N"',"[grid], [row]","Gap between columns/rows (1\u20136)"],['span="N"',"[col] only","How many columns this cell spans"],['fullwidth="true"',"[grid] only","Break out of page container to span full viewport"],['class="x"',"all","Add extra CSS classes"]].forEach(([b,w,i])=>{const s=document.createElement("tr");[b,w,i].forEach((o,_)=>{const K=document.createElement("td");K.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",_===0?K.appendChild(G(b)):(K.style.color="var(--dm-text-muted,#aaa)",K.textContent=o),s.appendChild(K)}),te.appendChild(s)}),ee.appendChild(te),ee.appendChild(B("Equal columns",`[grid cols="3" gap="4"]
2
2
  [col]One[/col]
3
3
  [col]Two[/col]
4
4
  [col]Three[/col]
@@ -81,18 +81,18 @@ In active development.
81
81
  Markdown content here.
82
82
  [/slideover]`,"Nested [card] and [grid] shortcodes work inside the slideover body.")),ie.appendChild(p);const L=document.createElement("div");L.appendChild(J("DConfig \u2014 Declarative Behaviour")),L.appendChild(U("Define click handlers and class toggles without writing JavaScript. Use the DConfig section above or embed inline with [dconfig]...[/dconfig] in the content body. Inline shortcodes win on selector conflict.")),L.appendChild(B("Toggle a class on click",'{ "#my-btn": { "events": { "click": { "target": "#panel", "toggleClass": "hidden" } } } }','Selector keys use standard CSS selectors. "target" is optional \u2014 defaults to the element itself.')),L.appendChild(B("Inline shortcode syntax",`[dconfig]
83
83
  { "#my-btn": { "events": { "click": { "target": "#panel", "toggleClass": "hidden" } } } }
84
- [/dconfig]`,null)),Ee.appendChild(L);const u=document.createElement("div");u.appendChild(J("CSS Editor")),u.appendChild(U("The toolbar's </> button (left of the Split View icon) swaps the left pane between Markdown and Custom CSS. Edits are saved together with the page \u2014 one Save, one toast."));const z=document.createElement("table");z.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["</> button","Toggle between Markdown editor and Custom CSS editor"],["Split / Write / Preview","Standard view mode buttons to the right of </>"],["Save","Saves both page content and CSS in a single operation"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=w,i.appendChild(s),i.appendChild(o),z.appendChild(i)}),u.appendChild(z),Ee.appendChild(u);const n=document.createElement("div");n.appendChild(J("Colour Picker")),n.appendChild(U("Insert \u2192 Colour Picker opens a centred colour picker. Pick a colour, then use Copy to copy the hex code to the clipboard or Insert to drop it at the cursor. Click outside the panel to dismiss.")),Ee.appendChild(n);const c=document.createElement("div");c.appendChild(J("Keyboard Shortcuts"));const h=document.createElement("table");h.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["Ctrl + B","Bold selected text"],["Ctrl + I","Italic selected text"],["Ctrl + K","Insert link dialog"],["Tab","Indent 2 spaces at cursor"],["Shift + Tab","Dedent 2 spaces on current line"],["Ctrl + X","Cut current line (no selection) or cut selection"],["Ctrl + C","Copy current line (no selection) or copy selection"],["Ctrl + V","Paste from clipboard"],["Ctrl + Z","Undo"],["Ctrl + Y","Redo"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;white-space:nowrap;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=w,i.appendChild(s),i.appendChild(o),h.appendChild(i)}),c.appendChild(h),$e.appendChild(c);const T=document.createElement("div");T.appendChild(J("Tips"));const M=document.createElement("table");M.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['class="text-center"',"Centre text and inline elements on any shortcode"],['class="mx-auto"',"Centre a block element horizontally"],["[center]...[/center]","Shorthand wrapper for centred content"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=w,i.appendChild(s),i.appendChild(o),M.appendChild(i)}),T.appendChild(M),T.appendChild(U("Most shortcodes accept a class attribute for custom styling.")),$e.appendChild(T),l.setContent(Ne),l.open(),E.tabs(Ie),I.scan(Ne)}function at(l,se){const de=l.find("#history-tab").get(0),G=l.find("#version-list").get(0),J=l.find("#version-compare").get(0),Ne=l.find("#version-compare-old").get(0),Ie=l.find("#version-compare-new").get(0),Pe=l.find("#version-compare-label").get(0),W=l.find("#version-compare-back-btn").get(0),Se=l.find("#version-restore-btn").get(0),$e=l.find("#history-save-named-btn").get(0),fe=l.find("#history-delete-selected-btn").get(0);let ie=!1,ve=null;function Ee(){G.style.display="",J.style.display="none",ve=null}function Re(){G.style.display="none",J.style.display=""}async function me(){G.textContent="";const Q=document.createElement("p");Q.style.color="var(--dm-text-muted)",Q.textContent="Loading\u2026",G.appendChild(Q);let ne;try{ne=(await j.versions.list(se)).versions||[]}catch(V){G.textContent="";const H=document.createElement("p");H.style.color="var(--dm-text-danger,#e55)",H.textContent="Failed to load versions: "+V.message,G.appendChild(H);return}if(G.textContent="",fe.style.display="none",!ne.length){const V=document.createElement("p");V.style.color="var(--dm-text-muted)",V.textContent="No versions saved yet. Versions are created automatically on each save.",G.appendChild(V);return}const he=document.createElement("table");he.style.cssText="width:100%;border-collapse:collapse;font-size:.875rem;";const ee=document.createElement("thead"),U=document.createElement("tr"),B=document.createElement("th");B.style.cssText="padding:.5rem .75rem;width:2rem;border-bottom:1px solid var(--dm-border);";const te=document.createElement("input");te.type="checkbox",te.setAttribute("aria-label","Select all versions"),B.appendChild(te),U.appendChild(B),["Date","Author","Type","Label","Actions"].forEach(V=>{const H=document.createElement("th");H.style.cssText="text-align:left;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border);font-size:.8rem;color:var(--dm-text-muted);",H.textContent=V,U.appendChild(H)}),ee.appendChild(U),he.appendChild(ee);const re=[];function Le(){const V=re.some(ce=>ce.checked),H=re.length>0&&re.every(ce=>ce.checked);fe.style.display=V?"":"none",te.checked=H,te.indeterminate=V&&!H}te.addEventListener("change",()=>{re.forEach(V=>{V.checked=te.checked}),Le()});const De=document.createElement("tbody");ne.forEach(V=>{const H=document.createElement("tr");H.style.borderBottom="1px solid var(--dm-border)";const ce=document.createElement("td");ce.style.padding=".5rem .75rem";const xe=document.createElement("input");xe.type="checkbox",xe.value=V.filename,xe.addEventListener("change",Le),ce.appendChild(xe),re.push(xe);const we=document.createElement("td");we.style.padding=".5rem .75rem",we.textContent=D(V.createdAt).format("D MMM YYYY, HH:mm");const ue=document.createElement("td");ue.style.padding=".5rem .75rem",ue.textContent=V.author||"\u2014";const ke=document.createElement("td");ke.style.padding=".5rem .75rem";const be=document.createElement("span");be.className="badge badge-"+(V.type==="manual"?"primary":"secondary"),be.style.cssText="font-size:.75rem;padding:.2rem .5rem;border-radius:4px;",be.textContent=V.type,ke.appendChild(be);const ze=document.createElement("td");ze.style.cssText="padding:.5rem .75rem;color:var(--dm-text-muted);",ze.textContent=V.label||"\u2014";const ge=document.createElement("td");ge.style.padding=".5rem .75rem";const oe=document.createElement("button");oe.className="btn btn-ghost btn-xs",oe.style.marginRight=".4rem",oe.textContent="Compare",oe.addEventListener("click",async()=>{try{const Ce=await j.versions.get(se,V.filename);Ne.textContent=Ce.content,Ie.textContent=l.find("#markdown-editor").get(0).value,Pe.textContent=D(V.createdAt).format("D MMM YYYY, HH:mm")+(V.label?` \u2014 ${V.label}`:""),ve=V.filename,Re()}catch(Ce){E.toast("Failed to load version: "+Ce.message,{type:"error"})}});const le=document.createElement("button");le.className="btn btn-ghost btn-xs",le.style.color="var(--dm-text-danger,#e55)",le.textContent="Delete",le.addEventListener("click",async()=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await j.versions.delete(se,V.filename),E.toast("Version deleted.",{type:"success"}),await me()}catch(Ce){E.toast("Failed to delete: "+Ce.message,{type:"error"})}}),ge.appendChild(oe),ge.appendChild(le),H.appendChild(ce),H.appendChild(we),H.appendChild(ue),H.appendChild(ke),H.appendChild(ze),H.appendChild(ge),De.appendChild(H)}),he.appendChild(De),G.appendChild(he)}de.addEventListener("click",async()=>{ie||(ie=!0,await me())}),W.addEventListener("click",()=>{Ee()}),Se.addEventListener("click",async()=>{if(!(!ve||!await E.confirm("Restore this version? The current page content will be overwritten (a pre-restore snapshot will be saved automatically).")))try{await j.versions.restore(se,ve),E.toast("Page restored. Reloading editor\u2026",{type:"success"}),R.navigate("/pages"),setTimeout(()=>R.navigate(`/pages/edit${se}`),300)}catch(Q){E.toast("Restore failed: "+Q.message,{type:"error"})}}),fe.addEventListener("click",async()=>{const Q=[...G.querySelectorAll("tbody input[type=checkbox]:checked")].map(ne=>ne.value);if(!(!Q.length||!await E.confirm(`Delete ${Q.length} version${Q.length>1?"s":""}? This cannot be undone.`)))try{await j.versions.bulkDelete(se,Q),E.toast(`${Q.length} version${Q.length>1?"s":""} deleted.`,{type:"success"}),await me()}catch(ne){E.toast("Delete failed: "+ne.message,{type:"error"})}}),$e.addEventListener("click",()=>{const Q=E.modal({title:"Save Named Version"}),ne=document.createElement("div");ne.style.padding="1rem";const he=document.createElement("label");he.className="form-label",he.textContent="Version Label";const ee=document.createElement("input");ee.type="text",ee.className="form-input",ee.placeholder="e.g. Initial design, Before restructure",ee.style.marginBottom=".75rem";const U=document.createElement("button");U.className="btn btn-primary",U.textContent="Save Version",U.addEventListener("click",async()=>{const B=ee.value.trim();try{await j.versions.create(se,B||null),E.toast("Named version saved.",{type:"success"}),Q.close(),ie=!1,de.classList.contains("active")&&(ie=!0,await me())}catch(te){E.toast("Failed to save version: "+te.message,{type:"error"})}}),ne.appendChild(he),ne.appendChild(ee),ne.appendChild(U),Q.element.appendChild(ne),Q.open(),setTimeout(()=>ee.focus(),100)})}let Fe=!1,Oe=null,Ye=!1;function ot(l){return l.split(`
84
+ [/dconfig]`,null)),Ee.appendChild(L);const u=document.createElement("div");u.appendChild(J("CSS Editor")),u.appendChild(U("The toolbar's </> button (left of the Split View icon) swaps the left pane between Markdown and Custom CSS. Edits are saved together with the page \u2014 one Save, one toast."));const z=document.createElement("table");z.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["</> button","Toggle between Markdown editor and Custom CSS editor"],["Split / Write / Preview","Standard view mode buttons to the right of </>"],["Save","Saves both page content and CSS in a single operation"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=w,i.appendChild(s),i.appendChild(o),z.appendChild(i)}),u.appendChild(z),Ee.appendChild(u);const n=document.createElement("div");n.appendChild(J("Colour Picker")),n.appendChild(U("Insert \u2192 Colour Picker opens a centred colour picker. Pick a colour, then use Copy to copy the hex code to the clipboard or Insert to drop it at the cursor. Click outside the panel to dismiss.")),Ee.appendChild(n);const c=document.createElement("div");c.appendChild(J("Keyboard Shortcuts"));const h=document.createElement("table");h.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["Ctrl + B","Bold selected text"],["Ctrl + I","Italic selected text"],["Ctrl + K","Insert link dialog"],["Tab","Indent 2 spaces at cursor"],["Shift + Tab","Dedent 2 spaces on current line"],["Ctrl + X","Cut current line (no selection) or cut selection"],["Ctrl + C","Copy current line (no selection) or copy selection"],["Ctrl + V","Paste from clipboard"],["Ctrl + Z","Undo"],["Ctrl + Y","Redo"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;white-space:nowrap;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=w,i.appendChild(s),i.appendChild(o),h.appendChild(i)}),c.appendChild(h),$e.appendChild(c);const T=document.createElement("div");T.appendChild(J("Tips"));const M=document.createElement("table");M.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['class="text-center"',"Centre text and inline elements on any shortcode"],['class="mx-auto"',"Centre a block element horizontally"],["[center]...[/center]","Shorthand wrapper for centred content"]].forEach(([b,w])=>{const i=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",s.appendChild(G(b));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=w,i.appendChild(s),i.appendChild(o),M.appendChild(i)}),T.appendChild(M),T.appendChild(U("Most shortcodes accept a class attribute for custom styling.")),$e.appendChild(T),l.setContent(Ne),l.open(),E.tabs(Ie),I.scan(Ne)}function ot(l,se){const de=l.find("#history-tab").get(0),G=l.find("#version-list").get(0),J=l.find("#version-compare").get(0),Ne=l.find("#version-compare-old").get(0),Ie=l.find("#version-compare-new").get(0),Pe=l.find("#version-compare-label").get(0),W=l.find("#version-compare-back-btn").get(0),Se=l.find("#version-restore-btn").get(0),$e=l.find("#history-save-named-btn").get(0),fe=l.find("#history-delete-selected-btn").get(0);let ie=!1,ve=null;function Ee(){G.style.display="",J.style.display="none",ve=null}function Re(){G.style.display="none",J.style.display=""}async function me(){G.textContent="";const Q=document.createElement("p");Q.style.color="var(--dm-text-muted)",Q.textContent="Loading\u2026",G.appendChild(Q);let ne;try{ne=(await j.versions.list(se)).versions||[]}catch(V){G.textContent="";const H=document.createElement("p");H.style.color="var(--dm-text-danger,#e55)",H.textContent="Failed to load versions: "+V.message,G.appendChild(H);return}if(G.textContent="",fe.style.display="none",!ne.length){const V=document.createElement("p");V.style.color="var(--dm-text-muted)",V.textContent="No versions saved yet. Versions are created automatically on each save.",G.appendChild(V);return}const he=document.createElement("table");he.style.cssText="width:100%;border-collapse:collapse;font-size:.875rem;";const ee=document.createElement("thead"),U=document.createElement("tr"),B=document.createElement("th");B.style.cssText="padding:.5rem .75rem;width:2rem;border-bottom:1px solid var(--dm-border);";const te=document.createElement("input");te.type="checkbox",te.setAttribute("aria-label","Select all versions"),B.appendChild(te),U.appendChild(B),["Date","Author","Type","Label","Actions"].forEach(V=>{const H=document.createElement("th");H.style.cssText="text-align:left;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border);font-size:.8rem;color:var(--dm-text-muted);",H.textContent=V,U.appendChild(H)}),ee.appendChild(U),he.appendChild(ee);const re=[];function Le(){const V=re.some(ce=>ce.checked),H=re.length>0&&re.every(ce=>ce.checked);fe.style.display=V?"":"none",te.checked=H,te.indeterminate=V&&!H}te.addEventListener("change",()=>{re.forEach(V=>{V.checked=te.checked}),Le()});const De=document.createElement("tbody");ne.forEach(V=>{const H=document.createElement("tr");H.style.borderBottom="1px solid var(--dm-border)";const ce=document.createElement("td");ce.style.padding=".5rem .75rem";const xe=document.createElement("input");xe.type="checkbox",xe.value=V.filename,xe.addEventListener("change",Le),ce.appendChild(xe),re.push(xe);const we=document.createElement("td");we.style.padding=".5rem .75rem",we.textContent=D(V.createdAt).format("D MMM YYYY, HH:mm");const ue=document.createElement("td");ue.style.padding=".5rem .75rem",ue.textContent=V.author||"\u2014";const ke=document.createElement("td");ke.style.padding=".5rem .75rem";const be=document.createElement("span");be.className="badge badge-"+(V.type==="manual"?"primary":"secondary"),be.style.cssText="font-size:.75rem;padding:.2rem .5rem;border-radius:4px;",be.textContent=V.type,ke.appendChild(be);const ze=document.createElement("td");ze.style.cssText="padding:.5rem .75rem;color:var(--dm-text-muted);",ze.textContent=V.label||"\u2014";const ge=document.createElement("td");ge.style.padding=".5rem .75rem";const oe=document.createElement("button");oe.className="btn btn-ghost btn-xs",oe.style.marginRight=".4rem",oe.textContent="Compare",oe.addEventListener("click",async()=>{try{const Ce=await j.versions.get(se,V.filename);Ne.textContent=Ce.content,Ie.textContent=l.find("#markdown-editor").get(0).value,Pe.textContent=D(V.createdAt).format("D MMM YYYY, HH:mm")+(V.label?` \u2014 ${V.label}`:""),ve=V.filename,Re()}catch(Ce){E.toast("Failed to load version: "+Ce.message,{type:"error"})}});const le=document.createElement("button");le.className="btn btn-ghost btn-xs",le.style.color="var(--dm-text-danger,#e55)",le.textContent="Delete",le.addEventListener("click",async()=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await j.versions.delete(se,V.filename),E.toast("Version deleted.",{type:"success"}),await me()}catch(Ce){E.toast("Failed to delete: "+Ce.message,{type:"error"})}}),ge.appendChild(oe),ge.appendChild(le),H.appendChild(ce),H.appendChild(we),H.appendChild(ue),H.appendChild(ke),H.appendChild(ze),H.appendChild(ge),De.appendChild(H)}),he.appendChild(De),G.appendChild(he)}de.addEventListener("click",async()=>{ie||(ie=!0,await me())}),W.addEventListener("click",()=>{Ee()}),Se.addEventListener("click",async()=>{if(!(!ve||!await E.confirm("Restore this version? The current page content will be overwritten (a pre-restore snapshot will be saved automatically).")))try{await j.versions.restore(se,ve),E.toast("Page restored. Reloading editor\u2026",{type:"success"}),R.navigate("/pages"),setTimeout(()=>R.navigate(`/pages/edit${se}`),300)}catch(Q){E.toast("Restore failed: "+Q.message,{type:"error"})}}),fe.addEventListener("click",async()=>{const Q=[...G.querySelectorAll("tbody input[type=checkbox]:checked")].map(ne=>ne.value);if(!(!Q.length||!await E.confirm(`Delete ${Q.length} version${Q.length>1?"s":""}? This cannot be undone.`)))try{await j.versions.bulkDelete(se,Q),E.toast(`${Q.length} version${Q.length>1?"s":""} deleted.`,{type:"success"}),await me()}catch(ne){E.toast("Delete failed: "+ne.message,{type:"error"})}}),$e.addEventListener("click",()=>{const Q=E.modal({title:"Save Named Version"}),ne=document.createElement("div");ne.style.padding="1rem";const he=document.createElement("label");he.className="form-label",he.textContent="Version Label";const ee=document.createElement("input");ee.type="text",ee.className="form-input",ee.placeholder="e.g. Initial design, Before restructure",ee.style.marginBottom=".75rem";const U=document.createElement("button");U.className="btn btn-primary",U.textContent="Save Version",U.addEventListener("click",async()=>{const B=ee.value.trim();try{await j.versions.create(se,B||null),E.toast("Named version saved.",{type:"success"}),Q.close(),ie=!1,de.classList.contains("active")&&(ie=!0,await me())}catch(te){E.toast("Failed to save version: "+te.message,{type:"error"})}}),ne.appendChild(he),ne.appendChild(ee),ne.appendChild(U),Q.element.appendChild(ne),Q.open(),setTimeout(()=>ee.focus(),100)})}let Fe=!1,Oe=null,Ye=!1;function lt(l){return l.split(`
85
85
  `).map(se=>se.trimEnd()).join(`
86
86
  `).replace(/\n{3,}/g,`
87
87
 
88
- `)}const je="editor_prefs";function Je(){return S.get(je)||{viewMode:"split",fullscreen:!1}}function Qe(l,se){const de=Je();de[l]=se,S.set(je,de)}export const pageEditorView={templateUrl:"/admin/js/templates/page-editor.html",async onMount(l){const se=window.location.hash.match(/#\/pages\/edit(\/.*)/),de=se?se[1]:null,G=!!de,J=E.loader(l.get(0),{type:"dots"}),Ne=[j.layouts.get().catch(()=>({})),j.settings.get().catch(()=>({}))];G&&(Ne.push(j.pages.get(de).catch(()=>null)),Ne.push(j.pages.list().catch(()=>[])));const[Ie,Pe,W,Se]=await Promise.all(Ne);J.destroy(),et(l.find("#field-theme").get(0),{includeDefault:!0});const $e=Pe?.layoutOptions?.spacerSize??40;if(G&&!W){E.toast("Page not found.",{type:"error"}),R.navigate("/pages");return}l.find("#editor-title").text(G?`Edit Page \u2014 ${W.title||de}`:"New Page"),G&&l.find("#page-url-path").val(de),W&&(l.find("#field-title").val(W.title||""),l.find("#field-description").val(W.description||""),l.find("#field-status").val(W.status||"draft"),l.find("#field-sort-order").val(W.sortOrder??99),l.find("#field-show-in-nav").prop("checked",!!W.showInNav),l.find("#field-sidebar").prop("checked",!!W.sidebar),l.find("#field-show-breadcrumbs").prop("checked",W.breadcrumbs!==!1),l.find("#field-bundled").prop("checked",!!W.bundled),l.find("#field-category").val(W.category||""),l.find("#field-visibility").val(W.visibility||"public"),l.find("#field-theme").val(W.theme||""),l.find("#field-seo-title").val(W.seo?.title||""),l.find("#field-seo-desc").val(W.seo?.description||""),W.dconfig&&l.find("#field-dconfig").val(JSON.stringify(W.dconfig,null,2)));const fe=l.find("#quick-switch");G&&Array.isArray(Se)&&Se.length&&([...Se].sort((e,t)=>(e.title||e.urlPath).localeCompare(t.title||t.urlPath)).forEach(e=>{const t=document.createElement("option");t.value=e.urlPath,t.textContent=`${e.title||"Untitled"} (${e.urlPath})`,e.urlPath===de&&(t.selected=!0),fe.get(0).appendChild(t)}),fe.css("display",""),fe.on("change",function(){const e=this.value;e&&R.navigate("/pages/edit"+e)}));const ie=await j.pages.tags().catch(()=>[]),ve=l.find("#field-tags").get(0),Ee=ve?E.pillbox(ve,{data:ie,value:W?.tags||[],creatable:!0,searchable:!0,placeholder:"Add tag\u2026"}):null,Re=l.find("#field-layout").empty();if(Object.entries(Ie).forEach(([e,t])=>{const a=(W?.layout||"default")===e?"selected":"";Re.append(`<option value="${e}" ${a}>${t.label||e}</option>`)}),G){const e=l.find("#view-page-btn").get(0);e.href=de,e.style.display="";const t=l.find("#live-preview-tab").get(0);t.style.display="";const a=l.find("#history-tab").get(0);a.style.display=""}if(E.tabs(l.find("#editor-meta-tabs").get(0)),G){const e=l.find("#live-preview-tab").get(0),t=l.find("#live-preview-frame").get(0);let a=!1;e.addEventListener("click",function(){a||(t.src=de,a=!0)}),at(l,de)}const me=l.find("#markdown-editor"),Q=l.find("#markdown-preview");W&&me.val(W.content||"");let ne=!1,he="";j.settings.getCustomCss().then(({css:e})=>{if(he=e||"",!he)return;const t=document.createElement("style");t.id="preview-custom-css",t.textContent=he,Q.get(0).parentNode.insertBefore(t,Q.get(0))}).catch(()=>{});let ee=!1;const U=me.get(0),B=document.createElement("div");B.className="editor-line-numbers editor-line-numbers--foldable",U.parentElement.insertBefore(B,U);const te=tt(U,B,{onFoldChange:()=>{}});te.setGuard(e=>{ee=e});function re(){const e=l.find("#css-editor").get(0);if(!e)return;const t=e.value.split(`
89
- `);for(;B.firstChild;)B.removeChild(B.firstChild);t.forEach((a,y)=>{const r=document.createElement("span");r.className="editor-line-number-row";const m=document.createElement("span");m.className="fold-toggle fold-toggle--empty";const x=document.createElement("span");x.className="editor-line-num",x.textContent=String(y+1),r.appendChild(m),r.appendChild(x),B.appendChild(r)}),B.scrollTop=e.scrollTop}{const e=l.find("#css-editor").get(0);e&&e.addEventListener("scroll",()=>{B.scrollTop=e.scrollTop})}const Le=()=>{te.refresh(),B.scrollTop=U.scrollTop};U.addEventListener("input",Le),U.addEventListener("scroll",()=>{B.scrollTop=U.scrollTop});let De=null;const V=()=>{clearTimeout(De),De=setTimeout(async()=>{const e=te.getUnfoldedContent();try{const{html:t}=await j.pages.preview(e);Q.html(t,{safe:!1}),I.scan(Q.get(0)),Q.get(0).querySelectorAll(".tabs").forEach(a=>Domma.elements.tabs(a))}catch{window.marked&&Q.html(marked.parse(e))}},400)},H=Xe(me,l.find("#editor-toolbar"),{spacerDefault:$e});let ce=!1,xe="split",we=null;const ue=document.createElement("button");ue.className="editor-view-btn",ue.type="button";const ke=document.createElement("span");ke.setAttribute("data-icon","css-code"),ue.appendChild(ke);const be=document.createElement("button");be.className="editor-view-btn",be.type="button";const ze=document.createElement("span");ze.setAttribute("data-icon","code"),be.appendChild(ze);let ge=!1;const oe=document.createElement("button");oe.className="editor-view-btn",oe.type="button",oe.textContent="\u25BC\u25BC",oe.style.cssText="font-size:9px;letter-spacing:-1px;";const le=l.find(".editor-toolbar-right").get(0);le.prepend(oe),le.prepend(be),le.prepend(ue),I.scan(ue),I.scan(be),E.tooltip(ue,{content:"Edit Custom CSS",position:"top"}),E.tooltip(be,{content:"Format Markdown",position:"top"}),E.tooltip(oe,{content:"Fold / unfold all shortcodes",position:"top"}),be.addEventListener("click",()=>{const e=me.get(0),t=e.selectionStart,a=ot(te.getUnfoldedContent());te.unfoldAll(),ee=!0,e.value=a,ee=!1,e.selectionStart=e.selectionEnd=Math.min(t,a.length),e.dispatchEvent(new Event("input")),te.refresh(),E.toast("Markdown formatted.",{type:"success"})}),oe.addEventListener("click",()=>{ge?(te.unfoldAll(),oe.textContent="\u25BC\u25BC",oe.classList.remove("active")):(te.foldAll(),oe.textContent="\u25B6\u25B6",oe.classList.add("active")),ge=!ge});const Ce=document.createElement("span");Ce.className="editor-toolbar-sep",le.insertBefore(Ce,le.children[3]),ue.addEventListener("click",()=>{ce=!ce;const e=l.find("#markdown-editor"),t=l.find("#css-editor"),a=l.find("#editor-body");if(ce){const y=l.find(".editor-view-btn[data-mode].active").get(0);xe=y?y.getAttribute("data-mode"):"split",l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find('.editor-view-btn[data-mode="split"]').addClass("active"),a.removeClass("editor-mode-write editor-mode-preview").addClass("editor-mode-split"),e.hide(),t.show(),ne||(t.val(he),ne=!0,Ze(t.get(0))),re(),ue.classList.add("active")}else l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find(`.editor-view-btn[data-mode="${xe}"]`).addClass("active"),a.removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${xe}`),t.hide(),e.show(),te.refresh(),ue.classList.remove("active")});const Ae=Je();Ae.viewMode&&Ae.viewMode!=="split"&&(l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find(`.editor-view-btn[data-mode="${Ae.viewMode}"]`).addClass("active"),l.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${Ae.viewMode}`)),Ae.fullscreen&&l.find(".editor-card").addClass("editor-fullscreen"),l.find("#css-editor").on("input",()=>{re(),clearTimeout(we),we=setTimeout(()=>{let e=document.getElementById("preview-custom-css");e||(e=document.createElement("style"),e.id="preview-custom-css",Q.get(0).parentNode.insertBefore(e,Q.get(0))),e.textContent=l.find("#css-editor").val()},400)}),H.onLink(async e=>{const t=(await j.pages.list().catch(()=>[])).map(p=>({label:p.title||p.urlPath,value:p.urlPath})),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const y=document.createElement("label");y.className="form-label",y.textContent="URL";const r=document.createElement("input");r.type="text",r.className="form-input",r.placeholder="/about or https://example.com";const m=e.value.substring(e.selectionStart,e.selectionEnd);m&&m.startsWith("/")&&(r.value=m),a.appendChild(y),a.appendChild(r);const x=document.createElement("label");x.className="form-label",x.textContent="Link text";const g=document.createElement("input");g.type="text",g.className="form-input",g.placeholder="Display text",m&&!m.startsWith("/")&&(g.value=m),a.appendChild(x),a.appendChild(g);const v=document.createElement("label");v.className="form-label",v.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;";const d=document.createElement("input");d.type="checkbox",d.style.cssText="width:1rem;height:1rem;cursor:pointer;",v.appendChild(d),v.appendChild(document.createTextNode("Display as button")),a.appendChild(v);const C=document.createElement("label");C.className="form-label",C.textContent="Button colour",C.style.display="none";const A=document.createElement("select");A.className="form-select",A.style.display="none",[["primary","Primary"],["secondary","Secondary"],["success","Success (Green)"],["danger","Danger (Red)"],["warning","Warning (Orange)"],["info","Info (Blue)"],["outline","Outline"],["outline-success","Outline Success"],["outline-danger","Outline Danger"],["ghost","Ghost"]].forEach(([p,k])=>{const L=document.createElement("option");L.value=p,L.textContent=k,A.appendChild(L)}),a.appendChild(C),a.appendChild(A),d.addEventListener("change",()=>{const p=d.checked;C.style.display=p?"":"none",A.style.display=p?"":"none"});const N=document.createElement("button");N.type="button",N.className="btn btn-primary",N.textContent="Insert Link",a.appendChild(N);const f=E.modal({title:"Insert Link",size:"sm"});f.element.appendChild(a),f.open(),requestAnimationFrame(()=>{E.autocomplete(r,{data:t,minChars:1,onSelect:p=>{r.value=p.value,g.value||(g.value=p.label)}}),r.focus()}),N.addEventListener("click",()=>{const p=r.value.trim(),k=g.value.trim();if(!p)return;f.close();const L=d.checked?`[button href="${p}" variant="${A.value}"]${k||p}[/button]`:`[${k||p}](${p})`,u=e.selectionStart,z=e.selectionEnd;e.value=e.value.substring(0,u)+L+e.value.substring(z),e.selectionStart=e.selectionEnd=u+L.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onImage(async e=>{const t=(await j.media.list().catch(()=>[])).filter(r=>/\.(png|jpe?g|gif|webp|svg)$/i.test(r.name)),a=document.createElement("div");if(a.className="media-picker-grid",t.length)t.forEach(r=>{const m=document.createElement("div");m.className="media-picker-item",m.dataset.url=r.url;const x=document.createElement("img");x.src=r.url,x.alt=r.name;const g=document.createElement("span");g.textContent=r.name,m.appendChild(x),m.appendChild(g),a.appendChild(m)});else{const r=document.createElement("p");r.className="text-muted p-3",r.textContent="No images uploaded yet.",a.appendChild(r)}const y=E.modal({title:"Insert Image",size:"lg"});y.element.appendChild(a),$(y.element).on("click",".media-picker-item",function(){const r=$(this).data("url"),m=$(this).find("span").text();ye(e,`![${m}](${r})`),y.close(),me.get(0).dispatchEvent(new Event("input",{bubbles:!0}))}),y.open()}),H.onCollection(async e=>{const[t,a]=await Promise.all([j.collections.list().catch(()=>[]),j.blocks.list().catch(()=>[])]),y=document.createElement("div");y.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const r="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",m="width:100%;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;",x=document.createElement("div"),g=document.createElement("label");g.style.cssText=r,g.textContent="Collection";const v=document.createElement("select");if(v.style.cssText=m,t.length)t.forEach(O=>{const Z=document.createElement("option");Z.value=O.slug,Z.textContent=O.title||O.slug,v.appendChild(Z)});else{const O=document.createElement("option");O.value="",O.textContent="No collections found",v.appendChild(O)}x.appendChild(g),x.appendChild(v),y.appendChild(x);const d=document.createElement("div"),C=document.createElement("label");C.style.cssText=r,C.textContent="Display";const A=document.createElement("select");A.style.cssText=m,["table","cards","list","block"].forEach(O=>{const Z=document.createElement("option");Z.value=O,Z.textContent=O.charAt(0).toUpperCase()+O.slice(1),A.appendChild(Z)}),d.appendChild(C),d.appendChild(A),y.appendChild(d);const N=document.createElement("div");N.style.display="none";const f=document.createElement("label");f.style.cssText=r,f.textContent="Columns (2\u20134)";const p=document.createElement("input");p.type="number",p.min="2",p.max="4",p.value="3",p.style.cssText=m,N.appendChild(f),N.appendChild(p),y.appendChild(N);const k=document.createElement("div");k.style.display="none";const L=document.createElement("label");L.style.cssText=r,L.textContent="Block template";const u=document.createElement("select");if(u.style.cssText=m,a.length)a.forEach(O=>{const Z=document.createElement("option");Z.value=O.name??O,Z.textContent=O.name??O,u.appendChild(Z)});else{const O=document.createElement("option");O.value="",O.textContent="No block templates found",u.appendChild(O)}k.appendChild(L),k.appendChild(u),y.appendChild(k);const z=document.createElement("div"),n=document.createElement("label");n.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const c=document.createElement("input");c.type="checkbox",c.checked=!0,n.appendChild(c),n.appendChild(document.createTextNode("Enable search")),z.appendChild(n),y.appendChild(z);const h=document.createElement("div"),T=document.createElement("label");T.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const M=document.createElement("input");M.type="checkbox",M.checked=!0,T.appendChild(M),T.appendChild(document.createTextNode("Sortable columns")),h.appendChild(T),y.appendChild(h);const b=document.createElement("div"),w=document.createElement("label");w.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1,w.appendChild(i),w.appendChild(document.createTextNode("CSV export")),b.appendChild(w),y.appendChild(b);const s=document.createElement("div"),o=document.createElement("label");o.style.cssText=r,o.textContent="Rows per page";const _=document.createElement("input");_.type="number",_.min="5",_.max="100",_.value="25",_.style.cssText=m,s.appendChild(o),s.appendChild(_),y.appendChild(s);const K=document.createElement("div"),ae=document.createElement("label");ae.style.cssText=r,ae.textContent="Limit (optional)";const X=document.createElement("input");X.type="number",X.placeholder="All",X.style.cssText=m,K.appendChild(ae),K.appendChild(X),y.appendChild(K);const P=document.createElement("button");P.type="button",P.className="btn btn-primary",P.textContent="Insert",y.appendChild(P);const F=[z,h,b,s],q=()=>{const O=A.value,Z=O==="table";F.forEach(Te=>{Te.style.display=Z?"":"none"}),N.style.display=O==="cards"||O==="block"?"":"none",k.style.display=O==="block"?"":"none"};A.addEventListener("change",q),q();const Y=E.modal({title:"Insert Collection",size:"sm"});Y.element.appendChild(y),Y.open(),P.addEventListener("click",()=>{const O=v.value;if(!O)return;const Z=A.value;let Te=`[collection slug="${O}" display="${Z}"`;if(Z==="cards"&&(Te+=` columns="${p.value}"`),Z==="block"){const Ue=u.value;Ue&&(Te+=` block="${Ue}"`);const Ve=p.value.trim();Ve&&(Te+=` cols="${Ve}"`)}Z==="table"&&!c.checked&&(Te+=' search="false"'),Z==="table"&&!M.checked&&(Te+=' sortable="false"'),Z==="table"&&i.checked&&(Te+=' exportable="true"'),Z==="table"&&_.value!=="25"&&(Te+=` page-size="${_.value}"`);const Ge=X.value.trim();Ge&&(Te+=` limit="${Ge}"`),Te+=" /]",Y.close(),ye(e,Te),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onBlock(async e=>{let t=[];try{t=await j.blocks.list()}catch{E.toast("Could not load blocks.",{type:"error"});return}if(!t.length){E.toast("No block templates found. Create one in Blocks first.",{type:"warning"});return}const a=E.modal({title:"Insert Block",size:"lg"}),y=document.createElement("div");y.style.cssText="display:flex;gap:1rem;min-height:320px;";const r=document.createElement("div");r.style.cssText="flex:1;display:flex;flex-direction:column;gap:.75rem;";const m=document.createElement("label");m.className="form-label",m.textContent="Block Template";const x=document.createElement("select");x.className="form-select";const g=document.createElement("option");g.value="",g.textContent="\u2014 select a template \u2014",x.appendChild(g),t.forEach(u=>{const z=document.createElement("option");z.value=u.name,z.textContent=u.name,x.appendChild(z)}),r.appendChild(m),r.appendChild(x);const v=document.createElement("div");v.style.cssText="display:flex;flex-direction:column;gap:.5rem;overflow-y:auto;max-height:260px;",r.appendChild(v);const d=document.createElement("button");d.className="btn btn-primary",d.type="button",d.textContent="Insert",d.disabled=!0,r.appendChild(d);const C=document.createElement("div");C.style.cssText="flex:1;border:1px solid var(--dm-border-color);border-radius:var(--dm-radius);padding:.75rem;overflow:auto;background:var(--dm-surface-bg);";const A=document.createElement("p");A.className="text-muted",A.style.cssText="font-size:.8rem;margin:0;",A.textContent="Select a template to see a preview.",C.appendChild(A),y.appendChild(r),y.appendChild(C),a.element.appendChild(y),a.open();let N=null,f=[];function p(u){return u.replace(/_/g," ").replace(/\b\w/g,z=>z.toUpperCase())}function k(){if(!N)return;const u={};f.forEach(({key:n,input:c})=>{u[n]=c.value});const z=N.replace(/\{\{([\w_]+)\}\}/g,(n,c)=>(u[c]??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"));C.innerHTML=DOMPurify.sanitize(z)}function L(u){v.textContent="",f=[];const z=new Set(["_id","_createdAt","_updatedAt"]),n=new Set;for(const[,c]of u.matchAll(/\{\{([\w_]+)\}\}/g))z.has(c)||n.add(c);if(!n.size){const c=document.createElement("p");c.className="text-muted",c.style.cssText="font-size:.8rem;margin:0;",c.textContent="No editable placeholders in this template.",v.appendChild(c);return}n.forEach(c=>{const h=document.createElement("div"),T=document.createElement("label");T.className="form-label",T.style.cssText="font-size:.8rem;margin-bottom:.2rem;display:block;",T.textContent=p(c);const M=document.createElement("input");M.type="text",M.className="form-input",M.placeholder=p(c),M.addEventListener("input",k),h.appendChild(T),h.appendChild(M),v.appendChild(h),f.push({key:c,input:M})})}x.addEventListener("change",async()=>{const u=x.value;if(!u){N=null,f=[],v.textContent="",C.textContent="",C.appendChild(A),d.disabled=!0;return}N=null,f=[],v.textContent="",d.disabled=!0;try{N=(await j.blocks.get(u)).content||"",L(N),k(),d.disabled=!1}catch{E.toast("Could not load template.",{type:"error"})}}),d.addEventListener("click",()=>{if(!x.value)return;const u=c=>c.replace(/"/g,"&quot;");let z=`template="${u(x.value)}"`;f.forEach(({key:c,input:h})=>{h.value!==""&&(z+=` ${c}="${u(h.value)}"`)});const n=`[block ${z} /]`;ye(e,n),e.dispatchEvent(new Event("input",{bubbles:!0})),a.close(),e.focus()})}),H.onForm(async e=>{const t=await j.forms.list().catch(()=>[]),a=document.createElement("div");a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;",m=document.createElement("div"),x=document.createElement("label");x.style.cssText=y,x.textContent="Form";const g=document.createElement("select");if(g.style.cssText=r,t.length)t.forEach(C=>{const A=document.createElement("option");A.value=C.slug,A.textContent=C.title||C.slug,g.appendChild(A)});else{const C=document.createElement("option");C.value="",C.textContent="No forms found",g.appendChild(C)}m.appendChild(x),m.appendChild(g),a.appendChild(m);const v=document.createElement("button");v.className="btn btn-primary btn-sm",v.style.cssText="align-self:flex-end;margin-top:.5rem;",v.textContent="Insert Form",a.appendChild(v);const d=E.modal({title:"Insert Form",size:"sm"});d.element.appendChild(a),d.open(),v.addEventListener("click",()=>{const C=g.value;C&&(ye(e,`[form slug="${C}" /]`),d.close(),me.get(0).dispatchEvent(new Event("input",{bubbles:!0})))})}),H.onView(async e=>{const t=await j.views.list().catch(()=>[]),a=document.createElement("div");a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;",m=document.createElement("div"),x=document.createElement("label");x.style.cssText=y,x.textContent="View";const g=document.createElement("select");if(g.style.cssText=r,t.length)t.forEach(f=>{const p=document.createElement("option");p.value=f.slug,p.textContent=f.title||f.slug,g.appendChild(p)});else{const f=document.createElement("option");f.value="",f.textContent="No Views configured yet \u2014 create one under Data \u2192 Views",g.appendChild(f)}m.appendChild(x),m.appendChild(g),a.appendChild(m);const v=document.createElement("div"),d=document.createElement("label");d.style.cssText=y,d.textContent="Display";const C=document.createElement("select");C.style.cssText=r,["table","cards","list"].forEach(f=>{const p=document.createElement("option");p.value=f,p.textContent=f.charAt(0).toUpperCase()+f.slice(1),C.appendChild(p)}),v.appendChild(d),v.appendChild(C),a.appendChild(v);const A=document.createElement("button");A.type="button",A.className="btn btn-primary",A.textContent="Insert",a.appendChild(A);const N=E.modal({title:"Insert View",size:"sm"});N.element.appendChild(a),N.open(),A.addEventListener("click",()=>{const f=g.value;if(!f)return;const p=`[view slug="${f}" display="${C.value}" /]`;N.close(),ye(e,p),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onCta(async e=>{const t=await j.actions.list().catch(()=>[]),a=document.createElement("div");a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;";function m(L,u){const z=document.createElement("div"),n=document.createElement("label");return n.style.cssText=y,n.textContent=L,z.appendChild(n),z.appendChild(u),z}function x(L){const u=document.createElement("select");return u.style.cssText=r,L.forEach(([z,n])=>{const c=document.createElement("option");c.value=z,c.textContent=n,u.appendChild(c)}),u}function g(L,u,z){const n=document.createElement("input");return n.type=L,n.placeholder=u||"",n.value=z||"",n.style.cssText=r,n}const v=x(t.length?t.map(L=>[L.slug,L.title||L.slug]):[["","No Actions configured yet \u2014 create one under Data \u2192 Actions"]]);a.appendChild(m("Action",v));const d=g("text","Button label","Run");if(a.appendChild(m("Label",d)),v.addEventListener("change",()=>{const L=t.find(u=>u.slug===v.value);L?.trigger?.label&&(d.value=L.trigger.label)}),t.length){const L=t[0];L?.trigger?.label&&(d.value=L.trigger.label)}const C=g("text","Paste entry UUID\u2026","");a.appendChild(m("Entry ID",C));const A=x([["primary","Primary"],["secondary","Secondary"],["ghost","Ghost"],["danger","Danger"]]);a.appendChild(m("Style",A));const N=g("text","e.g. check, zap, send (optional)","");a.appendChild(m("Icon",N));const f=g("text","Confirmation message (optional)","");a.appendChild(m("Confirm prompt",f));const p=document.createElement("button");p.type="button",p.className="btn btn-primary",p.textContent="Insert",a.appendChild(p);const k=E.modal({title:"Insert CTA Button",size:"sm"});k.element.appendChild(a),k.open(),p.addEventListener("click",()=>{const L=v.value;if(!L)return;const u=C.value.trim(),z=(d.value.trim()||"Run").replace(/\[\/cta\]/gi,""),n=A.value,c=N.value.trim().replace(/"/g,""),h=f.value.trim().replace(/"/g,""),T=u.replace(/"/g,"");let M=`action="${L}" style="${n}"`;T&&(M+=` entry="${T}"`),c&&(M+=` icon="${c}"`),h&&(M+=` confirm="${h}"`);const b=`[cta ${M}]${z}[/cta]`;k.close(),ye(e,b),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onButton(async e=>{const t=(await j.pages.list().catch(()=>[])).map(n=>({label:n.title||n.urlPath,value:n.urlPath})),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;";function m(n,c){const h=document.createElement("div"),T=document.createElement("label");return T.style.cssText=y,T.textContent=n,h.appendChild(T),h.appendChild(c),h}function x(n,c){const h=document.createElement("input");return h.type="text",h.placeholder=n,h.value=c||"",h.style.cssText=r,h}function g(n){const c=document.createElement("select");return c.style.cssText=r,n.forEach(([h,T])=>{const M=document.createElement("option");M.value=h,M.textContent=T,c.appendChild(M)}),c}const v=e.value.substring(e.selectionStart,e.selectionEnd),d=x("/about or https://example.com",v.startsWith("/")?v:"");a.appendChild(m("URL",d));const C=x("Button label",v&&!v.startsWith("/")?v:"");a.appendChild(m("Label",C));const A=g([["primary","Primary"],["secondary","Secondary"],["success","Success (Green)"],["danger","Danger (Red)"],["warning","Warning (Orange)"],["info","Info (Blue)"],["outline","Outline"],["ghost","Ghost"],["link","Link"],["outline-success","Outline Success"],["outline-danger","Outline Danger"]]);a.appendChild(m("Variant",A));const N=g([["","Default"],["sm","Small"],["lg","Large"]]);a.appendChild(m("Size",N));const f=x("e.g. arrow-right, star (optional)","");a.appendChild(m("Icon (before label)",f));const p=x("e.g. arrow-right (optional)","");a.appendChild(m("Icon (after label)",p));const k=document.createElement("label");k.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9em;";const L=document.createElement("input");L.type="checkbox",L.style.cssText="width:1rem;height:1rem;",k.appendChild(L),k.appendChild(document.createTextNode("Open in new tab")),a.appendChild(k);const u=document.createElement("button");u.type="button",u.className="btn btn-primary",u.textContent="Insert Button",a.appendChild(u);const z=E.modal({title:"Insert Button",size:"sm"});z.element.appendChild(a),z.open(),requestAnimationFrame(()=>{E.autocomplete(d,{data:t,minChars:1,onSelect:n=>{d.value=n.value,C.value||(C.value=n.label)}}),d.focus()}),u.addEventListener("click",()=>{const n=d.value.trim();if(!n)return;z.close();const c=C.value.trim()||n;let h=`href="${n}" variant="${A.value}"`;N.value&&(h+=` size="${N.value}"`);const T=f.value.trim().replace(/"/g,"");T&&(h+=` icon="${T}"`);const M=p.value.trim().replace(/"/g,"");M&&(h+=` icon-after="${M}"`),L.checked&&(h+=' target="_blank"');const b=`[button ${h}]${c}[/button]`;ye(e,b)})}),H.onLinkShortcode(async e=>{const t=(await j.pages.list().catch(()=>[])).map(u=>({label:u.title||u.urlPath,value:u.urlPath})),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;";function m(u,z){const n=document.createElement("div"),c=document.createElement("label");return c.style.cssText=y,c.textContent=u,n.appendChild(c),n.appendChild(z),n}function x(u,z){const n=document.createElement("input");return n.type="text",n.placeholder=u,n.value=z||"",n.style.cssText=r,n}const g=e.value.substring(e.selectionStart,e.selectionEnd),v=x("/about or https://example.com",g.startsWith("/")?g:"");a.appendChild(m("URL",v));const d=x("Link text",g&&!g.startsWith("/")?g:"");a.appendChild(m("Link text",d));const C=x("e.g. text-primary, fw-bold (optional)","");a.appendChild(m("CSS class",C));const A=x("e.g. arrow-right (optional)","");a.appendChild(m("Icon (before text)",A));const N=x("e.g. external-link (optional)","");a.appendChild(m("Icon (after text)",N));const f=document.createElement("label");f.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9em;";const p=document.createElement("input");p.type="checkbox",p.style.cssText="width:1rem;height:1rem;",f.appendChild(p),f.appendChild(document.createTextNode("Open in new tab")),a.appendChild(f);const k=document.createElement("button");k.type="button",k.className="btn btn-primary",k.textContent="Insert Link",a.appendChild(k);const L=E.modal({title:"Insert Link Shortcode",size:"sm"});L.element.appendChild(a),L.open(),requestAnimationFrame(()=>{E.autocomplete(v,{data:t,minChars:1,onSelect:u=>{v.value=u.value,d.value||(d.value=u.label)}}),v.focus()}),k.addEventListener("click",()=>{const u=v.value.trim();if(!u)return;L.close();const z=d.value.trim()||u;let n=`href="${u}"`;const c=C.value.trim().replace(/"/g,"");c&&(n+=` class="${c}"`);const h=A.value.trim().replace(/"/g,"");h&&(n+=` icon="${h}"`);const T=N.value.trim().replace(/"/g,"");T&&(n+=` icon-after="${T}"`),p.checked&&(n+=' target="_blank"');const M=`[link ${n}]${z}[/link]`;ye(e,M)})}),H.onTabs(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a=qe([["","Default"],["pills","Pills"],["bordered","Bordered"]]);t.appendChild(pe("Style",a));const y=qe([["","Left"],["center","Centre"],["right","Right"]]);t.appendChild(pe("Alignment",y));const r=qe([["","None"],["fade","Fade"]]);t.appendChild(pe("Animation",r));const m=We("Allow multiple panels open at once"),x=m.querySelector("input");t.appendChild(m);const g=document.createElement("div");g.style.cssText="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",g.textContent="Tabs",t.appendChild(g);const v=document.createElement("div");v.style.cssText="display:flex;flex-direction:column;gap:.4rem;";const d=[];function C(){d.forEach(z=>{z.removeBtn.disabled=d.length<=2,z.removeBtn.style.opacity=d.length<=2?"0.3":"1"})}function A(){const z=a.value,n=y.value,c=r.value,h=x.checked,T=[];z&&T.push(`style="${z}"`),n&&T.push(`align="${n}"`),c&&T.push(c),h&&T.push('multiple="true"');let b=`[tabs${T.length?" "+T.join(" "):""}]
88
+ `)}const je="editor_prefs";function Je(){return S.get(je)||{viewMode:"split",fullscreen:!1}}function Qe(l,se){const de=Je();de[l]=se,S.set(je,de)}export const pageEditorView={templateUrl:"/admin/js/templates/page-editor.html",async onMount(l){const se=window.location.hash.match(/#\/pages\/edit(\/.*)/),de=se?se[1]:null,G=!!de,J=E.loader(l.get(0),{type:"dots"}),Ne=[j.layouts.get().catch(()=>({})),j.settings.get().catch(()=>({}))];G&&(Ne.push(j.pages.get(de).catch(()=>null)),Ne.push(j.pages.list().catch(()=>[])));const[Ie,Pe,W,Se]=await Promise.all(Ne);J.destroy(),et(l.find("#field-theme").get(0),{includeDefault:!0});const $e=Pe?.layoutOptions?.spacerSize??40;if(G&&!W){E.toast("Page not found.",{type:"error"}),R.navigate("/pages");return}l.find("#editor-title").text(G?`Edit Page \u2014 ${W.title||de}`:"New Page"),G&&l.find("#page-url-path").val(de),W&&(l.find("#field-title").val(W.title||""),l.find("#field-description").val(W.description||""),l.find("#field-status").val(W.status||"draft"),l.find("#field-sort-order").val(W.sortOrder??99),l.find("#field-show-in-nav").prop("checked",!!W.showInNav),l.find("#field-sidebar").prop("checked",!!W.sidebar),l.find("#field-show-breadcrumbs").prop("checked",W.breadcrumbs!==!1),l.find("#field-bundled").prop("checked",!!W.bundled),l.find("#field-category").val(W.category||""),l.find("#field-visibility").val(W.visibility||"public"),l.find("#field-theme").val(W.theme||""),l.find("#field-seo-title").val(W.seo?.title||""),l.find("#field-seo-desc").val(W.seo?.description||""),W.dconfig&&l.find("#field-dconfig").val(JSON.stringify(W.dconfig,null,2)));const fe=l.find("#quick-switch");G&&Array.isArray(Se)&&Se.length&&([...Se].sort((e,t)=>(e.title||e.urlPath).localeCompare(t.title||t.urlPath)).forEach(e=>{const t=document.createElement("option");t.value=e.urlPath,t.textContent=`${e.title||"Untitled"} (${e.urlPath})`,e.urlPath===de&&(t.selected=!0),fe.get(0).appendChild(t)}),fe.css("display",""),fe.on("change",function(){const e=this.value;e&&R.navigate("/pages/edit"+e)}));const ie=await j.pages.tags().catch(()=>[]),ve=l.find("#field-tags").get(0),Ee=ve?E.pillbox(ve,{data:ie,value:W?.tags||[],creatable:!0,searchable:!0,placeholder:"Add tag\u2026"}):null,Re=l.find("#field-layout").empty();if(Object.entries(Ie).forEach(([e,t])=>{const a=(W?.layout||"default")===e?"selected":"";Re.append(`<option value="${e}" ${a}>${t.label||e}</option>`)}),G){const e=l.find("#view-page-btn").get(0);e.href=de,e.style.display="";const t=l.find("#live-preview-tab").get(0);t.style.display="";const a=l.find("#history-tab").get(0);a.style.display=""}if(E.tabs(l.find("#editor-meta-tabs").get(0)),G){const e=l.find("#live-preview-tab").get(0),t=l.find("#live-preview-frame").get(0);let a=!1;e.addEventListener("click",function(){a||(t.src=de,a=!0)}),ot(l,de)}const me=l.find("#markdown-editor"),Q=l.find("#markdown-preview");W&&me.val(W.content||"");let ne=!1,he="";j.settings.getCustomCss().then(({css:e})=>{if(he=e||"",!he)return;const t=document.createElement("style");t.id="preview-custom-css",t.textContent=he,Q.get(0).parentNode.insertBefore(t,Q.get(0))}).catch(()=>{});let ee=!1;const U=me.get(0),B=document.createElement("div");B.className="editor-line-numbers editor-line-numbers--foldable",U.parentElement.insertBefore(B,U);const te=tt(U,B,{onFoldChange:()=>{}});te.setGuard(e=>{ee=e});function re(){const e=l.find("#css-editor").get(0);if(!e)return;const t=e.value.split(`
89
+ `);for(;B.firstChild;)B.removeChild(B.firstChild);t.forEach((a,y)=>{const r=document.createElement("span");r.className="editor-line-number-row";const m=document.createElement("span");m.className="fold-toggle fold-toggle--empty";const x=document.createElement("span");x.className="editor-line-num",x.textContent=String(y+1),r.appendChild(m),r.appendChild(x),B.appendChild(r)}),B.scrollTop=e.scrollTop}{const e=l.find("#css-editor").get(0);e&&e.addEventListener("scroll",()=>{B.scrollTop=e.scrollTop})}const Le=()=>{te.refresh(),B.scrollTop=U.scrollTop};U.addEventListener("input",Le),U.addEventListener("scroll",()=>{B.scrollTop=U.scrollTop});let De=null;const V=()=>{clearTimeout(De),De=setTimeout(async()=>{const e=te.getUnfoldedContent();try{const{html:t}=await j.pages.preview(e);Q.html(t,{safe:!1}),I.scan(Q.get(0)),Q.get(0).querySelectorAll(".tabs").forEach(a=>Domma.elements.tabs(a))}catch{window.marked&&Q.html(marked.parse(e))}},400)},H=Xe(me,l.find("#editor-toolbar"),{spacerDefault:$e});let ce=!1,xe="split",we=null;const ue=document.createElement("button");ue.className="editor-view-btn",ue.type="button";const ke=document.createElement("span");ke.setAttribute("data-icon","css-code"),ue.appendChild(ke);const be=document.createElement("button");be.className="editor-view-btn",be.type="button";const ze=document.createElement("span");ze.setAttribute("data-icon","code"),be.appendChild(ze);let ge=!1;const oe=document.createElement("button");oe.className="editor-view-btn",oe.type="button",oe.textContent="\u25BC\u25BC",oe.style.cssText="font-size:9px;letter-spacing:-1px;";const le=l.find(".editor-toolbar-right").get(0);le.prepend(oe),le.prepend(be),le.prepend(ue),I.scan(ue),I.scan(be),E.tooltip(ue,{content:"Edit Custom CSS",position:"top"}),E.tooltip(be,{content:"Format Markdown",position:"top"}),E.tooltip(oe,{content:"Fold / unfold all shortcodes",position:"top"}),be.addEventListener("click",()=>{const e=me.get(0),t=e.selectionStart,a=lt(te.getUnfoldedContent());te.unfoldAll(),ee=!0,e.value=a,ee=!1,e.selectionStart=e.selectionEnd=Math.min(t,a.length),e.dispatchEvent(new Event("input")),te.refresh(),E.toast("Markdown formatted.",{type:"success"})}),oe.addEventListener("click",()=>{ge?(te.unfoldAll(),oe.textContent="\u25BC\u25BC",oe.classList.remove("active")):(te.foldAll(),oe.textContent="\u25B6\u25B6",oe.classList.add("active")),ge=!ge});const Ce=document.createElement("span");Ce.className="editor-toolbar-sep",le.insertBefore(Ce,le.children[3]),ue.addEventListener("click",()=>{ce=!ce;const e=l.find("#markdown-editor"),t=l.find("#css-editor"),a=l.find("#editor-body");if(ce){const y=l.find(".editor-view-btn[data-mode].active").get(0);xe=y?y.getAttribute("data-mode"):"split",l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find('.editor-view-btn[data-mode="split"]').addClass("active"),a.removeClass("editor-mode-write editor-mode-preview").addClass("editor-mode-split"),e.hide(),t.show(),ne||(t.val(he),ne=!0,Ze(t.get(0))),re(),ue.classList.add("active")}else l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find(`.editor-view-btn[data-mode="${xe}"]`).addClass("active"),a.removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${xe}`),t.hide(),e.show(),te.refresh(),ue.classList.remove("active")});const Ae=Je();Ae.viewMode&&Ae.viewMode!=="split"&&(l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find(`.editor-view-btn[data-mode="${Ae.viewMode}"]`).addClass("active"),l.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${Ae.viewMode}`)),Ae.fullscreen&&l.find(".editor-card").addClass("editor-fullscreen"),l.find("#css-editor").on("input",()=>{re(),clearTimeout(we),we=setTimeout(()=>{let e=document.getElementById("preview-custom-css");e||(e=document.createElement("style"),e.id="preview-custom-css",Q.get(0).parentNode.insertBefore(e,Q.get(0))),e.textContent=l.find("#css-editor").val()},400)}),H.onLink(async e=>{const t=(await j.pages.list().catch(()=>[])).map(p=>({label:p.title||p.urlPath,value:p.urlPath})),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const y=document.createElement("label");y.className="form-label",y.textContent="URL";const r=document.createElement("input");r.type="text",r.className="form-input",r.placeholder="/about or https://example.com";const m=e.value.substring(e.selectionStart,e.selectionEnd);m&&m.startsWith("/")&&(r.value=m),a.appendChild(y),a.appendChild(r);const x=document.createElement("label");x.className="form-label",x.textContent="Link text";const g=document.createElement("input");g.type="text",g.className="form-input",g.placeholder="Display text",m&&!m.startsWith("/")&&(g.value=m),a.appendChild(x),a.appendChild(g);const v=document.createElement("label");v.className="form-label",v.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;";const d=document.createElement("input");d.type="checkbox",d.style.cssText="width:1rem;height:1rem;cursor:pointer;",v.appendChild(d),v.appendChild(document.createTextNode("Display as button")),a.appendChild(v);const C=document.createElement("label");C.className="form-label",C.textContent="Button colour",C.style.display="none";const A=document.createElement("select");A.className="form-select",A.style.display="none",[["primary","Primary"],["secondary","Secondary"],["success","Success (Green)"],["danger","Danger (Red)"],["warning","Warning (Orange)"],["info","Info (Blue)"],["outline","Outline"],["outline-success","Outline Success"],["outline-danger","Outline Danger"],["ghost","Ghost"]].forEach(([p,k])=>{const L=document.createElement("option");L.value=p,L.textContent=k,A.appendChild(L)}),a.appendChild(C),a.appendChild(A),d.addEventListener("change",()=>{const p=d.checked;C.style.display=p?"":"none",A.style.display=p?"":"none"});const N=document.createElement("button");N.type="button",N.className="btn btn-primary",N.textContent="Insert Link",a.appendChild(N);const f=E.modal({title:"Insert Link",size:"sm"});f.element.appendChild(a),f.open(),requestAnimationFrame(()=>{E.autocomplete(r,{data:t,minChars:1,onSelect:p=>{r.value=p.value,g.value||(g.value=p.label)}}),r.focus()}),N.addEventListener("click",()=>{const p=r.value.trim(),k=g.value.trim();if(!p)return;f.close();const L=d.checked?`[button href="${p}" variant="${A.value}"]${k||p}[/button]`:`[${k||p}](${p})`,u=e.selectionStart,z=e.selectionEnd;e.value=e.value.substring(0,u)+L+e.value.substring(z),e.selectionStart=e.selectionEnd=u+L.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onImage(async e=>{const t=(await j.media.list().catch(()=>[])).filter(r=>/\.(png|jpe?g|gif|webp|svg)$/i.test(r.name)),a=document.createElement("div");if(a.className="media-picker-grid",t.length)t.forEach(r=>{const m=document.createElement("div");m.className="media-picker-item",m.dataset.url=r.url;const x=document.createElement("img");x.src=r.url,x.alt=r.name;const g=document.createElement("span");g.textContent=r.name,m.appendChild(x),m.appendChild(g),a.appendChild(m)});else{const r=document.createElement("p");r.className="text-muted p-3",r.textContent="No images uploaded yet.",a.appendChild(r)}const y=E.modal({title:"Insert Image",size:"lg"});y.element.appendChild(a),$(y.element).on("click",".media-picker-item",function(){const r=$(this).data("url"),m=$(this).find("span").text();ye(e,`![${m}](${r})`),y.close(),me.get(0).dispatchEvent(new Event("input",{bubbles:!0}))}),y.open()}),H.onCollection(async e=>{const[t,a]=await Promise.all([j.collections.list().catch(()=>[]),j.blocks.list().catch(()=>[])]),y=document.createElement("div");y.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const r="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",m="width:100%;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;",x=document.createElement("div"),g=document.createElement("label");g.style.cssText=r,g.textContent="Collection";const v=document.createElement("select");if(v.style.cssText=m,t.length)t.forEach(O=>{const Z=document.createElement("option");Z.value=O.slug,Z.textContent=O.title||O.slug,v.appendChild(Z)});else{const O=document.createElement("option");O.value="",O.textContent="No collections found",v.appendChild(O)}x.appendChild(g),x.appendChild(v),y.appendChild(x);const d=document.createElement("div"),C=document.createElement("label");C.style.cssText=r,C.textContent="Display";const A=document.createElement("select");A.style.cssText=m,["table","cards","list","block"].forEach(O=>{const Z=document.createElement("option");Z.value=O,Z.textContent=O.charAt(0).toUpperCase()+O.slice(1),A.appendChild(Z)}),d.appendChild(C),d.appendChild(A),y.appendChild(d);const N=document.createElement("div");N.style.display="none";const f=document.createElement("label");f.style.cssText=r,f.textContent="Columns (2\u20134)";const p=document.createElement("input");p.type="number",p.min="2",p.max="4",p.value="3",p.style.cssText=m,N.appendChild(f),N.appendChild(p),y.appendChild(N);const k=document.createElement("div");k.style.display="none";const L=document.createElement("label");L.style.cssText=r,L.textContent="Block template";const u=document.createElement("select");if(u.style.cssText=m,a.length)a.forEach(O=>{const Z=document.createElement("option");Z.value=O.name??O,Z.textContent=O.name??O,u.appendChild(Z)});else{const O=document.createElement("option");O.value="",O.textContent="No block templates found",u.appendChild(O)}k.appendChild(L),k.appendChild(u),y.appendChild(k);const z=document.createElement("div"),n=document.createElement("label");n.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const c=document.createElement("input");c.type="checkbox",c.checked=!0,n.appendChild(c),n.appendChild(document.createTextNode("Enable search")),z.appendChild(n),y.appendChild(z);const h=document.createElement("div"),T=document.createElement("label");T.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const M=document.createElement("input");M.type="checkbox",M.checked=!0,T.appendChild(M),T.appendChild(document.createTextNode("Sortable columns")),h.appendChild(T),y.appendChild(h);const b=document.createElement("div"),w=document.createElement("label");w.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const i=document.createElement("input");i.type="checkbox",i.checked=!1,w.appendChild(i),w.appendChild(document.createTextNode("CSV export")),b.appendChild(w),y.appendChild(b);const s=document.createElement("div"),o=document.createElement("label");o.style.cssText=r,o.textContent="Rows per page";const _=document.createElement("input");_.type="number",_.min="5",_.max="100",_.value="25",_.style.cssText=m,s.appendChild(o),s.appendChild(_),y.appendChild(s);const K=document.createElement("div"),ae=document.createElement("label");ae.style.cssText=r,ae.textContent="Limit (optional)";const X=document.createElement("input");X.type="number",X.placeholder="All",X.style.cssText=m,K.appendChild(ae),K.appendChild(X),y.appendChild(K);const P=document.createElement("button");P.type="button",P.className="btn btn-primary",P.textContent="Insert",y.appendChild(P);const F=[z,h,b,s],q=()=>{const O=A.value,Z=O==="table";F.forEach(Te=>{Te.style.display=Z?"":"none"}),N.style.display=O==="cards"||O==="block"?"":"none",k.style.display=O==="block"?"":"none"};A.addEventListener("change",q),q();const Y=E.modal({title:"Insert Collection",size:"sm"});Y.element.appendChild(y),Y.open(),P.addEventListener("click",()=>{const O=v.value;if(!O)return;const Z=A.value;let Te=`[collection slug="${O}" display="${Z}"`;if(Z==="cards"&&(Te+=` columns="${p.value}"`),Z==="block"){const Ue=u.value;Ue&&(Te+=` block="${Ue}"`);const Ve=p.value.trim();Ve&&(Te+=` cols="${Ve}"`)}Z==="table"&&!c.checked&&(Te+=' search="false"'),Z==="table"&&!M.checked&&(Te+=' sortable="false"'),Z==="table"&&i.checked&&(Te+=' exportable="true"'),Z==="table"&&_.value!=="25"&&(Te+=` page-size="${_.value}"`);const Ge=X.value.trim();Ge&&(Te+=` limit="${Ge}"`),Te+=" /]",Y.close(),ye(e,Te),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onBlock(async e=>{let t=[];try{t=await j.blocks.list()}catch{E.toast("Could not load blocks.",{type:"error"});return}if(!t.length){E.toast("No block templates found. Create one in Blocks first.",{type:"warning"});return}const a=E.modal({title:"Insert Block",size:"lg"}),y=document.createElement("div");y.style.cssText="display:flex;gap:1rem;min-height:320px;";const r=document.createElement("div");r.style.cssText="flex:1;display:flex;flex-direction:column;gap:.75rem;";const m=document.createElement("label");m.className="form-label",m.textContent="Block Template";const x=document.createElement("select");x.className="form-select";const g=document.createElement("option");g.value="",g.textContent="\u2014 select a template \u2014",x.appendChild(g),t.forEach(u=>{const z=document.createElement("option");z.value=u.name,z.textContent=u.name,x.appendChild(z)}),r.appendChild(m),r.appendChild(x);const v=document.createElement("div");v.style.cssText="display:flex;flex-direction:column;gap:.5rem;overflow-y:auto;max-height:260px;",r.appendChild(v);const d=document.createElement("button");d.className="btn btn-primary",d.type="button",d.textContent="Insert",d.disabled=!0,r.appendChild(d);const C=document.createElement("div");C.style.cssText="flex:1;border:1px solid var(--dm-border-color);border-radius:var(--dm-radius);padding:.75rem;overflow:auto;background:var(--dm-surface-bg);";const A=document.createElement("p");A.className="text-muted",A.style.cssText="font-size:.8rem;margin:0;",A.textContent="Select a template to see a preview.",C.appendChild(A),y.appendChild(r),y.appendChild(C),a.element.appendChild(y),a.open();let N=null,f=[];function p(u){return u.replace(/_/g," ").replace(/\b\w/g,z=>z.toUpperCase())}function k(){if(!N)return;const u={};f.forEach(({key:n,input:c})=>{u[n]=c.value});const z=N.replace(/\{\{([\w_]+)\}\}/g,(n,c)=>(u[c]??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;"));C.innerHTML=DOMPurify.sanitize(z)}function L(u){v.textContent="",f=[];const z=new Set(["_id","_createdAt","_updatedAt"]),n=new Set;for(const[,c]of u.matchAll(/\{\{([\w_]+)\}\}/g))z.has(c)||n.add(c);if(!n.size){const c=document.createElement("p");c.className="text-muted",c.style.cssText="font-size:.8rem;margin:0;",c.textContent="No editable placeholders in this template.",v.appendChild(c);return}n.forEach(c=>{const h=document.createElement("div"),T=document.createElement("label");T.className="form-label",T.style.cssText="font-size:.8rem;margin-bottom:.2rem;display:block;",T.textContent=p(c);const M=document.createElement("input");M.type="text",M.className="form-input",M.placeholder=p(c),M.addEventListener("input",k),h.appendChild(T),h.appendChild(M),v.appendChild(h),f.push({key:c,input:M})})}x.addEventListener("change",async()=>{const u=x.value;if(!u){N=null,f=[],v.textContent="",C.textContent="",C.appendChild(A),d.disabled=!0;return}N=null,f=[],v.textContent="",d.disabled=!0;try{N=(await j.blocks.get(u)).content||"",L(N),k(),d.disabled=!1}catch{E.toast("Could not load template.",{type:"error"})}}),d.addEventListener("click",()=>{if(!x.value)return;const u=c=>c.replace(/"/g,"&quot;");let z=`template="${u(x.value)}"`;f.forEach(({key:c,input:h})=>{h.value!==""&&(z+=` ${c}="${u(h.value)}"`)});const n=`[block ${z} /]`;ye(e,n),e.dispatchEvent(new Event("input",{bubbles:!0})),a.close(),e.focus()})}),H.onForm(async e=>{const t=await j.forms.list().catch(()=>[]),a=document.createElement("div");a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;",m=document.createElement("div"),x=document.createElement("label");x.style.cssText=y,x.textContent="Form";const g=document.createElement("select");if(g.style.cssText=r,t.length)t.forEach(C=>{const A=document.createElement("option");A.value=C.slug,A.textContent=C.title||C.slug,g.appendChild(A)});else{const C=document.createElement("option");C.value="",C.textContent="No forms found",g.appendChild(C)}m.appendChild(x),m.appendChild(g),a.appendChild(m);const v=document.createElement("button");v.className="btn btn-primary btn-sm",v.style.cssText="align-self:flex-end;margin-top:.5rem;",v.textContent="Insert Form",a.appendChild(v);const d=E.modal({title:"Insert Form",size:"sm"});d.element.appendChild(a),d.open(),v.addEventListener("click",()=>{const C=g.value;C&&(ye(e,`[form slug="${C}" /]`),d.close(),me.get(0).dispatchEvent(new Event("input",{bubbles:!0})))})}),H.onView(async e=>{const t=await j.views.list().catch(()=>[]),a=document.createElement("div");a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;",m=document.createElement("div"),x=document.createElement("label");x.style.cssText=y,x.textContent="View";const g=document.createElement("select");if(g.style.cssText=r,t.length)t.forEach(f=>{const p=document.createElement("option");p.value=f.slug,p.textContent=f.title||f.slug,g.appendChild(p)});else{const f=document.createElement("option");f.value="",f.textContent="No Views configured yet \u2014 create one under Data \u2192 Views",g.appendChild(f)}m.appendChild(x),m.appendChild(g),a.appendChild(m);const v=document.createElement("div"),d=document.createElement("label");d.style.cssText=y,d.textContent="Display";const C=document.createElement("select");C.style.cssText=r,["table","cards","list"].forEach(f=>{const p=document.createElement("option");p.value=f,p.textContent=f.charAt(0).toUpperCase()+f.slice(1),C.appendChild(p)}),v.appendChild(d),v.appendChild(C),a.appendChild(v);const A=document.createElement("button");A.type="button",A.className="btn btn-primary",A.textContent="Insert",a.appendChild(A);const N=E.modal({title:"Insert View",size:"sm"});N.element.appendChild(a),N.open(),A.addEventListener("click",()=>{const f=g.value;if(!f)return;const p=`[view slug="${f}" display="${C.value}" /]`;N.close(),ye(e,p),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onCta(async e=>{const t=await j.actions.list().catch(()=>[]),a=document.createElement("div");a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;";function m(L,u){const z=document.createElement("div"),n=document.createElement("label");return n.style.cssText=y,n.textContent=L,z.appendChild(n),z.appendChild(u),z}function x(L){const u=document.createElement("select");return u.style.cssText=r,L.forEach(([z,n])=>{const c=document.createElement("option");c.value=z,c.textContent=n,u.appendChild(c)}),u}function g(L,u,z){const n=document.createElement("input");return n.type=L,n.placeholder=u||"",n.value=z||"",n.style.cssText=r,n}const v=x(t.length?t.map(L=>[L.slug,L.title||L.slug]):[["","No Actions configured yet \u2014 create one under Data \u2192 Actions"]]);a.appendChild(m("Action",v));const d=g("text","Button label","Run");if(a.appendChild(m("Label",d)),v.addEventListener("change",()=>{const L=t.find(u=>u.slug===v.value);L?.trigger?.label&&(d.value=L.trigger.label)}),t.length){const L=t[0];L?.trigger?.label&&(d.value=L.trigger.label)}const C=g("text","Paste entry UUID\u2026","");a.appendChild(m("Entry ID",C));const A=x([["primary","Primary"],["secondary","Secondary"],["ghost","Ghost"],["danger","Danger"]]);a.appendChild(m("Style",A));const N=g("text","e.g. check, zap, send (optional)","");a.appendChild(m("Icon",N));const f=g("text","Confirmation message (optional)","");a.appendChild(m("Confirm prompt",f));const p=document.createElement("button");p.type="button",p.className="btn btn-primary",p.textContent="Insert",a.appendChild(p);const k=E.modal({title:"Insert CTA Button",size:"sm"});k.element.appendChild(a),k.open(),p.addEventListener("click",()=>{const L=v.value;if(!L)return;const u=C.value.trim(),z=(d.value.trim()||"Run").replace(/\[\/cta\]/gi,""),n=A.value,c=N.value.trim().replace(/"/g,""),h=f.value.trim().replace(/"/g,""),T=u.replace(/"/g,"");let M=`action="${L}" style="${n}"`;T&&(M+=` entry="${T}"`),c&&(M+=` icon="${c}"`),h&&(M+=` confirm="${h}"`);const b=`[cta ${M}]${z}[/cta]`;k.close(),ye(e,b),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onButton(async e=>{const t=(await j.pages.list().catch(()=>[])).map(n=>({label:n.title||n.urlPath,value:n.urlPath})),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;";function m(n,c){const h=document.createElement("div"),T=document.createElement("label");return T.style.cssText=y,T.textContent=n,h.appendChild(T),h.appendChild(c),h}function x(n,c){const h=document.createElement("input");return h.type="text",h.placeholder=n,h.value=c||"",h.style.cssText=r,h}function g(n){const c=document.createElement("select");return c.style.cssText=r,n.forEach(([h,T])=>{const M=document.createElement("option");M.value=h,M.textContent=T,c.appendChild(M)}),c}const v=e.value.substring(e.selectionStart,e.selectionEnd),d=x("/about or https://example.com",v.startsWith("/")?v:"");a.appendChild(m("URL",d));const C=x("Button label",v&&!v.startsWith("/")?v:"");a.appendChild(m("Label",C));const A=g([["primary","Primary"],["secondary","Secondary"],["success","Success (Green)"],["danger","Danger (Red)"],["warning","Warning (Orange)"],["info","Info (Blue)"],["outline","Outline"],["ghost","Ghost"],["link","Link"],["outline-success","Outline Success"],["outline-danger","Outline Danger"]]);a.appendChild(m("Variant",A));const N=g([["","Default"],["sm","Small"],["lg","Large"]]);a.appendChild(m("Size",N));const f=x("e.g. arrow-right, star (optional)","");a.appendChild(m("Icon (before label)",f));const p=x("e.g. arrow-right (optional)","");a.appendChild(m("Icon (after label)",p));const k=document.createElement("label");k.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9em;";const L=document.createElement("input");L.type="checkbox",L.style.cssText="width:1rem;height:1rem;",k.appendChild(L),k.appendChild(document.createTextNode("Open in new tab")),a.appendChild(k);const u=document.createElement("button");u.type="button",u.className="btn btn-primary",u.textContent="Insert Button",a.appendChild(u);const z=E.modal({title:"Insert Button",size:"sm"});z.element.appendChild(a),z.open(),requestAnimationFrame(()=>{E.autocomplete(d,{data:t,minChars:1,onSelect:n=>{d.value=n.value,C.value||(C.value=n.label)}}),d.focus()}),u.addEventListener("click",()=>{const n=d.value.trim();if(!n)return;z.close();const c=C.value.trim()||n;let h=`href="${n}" variant="${A.value}"`;N.value&&(h+=` size="${N.value}"`);const T=f.value.trim().replace(/"/g,"");T&&(h+=` icon="${T}"`);const M=p.value.trim().replace(/"/g,"");M&&(h+=` icon-after="${M}"`),L.checked&&(h+=' target="_blank"');const b=`[button ${h}]${c}[/button]`;ye(e,b)})}),H.onLinkShortcode(async e=>{const t=(await j.pages.list().catch(()=>[])).map(u=>({label:u.title||u.urlPath,value:u.urlPath})),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const y="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",r="width:100%;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;";function m(u,z){const n=document.createElement("div"),c=document.createElement("label");return c.style.cssText=y,c.textContent=u,n.appendChild(c),n.appendChild(z),n}function x(u,z){const n=document.createElement("input");return n.type="text",n.placeholder=u,n.value=z||"",n.style.cssText=r,n}const g=e.value.substring(e.selectionStart,e.selectionEnd),v=x("/about or https://example.com",g.startsWith("/")?g:"");a.appendChild(m("URL",v));const d=x("Link text",g&&!g.startsWith("/")?g:"");a.appendChild(m("Link text",d));const C=x("e.g. text-primary, fw-bold (optional)","");a.appendChild(m("CSS class",C));const A=x("e.g. arrow-right (optional)","");a.appendChild(m("Icon (before text)",A));const N=x("e.g. external-link (optional)","");a.appendChild(m("Icon (after text)",N));const f=document.createElement("label");f.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9em;";const p=document.createElement("input");p.type="checkbox",p.style.cssText="width:1rem;height:1rem;",f.appendChild(p),f.appendChild(document.createTextNode("Open in new tab")),a.appendChild(f);const k=document.createElement("button");k.type="button",k.className="btn btn-primary",k.textContent="Insert Link",a.appendChild(k);const L=E.modal({title:"Insert Link Shortcode",size:"sm"});L.element.appendChild(a),L.open(),requestAnimationFrame(()=>{E.autocomplete(v,{data:t,minChars:1,onSelect:u=>{v.value=u.value,d.value||(d.value=u.label)}}),v.focus()}),k.addEventListener("click",()=>{const u=v.value.trim();if(!u)return;L.close();const z=d.value.trim()||u;let n=`href="${u}"`;const c=C.value.trim().replace(/"/g,"");c&&(n+=` class="${c}"`);const h=A.value.trim().replace(/"/g,"");h&&(n+=` icon="${h}"`);const T=N.value.trim().replace(/"/g,"");T&&(n+=` icon-after="${T}"`),p.checked&&(n+=' target="_blank"');const M=`[link ${n}]${z}[/link]`;ye(e,M)})}),H.onTabs(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a=qe([["","Default"],["pills","Pills"],["bordered","Bordered"]]);t.appendChild(pe("Style",a));const y=qe([["","Left"],["center","Centre"],["right","Right"]]);t.appendChild(pe("Alignment",y));const r=qe([["","None"],["fade","Fade"]]);t.appendChild(pe("Animation",r));const m=We("Allow multiple panels open at once"),x=m.querySelector("input");t.appendChild(m);const g=document.createElement("div");g.style.cssText="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",g.textContent="Tabs",t.appendChild(g);const v=document.createElement("div");v.style.cssText="display:flex;flex-direction:column;gap:.4rem;";const d=[];function C(){d.forEach(z=>{z.removeBtn.disabled=d.length<=2,z.removeBtn.style.opacity=d.length<=2?"0.3":"1"})}function A(){const z=a.value,n=y.value,c=r.value,h=x.checked,T=[];z&&T.push(`style="${z}"`),n&&T.push(`align="${n}"`),c&&T.push(c),h&&T.push('multiple="true"');let b=`[tabs${T.length?" "+T.join(" "):""}]
90
90
  `;return d.forEach((w,i)=>{const s=w.titleInput.value.trim()||`Tab ${i+1}`,o=w.iconInput.value.trim(),_=o?` title="${s}" icon="${o}"`:` title="${s}"`;b+=`[tab${_}]Tab content here.[/tab]
91
91
  `}),b+="[/tabs]",b}function N(z=""){if(d.length>=10)return;const n=document.createElement("div");n.style.cssText="display:flex;gap:.4rem;align-items:center;";const c=Me("Tab title",z);c.style.cssText+="flex:1;";const h=_e("icon (optional)");h.el.style.flex=".6";const T=document.createElement("button");T.type="button",T.textContent="\xD7",T.style.cssText="padding:.3rem .5rem;background:transparent;border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text-muted,#aaa);cursor:pointer;font-size:.85em;flex-shrink:0;";const M={row:n,titleInput:c,iconInput:h.input,removeBtn:T};d.push(M),n.appendChild(c),n.appendChild(h.el),n.appendChild(T),v.appendChild(n),T.addEventListener("click",()=>{if(d.length<=2)return;const b=d.indexOf(M);d.splice(b,1),v.removeChild(n),C(),p(),k.update(A())}),[c,h.input].forEach(b=>b.addEventListener("input",()=>k.update(A()))),C()}N("Overview"),N("Details"),t.appendChild(v);const f=document.createElement("button");f.type="button",f.textContent="+ Add Tab",f.style.cssText="padding:.35rem .75rem;background:transparent;border:1px dashed var(--dm-border,#555);border-radius:4px;color:var(--dm-text-muted,#aaa);cursor:pointer;font-size:.85em;align-self:flex-start;",f.addEventListener("click",()=>{N(""),p(),d[d.length-1].titleInput.focus(),k.update(A())}),t.appendChild(f);function p(){f.disabled=d.length>=10}const k=He();k.update(A()),t.appendChild(pe("Shortcode preview",k.el)),[a,y,r].forEach(z=>z.addEventListener("change",()=>k.update(A()))),x.addEventListener("change",()=>k.update(A()));const L=document.createElement("button");L.type="button",L.className="btn btn-primary",L.textContent="Insert Tabs",t.appendChild(L);const u=E.modal({title:"Insert Tabs",size:"sm"});u.element.appendChild(t),u.open(),requestAnimationFrame(()=>d[0].titleInput.focus()),L.addEventListener("click",()=>{ye(e,A()),u.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onHero(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a=Me("Hero title");t.appendChild(pe("Title",a));const y=Me("Tagline (optional)");t.appendChild(pe("Tagline",y));const r=qe([["sm","Small"],["md","Medium (default)"],["lg","Large"],["full","Full"]]);r.value="md",t.appendChild(pe("Size",r));const m=qe([["","Left"],["center","Centre"],["right","Right"]]);t.appendChild(pe("Alignment",m));const x=document.createElement("div");x.style.cssText="display:flex;gap:.75rem;align-items:center;";const g={};["none","colour","image"].forEach(n=>{const c=document.createElement("label");c.style.cssText="display:flex;align-items:center;gap:.3rem;font-size:.9em;cursor:pointer;";const h=document.createElement("input");h.type="radio",h.name="hero-bg",h.value=n,n==="none"&&(h.checked=!0),g[n]=h,c.appendChild(h),c.appendChild(document.createTextNode(n.charAt(0).toUpperCase()+n.slice(1))),x.appendChild(c)}),t.appendChild(pe("Background",x));const v=Me("#hex or CSS colour"),d=pe("Colour",v);d.style.display="none",t.appendChild(d);const C=Me("/media/hero.jpg"),A=qe([["","None"],["dark","Dark"],["light","Light"]]),N=document.createElement("div");N.style.cssText="display:none;flex-direction:column;gap:.5rem;",N.appendChild(pe("Image path",C)),N.appendChild(pe("Overlay",A)),t.appendChild(N);const f=Me("e.g. 400px");t.appendChild(pe("Min height",f));function p(){const n=a.value.trim(),c=y.value.trim(),h=r.value,T=m.value,M=Object.keys(g).find(_=>g[_].checked)||"none",b=v.value.trim(),w=C.value.trim(),i=A.value,s=f.value.trim(),o=[`title="${n}"`];return c&&o.push(`tagline="${c}"`),h&&h!=="md"&&o.push(`size="${h}"`),T&&o.push(`align="${T}"`),M==="colour"&&b&&o.push(`color="${b}"`),M==="image"&&w&&o.push(`image="${w}"`),M==="image"&&i&&o.push(`overlay="${i}"`),s&&o.push(`min-height="${s}"`),`[hero ${o.join(" ")}]
92
92
  Content here.
93
93
  [/hero]`}const k=He();k.update(p()),t.appendChild(pe("Shortcode preview",k.el));function L(){const n=Object.keys(g).find(c=>g[c].checked)||"none";d.style.display=n==="colour"?"":"none",N.style.display=n==="image"?"flex":"none",k.update(p())}Object.values(g).forEach(n=>n.addEventListener("change",L)),[a,y,v,C,f].forEach(n=>n.addEventListener("input",()=>k.update(p()))),[r,m,A].forEach(n=>n.addEventListener("change",()=>k.update(p())));const u=document.createElement("button");u.type="button",u.className="btn btn-primary",u.textContent="Insert Hero",t.appendChild(u);const z=E.modal({title:"Insert Hero",size:"sm"});z.element.appendChild(t),z.open(),requestAnimationFrame(()=>a.focus()),u.addEventListener("click",()=>{ye(e,p()),z.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onBanner(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a=[{value:"info",label:"Info",color:"#3b82f6"},{value:"success",label:"Success",color:"#22c55e"},{value:"warning",label:"Warning",color:"#f59e0b"},{value:"danger",label:"Danger",color:"#ef4444"},{value:"neutral",label:"Neutral",color:"#888"}];let y="info";const r=document.createElement("div");r.style.cssText="display:flex;gap:.35rem;flex-wrap:wrap;";const m={};a.forEach(p=>{const k=document.createElement("button");k.type="button",k.style.cssText="display:flex;align-items:center;gap:.3rem;padding:.3rem .6rem;border:1px solid var(--dm-border,#333);border-radius:4px;background:transparent;color:var(--dm-text,#eee);cursor:pointer;font-size:.85em;";const L=document.createElement("span");L.style.cssText=`display:inline-block;width:.55rem;height:.55rem;border-radius:50%;background:${p.color};flex-shrink:0;`,k.appendChild(L),k.appendChild(document.createTextNode(p.label)),m[p.value]=k,r.appendChild(k),k.addEventListener("click",()=>{y=p.value,Object.entries(m).forEach(([u,z])=>{z.style.borderColor=u===y?p.color:"var(--dm-border,#333)",z.style.background=u===y?`${p.color}22`:"transparent"}),A.update(C())})}),m.info.style.borderColor="#3b82f6",m.info.style.background="#3b82f622",t.appendChild(pe("Type",r));const x=Me("Title (optional)");t.appendChild(pe("Title",x));const g=_e("Icon name (optional)");t.appendChild(pe("Icon",g.el));const v=We("Dismissible"),d=v.querySelector("input");t.appendChild(v);function C(){const p=[];y!=="info"&&p.push(`type="${y}"`);const k=x.value.trim();k&&p.push(`title="${k}"`);const L=g.input.value.trim();return L&&p.push(`icon="${L}"`),d.checked&&p.push("dismissible"),`[banner${p.length?" "+p.join(" "):""}]
94
94
  Banner content here.
95
- [/banner]`}const A=He();A.update(C()),t.appendChild(pe("Shortcode preview",A.el)),[x,g.input].forEach(p=>p.addEventListener("input",()=>A.update(C()))),d.addEventListener("change",()=>A.update(C()));const N=document.createElement("button");N.type="button",N.className="btn btn-primary",N.textContent="Insert Banner",t.appendChild(N);const f=E.modal({title:"Insert Banner",size:"sm"});f.element.appendChild(t),f.open(),requestAnimationFrame(()=>x.focus()),N.addEventListener("click",()=>{ye(e,C()),f.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onGrid(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",y="width:100%;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;";function r(ae,X){const P=document.createElement("div"),F=document.createElement("label");return F.style.cssText=a,F.textContent=ae,P.appendChild(F),P.appendChild(X),P}function m(ae){const X=document.createElement("select");return X.style.cssText=y,ae.forEach(([P,F])=>{const q=document.createElement("option");q.value=P,q.textContent=F,X.appendChild(q)}),X}let x="grid";const g=document.createElement("div");g.style.cssText="display:flex;gap:.5rem;";const v=document.createElement("button");v.type="button",v.className="btn btn-sm btn-primary",v.textContent="Grid";const d=document.createElement("button");d.type="button",d.className="btn btn-sm btn-ghost",d.textContent="Row",g.appendChild(v),g.appendChild(d),t.appendChild(g);const C=document.createElement("input");C.type="number",C.min="1",C.max="12",C.value="2",C.style.cssText=y,t.appendChild(r("Columns",C));const A=m([["0","0"],["1","1"],["2","2"],["3","3"],["4","4 (default)"],["6","6"],["8","8"],["10","10"],["12","12"],["16","16"]]);A.value="4",t.appendChild(r("Gap",A));const N=document.createElement("div");N.style.cssText="display:flex;flex-direction:column;gap:.5rem;";const f=document.createElement("label");f.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const p=document.createElement("input");p.type="checkbox",f.appendChild(p),f.appendChild(document.createTextNode("Full width (breakout)")),N.appendChild(f);const k=document.createElement("div");k.style.cssText=a+"margin-top:.25rem;",k.textContent="Column Spans",N.appendChild(k);const L=document.createElement("div");L.style.cssText="display:flex;flex-direction:column;gap:.3rem;",N.appendChild(L),t.appendChild(N);const u=[];function z(){const ae=Math.min(Math.max(parseInt(C.value)||2,1),12),X=u.map(P=>P.value);L.textContent="",u.length=0;for(let P=0;P<ae;P++){const F=document.createElement("div");F.style.cssText="display:flex;align-items:center;gap:.5rem;";const q=document.createElement("span");q.style.cssText="font-size:.85em;color:var(--dm-text-muted,#aaa);white-space:nowrap;min-width:3em;",q.textContent=`Col ${P+1}`;const Y=document.createElement("input");Y.type="number",Y.min="1",Y.max="12",Y.placeholder="auto",Y.value=X[P]||"",Y.style.cssText=y+"width:5em;flex:none;",F.appendChild(q),F.appendChild(Y),L.appendChild(F),u.push(Y)}}C.addEventListener("input",z),z();const n=document.createElement("div");n.style.cssText="display:none;flex-direction:column;gap:.5rem;";const c=document.createElement("label");c.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const h=document.createElement("input");h.type="checkbox",c.appendChild(h),c.appendChild(document.createTextNode("Enable staggered reveal")),n.appendChild(c);const T=document.createElement("div");T.style.cssText="display:none;flex-direction:column;gap:.5rem;padding-left:.5rem;border-left:2px solid var(--dm-border,#333);";const M=m([["slide-up","Slide Up"],["slide-down","Slide Down"],["slide-left","Slide Left"],["slide-right","Slide Right"],["fade","Fade"],["zoom","Zoom"],["flip","Flip"]]);T.appendChild(r("Animation",M));const b=m([["stagger","Stagger"],["sequence","Sequence"]]);T.appendChild(r("Mode",b));const w=document.createElement("input");w.type="number",w.value="400",w.style.cssText=y,T.appendChild(r("Duration (ms)",w));const i=document.createElement("input");i.type="number",i.value="60",i.style.cssText=y,T.appendChild(r("Stagger (ms)",i));const s=document.createElement("input");s.type="number",s.value="0",s.style.cssText=y,T.appendChild(r("Delay (ms)",s));const o=m([["ltr","Left to Right"],["rtl","Right to Left"]]);T.appendChild(r("Direction",o)),n.appendChild(T),t.appendChild(n),h.addEventListener("change",()=>{T.style.display=h.checked?"flex":"none"});const _=document.createElement("button");_.type="button",_.className="btn btn-primary",_.textContent="Insert Grid",t.appendChild(_),v.addEventListener("click",()=>{x="grid",v.className="btn btn-sm btn-primary",d.className="btn btn-sm btn-ghost",N.style.display="flex",n.style.display="none",_.textContent="Insert Grid"}),d.addEventListener("click",()=>{x="row",d.className="btn btn-sm btn-primary",v.className="btn btn-sm btn-ghost",n.style.display="flex",N.style.display="none",_.textContent="Insert Row"});const K=E.modal({title:"Insert Grid / Row",size:"sm"});K.element.appendChild(t),K.open(),requestAnimationFrame(()=>C.focus()),_.addEventListener("click",()=>{K.close();const ae=Math.min(Math.max(parseInt(C.value)||2,1),12),X=A.value;let P;if(x==="grid"){let F=`cols="${ae}"`;X!=="4"&&(F+=` gap="${X}"`),p.checked&&(F+=' fullwidth="true"'),P=`[grid ${F}]
95
+ [/banner]`}const A=He();A.update(C()),t.appendChild(pe("Shortcode preview",A.el)),[x,g.input].forEach(p=>p.addEventListener("input",()=>A.update(C()))),d.addEventListener("change",()=>A.update(C()));const N=document.createElement("button");N.type="button",N.className="btn btn-primary",N.textContent="Insert Banner",t.appendChild(N);const f=E.modal({title:"Insert Banner",size:"sm"});f.element.appendChild(t),f.open(),requestAnimationFrame(()=>x.focus()),N.addEventListener("click",()=>{ye(e,C()),f.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onScribe(e=>nt(e)),H.onGrid(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",y="width:100%;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;";function r(ae,X){const P=document.createElement("div"),F=document.createElement("label");return F.style.cssText=a,F.textContent=ae,P.appendChild(F),P.appendChild(X),P}function m(ae){const X=document.createElement("select");return X.style.cssText=y,ae.forEach(([P,F])=>{const q=document.createElement("option");q.value=P,q.textContent=F,X.appendChild(q)}),X}let x="grid";const g=document.createElement("div");g.style.cssText="display:flex;gap:.5rem;";const v=document.createElement("button");v.type="button",v.className="btn btn-sm btn-primary",v.textContent="Grid";const d=document.createElement("button");d.type="button",d.className="btn btn-sm btn-ghost",d.textContent="Row",g.appendChild(v),g.appendChild(d),t.appendChild(g);const C=document.createElement("input");C.type="number",C.min="1",C.max="12",C.value="2",C.style.cssText=y,t.appendChild(r("Columns",C));const A=m([["0","0"],["1","1"],["2","2"],["3","3"],["4","4 (default)"],["6","6"],["8","8"],["10","10"],["12","12"],["16","16"]]);A.value="4",t.appendChild(r("Gap",A));const N=document.createElement("div");N.style.cssText="display:flex;flex-direction:column;gap:.5rem;";const f=document.createElement("label");f.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const p=document.createElement("input");p.type="checkbox",f.appendChild(p),f.appendChild(document.createTextNode("Full width (breakout)")),N.appendChild(f);const k=document.createElement("div");k.style.cssText=a+"margin-top:.25rem;",k.textContent="Column Spans",N.appendChild(k);const L=document.createElement("div");L.style.cssText="display:flex;flex-direction:column;gap:.3rem;",N.appendChild(L),t.appendChild(N);const u=[];function z(){const ae=Math.min(Math.max(parseInt(C.value)||2,1),12),X=u.map(P=>P.value);L.textContent="",u.length=0;for(let P=0;P<ae;P++){const F=document.createElement("div");F.style.cssText="display:flex;align-items:center;gap:.5rem;";const q=document.createElement("span");q.style.cssText="font-size:.85em;color:var(--dm-text-muted,#aaa);white-space:nowrap;min-width:3em;",q.textContent=`Col ${P+1}`;const Y=document.createElement("input");Y.type="number",Y.min="1",Y.max="12",Y.placeholder="auto",Y.value=X[P]||"",Y.style.cssText=y+"width:5em;flex:none;",F.appendChild(q),F.appendChild(Y),L.appendChild(F),u.push(Y)}}C.addEventListener("input",z),z();const n=document.createElement("div");n.style.cssText="display:none;flex-direction:column;gap:.5rem;";const c=document.createElement("label");c.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const h=document.createElement("input");h.type="checkbox",c.appendChild(h),c.appendChild(document.createTextNode("Enable staggered reveal")),n.appendChild(c);const T=document.createElement("div");T.style.cssText="display:none;flex-direction:column;gap:.5rem;padding-left:.5rem;border-left:2px solid var(--dm-border,#333);";const M=m([["slide-up","Slide Up"],["slide-down","Slide Down"],["slide-left","Slide Left"],["slide-right","Slide Right"],["fade","Fade"],["zoom","Zoom"],["flip","Flip"]]);T.appendChild(r("Animation",M));const b=m([["stagger","Stagger"],["sequence","Sequence"]]);T.appendChild(r("Mode",b));const w=document.createElement("input");w.type="number",w.value="400",w.style.cssText=y,T.appendChild(r("Duration (ms)",w));const i=document.createElement("input");i.type="number",i.value="60",i.style.cssText=y,T.appendChild(r("Stagger (ms)",i));const s=document.createElement("input");s.type="number",s.value="0",s.style.cssText=y,T.appendChild(r("Delay (ms)",s));const o=m([["ltr","Left to Right"],["rtl","Right to Left"]]);T.appendChild(r("Direction",o)),n.appendChild(T),t.appendChild(n),h.addEventListener("change",()=>{T.style.display=h.checked?"flex":"none"});const _=document.createElement("button");_.type="button",_.className="btn btn-primary",_.textContent="Insert Grid",t.appendChild(_),v.addEventListener("click",()=>{x="grid",v.className="btn btn-sm btn-primary",d.className="btn btn-sm btn-ghost",N.style.display="flex",n.style.display="none",_.textContent="Insert Grid"}),d.addEventListener("click",()=>{x="row",d.className="btn btn-sm btn-primary",v.className="btn btn-sm btn-ghost",n.style.display="flex",N.style.display="none",_.textContent="Insert Row"});const K=E.modal({title:"Insert Grid / Row",size:"sm"});K.element.appendChild(t),K.open(),requestAnimationFrame(()=>C.focus()),_.addEventListener("click",()=>{K.close();const ae=Math.min(Math.max(parseInt(C.value)||2,1),12),X=A.value;let P;if(x==="grid"){let F=`cols="${ae}"`;X!=="4"&&(F+=` gap="${X}"`),p.checked&&(F+=' fullwidth="true"'),P=`[grid ${F}]
96
96
  `;for(let q=0;q<ae;q++){const Y=u[q]?.value?.trim(),O=Y?` span="${Y}"`:"";P+=`[col${O}]
97
97
  Column ${q+1}
98
98
  [/col]
@@ -102,4 +102,4 @@ Column ${q+1}
102
102
  `,C.forEach((F,q)=>{const Y=F.input.value.trim()||`Item ${q+1}`;P+=`[item title="${Y}"]Content here.[/item]
103
103
  `}),P+="[/accordion]";else{const F=z.value;if(!F)return;const q=h.value,Y=b.value;let O=`slug="${F}" display="accordion"`;q&&(O+=` title-field="${q}"`),Y&&(O+=` body-field="${Y}"`);const Z=o.value.trim();Z&&(O+=` limit="${Z}"`),K.checked&&(O+=' multiple="true"'),P=`[collection ${O} /]`}ye(e,P),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onListGroup(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",y="width:100%;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;";function r(n,c){const h=document.createElement("div"),T=document.createElement("label");return T.style.cssText=a,T.textContent=n,h.appendChild(T),h.appendChild(c),h}function m(n){const c=document.createElement("select");return c.style.cssText=y,n.forEach(([h,T])=>{const M=document.createElement("option");M.value=h,M.textContent=T,c.appendChild(M)}),c}const x=m([["","Default"],["flush","Flush (no outer border)"],["numbered","Numbered"],["horizontal","Horizontal"]]);t.appendChild(r("Variant",x));const g=m([["","Default"],["sm","Small"],["lg","Large"]]);t.appendChild(r("Size",g));const v=m([["","Default"],["primary","Primary"],["secondary","Secondary"],["success","Success"],["danger","Danger"],["warning","Warning"],["info","Info"]]);t.appendChild(r("Item Colour",v));const d=document.createElement("label");d.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const C=document.createElement("input");C.type="checkbox",d.appendChild(C),d.appendChild(document.createTextNode("Actionable items (hover highlight)")),t.appendChild(d);const A=document.createElement("div");A.style.cssText=a+"margin-bottom:.35rem;",A.textContent="Items",t.appendChild(A);const N=document.createElement("div");N.style.cssText="display:flex;flex-direction:column;gap:.4rem;",t.appendChild(N);const f=[];function p(){f.forEach(n=>{n.removeBtn.disabled=f.length<=1,n.removeBtn.style.opacity=f.length<=1?"0.3":"1"})}function k(n){const c=document.createElement("div");c.style.cssText="display:flex;gap:.4rem;align-items:center;";const h=document.createElement("input");h.type="text",h.placeholder="Item text",h.value=n||"",h.style.cssText=y+"flex:1;";const T=document.createElement("button");T.type="button",T.textContent="\u2715",T.style.cssText="padding:.3rem .5rem;background:transparent;border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text-muted,#aaa);cursor:pointer;font-size:.85em;flex-shrink:0;";const M={row:c,input:h,removeBtn:T};f.push(M),c.appendChild(h),c.appendChild(T),N.appendChild(c),T.addEventListener("click",()=>{if(f.length<=1)return;const b=f.indexOf(M);f.splice(b,1),N.removeChild(c),p()}),p()}k("Item 1"),k("Item 2"),k("Item 3");const L=document.createElement("button");L.type="button",L.textContent="+ Add Item",L.style.cssText="padding:.35rem .75rem;background:transparent;border:1px dashed var(--dm-border,#555);border-radius:4px;color:var(--dm-text-muted,#aaa);cursor:pointer;font-size:.85em;align-self:flex-start;",L.addEventListener("click",()=>{f.length>=20||(k(""),f[f.length-1].input.focus())}),t.appendChild(L);const u=document.createElement("button");u.type="button",u.className="btn btn-primary",u.textContent="Insert List Group",t.appendChild(u);const z=E.modal({title:"Insert List Group",size:"sm"});z.element.appendChild(t),z.open(),requestAnimationFrame(()=>f[0].input.focus()),u.addEventListener("click",()=>{z.close();let n="";x.value&&(n+=` variant="${x.value}"`),g.value&&(n+=` size="${g.value}"`),v.value&&(n+=` itemvariant="${v.value}"`),C.checked&&(n+=' action="true"');let c=`[listgroup${n}]
104
104
  `;f.forEach(h=>{const T=h.input.value.trim();T&&(c+=`[item]${T}[/item]
105
- `)}),c+="[/listgroup]",ye(e,c),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onCard(e=>{Ke.open(e,{onMediaBrowse:()=>j.media.list().catch(()=>[])})}),H.onHelp(()=>{nt()}),l.find(".editor-view-btn").on("click",function(){const e=$(this).data("mode");e&&(l.find(".editor-view-btn").removeClass("active"),$(this).addClass("active"),l.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${e}`),Qe("viewMode",e))}),l.find("#fullscreen-btn").on("click",function(){l.find(".editor-card").toggleClass("editor-fullscreen"),Qe("fullscreen",l.find(".editor-card").hasClass("editor-fullscreen"))}),Fe=!1,l.find("#quick-switch").prop("disabled",!1),Oe&&window.removeEventListener("beforeunload",Oe),Oe=e=>{Fe&&e.preventDefault()},window.addEventListener("beforeunload",Oe),Ye||(Ye=!0,R.use((e,t,a)=>{const y=window.location.hash.startsWith("#/pages/edit")||window.location.hash==="#/pages/new";if(!Fe||!y)return a();E.confirm("You have unsaved changes. Leave this page?").then(r=>{r&&(Fe=!1,a())})})),me.on("input",()=>{ee||(Fe=!0,l.find("#quick-switch").prop("disabled",!0),V())});const Be=l.find("#editor-meta-tabs").get(0);Be&&(Be.addEventListener("input",()=>{Fe=!0,l.find("#quick-switch").prop("disabled",!0)}),Be.addEventListener("change",e=>{e.target.id!=="quick-switch"&&(Fe=!0,l.find("#quick-switch").prop("disabled",!0))})),V(),l.find("#save-btn").on("click",async()=>{const e=l.find("#page-url-path").val().trim();if(!e){E.toast("URL path is required.",{type:"warning"});return}const t=l.find("#field-dconfig").val().trim();let a=null;if(t)try{a=JSON.parse(t)}catch{E.toast("DConfig JSON is invalid. Please check the format before saving.",{type:"warning"});return}const y={title:l.find("#field-title").val().trim()||"Untitled",description:l.find("#field-description").val().trim(),layout:l.find("#field-layout").val(),status:l.find("#field-status").val(),sortOrder:parseInt(l.find("#field-sort-order").val(),10)||99,showInNav:l.find("#field-show-in-nav").is(":checked"),sidebar:l.find("#field-sidebar").is(":checked"),...l.find("#field-show-breadcrumbs").is(":checked")?{}:{breadcrumbs:!1},...l.find("#field-bundled").is(":checked")?{bundled:!0}:{},tags:Ee?Ee.getValue():[],category:l.find("#field-category").val().trim()||null,visibility:l.find("#field-visibility").val()||"public",seo:{title:l.find("#field-seo-title").val().trim(),description:l.find("#field-seo-desc").val().trim()},dconfig:a,...l.find("#field-theme").val()?{theme:l.find("#field-theme").val()}:{}};try{l.find("#save-btn").prop("disabled",!0).text("Saving\u2026");const r=te.getUnfoldedContent();if(G){const m={frontmatter:y,body:r};e!==de&&(m.newUrlPath=e),await j.pages.update(de,m),ne&&await j.settings.saveCustomCss(l.find("#css-editor").val()),E.toast(ne?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),Fe=!1,l.find("#quick-switch").prop("disabled",!1),e!==de&&R.navigate(`/pages/edit${e}`)}else await j.pages.create({urlPath:e,frontmatter:y,body:r}),ne&&await j.settings.saveCustomCss(l.find("#css-editor").val()),E.toast(ne?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),Fe=!1,R.navigate("/pages")}catch(r){E.toast(`Save failed: ${r.message||"Unknown error"}`,{type:"error"})}finally{l.find("#save-btn").prop("disabled",!1).text("Save")}}),l.find("#cancel-btn").on("click",()=>R.navigate("/pages")),Domma.icons.scan()}};
105
+ `)}),c+="[/listgroup]",ye(e,c),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),H.onCard(e=>{Ke.open(e,{onMediaBrowse:()=>j.media.list().catch(()=>[])})}),H.onHelp(()=>{at()}),l.find(".editor-view-btn").on("click",function(){const e=$(this).data("mode");e&&(l.find(".editor-view-btn").removeClass("active"),$(this).addClass("active"),l.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${e}`),Qe("viewMode",e))}),l.find("#fullscreen-btn").on("click",function(){l.find(".editor-card").toggleClass("editor-fullscreen"),Qe("fullscreen",l.find(".editor-card").hasClass("editor-fullscreen"))}),Fe=!1,l.find("#quick-switch").prop("disabled",!1),Oe&&window.removeEventListener("beforeunload",Oe),Oe=e=>{Fe&&e.preventDefault()},window.addEventListener("beforeunload",Oe),Ye||(Ye=!0,R.use((e,t,a)=>{const y=window.location.hash.startsWith("#/pages/edit")||window.location.hash==="#/pages/new";if(!Fe||!y)return a();E.confirm("You have unsaved changes. Leave this page?").then(r=>{r&&(Fe=!1,a())})})),me.on("input",()=>{ee||(Fe=!0,l.find("#quick-switch").prop("disabled",!0),V())});const Be=l.find("#editor-meta-tabs").get(0);Be&&(Be.addEventListener("input",()=>{Fe=!0,l.find("#quick-switch").prop("disabled",!0)}),Be.addEventListener("change",e=>{e.target.id!=="quick-switch"&&(Fe=!0,l.find("#quick-switch").prop("disabled",!0))})),V(),l.find("#save-btn").on("click",async()=>{const e=l.find("#page-url-path").val().trim();if(!e){E.toast("URL path is required.",{type:"warning"});return}const t=l.find("#field-dconfig").val().trim();let a=null;if(t)try{a=JSON.parse(t)}catch{E.toast("DConfig JSON is invalid. Please check the format before saving.",{type:"warning"});return}const y={title:l.find("#field-title").val().trim()||"Untitled",description:l.find("#field-description").val().trim(),layout:l.find("#field-layout").val(),status:l.find("#field-status").val(),sortOrder:parseInt(l.find("#field-sort-order").val(),10)||99,showInNav:l.find("#field-show-in-nav").is(":checked"),sidebar:l.find("#field-sidebar").is(":checked"),...l.find("#field-show-breadcrumbs").is(":checked")?{}:{breadcrumbs:!1},...l.find("#field-bundled").is(":checked")?{bundled:!0}:{},tags:Ee?Ee.getValue():[],category:l.find("#field-category").val().trim()||null,visibility:l.find("#field-visibility").val()||"public",seo:{title:l.find("#field-seo-title").val().trim(),description:l.find("#field-seo-desc").val().trim()},dconfig:a,...l.find("#field-theme").val()?{theme:l.find("#field-theme").val()}:{}};try{l.find("#save-btn").prop("disabled",!0).text("Saving\u2026");const r=te.getUnfoldedContent();if(G){const m={frontmatter:y,body:r};e!==de&&(m.newUrlPath=e),await j.pages.update(de,m),ne&&await j.settings.saveCustomCss(l.find("#css-editor").val()),E.toast(ne?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),Fe=!1,l.find("#quick-switch").prop("disabled",!1),e!==de&&R.navigate(`/pages/edit${e}`)}else await j.pages.create({urlPath:e,frontmatter:y,body:r}),ne&&await j.settings.saveCustomCss(l.find("#css-editor").val()),E.toast(ne?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),Fe=!1,R.navigate("/pages")}catch(r){E.toast(`Save failed: ${r.message||"Unknown error"}`,{type:"error"})}finally{l.find("#save-btn").prop("disabled",!1).text("Save")}}),l.find("#cancel-btn").on("click",()=>R.navigate("/pages")),Domma.icons.scan()}};
@@ -1,5 +1,8 @@
1
- import{api as p}from"../api.js";export const pagesView={templateUrl:"/admin/js/templates/pages.html",async onMount(a){const c=E.loader(a.get(0),{type:"dots"});let i=await p.pages.list().catch(()=>[]);c.destroy();const l=s=>{T.create("#pages-table",{data:s,columns:[{key:"title",title:"Title",render:(t,e)=>{const n=e.bundled?'<span class="badge badge-outline" style="font-size:0.65rem;padding:1px 6px;color:var(--dm-info,#2563eb);border-color:var(--dm-info,#2563eb);margin-left:.35rem;">Bundled</span>':"",o=e.plugin?`<span class="badge badge-outline" style="font-size:0.65rem;padding:1px 6px;color:var(--dm-warning,#d97706);border-color:var(--dm-warning,#d97706);margin-left:.35rem;" title="Managed by the ${e.plugin} plugin">${e.plugin}</span>`:"";return`<a href="#/pages/edit${e.urlPath}" style="font-weight:600;">${t}</a>${n}${o}`}},{key:"urlPath",title:"URL",render:t=>`<code>${t}</code>`},{key:"layout",title:"Layout"},{key:"status",title:"Status",render:t=>`<span class="badge badge-${t==="published"?"success":"warning"}">${t}</span>`},{key:"tags",title:"Tags",render:t=>Array.isArray(t)&&t.length?t.map(e=>`<span class="badge badge-info badge-pill badge-sm">${e}</span>`).join(" "):"\u2014"},{key:"updatedAt",title:"Updated",render:t=>t?D(t).format("DD MMM YYYY"):"\u2014"},{key:"actions",title:"Actions",render:(t,e)=>`
1
+ import{api as p}from"../api.js";export const pagesView={templateUrl:"/admin/js/templates/pages.html",async onMount(n){const c=E.loader(n.get(0),{type:"dots"});let o=await p.pages.list().catch(()=>[]);c.destroy();const r=s=>{T.create("#pages-table",{data:s,columns:[{key:"title",title:"Title",render:(t,e)=>{const a=e.bundled?'<span class="badge badge-outline" style="font-size:0.65rem;padding:1px 6px;color:var(--dm-info,#2563eb);border-color:var(--dm-info,#2563eb);margin-left:.35rem;">Bundled</span>':"",i=e.plugin?`<span class="badge badge-outline" style="font-size:0.65rem;padding:1px 6px;color:var(--dm-warning,#d97706);border-color:var(--dm-warning,#d97706);margin-left:.35rem;" title="Managed by the ${e.plugin} plugin">${e.plugin}</span>`:"";return`<a href="#/pages/edit${e.urlPath}" style="font-weight:600;">${t}</a>${a}${i}`}},{key:"urlPath",title:"URL",render:t=>`<code>${t}</code>`},{key:"layout",title:"Layout"},{key:"status",title:"Status",render:t=>`<span class="badge badge-${t==="published"?"success":"warning"}">${t}</span>`},{key:"tags",title:"Tags",render:t=>Array.isArray(t)&&t.length?t.map(e=>`<span class="badge badge-info badge-pill badge-sm">${e}</span>`).join(" "):"\u2014"},{key:"versionCount",title:"Revisions",render:t=>Number.isFinite(t)&&t>0?`<span class="badge badge-secondary badge-pill badge-sm">${t}</span>`:'<span style="color:var(--dm-text-muted);">0</span>'},{key:"updatedAt",title:"Updated",render:t=>t?D(t).format("DD MMM YYYY"):"\u2014"},{key:"actions",title:"Actions",render:(t,e)=>`
2
2
  <a href="#/pages/edit${e.urlPath}" class="btn btn-sm btn-primary">Edit</a>
3
3
  <a href="${e.urlPath}" target="_blank" class="btn btn-sm btn-ghost" data-tooltip="View"><span data-icon="external-link"></span></a>
4
+ <button class="btn btn-sm btn-ghost btn-prune" data-path="${e.urlPath}" data-count="${e.versionCount||0}" data-tooltip="Prune revisions"${(e.versionCount||0)===0?" disabled":""}><span data-icon="archive"></span></button>
4
5
  <button class="btn btn-sm btn-danger btn-delete" data-path="${e.urlPath}" data-plugin="${e.plugin||""}">Delete</button>
5
- `}],emptyMessage:'No pages found. <a href="#/pages/new">Create one</a>.'}),Domma.icons.scan(),document.querySelectorAll("#pages-table [data-tooltip]").forEach(t=>{E.tooltip(t,{content:t.getAttribute("data-tooltip"),position:"top"})}),Domma.effects.reveal(".card",{animation:"fade",duration:350})};l(i);const g=s=>{const t=a.find("#pages-tree").empty().get(0);if(!s.length){t.textContent="No pages found.";return}const e=s.map(n=>{const o=n.urlPath.split("/").filter(Boolean),r=o.length>1?"/"+o.slice(0,-1).join("/"):null,u=r&&s.some(b=>b.urlPath===r);return{id:n.urlPath,parent_id:u?r:null,name:n.title||n.urlPath,icon:n.status==="published"?"check-circle":"file-text"}});E.treeView(t,{data:e,idKey:"id",parentKey:"parent_id",labelKey:"name",iconKey:"icon",expandedByDefault:!0,onSelect:n=>{R.navigate(`/pages/edit${n}`)}}),Domma.icons.scan(t)};a.find("#view-table-btn").on("click",function(){a.find("#pages-table").show(),a.find("#pages-tree").hide(),$(this).addClass("btn-primary").removeClass("btn-ghost"),a.find("#view-tree-btn").addClass("btn-ghost").removeClass("btn-primary")}),a.find("#view-tree-btn").on("click",function(){a.find("#pages-table").hide(),a.find("#pages-tree").show(),$(this).addClass("btn-primary").removeClass("btn-ghost"),a.find("#view-table-btn").addClass("btn-ghost").removeClass("btn-primary"),g(i)}),a.find("#view-table-btn, #view-tree-btn").each(function(){E.tooltip(this,{content:this.getAttribute("data-tooltip"),position:"top"})});const d=()=>{const s=a.find("#status-filter").val(),t=a.find("#pages-search").val().toLowerCase().trim(),e=i.filter(n=>!(s&&n.status!==s||t&&!`${n.title} ${n.urlPath} ${(n.tags||[]).join(" ")}`.toLowerCase().includes(t)));l(e)};a.find("#status-filter").off("change").on("change",d),a.find("#pages-search").get(0).addEventListener("input",d),a.off("click",".btn-delete").on("click",".btn-delete",async function(){const s=$(this).data("path"),t=$(this).data("plugin"),e=t?`This page is managed by the <strong>${t}</strong> plugin. Deleting it may cause the plugin to malfunction. Continue?`:`Delete page at <strong>${s}</strong>? This cannot be undone.`;if(await E.confirm(e))try{await p.pages.delete(s),E.toast("Page deleted.",{type:"success"}),i=i.filter(n=>n.urlPath!==s),l(i)}catch{E.toast("Failed to delete page.",{type:"error"})}})}};
6
+ `}],emptyMessage:'No pages found. <a href="#/pages/new">Create one</a>.'}),Domma.icons.scan(),document.querySelectorAll("#pages-table [data-tooltip]").forEach(t=>{E.tooltip(t,{content:t.getAttribute("data-tooltip"),position:"top"})}),Domma.effects.reveal(".card",{animation:"fade",duration:350})};r(o);const g=s=>{const t=n.find("#pages-tree").empty().get(0);if(!s.length){t.textContent="No pages found.";return}const e=s.map(a=>{const i=a.urlPath.split("/").filter(Boolean),l=i.length>1?"/"+i.slice(0,-1).join("/"):null,d=l&&s.some(b=>b.urlPath===l);return{id:a.urlPath,parent_id:d?l:null,name:a.title||a.urlPath,icon:a.status==="published"?"check-circle":"file-text"}});E.treeView(t,{data:e,idKey:"id",parentKey:"parent_id",labelKey:"name",iconKey:"icon",expandedByDefault:!0,onSelect:a=>R.navigate(`/pages/edit${a}`)}),Domma.icons.scan(t)};n.find("#view-table-btn").on("click",function(){n.find("#pages-table").show(),n.find("#pages-tree").hide(),$(this).addClass("btn-primary").removeClass("btn-ghost"),n.find("#view-tree-btn").addClass("btn-ghost").removeClass("btn-primary")}),n.find("#view-tree-btn").on("click",function(){n.find("#pages-table").hide(),n.find("#pages-tree").show(),$(this).addClass("btn-primary").removeClass("btn-ghost"),n.find("#view-table-btn").addClass("btn-ghost").removeClass("btn-primary"),g(o)}),n.find("#view-table-btn, #view-tree-btn").each(function(){E.tooltip(this,{content:this.getAttribute("data-tooltip"),position:"top"})});const u=()=>{const s=n.find("#status-filter").val(),t=n.find("#pages-search").val().toLowerCase().trim(),e=o.filter(a=>!(s&&a.status!==s||t&&!`${a.title} ${a.urlPath} ${(a.tags||[]).join(" ")}`.toLowerCase().includes(t)));r(e)};n.find("#status-filter").off("change").on("change",u),n.find("#pages-search").get(0).addEventListener("input",u),n.off("click",".btn-delete").on("click",".btn-delete",async function(){const s=$(this).data("path"),t=$(this).data("plugin"),e=t?`This page is managed by the <strong>${t}</strong> plugin. Deleting it may cause the plugin to malfunction. Continue?`:`Delete page at <strong>${s}</strong>? This cannot be undone.`;if(await E.confirm(e))try{await p.pages.delete(s),E.toast("Page deleted.",{type:"success"}),o=o.filter(a=>a.urlPath!==s),r(o)}catch{E.toast("Failed to delete page.",{type:"error"})}}),n.off("click",".btn-prune").on("click",".btn-prune",async function(){const s=$(this).data("path"),t=Number($(this).data("count"))||0,e=window.prompt(`This page has ${t} revision${t===1?"":"s"}.
7
+
8
+ How many of the most recent revisions do you want to keep?`,"5");if(e===null)return;const a=Number.parseInt(e,10);if(!Number.isFinite(a)||a<0){E.toast("Please enter a non-negative number.",{type:"error"});return}try{const i=await p.versions.prune(s,a);E.toast(`Pruned ${i.deleted} revision${i.deleted===1?"":"s"}; kept ${i.kept}.`,{type:"success"});const l=o.find(d=>d.urlPath===s);l&&(l.versionCount=i.kept),r(o)}catch(i){E.toast(i.message||"Failed to prune revisions.",{type:"error"})}})}};
@@ -15,6 +15,11 @@
15
15
  "url": "/about",
16
16
  "icon": "info"
17
17
  },
18
+ {
19
+ "text": "Resources",
20
+ "url": "/resources",
21
+ "icon": "book-open"
22
+ },
18
23
  {
19
24
  "text": "Contact",
20
25
  "url": "/contact",
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "todo": {
3
- "enabled": true,
3
+ "enabled": false,
4
4
  "bundled": true,
5
5
  "settings": {}
6
6
  },
7
7
  "notes": {
8
- "enabled": true,
8
+ "enabled": false,
9
9
  "bundled": true,
10
10
  "settings": {}
11
11
  },
12
12
  "contacts": {
13
- "enabled": true,
13
+ "enabled": false,
14
14
  "bundled": true,
15
15
  "settings": {}
16
16
  },
17
17
  "site-search": {
18
- "enabled": true,
18
+ "enabled": false,
19
19
  "bundled": true,
20
20
  "settings": {}
21
21
  },
22
22
  "blog": {
23
- "enabled": true,
23
+ "enabled": false,
24
24
  "bundled": false,
25
25
  "settings": {}
26
26
  }
@@ -1,17 +1,17 @@
1
1
  {
2
- "default": {
3
- "key": "default",
4
- "label": "Default",
5
- "description": "Standard page with navbar and footer.",
6
- "builtin": true,
7
- "navbar": true,
8
- "footer": true,
9
- "sidebar": false,
10
- "width": "normal",
11
- "bgColor": "",
12
- "bgImage": "",
13
- "class": ""
14
- },
2
+ "default": {
3
+ "key": "default",
4
+ "label": "Default",
5
+ "description": "Standard page with navbar and footer.",
6
+ "builtin": true,
7
+ "navbar": true,
8
+ "footer": true,
9
+ "sidebar": false,
10
+ "width": "normal",
11
+ "bgColor": "",
12
+ "bgImage": "",
13
+ "class": ""
14
+ },
15
15
  "landing": {
16
16
  "key": "landing",
17
17
  "label": "Landing Page",
@@ -37,31 +37,83 @@
37
37
  "bgColor": "",
38
38
  "bgImage": "",
39
39
  "class": ""
40
- },
41
- "with-sidebar": {
42
- "key": "with-sidebar",
43
- "label": "With Sidebar",
44
- "description": "Page with navbar, sidebar, and footer.",
45
- "builtin": false,
46
- "navbar": true,
47
- "footer": true,
48
- "sidebar": true,
49
- "width": "normal",
50
- "bgColor": "",
51
- "bgImage": "",
52
- "class": ""
53
- },
54
- "minimal": {
55
- "key": "minimal",
56
- "label": "Minimal",
57
- "description": "Clean page with no navbar or footer.",
58
- "builtin": false,
59
- "navbar": false,
60
- "footer": false,
61
- "sidebar": false,
62
- "width": "normal",
63
- "bgColor": "",
64
- "bgImage": "",
65
- "class": ""
66
- }
40
+ },
41
+ "with-sidebar": {
42
+ "key": "with-sidebar",
43
+ "label": "With Sidebar",
44
+ "description": "Page with navbar, sidebar, and footer.",
45
+ "builtin": false,
46
+ "navbar": true,
47
+ "footer": true,
48
+ "sidebar": true,
49
+ "width": "normal",
50
+ "bgColor": "",
51
+ "bgImage": "",
52
+ "class": ""
53
+ },
54
+ "minimal": {
55
+ "key": "minimal",
56
+ "label": "Minimal",
57
+ "description": "Clean page with no navbar or footer.",
58
+ "builtin": false,
59
+ "navbar": false,
60
+ "footer": false,
61
+ "sidebar": false,
62
+ "width": "normal",
63
+ "bgColor": "",
64
+ "bgImage": "",
65
+ "class": ""
66
+ },
67
+ "article": {
68
+ "key": "article",
69
+ "label": "Article",
70
+ "description": "Narrow reading column for long-form prose and blog posts.",
71
+ "builtin": true,
72
+ "navbar": true,
73
+ "footer": true,
74
+ "sidebar": false,
75
+ "width": "narrow",
76
+ "bgColor": "",
77
+ "bgImage": "",
78
+ "class": ""
79
+ },
80
+ "product": {
81
+ "key": "product",
82
+ "label": "Product Page",
83
+ "description": "Full-width marketing page that keeps the footer.",
84
+ "builtin": true,
85
+ "navbar": true,
86
+ "footer": true,
87
+ "sidebar": false,
88
+ "width": "full",
89
+ "bgColor": "",
90
+ "bgImage": "",
91
+ "class": ""
92
+ },
93
+ "dashboard": {
94
+ "key": "dashboard",
95
+ "label": "Dashboard",
96
+ "description": "Wide layout for data-heavy or app-like pages; no footer.",
97
+ "builtin": true,
98
+ "navbar": true,
99
+ "footer": false,
100
+ "sidebar": false,
101
+ "width": "wide",
102
+ "bgColor": "",
103
+ "bgImage": "",
104
+ "class": ""
105
+ },
106
+ "wide": {
107
+ "key": "wide",
108
+ "label": "Wide",
109
+ "description": "Standard page with navbar and footer, using a wide content column (~75% of viewport).",
110
+ "builtin": true,
111
+ "navbar": true,
112
+ "footer": true,
113
+ "sidebar": false,
114
+ "width": "wide",
115
+ "bgColor": "",
116
+ "bgImage": "",
117
+ "class": ""
118
+ }
67
119
  }