domma-cms 0.14.0 → 0.14.2
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.
|
@@ -47,7 +47,7 @@ Column 1
|
|
|
47
47
|
Column 2
|
|
48
48
|
[/col]
|
|
49
49
|
[/grid]
|
|
50
|
-
`;e.value=e.value.substring(0,s)+r+e.value.substring(s),e.selectionStart=e.selectionEnd=s+r.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()}else if(t==="badge"){const s=e.selectionStart,r=e.selectionEnd,d=`[badge variant="primary"]${e.value.substring(s,r)||"New"}[/badge]`;e.value=e.value.substring(0,s)+d+e.value.substring(r),e.selectionStart=s+16,e.selectionEnd=s+23,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()}else if(t==="timeline"){const s=e.selectionStart,r=`[timeline layout="vertical"]
|
|
50
|
+
`;e.value=e.value.substring(0,s)+r+e.value.substring(s),e.selectionStart=e.selectionEnd=s+r.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()}else if(t==="badge"){const s=e.selectionStart,r=e.selectionEnd,d=`[badge variant="primary"]${e.value.substring(s,r)||"New"}[/badge]`;e.value=e.value.substring(0,s)+d+e.value.substring(r),e.selectionStart=s+16,e.selectionEnd=s+23,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()}else if(t==="timeline")if(o.timeline)o.timeline(e);else{const s=e.selectionStart,r=`[timeline layout="vertical"]
|
|
51
51
|
[event title="First Event" date="${new Date().toISOString().slice(0,10)}" status="completed"]
|
|
52
52
|
Describe this event.
|
|
53
53
|
[/event]
|
|
@@ -70,6 +70,6 @@ Describe this event.
|
|
|
70
70
|
[item title="Item 1"]Content here.[/item]
|
|
71
71
|
[item title="Item 2"]Content here.[/item]
|
|
72
72
|
[/accordion]
|
|
73
|
-
`;e.value=e.value.substring(0,s)+r+e.value.substring(s),e.selectionStart=e.selectionEnd=s+r.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()}else if(t==="text"){let n=function(f,m){const g=document.createElement("div"),N=document.createElement("label");return N.style.cssText=d,N.textContent=f,g.appendChild(N),g.appendChild(m),g},c=function(f){const m=document.createElement("select");return m.style.cssText=h,[["","\u2014 default \u2014"],...f].forEach(([g,N])=>{const O=document.createElement("option");O.value=g,O.textContent=N,m.appendChild(O)}),m},u=function(f,m){const g=document.createElement("input");return g.type="text",g.placeholder=f||"",g.value=m||"",g.style.cssText=h,g},k=function(f){const m=document.createElement("label");m.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;";const g=document.createElement("input");g.type="checkbox";const N=document.createElement("span");return N.style.cssText="font-size:.85em;color:var(--dm-text,#eee);",N.textContent=f,m.appendChild(g),m.appendChild(N),{wrap:m,cb:g}},y=function(f,m){const g=document.createElement("div");return g.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:.5rem;",g.appendChild(f),g.appendChild(m),g},C=function(f){const m=document.createElement("div");return m.style.cssText="border-top:1px solid var(--dm-border,#333);padding-top:.5rem;margin-top:.1rem;font-size:.65rem;font-weight:700;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.08em;",m.textContent=f,m},F=function(){const f=[];M.value&&f.push(`font-size:${ee[M.value]||M.value}`);const m=parseFloat(v.value);!isNaN(m)&&m>0&&f.push(`font-size:${m}pt`),L.checked?f.push("font-weight:700"):b.value&&f.push(`font-weight:${te[b.value]||b.value}`),T.checked&&f.push("font-style:italic");const g=B.value.trim();g&&f.push(`color:${Y[g]||g}`),A.value&&f.push(`font-family:${oe[A.value]}`),R.value&&f.push(`text-transform:${ie[R.value]}`),P.value&&f.push(`text-decoration:${re[P.value]}`),W.value&&f.push(`letter-spacing:${ne[W.value]}`),H.value&&(f.push("display:block"),f.push(`text-align:${H.value}`)),V.value.trim()&&f.push(V.value.trim()),q.style.cssText=f.join(";"),q.textContent=S.value||"Preview text"};const s=e.selectionStart,r=e.selectionEnd,a=e.value.substring(s,r)||"",d="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",h="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");x.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.6rem;overflow-y:auto;max-height:75vh;";const S=u("Text to style\u2026",a);x.appendChild(n("Content",S)),x.appendChild(C("Typography"));const M=c([["xs","xs \u2014 0.75rem"],["sm","sm \u2014 0.875rem"],["base","base \u2014 1rem"],["lg","lg \u2014 1.125rem"],["xl","xl \u2014 1.25rem"],["2xl","2xl \u2014 1.5rem"],["3xl","3xl \u2014 1.875rem"],["4xl","4xl \u2014 2.25rem"]]),v=u("pt value (overrides Size)");x.appendChild(y(n("Size",M),n("Point Size (pt)",v)));const b=c([["thin","Thin (100)"],["light","Light (300)"],["normal","Normal (400)"],["medium","Medium (500)"],["semibold","Semibold (600)"],["bold","Bold (700)"],["extrabold","Extrabold (800)"],["black","Black (900)"]]),{wrap:w,cb:L}=k("Bold (overrides Weight)"),{wrap:z,cb:T}=k("Italic"),j=document.createElement("div");j.style.cssText="display:flex;flex-direction:column;gap:.4rem;justify-content:flex-end;",j.appendChild(w),j.appendChild(z),x.appendChild(y(n("Weight",b),j)),x.appendChild(C("Appearance"));const B=u("e.g. primary, #ff0000"),A=c([["Georgia","Georgia (serif)"],["Arial","Arial (sans-serif)"],["Verdana","Verdana (sans-serif)"],["Courier New","Courier New (mono)"],["Times New Roman","Times New Roman (serif)"],["Trebuchet MS","Trebuchet MS"]]);x.appendChild(y(n("Colour",B),n("Font",A))),x.appendChild(C("Formatting"));const R=c([["upper","Uppercase"],["lower","Lowercase"],["capitalize","Capitalise"],["none","None"]]),P=c([["underline","Underline"],["line-through","Line-through"],["none","None"]]);x.appendChild(y(n("Transform",R),n("Decoration",P)));const W=c([["tight","Tight"],["normal","Normal"],["wide","Wide"],["wider","Wider"]]),H=c([["left","Left"],["center","Centre"],["right","Right"],["justify","Justify"]]);x.appendChild(y(n("Spacing",W),n("Align",H))),x.appendChild(C("Advanced"));const V=u("e.g. margin-top:1rem;display:block");x.appendChild(n("Style",V));const _=u("CSS class(es)"),G=u("ID");x.appendChild(y(n("Class",_),n("ID",G)));const K=document.createElement("div");K.style.cssText="padding:.75rem;background:var(--dm-surface-subtle,#111);border-radius:4px;min-height:2.5rem;display:flex;align-items:center;";const q=document.createElement("span");q.textContent=a||"Preview text",K.appendChild(q),x.appendChild(n("Preview",K));const Y={primary:"var(--dm-color-primary)",secondary:"var(--dm-color-secondary)",muted:"var(--dm-text-muted)",danger:"var(--dm-color-danger)",success:"var(--dm-color-success)",warning:"var(--dm-color-warning)",info:"var(--dm-color-info)"},ee={xs:".75rem",sm:".875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem"},te={thin:"100",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},ne={tight:"-0.05em",normal:"0em",wide:"0.05em",wider:"0.1em"},oe={Georgia:"Georgia,serif",Arial:"Arial,sans-serif",Verdana:"Verdana,sans-serif","Courier New":"'Courier New',monospace","Times New Roman":"'Times New Roman',serif","Trebuchet MS":"'Trebuchet MS',sans-serif"},ie={upper:"uppercase",lower:"lowercase",capitalize:"capitalize",none:"none"},re={underline:"underline","line-through":"line-through",none:"none"};L.addEventListener("change",()=>{b.disabled=L.checked,L.checked&&(b.value=""),F()}),[M,b,A,R,P,W,H].forEach(f=>{f.addEventListener("change",F)}),[B,S,V,v].forEach(f=>{f.addEventListener("input",F)}),T.addEventListener("change",F);const D=document.createElement("button");D.type="button",D.className="btn btn-primary",D.textContent="Insert",x.appendChild(D);const Z=E.
|
|
73
|
+
`;e.value=e.value.substring(0,s)+r+e.value.substring(s),e.selectionStart=e.selectionEnd=s+r.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()}else if(t==="text"){let n=function(f,m){const g=document.createElement("div"),N=document.createElement("label");return N.style.cssText=d,N.textContent=f,g.appendChild(N),g.appendChild(m),g},c=function(f){const m=document.createElement("select");return m.style.cssText=h,[["","\u2014 default \u2014"],...f].forEach(([g,N])=>{const O=document.createElement("option");O.value=g,O.textContent=N,m.appendChild(O)}),m},u=function(f,m){const g=document.createElement("input");return g.type="text",g.placeholder=f||"",g.value=m||"",g.style.cssText=h,g},k=function(f){const m=document.createElement("label");m.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;";const g=document.createElement("input");g.type="checkbox";const N=document.createElement("span");return N.style.cssText="font-size:.85em;color:var(--dm-text,#eee);",N.textContent=f,m.appendChild(g),m.appendChild(N),{wrap:m,cb:g}},y=function(f,m){const g=document.createElement("div");return g.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:.5rem;",g.appendChild(f),g.appendChild(m),g},C=function(f){const m=document.createElement("div");return m.style.cssText="border-top:1px solid var(--dm-border,#333);padding-top:.5rem;margin-top:.1rem;font-size:.65rem;font-weight:700;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.08em;",m.textContent=f,m},F=function(){const f=[];M.value&&f.push(`font-size:${ee[M.value]||M.value}`);const m=parseFloat(v.value);!isNaN(m)&&m>0&&f.push(`font-size:${m}pt`),L.checked?f.push("font-weight:700"):b.value&&f.push(`font-weight:${te[b.value]||b.value}`),T.checked&&f.push("font-style:italic");const g=B.value.trim();g&&f.push(`color:${Y[g]||g}`),A.value&&f.push(`font-family:${oe[A.value]}`),R.value&&f.push(`text-transform:${ie[R.value]}`),P.value&&f.push(`text-decoration:${re[P.value]}`),W.value&&f.push(`letter-spacing:${ne[W.value]}`),H.value&&(f.push("display:block"),f.push(`text-align:${H.value}`)),V.value.trim()&&f.push(V.value.trim()),q.style.cssText=f.join(";"),q.textContent=S.value||"Preview text"};const s=e.selectionStart,r=e.selectionEnd,a=e.value.substring(s,r)||"",d="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",h="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");x.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.6rem;overflow-y:auto;max-height:75vh;";const S=u("Text to style\u2026",a);x.appendChild(n("Content",S)),x.appendChild(C("Typography"));const M=c([["xs","xs \u2014 0.75rem"],["sm","sm \u2014 0.875rem"],["base","base \u2014 1rem"],["lg","lg \u2014 1.125rem"],["xl","xl \u2014 1.25rem"],["2xl","2xl \u2014 1.5rem"],["3xl","3xl \u2014 1.875rem"],["4xl","4xl \u2014 2.25rem"]]),v=u("pt value (overrides Size)");x.appendChild(y(n("Size",M),n("Point Size (pt)",v)));const b=c([["thin","Thin (100)"],["light","Light (300)"],["normal","Normal (400)"],["medium","Medium (500)"],["semibold","Semibold (600)"],["bold","Bold (700)"],["extrabold","Extrabold (800)"],["black","Black (900)"]]),{wrap:w,cb:L}=k("Bold (overrides Weight)"),{wrap:z,cb:T}=k("Italic"),j=document.createElement("div");j.style.cssText="display:flex;flex-direction:column;gap:.4rem;justify-content:flex-end;",j.appendChild(w),j.appendChild(z),x.appendChild(y(n("Weight",b),j)),x.appendChild(C("Appearance"));const B=u("e.g. primary, #ff0000"),A=c([["Georgia","Georgia (serif)"],["Arial","Arial (sans-serif)"],["Verdana","Verdana (sans-serif)"],["Courier New","Courier New (mono)"],["Times New Roman","Times New Roman (serif)"],["Trebuchet MS","Trebuchet MS"]]);x.appendChild(y(n("Colour",B),n("Font",A))),x.appendChild(C("Formatting"));const R=c([["upper","Uppercase"],["lower","Lowercase"],["capitalize","Capitalise"],["none","None"]]),P=c([["underline","Underline"],["line-through","Line-through"],["none","None"]]);x.appendChild(y(n("Transform",R),n("Decoration",P)));const W=c([["tight","Tight"],["normal","Normal"],["wide","Wide"],["wider","Wider"]]),H=c([["left","Left"],["center","Centre"],["right","Right"],["justify","Justify"]]);x.appendChild(y(n("Spacing",W),n("Align",H))),x.appendChild(C("Advanced"));const V=u("e.g. margin-top:1rem;display:block");x.appendChild(n("Style",V));const _=u("CSS class(es)"),G=u("ID");x.appendChild(y(n("Class",_),n("ID",G)));const K=document.createElement("div");K.style.cssText="padding:.75rem;background:var(--dm-surface-subtle,#111);border-radius:4px;min-height:2.5rem;display:flex;align-items:center;";const q=document.createElement("span");q.textContent=a||"Preview text",K.appendChild(q),x.appendChild(n("Preview",K));const Y={primary:"var(--dm-color-primary)",secondary:"var(--dm-color-secondary)",muted:"var(--dm-text-muted)",danger:"var(--dm-color-danger)",success:"var(--dm-color-success)",warning:"var(--dm-color-warning)",info:"var(--dm-color-info)"},ee={xs:".75rem",sm:".875rem",base:"1rem",lg:"1.125rem",xl:"1.25rem","2xl":"1.5rem","3xl":"1.875rem","4xl":"2.25rem"},te={thin:"100",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},ne={tight:"-0.05em",normal:"0em",wide:"0.05em",wider:"0.1em"},oe={Georgia:"Georgia,serif",Arial:"Arial,sans-serif",Verdana:"Verdana,sans-serif","Courier New":"'Courier New',monospace","Times New Roman":"'Times New Roman',serif","Trebuchet MS":"'Trebuchet MS',sans-serif"},ie={upper:"uppercase",lower:"lowercase",capitalize:"capitalize",none:"none"},re={underline:"underline","line-through":"line-through",none:"none"};L.addEventListener("change",()=>{b.disabled=L.checked,L.checked&&(b.value=""),F()}),[M,b,A,R,P,W,H].forEach(f=>{f.addEventListener("change",F)}),[B,S,V,v].forEach(f=>{f.addEventListener("input",F)}),T.addEventListener("change",F);const D=document.createElement("button");D.type="button",D.className="btn btn-primary",D.textContent="Insert",x.appendChild(D);const Z=E.slideover({title:"Style Text",size:"md",position:"right"});Z.element.appendChild(x),Z.open(),D.addEventListener("click",()=>{const f=S.value;if(!f.trim())return;const m=[];M.value&&m.push(`size="${M.value}"`);const g=parseFloat(v.value);!isNaN(g)&&g>0&&m.push(`point-size="${g}"`),L.checked?m.push("bold"):b.value&&m.push(`weight="${b.value}"`),T.checked&&m.push("italic"),B.value.trim()&&m.push(`color="${B.value.trim()}"`),A.value&&m.push(`font="${A.value}"`),R.value&&m.push(`transform="${R.value}"`),P.value&&m.push(`decoration="${P.value}"`),W.value&&m.push(`spacing="${W.value}"`),H.value&&m.push(`align="${H.value}"`),V.value.trim()&&m.push(`style="${V.value.trim().replace(/"/g,""")}"`),_.value.trim()&&m.push(`class="${_.value.trim()}"`),G.value.trim()&&m.push(`id="${G.value.trim()}"`);const O=`[text${m.length?" "+m.join(" "):""}]${f}[/text]`;Z.close(),insertAtCursor(e,O),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}else t==="help"&&o.help&&o.help(e)}const Q=[{icon:"bold",title:"Bold (Ctrl+B)",action:t=>wrapSelection(t,"**","**")},{icon:"italic",title:"Italic (Ctrl+I)",action:t=>wrapSelection(t,"_","_")},{icon:"strikethrough",title:"Strikethrough",action:t=>wrapSelection(t,"~~","~~")},"|",{type:"dropdown",icon:"heading-1",title:"Headings",items:[{label:"Heading 1",icon:"heading-1",action:t=>insertLine(t,"# ")},{label:"Heading 2",icon:"heading-2",action:t=>insertLine(t,"## ")},{label:"Heading 3",icon:"heading-3",action:t=>insertLine(t,"### ")}]},"|",{icon:"list-bullet",title:"Bullet list",action:t=>insertLine(t,"- ")},{icon:"list-numbered",title:"Numbered list",action:t=>insertLine(t,"1. ")},"|",{type:"dropdown",icon:"quote",title:"Paragraph",items:[{label:"Blockquote",icon:"quote",action:t=>insertLine(t,"> ")},{label:"Horizontal rule",icon:"minus-circle",action:t=>insertAtCursor(t,`
|
|
74
74
|
---
|
|
75
|
-
`)}]},"|",{type:"dropdown",icon:"code-inline",title:"Code",items:[{label:"Inline code",icon:"code-inline",action:t=>wrapSelection(t,"`","`")},{label:"Code block",icon:"code-block",action:t=>wrapSelection(t,"\n```\n","\n```\n")}]},"|",{type:"dropdown",icon:"plus-circle",title:"Insert",items:[{label:"Accordion",icon:"accordion-insert",action:"accordion"},{label:"Banner",icon:"banner-insert",action:"banner"},{label:"Badge",icon:"badge",action:"badge"},{label:"Block",icon:"layout",action:"block"},{label:"Button",icon:"btn-insert",action:"button"},{label:"Card",icon:"card",action:"card"},{label:"Colour Picker",icon:"colour-picker",action:"colourpick"},{label:"Collection",icon:"database",action:"collection"},{label:"Component",icon:"component",action:"component"},{label:"CTA Button",icon:"mouse-pointer",action:"cta"},{label:"Form",icon:"file-text",action:"form"},{label:"Grid",icon:"columns",action:"grid"},{label:"Hero",icon:"hero",action:"hero"},{label:"Icon",icon:"icon-pick",action:"iconpick"},{label:"Image",icon:"image-add",action:"image"},{label:"Link",icon:"link-shortcode",action:"linksc"},{label:"List Group",icon:"list",action:"listgroup"},{label:"Scribe",icon:"scribe-insert",action:"scribe"},{label:"Spacer",icon:"spacer-insert",action:"spacerpick"},{label:"Tabs",icon:"layout-list",action:"tabs"},{label:"Text",icon:"text-style",action:"text"},{label:"Timeline",icon:"activity",action:"timeline"},{label:"View",icon:"eye",action:"view"}]},"|",{icon:"sparkles",title:"Effects",action:"effects"},{icon:"help-circle",title:"Editor help",action:"help"}];export function createToolbar(t,e,p={}){se();const i={link:null,image:null,card:null,grid:null,help:null,effects:null,collection:null,view:null,cta:null,form:null,button:null,linksc:null,tabs:null,accordion:null,hero:null,banner:null},l=p.spacerDefault??40,o=t.get(0),s=e.get(0);s.textContent="",Q.forEach((n,c)=>{if(n==="|"){const u=document.createElement("span");u.className="editor-toolbar-sep",s.appendChild(u)}else{const u=document.createElement("button");u.className=n.type==="dropdown"?"editor-toolbar-btn editor-toolbar-dropdown-trigger":"editor-toolbar-btn",u.setAttribute("data-tooltip",n.title),u.setAttribute("data-idx",String(c)),u.type="button";const k=document.createElement("span");if(k.setAttribute("data-icon",n.icon),u.appendChild(k),n.type==="dropdown"){const y=document.createElement("span");y.className="editor-toolbar-caret",y.textContent="\u25BE",u.appendChild(y)}s.appendChild(u)}});const r=document.createElement("div");r.className="editor-toolbar-right",[{mode:"split",icon:"columns",label:"Split view",active:!0},{mode:"write",icon:"file-text",label:"Write only",active:!1},{mode:"preview",icon:"eye",label:"Preview only",active:!1}].forEach(n=>{const c=document.createElement("button");c.className="editor-view-btn"+(n.active?" active":""),c.setAttribute("data-mode",n.mode),c.setAttribute("data-tooltip",n.label),c.type="button";const u=document.createElement("span");u.setAttribute("data-icon",n.icon),c.appendChild(u),r.appendChild(c)});const a=document.createElement("span");a.className="editor-toolbar-sep",r.appendChild(a);const d=document.createElement("button");d.id="fullscreen-btn",d.className="editor-toolbar-btn",d.setAttribute("data-tooltip","Toggle fullscreen"),d.type="button";const h=document.createElement("span");return h.setAttribute("data-icon","expand"),d.appendChild(h),r.appendChild(d),s.appendChild(r),Domma.icons.scan(),s.querySelectorAll("[data-tooltip]").forEach(n=>{E.tooltip(n,{content:n.getAttribute("data-tooltip"),position:"top"})}),e.on("click",".editor-toolbar-btn[data-idx]",function(){const n=parseInt($(this).data("idx"),10),c=Q[n];if(!c||c==="|")return;const u=e.get(0).querySelector(`[data-idx="${n}"]`),k={spacerDefault:l,handlers:i};c.type==="dropdown"?ue(o,u,c.items,k):U(c.action,o,u,k)}),attachEditorKeybindings(o),o.addEventListener("keydown",n=>{const c=n.key.toLowerCase();(n.ctrlKey||n.metaKey)&&(c==="b"?(n.preventDefault(),wrapSelection(o,"**","**")):c==="i"?(n.preventDefault(),wrapSelection(o,"_","_")):c==="k"&&(n.preventDefault(),i.link&&i.link(o)))}),{$toolbar:e,onLink(n){i.link=n},onImage(n){i.image=n},onCard(n){i.card=n},onGrid(n){i.grid=n},onHelp(n){i.help=n},onEffects(n){i.effects=n},onCollection(n){i.collection=n},onBlock(n){i.block=n},onView(n){i.view=n},onCta(n){i.cta=n},onForm(n){i.form=n},onButton(n){i.button=n},onLinkShortcode(n){i.linksc=n},onTabs(n){i.tabs=n},onAccordion(n){i.accordion=n},onHero(n){i.hero=n},onBanner(n){i.banner=n},onListGroup(n){i.listgroup=n},onScribe(n){i.scribe=n}}}async function pe(t){const{api:e}=await import("../api.js");let p;try{p=await e.components.list()}catch(v){E.toast(v.message||"Failed to load components.",{type:"error"});return}if(!p?.length){E.toast("No components yet. Create one in Data \u2192 Components first.",{type:"info"});return}const i=E.slideover({title:"Insert Component",size:"lg",position:"right"}),l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:1rem;padding:.75rem;min-height:100%;";const o=document.createElement("div");o.style.cssText="font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dm-text-muted,#888);",o.textContent="Gallery";const s=document.createElement("div");s.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:.5rem;";const r=document.createElement("div");r.style.cssText="font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dm-text-muted,#888);",r.textContent="Props";const a=document.createElement("div");a.style.cssText="padding:.6rem;border:1px solid var(--dm-border,rgba(255,255,255,.08));border-radius:4px;min-height:40px;",a.textContent="Select a component from the gallery above.";const d=document.createElement("div");d.style.cssText="font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dm-text-muted,#888);",d.textContent="Preview";const h=document.createElement("iframe");h.src="/admin/preview/component-preview.html",h.style.cssText="width:100%;min-height:180px;border:1px solid var(--dm-border,rgba(255,255,255,.08));border-radius:4px;background:#fff;";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:auto;padding-top:.75rem;border-top:1px solid var(--dm-border,rgba(255,255,255,.08));";const c=document.createElement("button");c.className="btn btn-ghost",c.textContent="Cancel";const u=document.createElement("button");u.className="btn btn-primary",u.textContent="Insert",u.disabled=!0,n.appendChild(c),n.appendChild(u),l.appendChild(o),l.appendChild(s),l.appendChild(r),l.appendChild(a),l.appendChild(d),l.appendChild(h),l.appendChild(n),i.element.appendChild(l),i.open();let k=null,y={};function C(){s.replaceChildren();for(const v of p){const b=document.createElement("button");b.type="button",b.className="btn btn-ghost",b.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:.25rem;padding:.6rem;border:1px solid var(--dm-border,rgba(255,255,255,.08));border-radius:4px;text-align:left;";const w=document.createElement("strong");w.style.cssText="font-size:.9rem;",w.textContent=v.name;const L=document.createElement("span");L.style.cssText="font-size:.72rem;color:var(--dm-text-muted,#888);",L.textContent=`${Object.keys(v.props||{}).length} prop(s)`,b.appendChild(w),b.appendChild(L),b.addEventListener("click",()=>x(v)),s.appendChild(b)}}function x(v){k=v,y={};for(const[b,w]of Object.entries(v.props||{}))y[b]=w.default!==void 0?w.default:"";u.disabled=!1,S(),M()}function S(){a.replaceChildren();const v=Object.entries(k.props||{});if(v.length===0){const b=document.createElement("p");b.className="text-muted",b.style.margin="0",b.textContent="This component takes no props.",a.appendChild(b);return}for(const[b,w]of v){const L=document.createElement("div");L.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const z=document.createElement("label");z.style.cssText="font-size:.8rem;min-width:120px;color:var(--dm-text-muted,#aaa);",z.textContent=w.label||b,L.appendChild(z);const T=me(w);he(T,w,y[b]),T.addEventListener("input",()=>{y[b]=X(T,w),h.contentWindow?.postMessage({type:"update",payload:{props:y}},"*")}),T.addEventListener("change",()=>{y[b]=X(T,w),h.contentWindow?.postMessage({type:"update",payload:{props:y}},"*")}),L.appendChild(T),a.appendChild(L)}}async function M(){if(k)try{const v=await fetch(`/api/components/${encodeURIComponent(k.name)}.js`);if(!v.ok)throw new Error(`Failed to load component (${v.status})`);const b=await v.text();h.contentWindow?.postMessage({type:"remount",payload:{compiledJs:b,tagName:`dm-${k.name}`,props:y}},"*")}catch(v){E.toast(v.message||"Failed to load preview.",{type:"error"})}}c.addEventListener("click",()=>i.close()),u.addEventListener("click",()=>{if(!k)return;const v=t.selectionStart,b=t.selectionEnd,w=Object.entries(y).map(([z,T])=>{const j=z.replace(/([A-Z])/g,"-$1").toLowerCase(),B=String(T??"").replace(/"/g,""");return`${j}="${B}"`}).join(" "),L=`[component name="${k.name}"${w?" "+w:""} /]`;t.value=t.value.substring(0,v)+L+t.value.substring(b),t.selectionStart=t.selectionEnd=v+L.length,t.dispatchEvent(new Event("input",{bubbles:!0})),t.focus(),i.close()}),C()}function me(t){let e;return t.type==="number"?(e=document.createElement("input"),e.type="number",e.className="form-input form-input--sm"):t.type==="boolean"?(e=document.createElement("input"),e.type="checkbox",e.className="form-check"):t.type==="array"||t.type==="object"?(e=document.createElement("textarea"),e.rows=2,e.className="form-input form-input--sm",e.style.fontFamily="var(--dm-font-mono, monospace)"):(e=document.createElement("input"),e.type="text",e.className="form-input form-input--sm"),e.style.flex="1",e}function X(t,e){if(e.type==="number")return t.value===""?null:Number(t.value);if(e.type==="boolean")return!!t.checked;if(e.type==="array"||e.type==="object")try{return JSON.parse(t.value||"null")}catch{return null}return t.value}function he(t,e,p){e.type==="boolean"?t.checked=!!p:e.type==="array"||e.type==="object"?t.value=JSON.stringify(p??null):t.value=p??""}
|
|
75
|
+
`)}]},"|",{type:"dropdown",icon:"code-inline",title:"Code",items:[{label:"Inline code",icon:"code-inline",action:t=>wrapSelection(t,"`","`")},{label:"Code block",icon:"code-block",action:t=>wrapSelection(t,"\n```\n","\n```\n")}]},"|",{type:"dropdown",icon:"plus-circle",title:"Insert",items:[{label:"Accordion",icon:"accordion-insert",action:"accordion"},{label:"Banner",icon:"banner-insert",action:"banner"},{label:"Badge",icon:"badge",action:"badge"},{label:"Block",icon:"layout",action:"block"},{label:"Button",icon:"btn-insert",action:"button"},{label:"Card",icon:"card",action:"card"},{label:"Colour Picker",icon:"colour-picker",action:"colourpick"},{label:"Collection",icon:"database",action:"collection"},{label:"Component",icon:"component",action:"component"},{label:"CTA Button",icon:"mouse-pointer",action:"cta"},{label:"Form",icon:"file-text",action:"form"},{label:"Grid",icon:"columns",action:"grid"},{label:"Hero",icon:"hero",action:"hero"},{label:"Icon",icon:"icon-pick",action:"iconpick"},{label:"Image",icon:"image-add",action:"image"},{label:"Link",icon:"link-shortcode",action:"linksc"},{label:"List Group",icon:"list",action:"listgroup"},{label:"Scribe",icon:"scribe-insert",action:"scribe"},{label:"Spacer",icon:"spacer-insert",action:"spacerpick"},{label:"Tabs",icon:"layout-list",action:"tabs"},{label:"Text",icon:"text-style",action:"text"},{label:"Timeline",icon:"activity",action:"timeline"},{label:"View",icon:"eye",action:"view"}]},"|",{icon:"sparkles",title:"Effects",action:"effects"},{icon:"help-circle",title:"Editor help",action:"help"}];export function createToolbar(t,e,p={}){se();const i={link:null,image:null,card:null,grid:null,help:null,effects:null,collection:null,view:null,cta:null,form:null,button:null,linksc:null,tabs:null,accordion:null,hero:null,banner:null},l=p.spacerDefault??40,o=t.get(0),s=e.get(0);s.textContent="",Q.forEach((n,c)=>{if(n==="|"){const u=document.createElement("span");u.className="editor-toolbar-sep",s.appendChild(u)}else{const u=document.createElement("button");u.className=n.type==="dropdown"?"editor-toolbar-btn editor-toolbar-dropdown-trigger":"editor-toolbar-btn",u.setAttribute("data-tooltip",n.title),u.setAttribute("data-idx",String(c)),u.type="button";const k=document.createElement("span");if(k.setAttribute("data-icon",n.icon),u.appendChild(k),n.type==="dropdown"){const y=document.createElement("span");y.className="editor-toolbar-caret",y.textContent="\u25BE",u.appendChild(y)}s.appendChild(u)}});const r=document.createElement("div");r.className="editor-toolbar-right",[{mode:"split",icon:"columns",label:"Split view",active:!0},{mode:"write",icon:"file-text",label:"Write only",active:!1},{mode:"preview",icon:"eye",label:"Preview only",active:!1}].forEach(n=>{const c=document.createElement("button");c.className="editor-view-btn"+(n.active?" active":""),c.setAttribute("data-mode",n.mode),c.setAttribute("data-tooltip",n.label),c.type="button";const u=document.createElement("span");u.setAttribute("data-icon",n.icon),c.appendChild(u),r.appendChild(c)});const a=document.createElement("span");a.className="editor-toolbar-sep",r.appendChild(a);const d=document.createElement("button");d.id="fullscreen-btn",d.className="editor-toolbar-btn",d.setAttribute("data-tooltip","Toggle fullscreen"),d.type="button";const h=document.createElement("span");return h.setAttribute("data-icon","expand"),d.appendChild(h),r.appendChild(d),s.appendChild(r),Domma.icons.scan(),s.querySelectorAll("[data-tooltip]").forEach(n=>{E.tooltip(n,{content:n.getAttribute("data-tooltip"),position:"top"})}),e.on("click",".editor-toolbar-btn[data-idx]",function(){const n=parseInt($(this).data("idx"),10),c=Q[n];if(!c||c==="|")return;const u=e.get(0).querySelector(`[data-idx="${n}"]`),k={spacerDefault:l,handlers:i};c.type==="dropdown"?ue(o,u,c.items,k):U(c.action,o,u,k)}),attachEditorKeybindings(o),o.addEventListener("keydown",n=>{const c=n.key.toLowerCase();(n.ctrlKey||n.metaKey)&&(c==="b"?(n.preventDefault(),wrapSelection(o,"**","**")):c==="i"?(n.preventDefault(),wrapSelection(o,"_","_")):c==="k"&&(n.preventDefault(),i.link&&i.link(o)))}),{$toolbar:e,onLink(n){i.link=n},onImage(n){i.image=n},onCard(n){i.card=n},onGrid(n){i.grid=n},onHelp(n){i.help=n},onEffects(n){i.effects=n},onCollection(n){i.collection=n},onBlock(n){i.block=n},onView(n){i.view=n},onCta(n){i.cta=n},onForm(n){i.form=n},onButton(n){i.button=n},onLinkShortcode(n){i.linksc=n},onTabs(n){i.tabs=n},onAccordion(n){i.accordion=n},onHero(n){i.hero=n},onBanner(n){i.banner=n},onListGroup(n){i.listgroup=n},onScribe(n){i.scribe=n},onTimeline(n){i.timeline=n}}}async function pe(t){const{api:e}=await import("../api.js");let p;try{p=await e.components.list()}catch(v){E.toast(v.message||"Failed to load components.",{type:"error"});return}if(!p?.length){E.toast("No components yet. Create one in Data \u2192 Components first.",{type:"info"});return}const i=E.slideover({title:"Insert Component",size:"lg",position:"right"}),l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:1rem;padding:.75rem;min-height:100%;";const o=document.createElement("div");o.style.cssText="font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dm-text-muted,#888);",o.textContent="Gallery";const s=document.createElement("div");s.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:.5rem;";const r=document.createElement("div");r.style.cssText="font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dm-text-muted,#888);",r.textContent="Props";const a=document.createElement("div");a.style.cssText="padding:.6rem;border:1px solid var(--dm-border,rgba(255,255,255,.08));border-radius:4px;min-height:40px;",a.textContent="Select a component from the gallery above.";const d=document.createElement("div");d.style.cssText="font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--dm-text-muted,#888);",d.textContent="Preview";const h=document.createElement("iframe");h.src="/admin/preview/component-preview.html",h.style.cssText="width:100%;min-height:180px;border:1px solid var(--dm-border,rgba(255,255,255,.08));border-radius:4px;background:#fff;";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:auto;padding-top:.75rem;border-top:1px solid var(--dm-border,rgba(255,255,255,.08));";const c=document.createElement("button");c.className="btn btn-ghost",c.textContent="Cancel";const u=document.createElement("button");u.className="btn btn-primary",u.textContent="Insert",u.disabled=!0,n.appendChild(c),n.appendChild(u),l.appendChild(o),l.appendChild(s),l.appendChild(r),l.appendChild(a),l.appendChild(d),l.appendChild(h),l.appendChild(n),i.element.appendChild(l),i.open();let k=null,y={};function C(){s.replaceChildren();for(const v of p){const b=document.createElement("button");b.type="button",b.className="btn btn-ghost",b.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:.25rem;padding:.6rem;border:1px solid var(--dm-border,rgba(255,255,255,.08));border-radius:4px;text-align:left;";const w=document.createElement("strong");w.style.cssText="font-size:.9rem;",w.textContent=v.name;const L=document.createElement("span");L.style.cssText="font-size:.72rem;color:var(--dm-text-muted,#888);",L.textContent=`${Object.keys(v.props||{}).length} prop(s)`,b.appendChild(w),b.appendChild(L),b.addEventListener("click",()=>x(v)),s.appendChild(b)}}function x(v){k=v,y={};for(const[b,w]of Object.entries(v.props||{}))y[b]=w.default!==void 0?w.default:"";u.disabled=!1,S(),M()}function S(){a.replaceChildren();const v=Object.entries(k.props||{});if(v.length===0){const b=document.createElement("p");b.className="text-muted",b.style.margin="0",b.textContent="This component takes no props.",a.appendChild(b);return}for(const[b,w]of v){const L=document.createElement("div");L.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const z=document.createElement("label");z.style.cssText="font-size:.8rem;min-width:120px;color:var(--dm-text-muted,#aaa);",z.textContent=w.label||b,L.appendChild(z);const T=me(w);he(T,w,y[b]),T.addEventListener("input",()=>{y[b]=X(T,w),h.contentWindow?.postMessage({type:"update",payload:{props:y}},"*")}),T.addEventListener("change",()=>{y[b]=X(T,w),h.contentWindow?.postMessage({type:"update",payload:{props:y}},"*")}),L.appendChild(T),a.appendChild(L)}}async function M(){if(k)try{const v=await fetch(`/api/components/${encodeURIComponent(k.name)}.js`);if(!v.ok)throw new Error(`Failed to load component (${v.status})`);const b=await v.text();h.contentWindow?.postMessage({type:"remount",payload:{compiledJs:b,tagName:`dm-${k.name}`,props:y}},"*")}catch(v){E.toast(v.message||"Failed to load preview.",{type:"error"})}}c.addEventListener("click",()=>i.close()),u.addEventListener("click",()=>{if(!k)return;const v=t.selectionStart,b=t.selectionEnd,w=Object.entries(y).map(([z,T])=>{const j=z.replace(/([A-Z])/g,"-$1").toLowerCase(),B=String(T??"").replace(/"/g,""");return`${j}="${B}"`}).join(" "),L=`[component name="${k.name}"${w?" "+w:""} /]`;t.value=t.value.substring(0,v)+L+t.value.substring(b),t.selectionStart=t.selectionEnd=v+L.length,t.dispatchEvent(new Event("input",{bubbles:!0})),t.focus(),i.close()}),C()}function me(t){let e;return t.type==="number"?(e=document.createElement("input"),e.type="number",e.className="form-input form-input--sm"):t.type==="boolean"?(e=document.createElement("input"),e.type="checkbox",e.className="form-check"):t.type==="array"||t.type==="object"?(e=document.createElement("textarea"),e.rows=2,e.className="form-input form-input--sm",e.style.fontFamily="var(--dm-font-mono, monospace)"):(e=document.createElement("input"),e.type="text",e.className="form-input form-input--sm"),e.style.flex="1",e}function X(t,e){if(e.type==="number")return t.value===""?null:Number(t.value);if(e.type==="boolean")return!!t.checked;if(e.type==="array"||e.type==="object")try{return JSON.parse(t.value||"null")}catch{return null}return t.value}function he(t,e,p){e.type==="boolean"?t.checked=!!p:e.type==="array"||e.type==="object"?t.value=JSON.stringify(p??null):t.value=p??""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{openIconPicker as Q}from"./card-builder.js";import{safeSetHTML as X}from"./safe-html.js";function R(e){const t={};for(const[,i,l,o]of e.matchAll(/([\w-]+)=(?:"([^"]*)"|'([^']*)')/g))t[i]=l??o??"";const n=e.replace(/([\w-]+)=(?:"[^"]*"|'[^']*')/g,i=>" ".repeat(i.length));for(const[,i]of n.matchAll(/\b([\w-]+)\b/g))i in t||(t[i]=!0);return t}function h(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}const Z=new Set(["layout","theme","mode","id","class"]),ee=new Set(["title","date","status","icon"]),te=new Set(["slug","display","layout","theme","mode","title-field","date-field","status-field","icon-field","body-field","limit"]),P=["vertical","centred","horizontal"],M=["minimal","corporate","modern"],ne=["","planned","in-progress","completed","blocked"];let F=null,a=null,C=null,T=null,k=null,$=null,q=0;export const TimelineBuilder={open(e,t={}){if(F)return;C=e,T=t,a=O(),k=null;const n=parseTimelineAtCursor(e.value,e.selectionStart);n.found&&(k=n.range,a=n.state),de()},close(){z()}};function O(){const e=new Date().toISOString().slice(0,10);return{mode:"static",layout:"vertical",theme:"minimal",roadmap:!1,id:"",className:"",extras:{},events:[{title:"First Event",date:e,status:"completed",icon:"",body:"Describe this event.",extras:{}},{title:"Second Event",date:"",status:"planned",icon:"",body:"Describe this event.",extras:{}}],collection:{slug:"",titleField:"",dateField:"",statusField:"",iconField:"",bodyField:"",limit:""}}}export function parseTimelineAtCursor(e,t){let n=null;const i=/\[timeline([^\]]*)\]([\s\S]*?)\[\/timeline\]/gi;for(const s of e.matchAll(i)){const c=s.index,u=c+s[0].length;t>=c&&t<=u&&(!n||u-c<n.range.end-n.range.start)&&(n={kind:"static",range:{start:c,end:u},attrStr:s[1],body:s[2]})}const l=/\[collection([^\]]*?)\/\]/gi;for(const s of e.matchAll(l)){const c=s.index,u=c+s[0].length;if(t<c||t>u)continue;const w=R(s[1]);w.display==="timeline"&&(!n||u-c<n.range.end-n.range.start)&&(n={kind:"collection",range:{start:c,end:u},attrs:w})}if(!n)return{found:!1};if(n.kind==="static"){const s=R(n.attrStr),c={};Object.keys(s).forEach(g=>{!Z.has(g)&&s[g]!==!0&&(c[g]=s[g])});const u=[],w=/\[event([^\]]*)\]([\s\S]*?)\[\/event\]/gi;for(const g of n.body.matchAll(w)){const y=R(g[1]),p={};Object.keys(y).forEach(v=>{!ee.has(v)&&y[v]!==!0&&(p[v]=y[v])}),u.push({title:y.title||"",date:y.date||"",status:y.status||"",icon:y.icon||"",body:g[2].trim(),extras:p})}return{found:!0,range:n.range,state:{mode:"static",layout:P.includes(s.layout)?s.layout:"vertical",theme:M.includes(s.theme)?s.theme:"minimal",roadmap:s.mode==="roadmap",id:s.id||"",className:s.class||"",extras:c,events:u.length?u:O().events,collection:O().collection}}}const o=n.attrs,f={};return Object.keys(o).forEach(s=>{!te.has(s)&&o[s]!==!0&&(f[s]=o[s])}),{found:!0,range:n.range,state:{mode:"collection",layout:P.includes(o.layout)?o.layout:"vertical",theme:M.includes(o.theme)?o.theme:"minimal",roadmap:o.mode==="roadmap",id:"",className:"",extras:f,events:O().events,collection:{slug:o.slug||"",titleField:o["title-field"]||"",dateField:o["date-field"]||"",statusField:o["status-field"]||"",iconField:o["icon-field"]||"",bodyField:o["body-field"]||"",limit:o.limit||""}}}}function U(){return a.mode==="collection"?oe():ie()}function ie(){const e=a,t=[];e.layout!=="vertical"&&t.push(`layout="${h(e.layout)}"`),e.theme!=="minimal"&&t.push(`theme="${h(e.theme)}"`),e.roadmap&&t.push('mode="roadmap"'),e.id&&t.push(`id="${h(e.id)}"`),e.className&&t.push(`class="${h(e.className)}"`),Object.entries(e.extras).forEach(([l,o])=>t.push(`${l}="${h(o)}"`));const n=t.length?" "+t.join(" "):"",i=e.events.map(l=>{const o=[];return l.title&&o.push(`title="${h(l.title)}"`),l.date&&o.push(`date="${h(l.date)}"`),l.status&&o.push(`status="${h(l.status)}"`),l.icon&&o.push(`icon="${h(l.icon)}"`),Object.entries(l.extras||{}).forEach(([s,c])=>o.push(`${s}="${h(c)}"`)),`[event${o.length?" "+o.join(" "):""}]
|
|
2
|
+
${(l.body||"").trim()}
|
|
3
|
+
[/event]`}).join(`
|
|
4
|
+
`);return`[timeline${n}]
|
|
5
|
+
${i}
|
|
6
|
+
[/timeline]`}function oe(){const e=a,t=e.collection,n=[`slug="${h(t.slug)}"`,'display="timeline"'];return e.layout!=="vertical"&&n.push(`layout="${h(e.layout)}"`),e.theme!=="minimal"&&n.push(`theme="${h(e.theme)}"`),e.roadmap&&n.push('mode="roadmap"'),t.titleField&&n.push(`title-field="${h(t.titleField)}"`),t.dateField&&n.push(`date-field="${h(t.dateField)}"`),t.statusField&&n.push(`status-field="${h(t.statusField)}"`),t.iconField&&n.push(`icon-field="${h(t.iconField)}"`),t.bodyField&&n.push(`body-field="${h(t.bodyField)}"`),t.limit&&n.push(`limit="${h(t.limit)}"`),Object.entries(e.extras).forEach(([i,l])=>n.push(`${i}="${h(l)}"`)),`[collection ${n.join(" ")} /]`}function z(){$&&(clearTimeout($),$=null),F&&(F.remove(),F=null,a=null,k=null)}function le(){const e=U();if(k){const{start:t,end:n}=k;C.value=C.value.slice(0,t)+e+C.value.slice(n),C.selectionStart=C.selectionEnd=t+e.length}else{const t=C.selectionStart,n=C.selectionEnd;C.value=C.value.slice(0,t)+e+C.value.slice(n),C.selectionStart=C.selectionEnd=t+e.length}C.dispatchEvent(new Event("input",{bubbles:!0})),C.focus(),z()}function d(e,t=""){const n=document.createElement(e);return t&&(n.style.cssText=t),n}const L="padding:7px 10px;border-radius:7px;border:1px solid var(--dm-border,#334155);background:var(--dm-surface,#0f172a);color:var(--dm-text,#e2e8f0);font-size:12px;font-family:inherit;width:100%",j="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--dm-text-muted,#475569)";function S(e,t){const n=d("div","display:flex;flex-direction:column;gap:5px"),i=d("div",j);return i.textContent=e,n.appendChild(i),n.appendChild(t),n}function H(){return d("div","height:1px;background:var(--dm-border,#334155);margin:2px 0")}function de(){F=d("div","position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:9999;padding:24px;isolation:isolate");const e=d("div","background:var(--dm-surface,#1e293b);border:1px solid var(--dm-border,#334155);border-radius:14px;width:100%;max-width:960px;max-height:90vh;display:flex;flex-direction:column;box-shadow:0 24px 64px rgba(0,0,0,.6);overflow:hidden"),t=d("div","display:flex;align-items:center;justify-content:space-between;padding:14px 20px;border-bottom:1px solid var(--dm-border,#334155);flex-shrink:0"),n=d("span","font-weight:700;color:var(--dm-text,#f1f5f9);font-size:14px");n.textContent=k?"Edit Timeline":"Insert Timeline";const i=d("button","background:var(--dm-border,#334155);border:none;color:var(--dm-text-muted,#94a3b8);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:14px");i.textContent="\u2715",i.addEventListener("click",z),t.appendChild(n),t.appendChild(i);const l=d("div","display:grid;grid-template-columns:340px 1fr;flex:1;overflow:hidden");l.appendChild(ae()),l.appendChild(me());const o=d("div","display:flex;justify-content:flex-end;gap:10px;padding:12px 20px;border-top:1px solid var(--dm-border,#334155);flex-shrink:0"),f=d("button","padding:8px 18px;border-radius:8px;border:none;background:var(--dm-border,#334155);color:var(--dm-text-muted,#94a3b8);font-size:12px;font-weight:700;cursor:pointer");f.textContent="Cancel",f.addEventListener("click",z);const s=d("button","padding:8px 18px;border-radius:8px;border:none;background:#6366f1;color:#fff;font-size:12px;font-weight:700;cursor:pointer");s.textContent=k?"Save Timeline":"Insert Timeline",s.addEventListener("click",le),o.appendChild(f),o.appendChild(s),e.appendChild(t),e.appendChild(l),e.appendChild(o),F.appendChild(e),F.addEventListener("click",c=>{c.target===F&&z()}),document.body.appendChild(F),x()}function ae(){const e=d("div","padding:18px;border-right:1px solid var(--dm-border,#334155);display:flex;flex-direction:column;gap:14px;overflow-y:auto");e.appendChild(re()),e.appendChild(H()),e.appendChild(S("Layout",V("layout",P.map(i=>[i,G(i)])))),e.appendChild(S("Theme",V("theme",M.map(i=>[i,G(i)])))),e.appendChild(S("Mode",se())),e.appendChild(H());const t=d("div","display:flex;flex-direction:column;gap:12px");t.id="tb-static",t.appendChild(ce()),e.appendChild(t);const n=d("div","display:flex;flex-direction:column;gap:12px");return n.id="tb-collection",n.appendChild(fe()),e.appendChild(n),K(),e}function re(){const e=d("div","display:flex;gap:6px"),t=(n,i)=>{const l=d("button"),o=()=>{const f=a.mode===n;l.style.cssText=`flex:1;padding:8px 10px;border-radius:8px;border:1px solid;font-size:12px;font-weight:700;cursor:pointer;${f?"border-color:#6366f1;background:#1e1b4b;color:#a5b4fc":"border-color:var(--dm-border,#334155);background:var(--dm-surface,#0f172a);color:var(--dm-text-muted,#94a3b8)"}`};return l.type="button",l.textContent=i,o(),l.addEventListener("click",()=>{a.mode=n,e.querySelectorAll("button").forEach(f=>f._paint&&f._paint()),K(),x()}),l._paint=o,l};return e.appendChild(t("static","Static")),e.appendChild(t("collection","From Collection")),e}function K(){const e=document.getElementById("tb-static"),t=document.getElementById("tb-collection");e&&(e.style.display=a.mode==="static"?"":"none"),t&&(t.style.display=a.mode==="collection"?"":"none")}function V(e,t){const n=d("select",L+";cursor:pointer");return t.forEach(([i,l])=>{const o=document.createElement("option");o.value=i,o.textContent=l,i===a[e]&&(o.selected=!0),n.appendChild(o)}),n.addEventListener("change",()=>{a[e]=n.value,x()}),n}function se(){const e=d("label","display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:12px;color:var(--dm-text,#e2e8f0)"),t=document.createElement("input");return t.type="checkbox",t.checked=!!a.roadmap,t.addEventListener("change",()=>{a.roadmap=t.checked,x()}),e.appendChild(t),e.appendChild(document.createTextNode("Roadmap mode")),e}function ce(){const e=d("div","display:flex;flex-direction:column;gap:8px"),t=d("div","display:flex;align-items:center;justify-content:space-between"),n=d("div",j);n.textContent="Events";const i=d("button","padding:4px 10px;border-radius:6px;border:1px dashed var(--dm-border,#334155);background:transparent;color:var(--dm-text-muted,#94a3b8);font-size:11px;cursor:pointer");i.type="button",i.textContent="+ Add event",i.addEventListener("click",()=>{a.events.push({title:"New Event",date:"",status:"",icon:"",body:"",extras:{}}),N(),x()}),t.appendChild(n),t.appendChild(i),e.appendChild(t);const l=d("div","display:flex;flex-direction:column;gap:8px");return l.id="tb-events",e.appendChild(l),N(l),e}function N(e){const t=e||document.getElementById("tb-events");if(t){for(;t.firstChild;)t.removeChild(t.firstChild);a.events.forEach((n,i)=>t.appendChild(pe(n,i)))}}function pe(e,t){const n=d("div","border:1px solid var(--dm-border,#334155);border-radius:8px;padding:10px;background:var(--dm-surface-subtle,#0b1120);display:flex;flex-direction:column;gap:8px");n.draggable=!0,n.dataset.idx=String(t);const i=d("div","display:flex;align-items:center;gap:6px"),l=d("span","cursor:grab;color:var(--dm-text-muted,#475569);font-size:14px;user-select:none;padding:0 4px");l.textContent="\u2261",l.title="Drag to reorder",i.appendChild(l);const o=d("div","flex:1;font-size:12px;color:var(--dm-text,#e2e8f0);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis");o.textContent=e.title||"(untitled event)",i.appendChild(o);const f=(r,m,b,E)=>{const _=d("button",`padding:2px 6px;border-radius:5px;border:1px solid var(--dm-border,#334155);background:transparent;color:var(--dm-text-muted,#94a3b8);font-size:11px;cursor:${E?"not-allowed":"pointer"};opacity:${E?"0.4":"1"}`);return _.type="button",_.title=m,_.textContent=r,E||_.addEventListener("click",b),_};i.appendChild(f("\u2191","Move up",()=>Y(t,-1),t===0)),i.appendChild(f("\u2193","Move down",()=>Y(t,1),t===a.events.length-1)),i.appendChild(f("\u2715","Delete",()=>ue(t),a.events.length<=1)),n.appendChild(i);const s=W(e.title,"Event title",r=>{e.title=r,o.textContent=r||"(untitled event)",x()});n.appendChild(A("Title",s));const c=d("div","display:grid;grid-template-columns:1fr 1fr;gap:6px"),u=document.createElement("input");u.type="date",u.value=e.date||"",u.style.cssText=L,u.addEventListener("input",()=>{e.date=u.value,x()}),c.appendChild(A("Date",u));const w=document.createElement("select");w.style.cssText=L+";cursor:pointer",ne.forEach(r=>{const m=document.createElement("option");m.value=r,m.textContent=r===""?"\u2014 none \u2014":G(r),r===e.status&&(m.selected=!0),w.appendChild(m)}),w.addEventListener("change",()=>{e.status=w.value,x()}),c.appendChild(A("Status",w)),n.appendChild(c);const g=d("div","display:flex;gap:6px"),y=W(e.icon,"e.g. rocket",r=>{e.icon=r,x()});y.style.flex="1";const p=d("button","padding:0 10px;background:var(--dm-border,#334155);border:none;color:var(--dm-text-muted,#94a3b8);border-radius:7px;font-size:12px;cursor:pointer;flex-shrink:0");p.type="button",p.title="Browse icons",p.textContent="\u2605",p.addEventListener("click",()=>Q(r=>{e.icon=r,y.value=r,x()})),g.appendChild(y),g.appendChild(p),n.appendChild(A("Icon",g));const v=document.createElement("textarea");return v.value=e.body||"",v.rows=2,v.style.cssText=L+";resize:vertical;min-height:48px;line-height:1.5",v.addEventListener("input",()=>{e.body=v.value,x()}),n.appendChild(A("Body (Markdown)",v)),n.addEventListener("dragstart",r=>{r.dataTransfer.effectAllowed="move",r.dataTransfer.setData("text/plain",String(t)),n.style.opacity="0.5"}),n.addEventListener("dragend",()=>{n.style.opacity=""}),n.addEventListener("dragover",r=>{r.preventDefault(),r.dataTransfer.dropEffect="move",n.style.borderColor="#6366f1"}),n.addEventListener("dragleave",()=>{n.style.borderColor="var(--dm-border,#334155)"}),n.addEventListener("drop",r=>{r.preventDefault(),n.style.borderColor="var(--dm-border,#334155)";const m=parseInt(r.dataTransfer.getData("text/plain"),10);if(Number.isNaN(m)||m===t)return;const[b]=a.events.splice(m,1);a.events.splice(t,0,b),N(),x()}),n}function Y(e,t){const n=e+t;if(n<0||n>=a.events.length)return;const[i]=a.events.splice(e,1);a.events.splice(n,0,i),N(),x()}function ue(e){a.events.length<=1||(a.events.splice(e,1),N(),x())}function W(e,t,n){const i=document.createElement("input");return i.type="text",i.value=e||"",i.placeholder=t||"",i.style.cssText=L,i.addEventListener("input",()=>n(i.value)),i}function A(e,t){const n=d("div","display:flex;flex-direction:column;gap:4px"),i=d("div","font-size:10px;font-weight:600;color:var(--dm-text-muted,#64748b);letter-spacing:.04em");return i.textContent=e,n.appendChild(i),n.appendChild(t),n}function fe(){const e=d("div","display:flex;flex-direction:column;gap:10px"),t=d("select",L+";cursor:pointer"),n=document.createElement("option");n.value="",n.textContent="Loading collections\u2026",t.appendChild(n),e.appendChild(S("Collection",t));const i=B("titleField"),l=B("dateField"),o=B("statusField"),f=B("iconField"),s=B("bodyField");e.appendChild(S("Title field",i));const c=d("div","display:grid;grid-template-columns:1fr 1fr;gap:8px");c.appendChild(S("Date field",l)),c.appendChild(S("Status field",o)),e.appendChild(c),e.appendChild(S("Icon field",f)),e.appendChild(S("Body field",s));const u=W(a.collection.limit,"All",p=>{a.collection.limit=p,x()});u.type="number",u.min="1",e.appendChild(S("Limit (optional)",u));const w=d("div","font-size:11px;color:var(--dm-text-muted,#64748b);line-height:1.4");w.textContent="Picks entries in their default collection order. Set date, status, and icon fields to drive visual cues on the page.",e.appendChild(w);const g=p=>{[i,l,o,f,s].forEach(b=>{for(;b.firstChild;)b.removeChild(b.firstChild);const E=document.createElement("option");E.value="",E.textContent="\u2014 none \u2014",b.appendChild(E),p.forEach(_=>{const D=document.createElement("option");D.value=_.name,D.textContent=_.label||_.name,b.appendChild(D)})});const r=new Set(p.map(b=>b.name)),m=(b,E)=>{a.collection[b]&&r.has(a.collection[b])||(a.collection[b]=r.has(E)?E:"")};m("titleField","title"),m("dateField","date"),m("statusField","status"),m("iconField","icon"),m("bodyField","description"),i.value=a.collection.titleField,l.value=a.collection.dateField,o.value=a.collection.statusField,f.value=a.collection.iconField,s.value=a.collection.bodyField},y=async p=>{if(!p){g([]);return}try{const v=T.onGetCollection?await T.onGetCollection(p):null,r=v&&v.fields||[];g(r)}catch{g([])}};return t.addEventListener("change",()=>{a.collection.slug=t.value,y(t.value).then(x)}),(async()=>{let p=[];try{p=T.onListCollections?await T.onListCollections():[]}catch{p=[]}for(;t.firstChild;)t.removeChild(t.firstChild);if(!p.length){const r=document.createElement("option");r.value="",r.textContent="No collections available",t.appendChild(r),g([]);return}p.forEach(r=>{const m=document.createElement("option");m.value=r.slug,m.textContent=r.title||r.slug,t.appendChild(m)});const v=a.collection.slug;v&&p.some(r=>r.slug===v)?t.value=v:(a.collection.slug=p[0].slug,t.value=p[0].slug),await y(t.value),x()})(),e}function B(e){const t=d("select",L+";cursor:pointer"),n=document.createElement("option");return n.value="",n.textContent="\u2014 none \u2014",t.appendChild(n),t.addEventListener("change",()=>{a.collection[e]=t.value,x()}),t}function me(){const e=d("div","padding:20px;background:var(--dm-surface,#0f172a);display:flex;flex-direction:column;gap:14px;overflow-y:auto"),t=d("div",j);t.textContent="Live Preview";const n=d("div","flex:1;min-height:160px;background:var(--dm-surface-subtle,#fff);border-radius:10px;padding:16px;color:#0f172a");n.id="tb-preview-area";const i=d("div",j+";margin-bottom:4px");i.textContent="Shortcode";const l=d("pre","background:var(--dm-surface-subtle,#1e293b);border:1px solid var(--dm-border,#334155);border-radius:8px;padding:10px 14px;font-family:monospace;font-size:11px;color:var(--dm-primary,#a5b4fc);line-height:1.6;white-space:pre-wrap;word-break:break-word;max-height:160px;overflow:auto;margin:0");return l.id="tb-snippet",e.appendChild(t),e.appendChild(n),e.appendChild(i),e.appendChild(l),e}function x(){const e=document.getElementById("tb-snippet");e&&(e.textContent=U()),he()}function he(){$&&clearTimeout($),$=setTimeout(ve,300)}async function ve(){const e=document.getElementById("tb-preview-area");if(!e)return;const t=U(),n=++q;xe(e);try{const i=T.onPreview?await T.onPreview(t):null;if(n!==q)return;if(!i||typeof i.html!="string"){J(e);return}X(e,i.html),typeof I<"u"&&I.scan&&I.scan(e)}catch{if(n!==q)return;J(e)}}function xe(e){if(!e.dataset.loaded){for(;e.firstChild;)e.removeChild(e.firstChild);const t=d("div","color:var(--dm-text-muted,#94a3b8);font-size:12px");t.textContent="Rendering preview\u2026",e.appendChild(t),e.dataset.loaded="1"}}function J(e){for(;e.firstChild;)e.removeChild(e.firstChild);const t=d("div","color:var(--dm-text-muted,#94a3b8);font-size:12px;font-style:italic");t.textContent="Preview unavailable",e.appendChild(t)}function G(e){return e.charAt(0).toUpperCase()+e.slice(1)}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import{api as
|
|
1
|
+
import{api as _}from"../api.js";import{CardBuilder as Ke}from"../lib/card-builder.js?v=4";import{TimelineBuilder as Ze}from"../lib/timeline-builder.js?v=1";import{attachEditorKeybindings as Xe,createToolbar as et,insertAtCursor as xe}from"../lib/markdown-toolbar.js?v=10";import{populateThemeSelect as tt}from"../lib/themes.js";import{createFoldingManager as nt}from"../lib/editor-folding.js";import{makeCheckbox as He,makeField as W,makeIconInput as Oe,makeLivePreview as Ue,makeSelect as Be,makeTextInput as Ce}from"../lib/shortcode-modal.js";import{openScribeComposer as at}from"../lib/scribe-composer.js?v=1";function ot(){const l=E.slideover({title:"Editor Reference",size:"md",position:"right"}),re="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 H(h){const y=document.createElement("code");return y.style.cssText=re,y.textContent=h,y}function Q(h){const y=document.createElement("h3");return y.style.cssText=de,y.textContent=h,y}const Ie=document.createElement("div");Ie.style.cssText="padding:1rem;";const De=document.createElement("div");De.className="tabs";const Me=document.createElement("div");Me.className="tab-list",["Basics","Layout","Components","Data","Advanced"].forEach((h,y)=>{const d=document.createElement("button");d.className="tab-item"+(y===0?" active":""),d.textContent=h,Me.appendChild(d)});const Y=document.createElement("div");Y.className="tab-content";const Le="display:flex;flex-direction:column;gap:1rem;",$e=document.createElement("div");$e.className="tab-panel active",$e.style.cssText=Le;const fe=document.createElement("div");fe.className="tab-panel",fe.style.cssText=Le;const se=document.createElement("div");se.className="tab-panel",se.style.cssText=Le;const ve=document.createElement("div");ve.className="tab-panel",ve.style.cssText=Le;const we=document.createElement("div");we.className="tab-panel",we.style.cssText=Le,Y.appendChild($e),Y.appendChild(fe),Y.appendChild(se),Y.appendChild(ve),Y.appendChild(we),De.appendChild(Me),De.appendChild(Y),Ie.appendChild(De);const qe=document.createElement("div");qe.appendChild(Q("Markdown Basics"));const me=document.createElement("table");me.style.cssText="width:100%;border-collapse:collapse;font-size:.9em;";const K=document.createElement("thead"),ae=document.createElement("tr");["Syntax","Result"].forEach(h=>{const y=document.createElement("th");y.style.cssText="text-align:left;padding:.4rem .5rem;border-bottom:1px solid var(--dm-border,#333);",y.textContent=h,ae.appendChild(y)}),K.appendChild(ae),me.appendChild(K);const he=document.createElement("tbody");[["**bold**","bold (rendered bold)"],["_italic_","italic (rendered italic)"],["## Heading","Heading (h2)"],["[text](url)","Link"],["","Image"],["- item","Bullet list"],["`code`","Inline code"],["---","Divider"]].forEach(([h,y])=>{const d=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.35rem .5rem;vertical-align:top;",s.appendChild(H(h));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=y,d.appendChild(s),d.appendChild(o),he.appendChild(d)}),me.appendChild(he),qe.appendChild(me),$e.appendChild(qe);const te=document.createElement("div");te.appendChild(Q("Grid & Columns"));function G(h){const y=document.createElement("p");return y.style.cssText="margin:.3rem 0 .6rem;font-size:.82em;color:var(--dm-text-muted,#aaa);",y.textContent=h,y}function T(h,y,d){const s=document.createElement("p");s.style.cssText="margin:.75rem 0 .25rem;font-size:.85em;font-weight:600;",s.textContent=h;const o=document.createElement("div");o.style.cssText="position:relative;";const j=document.createElement("pre");j.style.cssText=re+"display:block;padding:.5rem 2rem .5rem .75rem;white-space:pre;overflow-x:auto;margin:0;",j.textContent=y;const Z=document.createElement("button");Z.type="button",Z.title="Copy code",Z.style.cssText="position:absolute;top:.3rem;right:.3rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.15rem;line-height:1;color:inherit;",Z.addEventListener("mouseenter",()=>{Z.style.opacity="1"}),Z.addEventListener("mouseleave",()=>{Z.style.opacity=".45"});const oe=document.createElement("span");oe.setAttribute("data-icon","copy"),Z.appendChild(oe),Z.addEventListener("click",()=>{const F=document.createElement("textarea");F.value=y,F.style.cssText="position:fixed;opacity:0;",document.body.appendChild(F),F.select(),document.execCommand("copy"),F.remove(),E.toast("Copied!",{type:"success",duration:1200})}),o.appendChild(j),o.appendChild(Z);const ee=document.createDocumentFragment();return ee.appendChild(s),ee.appendChild(o),d&&ee.appendChild(G(d)),ee}const ne=document.createElement("table");ne.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(([h,y,d])=>{const s=document.createElement("tr");[h,y,d].forEach((o,j)=>{const Z=document.createElement("td");Z.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",j===0?Z.appendChild(H(h)):(Z.style.color="var(--dm-text-muted,#aaa)",Z.textContent=o),s.appendChild(Z)}),ne.appendChild(s)}),te.appendChild(ne),te.appendChild(T("Equal columns",`[grid cols="3" gap="4"]
|
|
2
2
|
[col]One[/col]
|
|
3
3
|
[col]Two[/col]
|
|
4
4
|
[col]Three[/col]
|
|
5
|
-
[/grid]`,"cols sets the track count; each [col] fills one track.")),
|
|
5
|
+
[/grid]`,"cols sets the track count; each [col] fills one track.")),te.appendChild(T("Column spanning (12-col base)",`[grid cols="12" gap="3"]
|
|
6
6
|
[col span="8"]Main content[/col]
|
|
7
7
|
[col span="4"]Sidebar[/col]
|
|
8
|
-
[/grid]`,"span values must add up to cols. Common splits: 8/4, 6/6, 9/3.")),
|
|
8
|
+
[/grid]`,"span values must add up to cols. Common splits: 8/4, 6/6, 9/3.")),te.appendChild(T("Row (flexbox, equal-width)",`[row gap="4"]
|
|
9
9
|
[col]Left[/col]
|
|
10
10
|
[col]Right[/col]
|
|
11
|
-
[/row]`,"Use [row] when you want equal-width columns without specifying a count.")),
|
|
11
|
+
[/row]`,"Use [row] when you want equal-width columns without specifying a count.")),te.appendChild(T("Row with staggered reveal",`[row reveal reveal-mode="stagger" reveal-animation="slide-up" reveal-duration="400" reveal-stagger="60" reveal-delay="0" reveal-direction="ltr"]
|
|
12
12
|
[col]First[/col]
|
|
13
13
|
[col]Second[/col]
|
|
14
14
|
[col]Third[/col]
|
|
15
|
-
[/row]`,'Columns reveal one by one as the row scrolls into view. reveal-direction="rtl" reverses the order. Animations: slide-up, slide-down, slide-left, slide-right, fade, zoom, flip.')),
|
|
15
|
+
[/row]`,'Columns reveal one by one as the row scrolls into view. reveal-direction="rtl" reverses the order. Animations: slide-up, slide-down, slide-left, slide-right, fade, zoom, flip.')),te.appendChild(T("Card in a grid",`[grid cols="3" gap="4"]
|
|
16
16
|
[col]
|
|
17
17
|
[card title="One"]Content[/card]
|
|
18
18
|
[/col]
|
|
@@ -22,21 +22,21 @@ import{api as j}from"../api.js";import{CardBuilder as Ke}from"../lib/card-builde
|
|
|
22
22
|
[col]
|
|
23
23
|
[card title="Three"]Content[/card]
|
|
24
24
|
[/col]
|
|
25
|
-
[/grid]`,null)),fe.appendChild(
|
|
25
|
+
[/grid]`,null)),fe.appendChild(te);const ce=document.createElement("div");ce.appendChild(Q("Cards")),ce.appendChild(T("Basic card",`[card title="Optional Title"]
|
|
26
26
|
Markdown **works** here.
|
|
27
|
-
[/card]`,"Omit title for a card with no header.")),
|
|
27
|
+
[/card]`,"Omit title for a card with no header.")),ce.appendChild(T("Icon \u2014 inline (default)",`[card title="Feature" icon="star"]
|
|
28
28
|
Icon sits left of the title in a flex row.
|
|
29
|
-
[/card]`,"icon accepts any Domma icon name. Default layout when icon is set.")),
|
|
29
|
+
[/card]`,"icon accepts any Domma icon name. Default layout when icon is set.")),ce.appendChild(T("Icon \u2014 stacked (centred)",`[card title="Feature" icon="star" icon-layout="stacked" hover]
|
|
30
30
|
Icon is centred above the title. Great for feature tiles.
|
|
31
|
-
[/card]`,'icon-layout="stacked" centres the icon above the title. Combine with hover for a lift effect.')),
|
|
31
|
+
[/card]`,'icon-layout="stacked" centres the icon above the title. Combine with hover for a lift effect.')),ce.appendChild(T("Icon with subtitle",`[card title="Feature" subtitle="Tagline here" icon="star" icon-layout="stacked"]
|
|
32
32
|
Body content.
|
|
33
|
-
[/card]`,"subtitle adds a secondary line beneath the title in both layouts.")),
|
|
33
|
+
[/card]`,"subtitle adds a secondary line beneath the title in both layouts.")),ce.appendChild(T("Collapsible card",`[card title="Click to expand" collapsible="true"]
|
|
34
34
|
Hidden by default.
|
|
35
|
-
[/card]`,null)),
|
|
35
|
+
[/card]`,null)),ce.appendChild(T("Full attribute reference",`[card title="Title" subtitle="Sub" icon="star" icon-layout="stacked"
|
|
36
36
|
variant="primary" hover footer="Footer text"
|
|
37
37
|
collapsible="true" class="extra" id="my-card"]
|
|
38
38
|
Body content.
|
|
39
|
-
[/card]`,'All attributes are optional. variant accepts "primary". icon-layout accepts "inline" (default) or "stacked".')),
|
|
39
|
+
[/card]`,'All attributes are optional. variant accepts "primary". icon-layout accepts "inline" (default) or "stacked".')),ce.appendChild(T("Rich header / footer sub-tags",`[card]
|
|
40
40
|
[header]
|
|
41
41
|
### Custom Title with **bold** and [a link](/about)
|
|
42
42
|
[/header]
|
|
@@ -46,60 +46,60 @@ Body content here.
|
|
|
46
46
|
[footer]
|
|
47
47
|
[Read more](/about) | [icon name="arrow-right" /]
|
|
48
48
|
[/footer]
|
|
49
|
-
[/card]`,"Use [header] and [footer] sub-tags for Markdown-rendered header/footer regions. Sub-tags override the title/subtitle/icon and footer attributes when both are present.")),
|
|
49
|
+
[/card]`,"Use [header] and [footer] sub-tags for Markdown-rendered header/footer regions. Sub-tags override the title/subtitle/icon and footer attributes when both are present.")),se.appendChild(ce);const Ne=document.createElement("div");Ne.appendChild(Q("Badge")),Ne.appendChild(G("Inline badge/label elements. Self-closing renders an empty coloured dot."));const Ae=document.createElement("table");Ae.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['variant="..."',"primary (default), secondary, success, danger, warning, info, light, dark"],["pill","Flag: rounded pill shape (.badge-pill)"],["outline","Flag: outlined style (.badge-outline)"],['size="small|large"',"Reduced or enlarged badge"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),Ae.appendChild(d)}),Ne.appendChild(Ae),Ne.appendChild(T("Basic badge",'[badge variant="success"]New[/badge]',null)),Ne.appendChild(T("Pill outline badge",'[badge variant="danger" outline pill]Deprecated[/badge]',null)),se.appendChild(Ne);const V=document.createElement("div");V.appendChild(Q("Button")),V.appendChild(G("Renders a styled anchor as a Domma button. Use the Insert \u2192 Button toolbar item for a guided dialog."));const M=document.createElement("table");M.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['href="..."',"Link destination (required)"],['label="..."',"Button text (self-closing form)"],['variant="..."',"primary (default), secondary, success, danger, warning, info, outline, ghost, link, outline-*"],['size="sm|lg"',"Button size modifier"],['icon="..."',"Domma icon name before the label"],['icon-after="..."',"Domma icon name after the label"],['target="..."','Link target, e.g. "_blank"'],['class="..."',"Extra CSS classes"],['id="..."',"Element id"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),M.appendChild(d)}),V.appendChild(M),V.appendChild(T("Primary button",'[button href="/contact" variant="primary"]Get in touch[/button]',null)),V.appendChild(T("Self-closing with icon",'[button href="/download" variant="success" icon="download" size="sm" label="Download" /]',null)),V.appendChild(T("Opens in new tab",'[button href="https://example.com" variant="outline" target="_blank"]Visit site[/button]',null)),se.appendChild(V);const pe=document.createElement("div");pe.appendChild(Q("Link (shortcode)")),pe.appendChild(G("Renders a plain anchor with optional icon, target, and class. Use Insert \u2192 Link for a guided dialog. For simple inline links, standard Markdown [text](url) is fine."));const Ee=document.createElement("table");Ee.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['href="..."',"Link destination (required)"],['label="..."',"Link text (self-closing form)"],['target="..."','Link target, e.g. "_blank"'],['class="..."',"CSS classes on the <a>"],['icon="..."',"Domma icon name before the text"],['icon-after="..."',"Domma icon name after the text"],['id="..."',"Element id"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),Ee.appendChild(d)}),pe.appendChild(Ee),pe.appendChild(T("External link in new tab",'[link href="https://example.com" target="_blank" icon-after="external-link"]Visit site[/link]',null)),pe.appendChild(T("Self-closing with icon",'[link href="/about" icon="arrow-right" label="About us" /]',null)),se.appendChild(pe);const ke=document.createElement("div");ke.appendChild(Q("Spacer")),ke.appendChild(G("Self-closing shortcode that inserts a fixed-height blank gap."));const ue=document.createElement("table");ue.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['size="N"',"Height in px (default: 8)"],['class="..."',"Extra CSS class on the spacer div"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),ue.appendChild(d)}),ke.appendChild(ue),ke.appendChild(T("32px gap",'[spacer size="32" /]',null)),fe.appendChild(ke);const Te=document.createElement("div");Te.appendChild(Q("Icon")),Te.appendChild(G("Self-closing shortcode that renders any Domma icon inline."));const be=document.createElement("table");be.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['name="..."',"Domma icon name (required). Also accepted as src=."],['size="N"',"Width and height in px"],['color="..."',"CSS colour applied via style"],['class="..."',"Extra CSS classes"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),be.appendChild(d)}),Te.appendChild(be),Te.appendChild(T("Coloured icon",'[icon name="star" size="24" color="#f5a623" /]',null)),se.appendChild(Te);const ze=document.createElement("div");ze.appendChild(Q("Center")),ze.appendChild(G("Wraps content in a centred div. Works with any content including cards, grids, and text.")),ze.appendChild(T("Example","[center]Centred content here[/center]",'Accepts an optional class="..." attribute for extra styling.')),fe.appendChild(ze);const ge=document.createElement("div");ge.appendChild(Q("Hero")),ge.appendChild(G("Full-width hero sections \u2014 no plugin required. Uses Domma's built-in Hero CSS component."));const le=document.createElement("table");le.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['title="..."',"Heading text"],['tagline="..."',"Subtitle text"],['size="sm|lg|full"',"Height variant (default: normal)"],['variant="dark|primary|gradient-blue|gradient-purple|gradient-sunset|gradient-ocean"',"Colour / gradient preset"],['image="url"',"Background image URL (adds cover mode)"],['overlay="light|dark|darker|gradient|gradient-reverse"',"Image overlay style"],['align="center|left"',"Content alignment (default: center)"],['fullwidth="true"',"Break out of the page container to span full viewport width"],['bg="..."',"Background colour CSS value"],["twinkle","Flag: adds particle overlay (requires Effects plugin)"],['twinkle-count="N"',"Number of particles"],['twinkle-colour="..."',"Particle colour CSS value"],["blobs","Flag: adds ambient blob background"],['blobs-type="..."',"Blob animation type (default: float-blobs)"],['class="..."',"Extra CSS classes"],['id="..."',"Element id"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),le.appendChild(d)}),ge.appendChild(le),ge.appendChild(T("Basic hero",'[hero title="Welcome" tagline="Build something great"][/hero]',null)),ge.appendChild(T("Gradient with body content",`[hero title="Get Started" tagline="Everything you need." size="lg" variant="gradient-blue" align="center"]
|
|
50
50
|
Some introductory **Markdown** content here.
|
|
51
|
-
[/hero]`,null)),ge.appendChild(
|
|
51
|
+
[/hero]`,null)),ge.appendChild(T("Background image with overlay",'[hero title="Our Story" image="/media/hero.jpg" overlay="dark" size="full"][/hero]',"Combine image + overlay for text legibility over photos.")),fe.appendChild(ge);const ie=document.createElement("div");ie.appendChild(Q("Interactive Components")),ie.appendChild(G("Tabs, accordion, carousel, and countdown \u2014 no plugin required.")),ie.appendChild(T("Tabs",`[tabs]
|
|
52
52
|
[tab title="First"]Content **A**[/tab]
|
|
53
53
|
[tab title="Second"]Content **B**[/tab]
|
|
54
|
-
[/tabs]`,'Add style="pills" for pill-style navigation.')),
|
|
54
|
+
[/tabs]`,'Add style="pills" for pill-style navigation.')),ie.appendChild(T("Accordion",`[accordion]
|
|
55
55
|
[item title="Question 1"]Answer here.[/item]
|
|
56
56
|
[item title="Question 2"]Answer here.[/item]
|
|
57
|
-
[/accordion]`,'Add multiple="true" to allow several panels open at once.')),
|
|
57
|
+
[/accordion]`,'Add multiple="true" to allow several panels open at once.')),ie.appendChild(T("Accordion \u2014 collection-bound",'[collection slug="faq" display="accordion" title-field="title" body-field="description" /]',"Renders collection entries as accordion items. Use Insert \u2192 Accordion for a guided dialog.")),ie.appendChild(T("Carousel",`[carousel autoplay="true" interval="5000"]
|
|
58
58
|
[slide title="Slide 1"]Description[/slide]
|
|
59
59
|
[slide image="/media/photo.jpg" title="Slide 2"]Caption[/slide]
|
|
60
|
-
[/carousel]`,'Omit autoplay for a manual carousel. loop="false" disables wrapping.')),
|
|
60
|
+
[/carousel]`,'Omit autoplay for a manual carousel. loop="false" disables wrapping.')),ie.appendChild(T("Countdown (to date)",'[countdown to="2026-12-31" format="DD:HH:mm:ss" /]',null)),ie.appendChild(T("Countdown (duration)",'[countdown duration="300" format="mm:ss" /]',"duration is in seconds. format options: mm:ss \xB7 HH:mm:ss \xB7 DD:HH:mm:ss")),se.appendChild(ie);const ye=document.createElement("div");ye.appendChild(Q("Timeline")),ye.appendChild(G("Renders a Domma Progression component with event items."));const Pe=document.createElement("table");Pe.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['layout="vertical|centred|horizontal"',"[timeline] \u2014 layout orientation (default: vertical)"],['theme="minimal|corporate|modern"',"[timeline] \u2014 visual theme (default: minimal)"],['mode="timeline|roadmap"',"[timeline] \u2014 display mode (default: timeline)"],['class="..."',"[timeline] \u2014 extra CSS classes"],['id="..."',"[timeline] \u2014 element id"],['title="..."',"[event] \u2014 event heading"],['date="..."',"[event] \u2014 display date string"],['status="planned|in-progress|completed|blocked"',"[event] \u2014 progress status"],['icon="..."',"[event] \u2014 Domma icon name"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),Pe.appendChild(d)}),ye.appendChild(Pe),ye.appendChild(T("Vertical timeline",`[timeline layout="vertical" theme="modern"]
|
|
61
61
|
[event title="Kickoff" date="Jan 2025" status="completed" icon="flag"]
|
|
62
62
|
Project launched.
|
|
63
63
|
[/event]
|
|
64
64
|
[event title="Beta" date="Jun 2025" status="in-progress" icon="rocket"]
|
|
65
65
|
In active development.
|
|
66
66
|
[/event]
|
|
67
|
-
[/timeline]`,null)),
|
|
67
|
+
[/timeline]`,null)),se.appendChild(ye);const Fe=document.createElement("div");Fe.appendChild(Q("Embedding a Form"));const e=document.createElement("table");e.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['name="..."',"Form slug (required). Also accepted as slug=."],['class="..."',"Extra CSS classes on the wrapper div"],['id="..."',"id attribute on the wrapper div"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),e.appendChild(d)}),Fe.appendChild(e),Fe.appendChild(T("Basic",'[form name="contact" /]',"Forms are managed under Forms in the sidebar.")),Fe.appendChild(T("With wrapper styling",'[form name="newsletter" class="mt-4" id="newsletter-form" /]',null)),ve.appendChild(Fe);const t=document.createElement("div");t.appendChild(Q("Displaying a Collection"));const n=document.createElement("pre");n.style.cssText=re+"display:block;padding:.5rem .75rem;white-space:pre;overflow-x:auto;",n.textContent='[collection slug="enquiries" display="table" /]',t.appendChild(n);const i=[["slug","Required. The collection slug."],["display","table (default), cards, or list."],["fields","Comma-separated field keys to show. Defaults to all."],["limit","Maximum number of entries to display."],["sort","Field key to sort by."],["order","asc or desc (default asc)."],["title-field","Field used as the card/list title (cards + list)."],["columns","Grid columns for cards display (2\u20134, default 3)."],["search","true/false \u2014 enable search in table mode (default true)."],["sortable","true/false \u2014 enable column sorting in table mode (default true)."],["exportable","true/false \u2014 show CSV export button in table mode (default false)."],["page-size","Rows per page in table mode (default 25)."],["empty","Text shown when there are no entries."],["cta","Action slug: enables per-entry CTA buttons."],["cta-label",'CTA button label (default: "Run").'],["cta-icon","CTA button icon name."],["cta-style","CTA button variant (default: primary)."],["cta-confirm","CTA confirmation prompt text."],["class","Extra CSS classes on the wrapper div."],["id","id attribute on the wrapper div."]],a=document.createElement("table");a.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",i.forEach(([h,y])=>{const d=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;width:35%;",s.appendChild(H(h));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=y,d.appendChild(s),d.appendChild(o),a.appendChild(d)}),t.appendChild(a),t.appendChild(G("Table display uses Domma Table \u2014 search, sort, pagination, column selector, and CSV export are all built in. Cards and lists are static.")),ve.appendChild(t);const m=document.createElement("div");m.appendChild(Q("View \u2014 Pro")),m.appendChild(G("Renders a Collection with full filtering, pagination, and display options. Requires a Pro MongoDB collection."));const w=document.createElement("table");w.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["slug","Required. The collection slug."],["display","table (default), cards, or list."],["limit","Maximum number of entries to display."],["fields","Comma-separated field keys to show."],["title-field","Field used as the card/list title."],["columns","Grid columns for cards display (2\u20134, default 3)."],["empty","Text shown when there are no entries."],["class","Extra CSS classes on the wrapper div."],["id","id attribute on the wrapper div."]].forEach(([h,y])=>{const d=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;width:35%;",s.appendChild(H(h));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=y,d.appendChild(s),d.appendChild(o),w.appendChild(d)}),m.appendChild(w),m.appendChild(T("Table display",'[view slug="products" display="table" limit="50" /]',null)),m.appendChild(T("Cards display",'[view slug="team" display="cards" columns="3" title-field="name" /]',null)),ve.appendChild(m);const b=document.createElement("div");b.appendChild(Q("CTA \u2014 Pro")),b.appendChild(G("Renders an action button that triggers a Pro Action against an entry. Requires the Pro Actions feature."));const k=document.createElement("table");k.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["action","Required. The action slug."],["entry","Required. The entry id to act on."],["style","Button variant (default: primary)."],["icon","Domma icon name for the button."],["size","Button size (sm, lg)."],["confirm","Confirmation prompt text before running."],["label","Self-closing only: button label text."]].forEach(([h,y])=>{const d=document.createElement("tr"),s=document.createElement("td");s.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;width:35%;",s.appendChild(H(h));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=y,d.appendChild(s),d.appendChild(o),k.appendChild(d)}),b.appendChild(k),b.appendChild(T("Wrapping form",'[cta action="approve" entry="abc123" style="success" confirm="Approve this entry?"]Approve[/cta]',null)),b.appendChild(T("Self-closing",'[cta action="archive" entry="abc123" icon="archive" label="Archive" /]',null)),ve.appendChild(b);const r=document.createElement("div");r.appendChild(Q("Effects")),r.appendChild(G("Shortcodes for scroll-triggered animations, counters, typewriter text, and more. Requires the Domma Effects plugin."));const f=[['[reveal animation="fade"]...[/reveal]',"Fade/slide/zoom on scroll"],["[breathe]...[/breathe]","Continuous gentle scale loop"],["[pulse]...[/pulse]","Repeating scale pulse"],["[shake]...[/shake]","One-shot shake"],['[scribe speed="50"]...[/scribe]',"Typewriter \u2014 simple mode (text typed letter by letter)"],['[scribe loop="true"][render]Text[/render][wait]1500[/wait][undo /][/scribe]',"Typewriter \u2014 script mode (sequenced render/wait/undo actions)"],["[scramble]...[/scramble]","Character-scramble reveal"],['[counter to="100" /]',"Animated number counter (self-closing)"],["[ripple]...[/ripple]","Click-triggered ripple"],['[twinkle count="50"]...[/twinkle]',"Particle/star overlay"],['[animate type="fade-in-up"]...[/animate]',"CSS-only animation (no plugin needed)"],['[ambient type="aurora"]...[/ambient]',"CSS-only animated background"],['[firework type="burst" colour="rainbow" /]',"CSS firework (self-closing)"],["[fireworks]...[/fireworks]","Fireworks display container"],['[celebrate theme="auto" /]',"Seasonal canvas celebration (auto-detects date)"],["[christmas /]","Christmas \u2014 snowflakes, trees, snowmen, sleigh"],["[halloween /]","Halloween \u2014 pumpkins, ghosts, bats, spiders"],["[st-patricks /]","St Patrick's Day \u2014 shamrocks, coins, rainbows, leprechaun"],["[valentines /]","Valentine's Day \u2014 hearts, roses"],["[guy-fawkes /]","Guy Fawkes \u2014 fireworks, sparkles"],["[st-andrews /]","St Andrew's Day \u2014 heather, thistles"],["[st-davids /]","St David's Day \u2014 daffodils, dragons"],["[st-georges /]","St George's Day \u2014 roses, flags"]],x=document.createElement("table");x.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",f.forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),x.appendChild(d)}),r.appendChild(x),r.appendChild(T("Scribe script \u2014 looping multi-phrase typewriter",`[scribe loop="true" loop-delay="2000" delete-speed="20"]
|
|
68
68
|
[render]We build things that matter.[/render]
|
|
69
69
|
[wait]1200[/wait]
|
|
70
70
|
[undo all="true" /]
|
|
71
71
|
[render]We design for humans.[/render]
|
|
72
72
|
[wait]1200[/wait]
|
|
73
73
|
[undo all="true" /]
|
|
74
|
-
[/scribe]`,'Use [render]...[/render] to type text, [wait]Ms[/wait] to pause, and [undo /] to delete. loop="true" replays the sequence. Only [render], [wait], and [undo] shortcodes are parsed \u2014 plain text between actions is ignored.')),
|
|
74
|
+
[/scribe]`,'Use [render]...[/render] to type text, [wait]Ms[/wait] to pause, and [undo /] to delete. loop="true" replays the sequence. Only [render], [wait], and [undo] shortcodes are parsed \u2014 plain text between actions is ignored.')),r.appendChild(T("Christmas",'[christmas intensity="medium" snowmen="off" trees="off" wreaths="off" northStars="off" sleigh="off" train="off" elf="off" robin="off" firework="off" /]',"intensity: light | medium | heavy. Count-based (off disables entirely): snowmen, trees, wreaths, northStars. Probability-based specials (off prevents spawning): sleigh, train, elf, robin, firework. Snowflakes always fall.")),r.appendChild(T("Halloween",'[halloween intensity="medium" gravestones="off" jackOLanterns="off" spiders="off" scarecrows="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): gravestones, jackOLanterns, spiders, scarecrows, twinklingStars. Particles: bats, ghosts, pumpkins (always on). Fixed decorations: haunted-house, cauldron (always present).")),r.appendChild(T("St Patrick's Day",'[st-patricks intensity="medium" pots="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): pots (pots of gold), twinklingStars. Particles: shamrocks, clover petals, gold coins, sparkles (always on). Fixed decorations: rainbow, harp, moon. Leprechaun appears randomly \u2014 more likely at higher intensity.")),r.appendChild(T("Valentine's Day",'[valentines intensity="medium" garlands="off" butterflies="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): garlands (heart garlands), butterflies. Particles: hearts, rose petals, sparkles, lips (always on). Fixed decorations: envelopes (always present). Cupid appears randomly \u2014 more likely at higher intensity.")),r.appendChild(T("Guy Fawkes Night",'[guy-fawkes intensity="medium" bonfires="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): bonfires. Particles: embers, fireworks, sparks, rockets, bursts, trails (always on). Fixed decorations: guy-effigy, catherine-wheel, roman-candle, sparkler-bundle, moon. Starts at 25% particle density and builds up gradually.")),r.appendChild(T("St Andrew's Day",'[st-andrews intensity="medium" thistles="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): thistles, twinklingStars. Particles: heather petals, saltire sparkles (always on). Fixed decorations: bagpiper, saltire-flag, tartan-pattern, highland-scene (always present). Bagpiper probability increases with intensity.")),r.appendChild(T("St David's Day",'[st-davids intensity="medium" daffodilFields="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): daffodilFields, twinklingStars. Particles: daffodil petals, spring sparkles (always on). Fixed decorations: welsh-dragon, harp, leek-bundle, flag (always present). Flying dragon appears randomly \u2014 more likely at higher intensity.")),r.appendChild(T("St George's Day",'[st-georges intensity="medium" roses="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): roses (English roses), twinklingStars. Particles: rose petals, Tudor roses, oak leaves, sparkles (always on). Fixed decorations: st-georges-cross, dragon, shield, castle (always present). Knight appears randomly \u2014 more likely at higher intensity.")),r.appendChild(G("Enable the Domma Effects plugin to activate these shortcodes on your site.")),we.appendChild(r);const g=document.createElement("div");g.appendChild(Q("Tables")),g.appendChild(G("Wrap a standard Markdown (GFM) table with Domma CSS classes and responsive horizontal scrolling."));const p=document.createElement("table");p.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['striped="true"',"Alternate row background (.table-striped)"],['bordered="true"',"Borders on all cells (.table-bordered)"],['compact="true"',"Reduced cell padding (.table-compact)"],['caption="..."',"Caption text above the table"],['class="..."',"Extra CSS classes appended to .table"],['id="..."',"id attribute on the <table> element"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),p.appendChild(d)}),g.appendChild(p),g.appendChild(T("Striped + bordered table",`[table striped="true" bordered="true" caption="Product Pricing"]
|
|
75
75
|
| Product | Price |
|
|
76
76
|
| ------- | ----: |
|
|
77
77
|
| Widget | $9.99 |
|
|
78
78
|
| Gadget | $14.99 |
|
|
79
|
-
[/table]`,"The inner content must be a valid GFM Markdown table. The shortcode adds Domma CSS classes and wraps in a responsive scroll container.")),
|
|
79
|
+
[/table]`,"The inner content must be a valid GFM Markdown table. The shortcode adds Domma CSS classes and wraps in a responsive scroll container.")),se.appendChild(g);const c=document.createElement("div");c.appendChild(Q("Slideover")),c.appendChild(G("A trigger button that opens a slide-in panel with Markdown content. No plugin required."));const v=document.createElement("table");v.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['title="..."',"Panel header text"],['trigger="..."','Button label (default: "Open")'],['size="sm|md|lg"',"Panel width (default: md)"],['position="right|left"',"Slide direction (default: right)"]].forEach(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),v.appendChild(d)}),c.appendChild(v),c.appendChild(T("Example",`[slideover title="More Info" trigger="Read more" size="md"]
|
|
80
80
|
## Details
|
|
81
81
|
Markdown content here.
|
|
82
|
-
[/slideover]`,"Nested [card] and [grid] shortcodes work inside the slideover body.")),
|
|
82
|
+
[/slideover]`,"Nested [card] and [grid] shortcodes work inside the slideover body.")),se.appendChild(c);const B=document.createElement("div");B.appendChild(Q("DConfig \u2014 Declarative Behaviour")),B.appendChild(G("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.")),B.appendChild(T("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.')),B.appendChild(T("Inline shortcode syntax",`[dconfig]
|
|
83
83
|
{ "#my-btn": { "events": { "click": { "target": "#panel", "toggleClass": "hidden" } } } }
|
|
84
|
-
[/dconfig]`,null)),
|
|
85
|
-
`).map(
|
|
84
|
+
[/dconfig]`,null)),we.appendChild(B);const L=document.createElement("div");L.appendChild(Q("CSS Editor")),L.appendChild(G("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 N=document.createElement("table");N.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(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),N.appendChild(d)}),L.appendChild(N),we.appendChild(L);const u=document.createElement("div");u.appendChild(Q("Colour Picker")),u.appendChild(G("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.")),we.appendChild(u);const C=document.createElement("div");C.appendChild(Q("Keyboard Shortcuts"));const z=document.createElement("table");z.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(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),z.appendChild(d)}),C.appendChild(z),$e.appendChild(C);const A=document.createElement("div");A.appendChild(Q("Tips"));const U=document.createElement("table");U.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(([h,y])=>{const d=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(H(h));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=y,d.appendChild(s),d.appendChild(o),U.appendChild(d)}),A.appendChild(U),A.appendChild(G("Most shortcodes accept a class attribute for custom styling.")),$e.appendChild(A),l.setContent(Ie),l.open(),E.tabs(De),I.scan(Ie)}function lt(l,re){const de=l.find("#history-tab").get(0),H=l.find("#version-list").get(0),Q=l.find("#version-compare").get(0),Ie=l.find("#version-compare-old").get(0),De=l.find("#version-compare-new").get(0),Me=l.find("#version-compare-label").get(0),Y=l.find("#version-compare-back-btn").get(0),Le=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 se=!1,ve=null;function we(){H.style.display="",Q.style.display="none",ve=null}function qe(){H.style.display="none",Q.style.display=""}async function me(){H.textContent="";const K=document.createElement("p");K.style.color="var(--dm-text-muted)",K.textContent="Loading\u2026",H.appendChild(K);let ae;try{ae=(await _.versions.list(re)).versions||[]}catch(V){H.textContent="";const M=document.createElement("p");M.style.color="var(--dm-text-danger,#e55)",M.textContent="Failed to load versions: "+V.message,H.appendChild(M);return}if(H.textContent="",fe.style.display="none",!ae.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.",H.appendChild(V);return}const he=document.createElement("table");he.style.cssText="width:100%;border-collapse:collapse;font-size:.875rem;";const te=document.createElement("thead"),G=document.createElement("tr"),T=document.createElement("th");T.style.cssText="padding:.5rem .75rem;width:2rem;border-bottom:1px solid var(--dm-border);";const ne=document.createElement("input");ne.type="checkbox",ne.setAttribute("aria-label","Select all versions"),T.appendChild(ne),G.appendChild(T),["Date","Author","Type","Label","Actions"].forEach(V=>{const M=document.createElement("th");M.style.cssText="text-align:left;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border);font-size:.8rem;color:var(--dm-text-muted);",M.textContent=V,G.appendChild(M)}),te.appendChild(G),he.appendChild(te);const ce=[];function Ne(){const V=ce.some(pe=>pe.checked),M=ce.length>0&&ce.every(pe=>pe.checked);fe.style.display=V?"":"none",ne.checked=M,ne.indeterminate=V&&!M}ne.addEventListener("change",()=>{ce.forEach(V=>{V.checked=ne.checked}),Ne()});const Ae=document.createElement("tbody");ae.forEach(V=>{const M=document.createElement("tr");M.style.borderBottom="1px solid var(--dm-border)";const pe=document.createElement("td");pe.style.padding=".5rem .75rem";const Ee=document.createElement("input");Ee.type="checkbox",Ee.value=V.filename,Ee.addEventListener("change",Ne),pe.appendChild(Ee),ce.push(Ee);const ke=document.createElement("td");ke.style.padding=".5rem .75rem",ke.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 Te=document.createElement("td");Te.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,Te.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 le=document.createElement("button");le.className="btn btn-ghost btn-xs",le.style.marginRight=".4rem",le.textContent="Compare",le.addEventListener("click",async()=>{try{const ye=await _.versions.get(re,V.filename);Ie.textContent=ye.content,De.textContent=l.find("#markdown-editor").get(0).value,Me.textContent=D(V.createdAt).format("D MMM YYYY, HH:mm")+(V.label?` \u2014 ${V.label}`:""),ve=V.filename,qe()}catch(ye){E.toast("Failed to load version: "+ye.message,{type:"error"})}});const ie=document.createElement("button");ie.className="btn btn-ghost btn-xs",ie.style.color="var(--dm-text-danger,#e55)",ie.textContent="Delete",ie.addEventListener("click",async()=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await _.versions.delete(re,V.filename),E.toast("Version deleted.",{type:"success"}),await me()}catch(ye){E.toast("Failed to delete: "+ye.message,{type:"error"})}}),ge.appendChild(le),ge.appendChild(ie),M.appendChild(pe),M.appendChild(ke),M.appendChild(ue),M.appendChild(Te),M.appendChild(ze),M.appendChild(ge),Ae.appendChild(M)}),he.appendChild(Ae),H.appendChild(he)}de.addEventListener("click",async()=>{se||(se=!0,await me())}),Y.addEventListener("click",()=>{we()}),Le.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 _.versions.restore(re,ve),E.toast("Page restored. Reloading editor\u2026",{type:"success"}),R.navigate("/pages"),setTimeout(()=>R.navigate(`/pages/edit${re}`),300)}catch(K){E.toast("Restore failed: "+K.message,{type:"error"})}}),fe.addEventListener("click",async()=>{const K=[...H.querySelectorAll("tbody input[type=checkbox]:checked")].map(ae=>ae.value);if(!(!K.length||!await E.confirm(`Delete ${K.length} version${K.length>1?"s":""}? This cannot be undone.`)))try{await _.versions.bulkDelete(re,K),E.toast(`${K.length} version${K.length>1?"s":""} deleted.`,{type:"success"}),await me()}catch(ae){E.toast("Delete failed: "+ae.message,{type:"error"})}}),$e.addEventListener("click",()=>{const K=E.modal({title:"Save Named Version"}),ae=document.createElement("div");ae.style.padding="1rem";const he=document.createElement("label");he.className="form-label",he.textContent="Version Label";const te=document.createElement("input");te.type="text",te.className="form-input",te.placeholder="e.g. Initial design, Before restructure",te.style.marginBottom=".75rem";const G=document.createElement("button");G.className="btn btn-primary",G.textContent="Save Version",G.addEventListener("click",async()=>{const T=te.value.trim();try{await _.versions.create(re,T||null),E.toast("Named version saved.",{type:"success"}),K.close(),se=!1,de.classList.contains("active")&&(se=!0,await me())}catch(ne){E.toast("Failed to save version: "+ne.message,{type:"error"})}}),ae.appendChild(he),ae.appendChild(te),ae.appendChild(G),K.element.appendChild(ae),K.open(),setTimeout(()=>te.focus(),100)})}let Re=!1,Ge=null,Ye=!1;function it(l){return l.split(`
|
|
85
|
+
`).map(re=>re.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,
|
|
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,``),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,"&").replace(/</g,"<").replace(/>/g,">"));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,""");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
|
-
`;return
|
|
91
|
-
`}),
|
|
88
|
+
`)}const je="editor_prefs";function Je(){return S.get(je)||{viewMode:"split",fullscreen:!1}}function Qe(l,re){const de=Je();de[l]=re,S.set(je,de)}export const pageEditorView={templateUrl:"/admin/js/templates/page-editor.html",async onMount(l){const re=window.location.hash.match(/#\/pages\/edit(\/.*)/),de=re?re[1]:null,H=!!de,Q=E.loader(l.get(0),{type:"dots"}),Ie=[_.layouts.get().catch(()=>({})),_.settings.get().catch(()=>({}))];H&&(Ie.push(_.pages.get(de).catch(()=>null)),Ie.push(_.pages.list().catch(()=>[])));const[De,Me,Y,Le]=await Promise.all(Ie);Q.destroy(),tt(l.find("#field-theme").get(0),{includeDefault:!0});const $e=Me?.layoutOptions?.spacerSize??40;if(H&&!Y){E.toast("Page not found.",{type:"error"}),R.navigate("/pages");return}l.find("#editor-title").text(H?`Edit Page \u2014 ${Y.title||de}`:"New Page"),H&&l.find("#page-url-path").val(de),Y&&(l.find("#field-title").val(Y.title||""),l.find("#field-description").val(Y.description||""),l.find("#field-status").val(Y.status||"draft"),l.find("#field-sort-order").val(Y.sortOrder??99),l.find("#field-show-in-nav").prop("checked",!!Y.showInNav),l.find("#field-sidebar").prop("checked",!!Y.sidebar),l.find("#field-show-breadcrumbs").prop("checked",Y.breadcrumbs!==!1),l.find("#field-bundled").prop("checked",!!Y.bundled),l.find("#field-category").val(Y.category||""),l.find("#field-visibility").val(Y.visibility||"public"),l.find("#field-theme").val(Y.theme||""),l.find("#field-seo-title").val(Y.seo?.title||""),l.find("#field-seo-desc").val(Y.seo?.description||""),Y.dconfig&&l.find("#field-dconfig").val(JSON.stringify(Y.dconfig,null,2)));const fe=l.find("#quick-switch");H&&Array.isArray(Le)&&Le.length&&([...Le].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 se=await _.pages.tags().catch(()=>[]),ve=l.find("#field-tags").get(0),we=ve?E.pillbox(ve,{data:se,value:Y?.tags||[],creatable:!0,searchable:!0,placeholder:"Add tag\u2026"}):null,qe=l.find("#field-layout").empty();if(Object.entries(De).forEach(([e,t])=>{const n=(Y?.layout||"default")===e?"selected":"";qe.append(`<option value="${e}" ${n}>${t.label||e}</option>`)}),H){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 n=l.find("#history-tab").get(0);n.style.display=""}if(E.tabs(l.find("#editor-meta-tabs").get(0)),H){const e=l.find("#live-preview-tab").get(0),t=l.find("#live-preview-frame").get(0);let n=!1;e.addEventListener("click",function(){n||(t.src=de,n=!0)}),lt(l,de)}const me=l.find("#markdown-editor"),K=l.find("#markdown-preview");Y&&me.val(Y.content||"");let ae=!1,he="";_.settings.getCustomCss().then(({css:e})=>{if(he=e||"",!he)return;const t=document.createElement("style");t.id="preview-custom-css",t.textContent=he,K.get(0).parentNode.insertBefore(t,K.get(0))}).catch(()=>{});let te=!1;const G=me.get(0),T=document.createElement("div");T.className="editor-line-numbers editor-line-numbers--foldable",G.parentElement.insertBefore(T,G);const ne=nt(G,T,{onFoldChange:()=>{}});ne.setGuard(e=>{te=e});function ce(){const e=l.find("#css-editor").get(0);if(!e)return;const t=e.value.split(`
|
|
89
|
+
`);for(;T.firstChild;)T.removeChild(T.firstChild);t.forEach((n,i)=>{const a=document.createElement("span");a.className="editor-line-number-row";const m=document.createElement("span");m.className="fold-toggle fold-toggle--empty";const w=document.createElement("span");w.className="editor-line-num",w.textContent=String(i+1),a.appendChild(m),a.appendChild(w),T.appendChild(a)}),T.scrollTop=e.scrollTop}{const e=l.find("#css-editor").get(0);e&&e.addEventListener("scroll",()=>{T.scrollTop=e.scrollTop})}const Ne=()=>{ne.refresh(),T.scrollTop=G.scrollTop};G.addEventListener("input",Ne),G.addEventListener("scroll",()=>{T.scrollTop=G.scrollTop});let Ae=null;const V=()=>{clearTimeout(Ae),Ae=setTimeout(async()=>{const e=ne.getUnfoldedContent();try{const{html:t}=await _.pages.preview(e);K.html(t,{safe:!1}),I.scan(K.get(0)),K.get(0).querySelectorAll(".tabs").forEach(n=>Domma.elements.tabs(n))}catch{window.marked&&K.html(marked.parse(e))}},400)},M=et(me,l.find("#editor-toolbar"),{spacerDefault:$e});let pe=!1,Ee="split",ke=null;const ue=document.createElement("button");ue.className="editor-view-btn",ue.type="button";const Te=document.createElement("span");Te.setAttribute("data-icon","css-code"),ue.appendChild(Te);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 le=document.createElement("button");le.className="editor-view-btn",le.type="button",le.textContent="\u25BC\u25BC",le.style.cssText="font-size:9px;letter-spacing:-1px;";const ie=l.find(".editor-toolbar-right").get(0);ie.prepend(le),ie.prepend(be),ie.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(le,{content:"Fold / unfold all shortcodes",position:"top"}),be.addEventListener("click",()=>{const e=me.get(0),t=e.selectionStart,n=it(ne.getUnfoldedContent());ne.unfoldAll(),te=!0,e.value=n,te=!1,e.selectionStart=e.selectionEnd=Math.min(t,n.length),e.dispatchEvent(new Event("input")),ne.refresh(),E.toast("Markdown formatted.",{type:"success"})}),le.addEventListener("click",()=>{ge?(ne.unfoldAll(),le.textContent="\u25BC\u25BC",le.classList.remove("active")):(ne.foldAll(),le.textContent="\u25B6\u25B6",le.classList.add("active")),ge=!ge});const ye=document.createElement("span");ye.className="editor-toolbar-sep",ie.insertBefore(ye,ie.children[3]),ue.addEventListener("click",()=>{pe=!pe;const e=l.find("#markdown-editor"),t=l.find("#css-editor"),n=l.find("#editor-body");if(pe){const i=l.find(".editor-view-btn[data-mode].active").get(0);Ee=i?i.getAttribute("data-mode"):"split",l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find('.editor-view-btn[data-mode="split"]').addClass("active"),n.removeClass("editor-mode-write editor-mode-preview").addClass("editor-mode-split"),e.hide(),t.show(),ae||(t.val(he),ae=!0,Xe(t.get(0))),ce(),ue.classList.add("active")}else l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find(`.editor-view-btn[data-mode="${Ee}"]`).addClass("active"),n.removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${Ee}`),t.hide(),e.show(),ne.refresh(),ue.classList.remove("active")});const Pe=Je();Pe.viewMode&&Pe.viewMode!=="split"&&(l.find(".editor-view-btn[data-mode]").removeClass("active"),l.find(`.editor-view-btn[data-mode="${Pe.viewMode}"]`).addClass("active"),l.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${Pe.viewMode}`)),Pe.fullscreen&&l.find(".editor-card").addClass("editor-fullscreen"),l.find("#css-editor").on("input",()=>{ce(),clearTimeout(ke),ke=setTimeout(()=>{let e=document.getElementById("preview-custom-css");e||(e=document.createElement("style"),e.id="preview-custom-css",K.get(0).parentNode.insertBefore(e,K.get(0))),e.textContent=l.find("#css-editor").val()},400)}),M.onLink(async e=>{const t=(await _.pages.list().catch(()=>[])).map(c=>({label:c.title||c.urlPath,value:c.urlPath})),n=document.createElement("div");n.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const i=document.createElement("label");i.className="form-label",i.textContent="URL";const a=document.createElement("input");a.type="text",a.className="form-input",a.placeholder="/about or https://example.com";const m=e.value.substring(e.selectionStart,e.selectionEnd);m&&m.startsWith("/")&&(a.value=m),n.appendChild(i),n.appendChild(a);const w=document.createElement("label");w.className="form-label",w.textContent="Link text";const b=document.createElement("input");b.type="text",b.className="form-input",b.placeholder="Display text",m&&!m.startsWith("/")&&(b.value=m),n.appendChild(w),n.appendChild(b);const k=document.createElement("label");k.className="form-label",k.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;";const r=document.createElement("input");r.type="checkbox",r.style.cssText="width:1rem;height:1rem;cursor:pointer;",k.appendChild(r),k.appendChild(document.createTextNode("Display as button")),n.appendChild(k);const f=document.createElement("label");f.className="form-label",f.textContent="Button colour",f.style.display="none";const x=document.createElement("select");x.className="form-select",x.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(([c,v])=>{const B=document.createElement("option");B.value=c,B.textContent=v,x.appendChild(B)}),n.appendChild(f),n.appendChild(x),r.addEventListener("change",()=>{const c=r.checked;f.style.display=c?"":"none",x.style.display=c?"":"none"});const g=document.createElement("button");g.type="button",g.className="btn btn-primary",g.textContent="Insert Link",n.appendChild(g);const p=E.slideover({title:"Insert Link",size:"sm",position:"right"});p.element.appendChild(n),p.open(),requestAnimationFrame(()=>{E.autocomplete(a,{data:t,minChars:1,onSelect:c=>{a.value=c.value,b.value||(b.value=c.label)}}),a.focus()}),g.addEventListener("click",()=>{const c=a.value.trim(),v=b.value.trim();if(!c)return;p.close();const B=r.checked?`[button href="${c}" variant="${x.value}"]${v||c}[/button]`:`[${v||c}](${c})`,L=e.selectionStart,N=e.selectionEnd;e.value=e.value.substring(0,L)+B+e.value.substring(N),e.selectionStart=e.selectionEnd=L+B.length,e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onImage(async e=>{const t=(await _.media.list().catch(()=>[])).filter(a=>/\.(png|jpe?g|gif|webp|svg)$/i.test(a.name)),n=document.createElement("div");if(n.className="media-picker-grid",t.length)t.forEach(a=>{const m=document.createElement("div");m.className="media-picker-item",m.dataset.url=a.url;const w=document.createElement("img");w.src=a.url,w.alt=a.name;const b=document.createElement("span");b.textContent=a.name,m.appendChild(w),m.appendChild(b),n.appendChild(m)});else{const a=document.createElement("p");a.className="text-muted p-3",a.textContent="No images uploaded yet.",n.appendChild(a)}const i=E.slideover({title:"Insert Image",size:"lg",position:"right"});i.element.appendChild(n),$(i.element).on("click",".media-picker-item",function(){const a=$(this).data("url"),m=$(this).find("span").text();xe(e,``),i.close(),me.get(0).dispatchEvent(new Event("input",{bubbles:!0}))}),i.open()}),M.onCollection(async e=>{const[t,n]=await Promise.all([_.collections.list().catch(()=>[]),_.blocks.list().catch(()=>[])]),i=document.createElement("div");i.style.cssText="padding:1rem;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;",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;",w=document.createElement("div"),b=document.createElement("label");b.style.cssText=a,b.textContent="Collection";const k=document.createElement("select");if(k.style.cssText=m,t.length)t.forEach(O=>{const X=document.createElement("option");X.value=O.slug,X.textContent=O.title||O.slug,k.appendChild(X)});else{const O=document.createElement("option");O.value="",O.textContent="No collections found",k.appendChild(O)}w.appendChild(b),w.appendChild(k),i.appendChild(w);const r=document.createElement("div"),f=document.createElement("label");f.style.cssText=a,f.textContent="Display";const x=document.createElement("select");x.style.cssText=m,["table","cards","list","block"].forEach(O=>{const X=document.createElement("option");X.value=O,X.textContent=O.charAt(0).toUpperCase()+O.slice(1),x.appendChild(X)}),r.appendChild(f),r.appendChild(x),i.appendChild(r);const g=document.createElement("div");g.style.display="none";const p=document.createElement("label");p.style.cssText=a,p.textContent="Columns (2\u20134)";const c=document.createElement("input");c.type="number",c.min="2",c.max="4",c.value="3",c.style.cssText=m,g.appendChild(p),g.appendChild(c),i.appendChild(g);const v=document.createElement("div");v.style.display="none";const B=document.createElement("label");B.style.cssText=a,B.textContent="Block template";const L=document.createElement("select");if(L.style.cssText=m,n.length)n.forEach(O=>{const X=document.createElement("option");X.value=O.name??O,X.textContent=O.name??O,L.appendChild(X)});else{const O=document.createElement("option");O.value="",O.textContent="No block templates found",L.appendChild(O)}v.appendChild(B),v.appendChild(L),i.appendChild(v);const N=document.createElement("div"),u=document.createElement("label");u.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,u.appendChild(C),u.appendChild(document.createTextNode("Enable search")),N.appendChild(u),i.appendChild(N);const z=document.createElement("div"),A=document.createElement("label");A.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const U=document.createElement("input");U.type="checkbox",U.checked=!0,A.appendChild(U),A.appendChild(document.createTextNode("Sortable columns")),z.appendChild(A),i.appendChild(z);const h=document.createElement("div"),y=document.createElement("label");y.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const d=document.createElement("input");d.type="checkbox",d.checked=!1,y.appendChild(d),y.appendChild(document.createTextNode("CSV export")),h.appendChild(y),i.appendChild(h);const s=document.createElement("div"),o=document.createElement("label");o.style.cssText=a,o.textContent="Rows per page";const j=document.createElement("input");j.type="number",j.min="5",j.max="100",j.value="25",j.style.cssText=m,s.appendChild(o),s.appendChild(j),i.appendChild(s);const Z=document.createElement("div"),oe=document.createElement("label");oe.style.cssText=a,oe.textContent="Limit (optional)";const ee=document.createElement("input");ee.type="number",ee.placeholder="All",ee.style.cssText=m,Z.appendChild(oe),Z.appendChild(ee),i.appendChild(Z);const F=document.createElement("button");F.type="button",F.className="btn btn-primary",F.textContent="Insert",i.appendChild(F);const P=[N,z,h,s],q=()=>{const O=x.value,X=O==="table";P.forEach(Se=>{Se.style.display=X?"":"none"}),g.style.display=O==="cards"||O==="block"?"":"none",v.style.display=O==="block"?"":"none"};x.addEventListener("change",q),q();const J=E.slideover({title:"Insert Collection",size:"sm",position:"right"});J.element.appendChild(i),J.open(),F.addEventListener("click",()=>{const O=k.value;if(!O)return;const X=x.value;let Se=`[collection slug="${O}" display="${X}"`;if(X==="cards"&&(Se+=` columns="${c.value}"`),X==="block"){const We=L.value;We&&(Se+=` block="${We}"`);const _e=c.value.trim();_e&&(Se+=` cols="${_e}"`)}X==="table"&&!C.checked&&(Se+=' search="false"'),X==="table"&&!U.checked&&(Se+=' sortable="false"'),X==="table"&&d.checked&&(Se+=' exportable="true"'),X==="table"&&j.value!=="25"&&(Se+=` page-size="${j.value}"`);const Ve=ee.value.trim();Ve&&(Se+=` limit="${Ve}"`),Se+=" /]",J.close(),xe(e,Se),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onBlock(async e=>{let t=[];try{t=await _.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 n=E.slideover({title:"Insert Block",size:"lg",position:"right"}),i=document.createElement("div");i.style.cssText="display:flex;gap:1rem;min-height:320px;";const a=document.createElement("div");a.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 w=document.createElement("select");w.className="form-select";const b=document.createElement("option");b.value="",b.textContent="\u2014 select a template \u2014",w.appendChild(b),t.forEach(L=>{const N=document.createElement("option");N.value=L.name,N.textContent=L.name,w.appendChild(N)}),a.appendChild(m),a.appendChild(w);const k=document.createElement("div");k.style.cssText="display:flex;flex-direction:column;gap:.5rem;overflow-y:auto;max-height:260px;",a.appendChild(k);const r=document.createElement("button");r.className="btn btn-primary",r.type="button",r.textContent="Insert",r.disabled=!0,a.appendChild(r);const f=document.createElement("div");f.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 x=document.createElement("p");x.className="text-muted",x.style.cssText="font-size:.8rem;margin:0;",x.textContent="Select a template to see a preview.",f.appendChild(x),i.appendChild(a),i.appendChild(f),n.element.appendChild(i),n.open();let g=null,p=[];function c(L){return L.replace(/_/g," ").replace(/\b\w/g,N=>N.toUpperCase())}function v(){if(!g)return;const L={};p.forEach(({key:u,input:C})=>{L[u]=C.value});const N=g.replace(/\{\{([\w_]+)\}\}/g,(u,C)=>(L[C]??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"));f.innerHTML=DOMPurify.sanitize(N)}function B(L){k.textContent="",p=[];const N=new Set(["_id","_createdAt","_updatedAt"]),u=new Set;for(const[,C]of L.matchAll(/\{\{([\w_]+)\}\}/g))N.has(C)||u.add(C);if(!u.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.",k.appendChild(C);return}u.forEach(C=>{const z=document.createElement("div"),A=document.createElement("label");A.className="form-label",A.style.cssText="font-size:.8rem;margin-bottom:.2rem;display:block;",A.textContent=c(C);const U=document.createElement("input");U.type="text",U.className="form-input",U.placeholder=c(C),U.addEventListener("input",v),z.appendChild(A),z.appendChild(U),k.appendChild(z),p.push({key:C,input:U})})}w.addEventListener("change",async()=>{const L=w.value;if(!L){g=null,p=[],k.textContent="",f.textContent="",f.appendChild(x),r.disabled=!0;return}g=null,p=[],k.textContent="",r.disabled=!0;try{g=(await _.blocks.get(L)).content||"",B(g),v(),r.disabled=!1}catch{E.toast("Could not load template.",{type:"error"})}}),r.addEventListener("click",()=>{if(!w.value)return;const L=C=>C.replace(/"/g,""");let N=`template="${L(w.value)}"`;p.forEach(({key:C,input:z})=>{z.value!==""&&(N+=` ${C}="${L(z.value)}"`)});const u=`[block ${N} /]`;xe(e,u),e.dispatchEvent(new Event("input",{bubbles:!0})),n.close(),e.focus()})}),M.onForm(async e=>{const t=await _.forms.list().catch(()=>[]),n=document.createElement("div");n.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const i="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",a="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"),w=document.createElement("label");w.style.cssText=i,w.textContent="Form";const b=document.createElement("select");if(b.style.cssText=a,t.length)t.forEach(f=>{const x=document.createElement("option");x.value=f.slug,x.textContent=f.title||f.slug,b.appendChild(x)});else{const f=document.createElement("option");f.value="",f.textContent="No forms found",b.appendChild(f)}m.appendChild(w),m.appendChild(b),n.appendChild(m);const k=document.createElement("button");k.className="btn btn-primary btn-sm",k.style.cssText="align-self:flex-end;margin-top:.5rem;",k.textContent="Insert Form",n.appendChild(k);const r=E.slideover({title:"Insert Form",size:"sm",position:"right"});r.element.appendChild(n),r.open(),k.addEventListener("click",()=>{const f=b.value;f&&(xe(e,`[form slug="${f}" /]`),r.close(),me.get(0).dispatchEvent(new Event("input",{bubbles:!0})))})}),M.onView(async e=>{const t=await _.views.list().catch(()=>[]),n=document.createElement("div");n.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const i="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",a="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"),w=document.createElement("label");w.style.cssText=i,w.textContent="View";const b=document.createElement("select");if(b.style.cssText=a,t.length)t.forEach(p=>{const c=document.createElement("option");c.value=p.slug,c.textContent=p.title||p.slug,b.appendChild(c)});else{const p=document.createElement("option");p.value="",p.textContent="No Views configured yet \u2014 create one under Data \u2192 Views",b.appendChild(p)}m.appendChild(w),m.appendChild(b),n.appendChild(m);const k=document.createElement("div"),r=document.createElement("label");r.style.cssText=i,r.textContent="Display";const f=document.createElement("select");f.style.cssText=a,["table","cards","list"].forEach(p=>{const c=document.createElement("option");c.value=p,c.textContent=p.charAt(0).toUpperCase()+p.slice(1),f.appendChild(c)}),k.appendChild(r),k.appendChild(f),n.appendChild(k);const x=document.createElement("button");x.type="button",x.className="btn btn-primary",x.textContent="Insert",n.appendChild(x);const g=E.slideover({title:"Insert View",size:"sm",position:"right"});g.element.appendChild(n),g.open(),x.addEventListener("click",()=>{const p=b.value;if(!p)return;const c=`[view slug="${p}" display="${f.value}" /]`;g.close(),xe(e,c),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onCta(async e=>{const t=await _.actions.list().catch(()=>[]),n=document.createElement("div");n.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const i=Be(t.length?t.map(p=>[p.slug,p.title||p.slug]):[["","No Actions configured yet \u2014 create one under Data \u2192 Actions"]]);n.appendChild(W("Action",i));const a=Ce("Button label","Run");n.appendChild(W("Label",a)),i.addEventListener("change",()=>{const p=t.find(c=>c.slug===i.value);p?.trigger?.label&&(a.value=p.trigger.label)}),t.length&&t[0]?.trigger?.label&&(a.value=t[0].trigger.label);const m=Ce("Paste entry UUID\u2026","");n.appendChild(W("Entry ID",m));const w=Be([["primary","Primary"],["secondary","Secondary"],["ghost","Ghost"],["danger","Danger"]]);n.appendChild(W("Style",w));const b=Oe("e.g. check, zap, send (optional)","");n.appendChild(W("Icon",b.el));const k=Ce("Confirmation message (optional)","");n.appendChild(W("Confirm prompt",k));const r=document.createElement("div");r.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:auto;padding-top:.75rem;border-top:1px solid var(--dm-border,#333);";const f=document.createElement("button");f.type="button",f.className="btn btn-ghost",f.textContent="Cancel";const x=document.createElement("button");x.type="button",x.className="btn btn-primary",x.textContent="Insert",r.appendChild(f),r.appendChild(x),n.appendChild(r);const g=E.slideover({title:"Insert CTA Button",size:"sm",position:"right"});g.element.appendChild(n),g.open(),I.scan(n),f.addEventListener("click",()=>g.close()),x.addEventListener("click",()=>{const p=i.value;if(!p)return;const c=m.value.trim().replace(/"/g,""),v=(a.value.trim()||"Run").replace(/\[\/cta\]/gi,""),B=w.value,L=b.input.value.trim().replace(/"/g,""),N=k.value.trim().replace(/"/g,"");let u=`action="${p}" style="${B}"`;c&&(u+=` entry="${c}"`),L&&(u+=` icon="${L}"`),N&&(u+=` confirm="${N}"`),g.close(),xe(e,`[cta ${u}]${v}[/cta]`),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onButton(async e=>{const t=(await _.pages.list().catch(()=>[])).map(B=>({label:B.title||B.urlPath,value:B.urlPath})),n=e.value.substring(e.selectionStart,e.selectionEnd),i=document.createElement("div");i.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const a=Ce("/about or https://example.com",n.startsWith("/")?n:"");i.appendChild(W("URL",a));const m=Ce("Button label",n&&!n.startsWith("/")?n:"");i.appendChild(W("Label",m));const w=Be([["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"]]);i.appendChild(W("Variant",w));const b=Be([["","Default"],["sm","Small"],["lg","Large"]]);i.appendChild(W("Size",b));const k=Oe("e.g. arrow-right, star (optional)","");i.appendChild(W("Icon (before label)",k.el));const r=Oe("e.g. arrow-right (optional)","");i.appendChild(W("Icon (after label)",r.el));const f=He("Open in new tab");i.appendChild(f);const x=f.querySelector("input"),g=document.createElement("div");g.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:auto;padding-top:.75rem;border-top:1px solid var(--dm-border,#333);";const p=document.createElement("button");p.type="button",p.className="btn btn-ghost",p.textContent="Cancel";const c=document.createElement("button");c.type="button",c.className="btn btn-primary",c.textContent="Insert Button",g.appendChild(p),g.appendChild(c),i.appendChild(g);const v=E.slideover({title:"Insert Button",size:"sm",position:"right"});v.element.appendChild(i),v.open(),I.scan(i),p.addEventListener("click",()=>v.close()),requestAnimationFrame(()=>{E.autocomplete(a,{data:t,minChars:1,onSelect:B=>{a.value=B.value,m.value||(m.value=B.label)}}),a.focus()}),c.addEventListener("click",()=>{const B=a.value.trim();if(!B)return;v.close();const L=m.value.trim()||B;let N=`href="${B}" variant="${w.value}"`;b.value&&(N+=` size="${b.value}"`);const u=k.input.value.trim().replace(/"/g,"");u&&(N+=` icon="${u}"`);const C=r.input.value.trim().replace(/"/g,"");C&&(N+=` icon-after="${C}"`),x.checked&&(N+=' target="_blank"'),xe(e,`[button ${N}]${L}[/button]`),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onLinkShortcode(async e=>{const t=(await _.pages.list().catch(()=>[])).map(v=>({label:v.title||v.urlPath,value:v.urlPath})),n=e.value.substring(e.selectionStart,e.selectionEnd),i=document.createElement("div");i.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;";const a=Ce("/about or https://example.com",n.startsWith("/")?n:"");i.appendChild(W("URL",a));const m=Ce("Link text",n&&!n.startsWith("/")?n:"");i.appendChild(W("Link text",m));const w=Ce("e.g. text-primary, fw-bold (optional)","");i.appendChild(W("CSS class",w));const b=Oe("e.g. arrow-right (optional)","");i.appendChild(W("Icon (before text)",b.el));const k=Oe("e.g. external-link (optional)","");i.appendChild(W("Icon (after text)",k.el));const r=He("Open in new tab");i.appendChild(r);const f=r.querySelector("input"),x=document.createElement("div");x.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:auto;padding-top:.75rem;border-top:1px solid var(--dm-border,#333);";const g=document.createElement("button");g.type="button",g.className="btn btn-ghost",g.textContent="Cancel";const p=document.createElement("button");p.type="button",p.className="btn btn-primary",p.textContent="Insert Link",x.appendChild(g),x.appendChild(p),i.appendChild(x);const c=E.slideover({title:"Insert Link Shortcode",size:"sm",position:"right"});c.element.appendChild(i),c.open(),I.scan(i),g.addEventListener("click",()=>c.close()),requestAnimationFrame(()=>{E.autocomplete(a,{data:t,minChars:1,onSelect:v=>{a.value=v.value,m.value||(m.value=v.label)}}),a.focus()}),p.addEventListener("click",()=>{const v=a.value.trim();if(!v)return;c.close();const B=m.value.trim()||v;let L=`href="${v}"`;const N=w.value.trim().replace(/"/g,"");N&&(L+=` class="${N}"`);const u=b.input.value.trim().replace(/"/g,"");u&&(L+=` icon="${u}"`);const C=k.input.value.trim().replace(/"/g,"");C&&(L+=` icon-after="${C}"`),f.checked&&(L+=' target="_blank"'),xe(e,`[link ${L}]${B}[/link]`),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onTabs(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const n=Be([["","Default"],["pills","Pills"],["bordered","Bordered"]]);t.appendChild(W("Style",n));const i=Be([["","Left"],["center","Centre"],["right","Right"]]);t.appendChild(W("Alignment",i));const a=Be([["","None"],["fade","Fade"]]);t.appendChild(W("Animation",a));const m=He("Allow multiple panels open at once"),w=m.querySelector("input");t.appendChild(m);const b=document.createElement("div");b.style.cssText="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",b.textContent="Tabs",t.appendChild(b);const k=document.createElement("div");k.style.cssText="display:flex;flex-direction:column;gap:.4rem;";const r=[];function f(){r.forEach(N=>{N.removeBtn.disabled=r.length<=2,N.removeBtn.style.opacity=r.length<=2?"0.3":"1"})}function x(){const N=n.value,u=i.value,C=a.value,z=w.checked,A=[];N&&A.push(`style="${N}"`),u&&A.push(`align="${u}"`),C&&A.push(C),z&&A.push('multiple="true"');let h=`[tabs${A.length?" "+A.join(" "):""}]
|
|
90
|
+
`;return r.forEach((y,d)=>{const s=y.titleInput.value.trim()||`Tab ${d+1}`,o=y.iconInput.value.trim(),j=o?` title="${s}" icon="${o}"`:` title="${s}"`;h+=`[tab${j}]Tab content here.[/tab]
|
|
91
|
+
`}),h+="[/tabs]",h}function g(N=""){if(r.length>=10)return;const u=document.createElement("div");u.style.cssText="display:flex;gap:.4rem;align-items:center;";const C=Ce("Tab title",N);C.style.cssText+="flex:1;";const z=Oe("icon (optional)");z.el.style.flex=".6";const A=document.createElement("button");A.type="button",A.textContent="\xD7",A.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 U={row:u,titleInput:C,iconInput:z.input,removeBtn:A};r.push(U),u.appendChild(C),u.appendChild(z.el),u.appendChild(A),k.appendChild(u),A.addEventListener("click",()=>{if(r.length<=2)return;const h=r.indexOf(U);r.splice(h,1),k.removeChild(u),f(),c(),v.update(x())}),[C,z.input].forEach(h=>h.addEventListener("input",()=>v.update(x()))),f()}g("Overview"),g("Details"),t.appendChild(k);const p=document.createElement("button");p.type="button",p.textContent="+ Add Tab",p.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;",p.addEventListener("click",()=>{g(""),c(),r[r.length-1].titleInput.focus(),v.update(x())}),t.appendChild(p);function c(){p.disabled=r.length>=10}const v=Ue();v.update(x()),t.appendChild(W("Shortcode preview",v.el)),[n,i,a].forEach(N=>N.addEventListener("change",()=>v.update(x()))),w.addEventListener("change",()=>v.update(x()));const B=document.createElement("button");B.type="button",B.className="btn btn-primary",B.textContent="Insert Tabs",t.appendChild(B);const L=E.slideover({title:"Insert Tabs",size:"sm",position:"right"});L.element.appendChild(t),L.open(),requestAnimationFrame(()=>r[0].titleInput.focus()),B.addEventListener("click",()=>{xe(e,x()),L.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onHero(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const n=Ce("Hero title");t.appendChild(W("Title",n));const i=Ce("Tagline (optional)");t.appendChild(W("Tagline",i));const a=Be([["sm","Small"],["md","Medium (default)"],["lg","Large"],["full","Full"]]);a.value="md",t.appendChild(W("Size",a));const m=Be([["","Left"],["center","Centre"],["right","Right"]]);t.appendChild(W("Alignment",m));const w=document.createElement("div");w.style.cssText="display:flex;gap:.75rem;align-items:center;";const b={};["none","colour","image"].forEach(u=>{const C=document.createElement("label");C.style.cssText="display:flex;align-items:center;gap:.3rem;font-size:.9em;cursor:pointer;";const z=document.createElement("input");z.type="radio",z.name="hero-bg",z.value=u,u==="none"&&(z.checked=!0),b[u]=z,C.appendChild(z),C.appendChild(document.createTextNode(u.charAt(0).toUpperCase()+u.slice(1))),w.appendChild(C)}),t.appendChild(W("Background",w));const k=Ce("#hex or CSS colour"),r=W("Colour",k);r.style.display="none",t.appendChild(r);const f=Ce("/media/hero.jpg"),x=Be([["","None"],["dark","Dark"],["light","Light"]]),g=document.createElement("div");g.style.cssText="display:none;flex-direction:column;gap:.5rem;",g.appendChild(W("Image path",f)),g.appendChild(W("Overlay",x)),t.appendChild(g);const p=Ce("e.g. 400px");t.appendChild(W("Min height",p));function c(){const u=n.value.trim(),C=i.value.trim(),z=a.value,A=m.value,U=Object.keys(b).find(j=>b[j].checked)||"none",h=k.value.trim(),y=f.value.trim(),d=x.value,s=p.value.trim(),o=[`title="${u}"`];return C&&o.push(`tagline="${C}"`),z&&z!=="md"&&o.push(`size="${z}"`),A&&o.push(`align="${A}"`),U==="colour"&&h&&o.push(`color="${h}"`),U==="image"&&y&&o.push(`image="${y}"`),U==="image"&&d&&o.push(`overlay="${d}"`),s&&o.push(`min-height="${s}"`),`[hero ${o.join(" ")}]
|
|
92
92
|
Content here.
|
|
93
|
-
[/hero]`}const
|
|
93
|
+
[/hero]`}const v=Ue();v.update(c()),t.appendChild(W("Shortcode preview",v.el));function B(){const u=Object.keys(b).find(C=>b[C].checked)||"none";r.style.display=u==="colour"?"":"none",g.style.display=u==="image"?"flex":"none",v.update(c())}Object.values(b).forEach(u=>u.addEventListener("change",B)),[n,i,k,f,p].forEach(u=>u.addEventListener("input",()=>v.update(c()))),[a,m,x].forEach(u=>u.addEventListener("change",()=>v.update(c())));const L=document.createElement("button");L.type="button",L.className="btn btn-primary",L.textContent="Insert Hero",t.appendChild(L);const N=E.slideover({title:"Insert Hero",size:"sm",position:"right"});N.element.appendChild(t),N.open(),requestAnimationFrame(()=>n.focus()),L.addEventListener("click",()=>{xe(e,c()),N.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onBanner(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const n=[{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 i="info";const a=document.createElement("div");a.style.cssText="display:flex;gap:.35rem;flex-wrap:wrap;";const m={};n.forEach(c=>{const v=document.createElement("button");v.type="button",v.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 B=document.createElement("span");B.style.cssText=`display:inline-block;width:.55rem;height:.55rem;border-radius:50%;background:${c.color};flex-shrink:0;`,v.appendChild(B),v.appendChild(document.createTextNode(c.label)),m[c.value]=v,a.appendChild(v),v.addEventListener("click",()=>{i=c.value,Object.entries(m).forEach(([L,N])=>{N.style.borderColor=L===i?c.color:"var(--dm-border,#333)",N.style.background=L===i?`${c.color}22`:"transparent"}),x.update(f())})}),m.info.style.borderColor="#3b82f6",m.info.style.background="#3b82f622",t.appendChild(W("Type",a));const w=Ce("Title (optional)");t.appendChild(W("Title",w));const b=Oe("Icon name (optional)");t.appendChild(W("Icon",b.el));const k=He("Dismissible"),r=k.querySelector("input");t.appendChild(k);function f(){const c=[];i!=="info"&&c.push(`type="${i}"`);const v=w.value.trim();v&&c.push(`title="${v}"`);const B=b.input.value.trim();return B&&c.push(`icon="${B}"`),r.checked&&c.push("dismissible"),`[banner${c.length?" "+c.join(" "):""}]
|
|
94
94
|
Banner content here.
|
|
95
|
-
[/banner]`}const
|
|
96
|
-
`;for(let q=0;q<
|
|
95
|
+
[/banner]`}const x=Ue();x.update(f()),t.appendChild(W("Shortcode preview",x.el)),[w,b.input].forEach(c=>c.addEventListener("input",()=>x.update(f()))),r.addEventListener("change",()=>x.update(f()));const g=document.createElement("button");g.type="button",g.className="btn btn-primary",g.textContent="Insert Banner",t.appendChild(g);const p=E.slideover({title:"Insert Banner",size:"sm",position:"right"});p.element.appendChild(t),p.open(),requestAnimationFrame(()=>w.focus()),g.addEventListener("click",()=>{xe(e,f()),p.close(),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onScribe(e=>at(e)),M.onGrid(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const n="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",i="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 a(oe,ee){const F=document.createElement("div"),P=document.createElement("label");return P.style.cssText=n,P.textContent=oe,F.appendChild(P),F.appendChild(ee),F}function m(oe){const ee=document.createElement("select");return ee.style.cssText=i,oe.forEach(([F,P])=>{const q=document.createElement("option");q.value=F,q.textContent=P,ee.appendChild(q)}),ee}let w="grid";const b=document.createElement("div");b.style.cssText="display:flex;gap:.5rem;";const k=document.createElement("button");k.type="button",k.className="btn btn-sm btn-primary",k.textContent="Grid";const r=document.createElement("button");r.type="button",r.className="btn btn-sm btn-ghost",r.textContent="Row",b.appendChild(k),b.appendChild(r),t.appendChild(b);const f=document.createElement("input");f.type="number",f.min="1",f.max="12",f.value="2",f.style.cssText=i,t.appendChild(a("Columns",f));const x=m([["0","0"],["1","1"],["2","2"],["3","3"],["4","4 (default)"],["6","6"],["8","8"],["10","10"],["12","12"],["16","16"]]);x.value="4",t.appendChild(a("Gap",x));const g=document.createElement("div");g.style.cssText="display:flex;flex-direction:column;gap:.5rem;";const p=document.createElement("label");p.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const c=document.createElement("input");c.type="checkbox",p.appendChild(c),p.appendChild(document.createTextNode("Full width (breakout)")),g.appendChild(p);const v=document.createElement("div");v.style.cssText=n+"margin-top:.25rem;",v.textContent="Column Spans",g.appendChild(v);const B=document.createElement("div");B.style.cssText="display:flex;flex-direction:column;gap:.3rem;",g.appendChild(B),t.appendChild(g);const L=[];function N(){const oe=Math.min(Math.max(parseInt(f.value)||2,1),12),ee=L.map(F=>F.value);B.textContent="",L.length=0;for(let F=0;F<oe;F++){const P=document.createElement("div");P.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 ${F+1}`;const J=document.createElement("input");J.type="number",J.min="1",J.max="12",J.placeholder="auto",J.value=ee[F]||"",J.style.cssText=i+"width:5em;flex:none;",P.appendChild(q),P.appendChild(J),B.appendChild(P),L.push(J)}}f.addEventListener("input",N),N();const u=document.createElement("div");u.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 z=document.createElement("input");z.type="checkbox",C.appendChild(z),C.appendChild(document.createTextNode("Enable staggered reveal")),u.appendChild(C);const A=document.createElement("div");A.style.cssText="display:none;flex-direction:column;gap:.5rem;padding-left:.5rem;border-left:2px solid var(--dm-border,#333);";const U=m([["slide-up","Slide Up"],["slide-down","Slide Down"],["slide-left","Slide Left"],["slide-right","Slide Right"],["fade","Fade"],["zoom","Zoom"],["flip","Flip"]]);A.appendChild(a("Animation",U));const h=m([["stagger","Stagger"],["sequence","Sequence"]]);A.appendChild(a("Mode",h));const y=document.createElement("input");y.type="number",y.value="400",y.style.cssText=i,A.appendChild(a("Duration (ms)",y));const d=document.createElement("input");d.type="number",d.value="60",d.style.cssText=i,A.appendChild(a("Stagger (ms)",d));const s=document.createElement("input");s.type="number",s.value="0",s.style.cssText=i,A.appendChild(a("Delay (ms)",s));const o=m([["ltr","Left to Right"],["rtl","Right to Left"]]);A.appendChild(a("Direction",o)),u.appendChild(A),t.appendChild(u),z.addEventListener("change",()=>{A.style.display=z.checked?"flex":"none"});const j=document.createElement("button");j.type="button",j.className="btn btn-primary",j.textContent="Insert Grid",t.appendChild(j),k.addEventListener("click",()=>{w="grid",k.className="btn btn-sm btn-primary",r.className="btn btn-sm btn-ghost",g.style.display="flex",u.style.display="none",j.textContent="Insert Grid"}),r.addEventListener("click",()=>{w="row",r.className="btn btn-sm btn-primary",k.className="btn btn-sm btn-ghost",u.style.display="flex",g.style.display="none",j.textContent="Insert Row"});const Z=E.slideover({title:"Insert Grid / Row",size:"sm",position:"right"});Z.element.appendChild(t),Z.open(),requestAnimationFrame(()=>f.focus()),j.addEventListener("click",()=>{Z.close();const oe=Math.min(Math.max(parseInt(f.value)||2,1),12),ee=x.value;let F;if(w==="grid"){let P=`cols="${oe}"`;ee!=="4"&&(P+=` gap="${ee}"`),c.checked&&(P+=' fullwidth="true"'),F=`[grid ${P}]
|
|
96
|
+
`;for(let q=0;q<oe;q++){const J=L[q]?.value?.trim(),O=J?` span="${J}"`:"";F+=`[col${O}]
|
|
97
97
|
Column ${q+1}
|
|
98
98
|
[/col]
|
|
99
|
-
`}
|
|
100
|
-
`;for(let q=0;q<
|
|
101
|
-
`;
|
|
102
|
-
`,
|
|
103
|
-
`}),
|
|
104
|
-
`;
|
|
105
|
-
`)}),
|
|
99
|
+
`}F+="[/grid]"}else{let P="";if(ee!=="4"&&(P+=` gap="${ee}"`),z.checked){P+=" reveal",P+=` reveal-mode="${h.value}"`,P+=` reveal-animation="${U.value}"`;const q=y.value.trim();q&&q!=="400"&&(P+=` reveal-duration="${q}"`);const J=d.value.trim();J&&J!=="60"&&(P+=` reveal-stagger="${J}"`);const O=s.value.trim();O&&O!=="0"&&(P+=` reveal-delay="${O}"`),o.value!=="ltr"&&(P+=` reveal-direction="${o.value}"`)}F=`[row${P?" "+P.trim():""}]
|
|
100
|
+
`;for(let q=0;q<oe;q++)F+=`[col]Column ${q+1}[/col]
|
|
101
|
+
`;F+="[/row]"}xe(e,F),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onAccordion(async e=>{const t=await _.collections.list().catch(()=>[]),n=document.createElement("div");n.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const i="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",a="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");m.style.cssText="display:flex;gap:.5rem;";const w=document.createElement("button");w.type="button",w.className="btn btn-sm btn-primary",w.textContent="Static";const b=document.createElement("button");b.type="button",b.className="btn btn-sm btn-ghost",b.textContent="Collection",m.appendChild(w),m.appendChild(b),n.appendChild(m);let k="static";const r=document.createElement("div");r.style.cssText="display:flex;flex-direction:column;gap:.5rem;";const f=[];function x(F){const P=document.createElement("div");P.style.cssText="display:flex;align-items:center;gap:.5rem;";const q=document.createElement("label");q.style.cssText="font-size:.85em;color:var(--dm-text-muted,#aaa);white-space:nowrap;",q.textContent=`Item ${F}`;const J=document.createElement("input");return J.type="text",J.placeholder="Item title",J.style.cssText=a,P.appendChild(q),P.appendChild(J),{row:P,input:J}}[1,2].forEach(F=>{const P=x(F);f.push(P),r.appendChild(P.row)});const g=document.createElement("button");g.type="button",g.className="btn btn-ghost btn-sm",g.textContent="+ Add Item",g.addEventListener("click",()=>{const F=x(f.length+1);f.push(F),r.insertBefore(F.row,g)}),r.appendChild(g);const p=document.createElement("label");p.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const c=document.createElement("input");c.type="checkbox",p.appendChild(c),p.appendChild(document.createTextNode("Allow multiple open")),r.appendChild(p),n.appendChild(r);const v=document.createElement("div");v.style.cssText="display:none;flex-direction:column;gap:.5rem;";const B=document.createElement("div"),L=document.createElement("label");L.style.cssText=i,L.textContent="Collection";const N=document.createElement("select");if(N.style.cssText=a,t.length)t.forEach(F=>{const P=document.createElement("option");P.value=F.slug,P.textContent=F.title||F.slug,N.appendChild(P)});else{const F=document.createElement("option");F.value="",F.textContent="No collections found",N.appendChild(F)}B.appendChild(L),B.appendChild(N),v.appendChild(B);const u=document.createElement("div"),C=document.createElement("label");C.style.cssText=i,C.textContent="Title field";const z=document.createElement("select");z.style.cssText=a,u.appendChild(C),u.appendChild(z),v.appendChild(u);const A=document.createElement("div"),U=document.createElement("label");U.style.cssText=i,U.textContent="Body field";const h=document.createElement("select");h.style.cssText=a,A.appendChild(U),A.appendChild(h),v.appendChild(A);async function y(F){z.textContent="",h.textContent="";try{const P=(await _.collections.get(F)).fields||[];if(!P.length){const q=document.createElement("option");q.value="",q.textContent="\u2014 none \u2014",z.appendChild(q.cloneNode(!0)),h.appendChild(q);return}P.forEach((q,J)=>{const O=()=>{const X=document.createElement("option");return X.value=q.name,X.textContent=q.label||q.name,X};z.appendChild(O()),h.appendChild(O()),q.name==="title"&&(z.value="title"),q.name==="description"&&(h.value="description")}),!z.value&&P[0]&&(z.value=P[0].name),!h.value&&P[1]&&(h.value=P[1].name)}catch{const P=document.createElement("option");P.value="",P.textContent="\u2014 unknown \u2014",z.appendChild(P.cloneNode(!0)),h.appendChild(P)}}t.length&&y(t[0].slug),N.addEventListener("change",()=>y(N.value));const d=document.createElement("div"),s=document.createElement("label");s.style.cssText=i,s.textContent="Limit (optional)";const o=document.createElement("input");o.type="number",o.placeholder="All",o.style.cssText=a,d.appendChild(s),d.appendChild(o),v.appendChild(d);const j=document.createElement("label");j.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const Z=document.createElement("input");Z.type="checkbox",j.appendChild(Z),j.appendChild(document.createTextNode("Allow multiple open")),v.appendChild(j),n.appendChild(v),w.addEventListener("click",()=>{k="static",w.className="btn btn-sm btn-primary",b.className="btn btn-sm btn-ghost",r.style.display="flex",v.style.display="none"}),b.addEventListener("click",()=>{k="collection",b.className="btn btn-sm btn-primary",w.className="btn btn-sm btn-ghost",v.style.display="flex",r.style.display="none"});const oe=document.createElement("button");oe.type="button",oe.className="btn btn-primary",oe.textContent="Insert Accordion",n.appendChild(oe);const ee=E.slideover({title:"Insert Accordion",size:"sm",position:"right"});ee.element.appendChild(n),ee.open(),requestAnimationFrame(()=>f[0].input.focus()),oe.addEventListener("click",()=>{if(k==="collection"&&!N.value)return;ee.close();let F;if(k==="static")F=`[accordion${c.checked?' multiple="true"':""}]
|
|
102
|
+
`,f.forEach((P,q)=>{const J=P.input.value.trim()||`Item ${q+1}`;F+=`[item title="${J}"]Content here.[/item]
|
|
103
|
+
`}),F+="[/accordion]";else{const P=N.value;if(!P)return;const q=z.value,J=h.value;let O=`slug="${P}" display="accordion"`;q&&(O+=` title-field="${q}"`),J&&(O+=` body-field="${J}"`);const X=o.value.trim();X&&(O+=` limit="${X}"`),Z.checked&&(O+=' multiple="true"'),F=`[collection ${O} /]`}xe(e,F),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onListGroup(e=>{const t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const n="display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;",i="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 a(u,C){const z=document.createElement("div"),A=document.createElement("label");return A.style.cssText=n,A.textContent=u,z.appendChild(A),z.appendChild(C),z}function m(u){const C=document.createElement("select");return C.style.cssText=i,u.forEach(([z,A])=>{const U=document.createElement("option");U.value=z,U.textContent=A,C.appendChild(U)}),C}const w=m([["","Default"],["flush","Flush (no outer border)"],["numbered","Numbered"],["horizontal","Horizontal"]]);t.appendChild(a("Variant",w));const b=m([["","Default"],["sm","Small"],["lg","Large"]]);t.appendChild(a("Size",b));const k=m([["","Default"],["primary","Primary"],["secondary","Secondary"],["success","Success"],["danger","Danger"],["warning","Warning"],["info","Info"]]);t.appendChild(a("Item Colour",k));const r=document.createElement("label");r.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.9em;cursor:pointer;";const f=document.createElement("input");f.type="checkbox",r.appendChild(f),r.appendChild(document.createTextNode("Actionable items (hover highlight)")),t.appendChild(r);const x=document.createElement("div");x.style.cssText=n+"margin-bottom:.35rem;",x.textContent="Items",t.appendChild(x);const g=document.createElement("div");g.style.cssText="display:flex;flex-direction:column;gap:.4rem;",t.appendChild(g);const p=[];function c(){p.forEach(u=>{u.removeBtn.disabled=p.length<=1,u.removeBtn.style.opacity=p.length<=1?"0.3":"1"})}function v(u){const C=document.createElement("div");C.style.cssText="display:flex;gap:.4rem;align-items:center;";const z=document.createElement("input");z.type="text",z.placeholder="Item text",z.value=u||"",z.style.cssText=i+"flex:1;";const A=document.createElement("button");A.type="button",A.textContent="\u2715",A.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 U={row:C,input:z,removeBtn:A};p.push(U),C.appendChild(z),C.appendChild(A),g.appendChild(C),A.addEventListener("click",()=>{if(p.length<=1)return;const h=p.indexOf(U);p.splice(h,1),g.removeChild(C),c()}),c()}v("Item 1"),v("Item 2"),v("Item 3");const B=document.createElement("button");B.type="button",B.textContent="+ Add Item",B.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;",B.addEventListener("click",()=>{p.length>=20||(v(""),p[p.length-1].input.focus())}),t.appendChild(B);const L=document.createElement("button");L.type="button",L.className="btn btn-primary",L.textContent="Insert List Group",t.appendChild(L);const N=E.slideover({title:"Insert List Group",size:"sm",position:"right"});N.element.appendChild(t),N.open(),requestAnimationFrame(()=>p[0].input.focus()),L.addEventListener("click",()=>{N.close();let u="";w.value&&(u+=` variant="${w.value}"`),b.value&&(u+=` size="${b.value}"`),k.value&&(u+=` itemvariant="${k.value}"`),f.checked&&(u+=' action="true"');let C=`[listgroup${u}]
|
|
104
|
+
`;p.forEach(z=>{const A=z.input.value.trim();A&&(C+=`[item]${A}[/item]
|
|
105
|
+
`)}),C+="[/listgroup]",xe(e,C),e.dispatchEvent(new Event("input",{bubbles:!0})),e.focus()})}),M.onCard(e=>{Ke.open(e,{onMediaBrowse:()=>_.media.list().catch(()=>[])})}),M.onTimeline(e=>{Ze.open(e,{onPreview:async t=>{try{return await _.pages.preview(t)}catch{return null}},onListCollections:()=>_.collections.list().catch(()=>[]),onGetCollection:t=>_.collections.get(t).catch(()=>null)})}),M.onHelp(()=>{ot()}),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"))}),Re=!1,l.find("#quick-switch").prop("disabled",!1),Ge&&window.removeEventListener("beforeunload",Ge),Ge=e=>{Re&&e.preventDefault()},window.addEventListener("beforeunload",Ge),Ye||(Ye=!0,R.use((e,t,n)=>{const i=window.location.hash.startsWith("#/pages/edit")||window.location.hash==="#/pages/new";if(!Re||!i)return n();E.confirm("You have unsaved changes. Leave this page?").then(a=>{a&&(Re=!1,n())})})),me.on("input",()=>{te||(Re=!0,l.find("#quick-switch").prop("disabled",!0),V())});const Fe=l.find("#editor-meta-tabs").get(0);Fe&&(Fe.addEventListener("input",()=>{Re=!0,l.find("#quick-switch").prop("disabled",!0)}),Fe.addEventListener("change",e=>{e.target.id!=="quick-switch"&&(Re=!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 n=null;if(t)try{n=JSON.parse(t)}catch{E.toast("DConfig JSON is invalid. Please check the format before saving.",{type:"warning"});return}const i={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:we?we.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:n,...l.find("#field-theme").val()?{theme:l.find("#field-theme").val()}:{}};try{l.find("#save-btn").prop("disabled",!0).text("Saving\u2026");const a=ne.getUnfoldedContent();if(H){const m={frontmatter:i,body:a};e!==de&&(m.newUrlPath=e),await _.pages.update(de,m),ae&&await _.settings.saveCustomCss(l.find("#css-editor").val()),E.toast(ae?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),Re=!1,l.find("#quick-switch").prop("disabled",!1),e!==de&&R.navigate(`/pages/edit${e}`)}else await _.pages.create({urlPath:e,frontmatter:i,body:a}),ae&&await _.settings.saveCustomCss(l.find("#css-editor").val()),E.toast(ae?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),Re=!1,R.navigate("/pages")}catch(a){E.toast(`Save failed: ${a.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()}};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domma-cms",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/server.js",
|
|
@@ -71,11 +71,11 @@
|
|
|
71
71
|
"@fastify/jwt": "^10.0.0",
|
|
72
72
|
"@fastify/multipart": "^9.3.0",
|
|
73
73
|
"@fastify/rate-limit": "^10.3.0",
|
|
74
|
-
"@fastify/static": "
|
|
74
|
+
"@fastify/static": "9.1.1",
|
|
75
75
|
"bcryptjs": "^3.0.3",
|
|
76
|
-
"domma-js": "^0.22.
|
|
76
|
+
"domma-js": "^0.22.6",
|
|
77
77
|
"dotenv": "^17.2.3",
|
|
78
|
-
"fastify": "5.8.
|
|
78
|
+
"fastify": "5.8.5",
|
|
79
79
|
"gray-matter": "^4.0.3",
|
|
80
80
|
"marked": "^15.0.0",
|
|
81
81
|
"nodemailer": "8.0.5",
|
|
@@ -98,7 +98,10 @@ export function requirePermission(resource, action) {
|
|
|
98
98
|
export {getPermissionsForRole};
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* Shorthand preHandler —
|
|
101
|
+
* Shorthand preHandler — admin-tier role (level ≤ 1) or above.
|
|
102
|
+
* Matches the base role hierarchy documented in roles.js:
|
|
103
|
+
* super-admin (0), admin (1), user (2).
|
|
104
|
+
* Both super-admin and admin pass; regular users and anything below do not.
|
|
102
105
|
*
|
|
103
106
|
* @param {FastifyRequest} request
|
|
104
107
|
* @param {FastifyReply} reply
|
|
@@ -108,7 +111,7 @@ export async function requireAdmin(request, reply) {
|
|
|
108
111
|
if (!request.user) {
|
|
109
112
|
return reply.code(401).send({ statusCode: 401, error: 'Unauthorised', message: 'Authentication required' });
|
|
110
113
|
}
|
|
111
|
-
if (getRoleLevel(request.user.role)
|
|
114
|
+
if (getRoleLevel(request.user.role) > 1) {
|
|
112
115
|
return reply.code(403).send({ statusCode: 403, error: 'Forbidden', message: 'Admin access required' });
|
|
113
116
|
}
|
|
114
117
|
}
|
|
@@ -413,6 +413,43 @@ function renderCollectionAccordion(entries, titleField, bodyField, multiple, emp
|
|
|
413
413
|
return `<div class="dm-collection-display accordion"${multiAttr}>\n${items}\n</div>`;
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
+
/**
|
|
417
|
+
* Render a collection as a Domma progression (timeline / roadmap).
|
|
418
|
+
* Output mirrors processTimelineBlocks so the same styling applies.
|
|
419
|
+
*
|
|
420
|
+
* @param {object[]} entries
|
|
421
|
+
* @param {object} opts
|
|
422
|
+
* @param {string} opts.titleField - entry data field used as item title
|
|
423
|
+
* @param {string} [opts.dateField] - optional field surfaced as data-date
|
|
424
|
+
* @param {string} [opts.statusField]- optional field surfaced as data-status
|
|
425
|
+
* @param {string} [opts.iconField] - optional field surfaced as data-icon
|
|
426
|
+
* @param {string} [opts.bodyField] - optional Markdown body field
|
|
427
|
+
* @param {string} opts.layout - vertical | centred | horizontal
|
|
428
|
+
* @param {string} opts.theme - minimal | corporate | modern
|
|
429
|
+
* @param {string} opts.mode - timeline | roadmap
|
|
430
|
+
* @param {string} opts.emptyMsg
|
|
431
|
+
* @returns {string}
|
|
432
|
+
*/
|
|
433
|
+
function renderCollectionTimeline(entries, opts) {
|
|
434
|
+
const {titleField, dateField, statusField, iconField, bodyField, layout, theme, mode, emptyMsg} = opts;
|
|
435
|
+
if (!entries.length) {
|
|
436
|
+
return `<div class="dm-collection-display dm-collection-empty"><p>${escapeHtmlText(emptyMsg)}</p></div>`;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const items = entries.map(e => {
|
|
440
|
+
const title = escapeHtmlText(String(e.data?.[titleField] ?? e.id ?? '(untitled)'));
|
|
441
|
+
const date = dateField && e.data?.[dateField] != null ? ` data-date="${escapeAttr(String(e.data[dateField]))}"` : '';
|
|
442
|
+
const status = statusField && e.data?.[statusField] != null ? ` data-status="${escapeAttr(String(e.data[statusField]))}"` : '';
|
|
443
|
+
const icon = iconField && e.data?.[iconField] != null ? ` data-icon="${escapeAttr(String(e.data[iconField]))}"` : '';
|
|
444
|
+
const bodyHtml = bodyField
|
|
445
|
+
? marked.parse(String(e.data?.[bodyField] ?? ''))
|
|
446
|
+
: '';
|
|
447
|
+
return `<div class="dm-progression-item"${date}${status}${icon}><div class="dm-progression-item-title">${title}</div><div class="dm-progression-item-body">${bodyHtml}</div></div>`;
|
|
448
|
+
}).join('\n');
|
|
449
|
+
|
|
450
|
+
return `<div class="dm-collection-display dm-progression" data-layout="${layout}" data-theme="${theme}" data-mode="${mode}">\n${items}\n</div>`;
|
|
451
|
+
}
|
|
452
|
+
|
|
416
453
|
/**
|
|
417
454
|
* Process [view slug="..." display="table|cards|list" /] shortcodes.
|
|
418
455
|
* Executes the View's aggregation pipeline and renders results using the
|
|
@@ -488,6 +525,21 @@ async function processViewBlocks(markdown) {
|
|
|
488
525
|
const bodyField = attrs['body-field'] || 'description';
|
|
489
526
|
const multiple = attrs.multiple === 'true';
|
|
490
527
|
replacement = renderCollectionAccordion(entries, accordionTitleField, bodyField, multiple, emptyMsg);
|
|
528
|
+
} else if (display === 'timeline') {
|
|
529
|
+
const timelineLayout = ['vertical', 'centred', 'horizontal'].includes(attrs.layout) ? attrs.layout : 'vertical';
|
|
530
|
+
const timelineTheme = ['minimal', 'corporate', 'modern'].includes(attrs.theme) ? attrs.theme : 'minimal';
|
|
531
|
+
const timelineMode = ['timeline', 'roadmap'].includes(attrs.mode) ? attrs.mode : 'timeline';
|
|
532
|
+
replacement = renderCollectionTimeline(entries, {
|
|
533
|
+
titleField: attrs['title-field'] || 'title',
|
|
534
|
+
dateField: attrs['date-field'] || '',
|
|
535
|
+
statusField: attrs['status-field'] || '',
|
|
536
|
+
iconField: attrs['icon-field'] || '',
|
|
537
|
+
bodyField: attrs['body-field'] || '',
|
|
538
|
+
layout: timelineLayout,
|
|
539
|
+
theme: timelineTheme,
|
|
540
|
+
mode: timelineMode,
|
|
541
|
+
emptyMsg,
|
|
542
|
+
});
|
|
491
543
|
} else if (display === 'block') {
|
|
492
544
|
const blockName = attrs.block || viewConfig?.display?.block || '';
|
|
493
545
|
if (blockName) {
|
|
@@ -607,6 +659,21 @@ async function processCollectionBlocks(markdown) {
|
|
|
607
659
|
const bodyField = attrs['body-field'] || 'description';
|
|
608
660
|
const multiple = attrs.multiple === 'true';
|
|
609
661
|
replacement = renderCollectionAccordion(entries, accordionTitleField, bodyField, multiple, emptyMsg);
|
|
662
|
+
} else if (display === 'timeline') {
|
|
663
|
+
const timelineLayout = ['vertical', 'centred', 'horizontal'].includes(attrs.layout) ? attrs.layout : 'vertical';
|
|
664
|
+
const timelineTheme = ['minimal', 'corporate', 'modern'].includes(attrs.theme) ? attrs.theme : 'minimal';
|
|
665
|
+
const timelineMode = ['timeline', 'roadmap'].includes(attrs.mode) ? attrs.mode : 'timeline';
|
|
666
|
+
replacement = renderCollectionTimeline(entries, {
|
|
667
|
+
titleField: attrs['title-field'] || 'title',
|
|
668
|
+
dateField: attrs['date-field'] || '',
|
|
669
|
+
statusField: attrs['status-field'] || '',
|
|
670
|
+
iconField: attrs['icon-field'] || '',
|
|
671
|
+
bodyField: attrs['body-field'] || '',
|
|
672
|
+
layout: timelineLayout,
|
|
673
|
+
theme: timelineTheme,
|
|
674
|
+
mode: timelineMode,
|
|
675
|
+
emptyMsg,
|
|
676
|
+
});
|
|
610
677
|
} else if (display === 'block') {
|
|
611
678
|
const blockName = attrs.block || '';
|
|
612
679
|
if (blockName) {
|
|
@@ -647,12 +714,14 @@ async function processCollectionBlocks(markdown) {
|
|
|
647
714
|
*/
|
|
648
715
|
export function parseShortcodeAttrs(attrStr) {
|
|
649
716
|
const attrs = {};
|
|
650
|
-
// Pass 1: quoted key="value" or key='value' pairs
|
|
651
|
-
|
|
652
|
-
|
|
717
|
+
// Pass 1: quoted key="value" or key='value' pairs — proper disjunction so
|
|
718
|
+
// a double-quoted value can contain apostrophes (and vice versa) without
|
|
719
|
+
// the opposite quote terminating the match.
|
|
720
|
+
for (const [, key, dq, sq] of attrStr.matchAll(/([\w-]+)=(?:"([^"]*)"|'([^']*)')/g)) {
|
|
721
|
+
attrs[key] = dq ?? sq ?? '';
|
|
653
722
|
}
|
|
654
723
|
// Pass 2: standalone flag attributes (no value) — blank out key=value matches first
|
|
655
|
-
const stripped = attrStr.replace(/([\w-]+)=["'
|
|
724
|
+
const stripped = attrStr.replace(/([\w-]+)=(?:"[^"]*"|'[^']*')/g, m => ' '.repeat(m.length));
|
|
656
725
|
for (const [, key] of stripped.matchAll(/\b([\w-]+)\b/g)) {
|
|
657
726
|
if (!(key in attrs)) attrs[key] = true;
|
|
658
727
|
}
|
|
@@ -2389,8 +2458,12 @@ function processCenterBlocks(markdown) {
|
|
|
2389
2458
|
(_, attrStr, body) => {
|
|
2390
2459
|
const attrs = parseShortcodeAttrs(attrStr);
|
|
2391
2460
|
const classAttr = attrs.class ? ` class="${escapeAttr(attrs.class)}"` : '';
|
|
2392
|
-
|
|
2393
|
-
|
|
2461
|
+
// Emit the wrapper with blank lines around the body so CommonMark
|
|
2462
|
+
// parses markdown inside the div. DO NOT eagerly call marked.parse
|
|
2463
|
+
// here — that HTML-escapes attribute quotes on any unprocessed
|
|
2464
|
+
// shortcodes inside (e.g. [button href="..."] becomes href="...),
|
|
2465
|
+
// which breaks every later shortcode processor in the pipeline.
|
|
2466
|
+
return `\n<div style="text-align:center;"${classAttr}>\n\n${body.trim()}\n\n</div>\n`;
|
|
2394
2467
|
}
|
|
2395
2468
|
));
|
|
2396
2469
|
}
|