domma-cms 1.6.12 → 1.6.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/js/lib/menu-editor-arrange.js +2 -2
- package/admin/js/lib/shortcode-context-menu.js +2 -2
- package/admin/js/lib/shortcode-registry.js +1 -1
- package/admin/js/templates/menu-editor.html +17 -0
- package/admin/js/views/menu-editor.js +16 -16
- package/package.json +1 -1
- package/public/css/site.css +1 -1
- package/public/js/site.js +1 -1
- package/server/services/markdown.js +26 -2
- package/server/services/menus.js +118 -0
- package/server/services/renderer.js +47 -7
- package/server/templates/page.html +21 -2
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{decodeBase64Json as N}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as O,applyColour as j,applyPill as Y,applyFloat as G,applyHighlight as B,applyItemHighlight as U,itemHighlightAttrs as K,isCurrentItem as R,menuAlign as Q,applyClasses as D,cssClasses as P}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{initFloatingMenus as Z}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as V,markInvalidFields as W,showValidationPopup as J}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as ee}from"/public/js/form-steps.mjs";import{applyFormClasses as X,applySubmitButtons as te,applyWizardButtons as ae}from"/public/js/form-submit.mjs";$(()=>{const x=window.__CMS_NAV__||{},g=window.__CMS_SITE__||{};if(g.autoTheme?.enabled){let t=function(e){const r=(e||"07:00").split(":");return+r[0]*60+(+r[1]||0)},n=function(){const e=new Date,r=e.getHours()*60+e.getMinutes();return r>=t(o.dayStart)&&r<t(o.nightStart)?o.dayTheme:o.nightTheme},s=function(e){const r=o.apply&&o.apply[e]||{theme:e,custom:""};Domma.theme.set(r.theme);for(const d of[...document.body.classList])d.startsWith("dm-custom-")&&document.body.classList.remove(d);r.custom&&document.body.classList.add(r.custom)};const o=g.autoTheme;s(n()),setInterval(()=>s(n()),6e4)}const A=$("#site-navbar");if(A.length&&x.brand){let n=function(c,f=0){return Array.isArray(c)?c.filter(i=>!(i&&(i.type==="spacer"||i.type==="theme-switcher"))).filter(i=>!(i&&i.type==="separator"&&f===0)).map(i=>i&&i.type==="separator"?{divider:!0}:Array.isArray(i?.items)?{...i,items:n(i.items,f+1)}:i):c},s=function(c){return Array.isArray(c)?c.filter(f=>!(f&&(f.type==="separator"||f.type==="spacer"||f.type==="theme-switcher"))):[]};const o={...x.brand},t=o.size&&o.size!=="md"?` navbar-brand-${o.size}`:"";if(o.logo||o.icon||o.tagline){let c="";o.logo?c+=`<img src="${o.logo}" class="navbar-brand-logo" alt="${o.text||""}">`:o.icon&&(c+=`<span data-icon="${o.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),o.text&&(c+=`<span class="navbar-brand-text${t}">${o.text}</span>`),o.tagline&&(c+=`<small class="navbar-brand-tagline">${o.tagline}</small>`),o.html=c}else t&&o.text&&(o.html=`<span class="navbar-brand-text${t}">${o.text}</span>`);const e=x.position==="floating",r=x.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:o,items:n(x.items||[]),variant:x.variant||"dark",position:e?"static":x.position||"sticky",collapsible:!0,appearOnHover:!!x.appearOnHover}),Domma.icons.scan("#site-navbar");const d=A.get(0);d.classList.add(`dm-nav-align-${Q(x)||"centre"}`),r&&A.get(0).classList.add("dm-nav-vertical",x.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),B(d,x),D(d,x.class),e&&(G(A.get(0),x),Z(A.get(0).parentNode||document));const h=d.querySelector(".navbar-toggle"),p=d.querySelector(".navbar-collapse");if(h&&p){let c=null;const f=()=>{p.classList.contains("show")&&h.click()},i=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},a=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",f),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};h.addEventListener("click",()=>{requestAnimationFrame(()=>{p.classList.contains("show")?a():i()})}),p.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(i)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&p.classList.contains("show")&&f()})}const m=d.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let f=0;for(const i of x.items||[])if(!(i&&i.type==="separator")){if(i&&i.type==="spacer"){const a=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(i.size)?i.size:"md";a.className=`dm-menu-spacer dm-menu-spacer--${l}`,a.setAttribute("aria-hidden","true"),m.insertBefore(a,c[f]||null);continue}if(i&&i.type==="theme-switcher"){const a=document.createElement("li");a.className="dm-menu-theme-switcher";const l=document.createElement("span");l.dataset.themeSwitcher="menu",l.dataset.position="inline",a.appendChild(l),m.insertBefore(a,c[f]||null);continue}f++}window.CMSThemeSwitcher?.scan(m)}const b=s(x.items||[]);d.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const f=b[parseInt(c.dataset.index,10)];if(!f)return;const i=c.dataset.subindex!=null,a=i&&Array.isArray(f.items)?f.items[parseInt(c.dataset.subindex,10)]:f;if(!a)return;a.colour&&j(c,a.colour),a.pill&&!i&&Y(c,a.pill),U(c,a),D(c.closest("li"),a.class);const l=O(a.badge);l&&c.appendChild(l),R(a.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const w=$("#site-footer");if(w.length){let e=function(a){return String(a??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},r=function(a){return e(a).replace(/'/g,"'")},d=function(a){if(a&&a.type==="separator")return'<li class="footer-sep"><hr></li>';if(a&&a.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(a.size)?a.size:"md"}" aria-hidden="true"></li>`;if(a&&a.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const l=r(a.url||"#"),u=e(a.text||""),C=Array.isArray(a.items)&&a.items.length?`<ul>${a.items.map(d).join("")}</ul>`:"",v=K(a),q=[v.hover&&` data-menu-item-hover="${r(v.hover)}"`,v.active&&` data-menu-item-active="${r(v.active)}"`].filter(Boolean).join(""),M=v.accent?` style="--dm-menu-highlight:${r(v.accent)}"`:"",k=P(a.class).join(" ");return`<li${k?` class="${r(k)}"`:""}><a href="${l}"${q}${M}>${u}</a>${C}</li>`},h=function(a,l){return(a||[]).forEach(u=>{u&&(u.type==="separator"||u.type==="spacer"||u.type==="theme-switcher")||(l.push(u),Array.isArray(u.items)&&u.items.length&&h(u.items,l))}),l};const o=g.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let n='<div class="footer-inner container">';const s=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(s.copyright&&(n+=`<p>${e(s.copyright)}</p>`),s.primary.length&&(n+=`<nav class="footer-nav footer-nav--primary"><ul>${s.primary.map(d).join("")}</ul></nav>`),s.legal.length&&(n+=`<nav class="footer-nav footer-nav--legal"><ul>${s.legal.map(d).join("")}</ul></nav>`),g.footer){const a=Object.keys(t).filter(u=>o[u]),l=P(g.footer.socialClass).join(" ");a.length&&(n+='<div class="footer-social">',a.forEach(u=>{const{label:C,svg:v}=t[u];n+=`<a href="${o[u]}" target="_blank" rel="noopener noreferrer" aria-label="${C}" class="footer-social-link${l?` ${r(l)}`:""}">${v}</a>`}),n+="</div>")}n+="</div>",w.html(n),window.CMSThemeSwitcher?.scan(w.get(0)),D(w.get(0),g.footer?.class);const p=[...h(s.primary,[]),...h(s.legal,[])];w.get(0).querySelectorAll(".footer-nav a").forEach((a,l)=>{const u=p[l];if(!u)return;u.colour&&j(a,u.colour);const C=O(u.badge);C&&a.appendChild(C),R(u.url,location.pathname)&&(a.classList.add("is-active"),a.setAttribute("aria-current","page"))}),B(w.get(0).querySelector(".footer-nav--primary"),{highlight:s.primaryHighlight}),B(w.get(0).querySelector(".footer-nav--legal"),{highlight:s.legalHighlight}),D(w.get(0).querySelector(".footer-nav--primary"),s.primaryClass),D(w.get(0).querySelector(".footer-nav--legal"),s.legalClass);const b=g.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),f=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),i=w.get(0).querySelector(".footer-inner");if(b&&i){const a=document.createElement("input");a.type="checkbox",a.className="form-switch-input",a.id="dm-motion-switch",a.checked=f,a.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const l=document.createElement("span");l.className="form-switch-label",l.textContent="Reduce motion";const u=document.createElement("label");u.className="form-switch footer-motion-switch",u.title="Reduce motion",u.appendChild(a),u.appendChild(l),i.appendChild(u)}}if($("#site-sidebar").length){const o=document.querySelector(".site-content"),t=d=>!d.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),n=d=>o?[...o.querySelectorAll(d)].filter(t):[],s=n("h2").length?n("h2"):n("h3"),e=new Set([...document.querySelectorAll("[id]")].map(d=>d.id)),r=[];for(const d of s){if(!d.id){const h=(d.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let p=h;for(let m=2;e.has(p);m++)p=`${h}-${m}`;e.add(p),d.id=p}r.push({text:d.textContent.trim(),url:`#${d.id}`,section:d.id})}r.length?Domma.elements.sidebar("#site-sidebar",{items:r,fixed:!1,push:!1,collapsible:!1,variant:"theme",scrollSpy:!0,position:document.querySelector(".site-main.sidebar-right")?"right":"left"}):document.querySelector(".site-main.with-sidebar")?.classList.add("no-sidebar-items")}Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const y=$(".page-body");if(y.length){y.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),y.find(".tabs").each(function(){Domma.elements.tabs(this)}),y.find(".carousel").each(function(){const o={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(o.animationDuration=t)}this.dataset.animationEasing&&(o.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=o),this._dmCarousel=Domma.elements.carousel(this,o)}),y.find(".dm-countdown").each(function(){const o={autoStart:!0},t=String(this.dataset.format||"").trim(),n=String(this.dataset.to||"").trim(),s=/^(\d{4})-(\d{2})-(\d{2})$/.exec(n),e=s?new Date(+s[1],+s[2]-1,+s[3]).getTime():n?new Date(n).getTime():NaN;Number.isFinite(e)?o.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(o.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const r=/^dd:/i.test(t);o.format=r?"hh:mm:ss":t||(o.duration>=36e5?"hh:mm:ss":"mm:ss");const d=this,h=m=>String(m).padStart(2,"0"),p=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=d.querySelector(".dm-timer-time");c&&(c.textContent=`${h(Math.floor(b/86400))}:${h(Math.floor(b%86400/3600))}:${h(Math.floor(b%3600/60))}:${h(b%60)}`)};r&&(o.onTick=p),Domma.elements.timer(this,o),r&&p(o.duration||0)}),y.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),y.find(".dm-progression").each(function(){const o=Array.from(this.querySelectorAll(".dm-progression-item")).map(s=>{const e={title:s.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:s.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return s.dataset.date&&(e.date=s.dataset.date),s.dataset.status&&(e.status=s.dataset.status),s.dataset.entryId&&(e._entryId=s.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",n=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...o.length?{items:o}:{}});o.length&&(this._dmCtx={instance:n,items:o})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(o=>{const t=o.dataset.revealMode||"stagger",n=o.dataset.revealAnimation||"slide-up",s=parseInt(o.dataset.revealDuration,10)||400,e=parseInt(o.dataset.revealStagger,10)||60,r=parseInt(o.dataset.revealDelay,10)||0,d=o.dataset.revealDirection==="rtl",h=Array.from(o.children),p={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};h.forEach((m,b)=>{m.style.opacity="0",m.style.transform=p[n]||"",m.style.transition=`opacity ${s}ms ease, transform ${s}ms ease`;const c=d?h.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${r+c*e}ms`:`${r}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});h.forEach(b=>m.observe(b))}))}),y.find(".card[data-collapsible]").each(function(){const o=this.querySelector(".card-header");o&&o.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),y.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const o=this.dataset.soTarget,t=document.getElementById(o);if(!t)return;const n=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",n.setContent(t),n.open()})})}if(typeof $.setup=="function"){const o=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const n=N(t.dataset.config);Object.assign(o,n)}catch{}}),Object.keys(o).length>0){const t={};for(const[n,s]of Object.entries(o)){const e=s?.events?.click,{confirm:r,toast:d,alert:h,prompt:p,...m}=e||{};r||d||h||p?($(n).on("click",async function(c){if(c.preventDefault(),r&&!await E.confirm(r))return;let f=null;if(!(p&&(f=await E.prompt(p,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),f===null))){if(m.target){const i=$(m.target);m.toggleClass&&i.toggleClass(m.toggleClass),m.addClass&&i.addClass(m.addClass),m.removeClass&&i.removeClass(m.removeClass),f!==null&&(m.setText&&i.text(f),m.setVal&&i.val(f),m.setAttr&&i.attr(m.setAttr,f))}m.href&&(window.location.href=m.href),d&&E.toast(d,{type:m.toastType||"success"}),h&&E.alert(h)}}),Object.keys(m).length&&(t[n]={...s,events:{...s.events,click:m}})):t[n]=s}$.setup(t)}}y.length&&I(y.get(0))}),window.wireCTAButtons=I;function I(x){x.querySelectorAll(".dm-cta-trigger").forEach(g=>{g.__ctaWired||(g.__ctaWired=!0,g.addEventListener("click",async()=>{const A=g.dataset.action,w=g.dataset.entry,_=g.dataset.confirm;let y=S.get("auth_token");if(!y){E.toast("Please log in to perform this action.",{type:"warning"});return}if(_&&!await E.confirm(_))return;const o=Array.from(g.childNodes).map(n=>n.cloneNode(!0));g.disabled=!0,g.textContent="Running\u2026";const t=n=>fetch(`/api/actions/${A}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify(g.dataset.scope?{entryId:w,scope:g.dataset.scope}:{entryId:w})});try{let n=await t(y);if(n.status===401){const e=S.get("auth_refresh_token");if(e){const r=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(r.ok){const{token:d}=await r.json();S.set("auth_token",d),y=d,n=await t(y)}}}const s=await n.json().catch(()=>({}));if(!n.ok)throw new Error(s.error||s.message||`Error ${n.status}`);E.toast(s.message||"Action completed.",{type:"success"})}catch(n){E.toast(n.message||"Action failed.",{type:"error"})}finally{g.disabled=!1,g.textContent="",o.forEach(n=>g.appendChild(n)),Domma.icons.scan(g)}}))})}(function(){const g=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!g.length)return;const A=S.get("auth_token");function w(y,o){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const n=document.createElement("p");if(o){n.appendChild(document.createTextNode("Please "));const s=document.createElement("a");s.href="/login",s.textContent="sign in",n.appendChild(s),n.appendChild(document.createTextNode(" to view your entries."))}else n.textContent=y;return t.appendChild(n),t}function _(y,o){const t=document.createElement("template");t.innerHTML=o||"",y.replaceWith(t.content)}g.forEach(async y=>{const o=y.dataset.collectionAttrs;if(!o)return;if(!A){y.replaceChildren(w("",!0));return}const t=n=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({attrs:o})});try{let n=A,s=await t(n);if(s.status===401){const r=S.get("auth_refresh_token");if(r){const d=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:r})});if(d.ok){const{token:h}=await d.json();S.set("auth_token",h),n=h,s=await t(n)}}}if(!s.ok){const{error:r}=await s.json().catch(()=>({}));y.replaceChildren(w(r||"Unable to load entries.",!1));return}const{html:e}=await s.json();_(y,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{y.replaceChildren(w("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const g=document.querySelectorAll("[data-collection-table]");!g.length||typeof T>"u"||!T.create||g.forEach(A=>{let w;try{w=N(A.dataset.payload)}catch{return}const{columns:_,rows:y,search:o,sortable:t,exportable:n,pageSize:s,empty:e,ctaConfig:r,slug:d,exportCfg:h}=w;if(!_?.length)return;if(r){const b=_.findIndex(c=>c.key==="_cta");b!==-1&&(_[b]={key:"_cta",title:"",render:(c,f)=>{const i=document.createElement("button");if(i.className=`btn btn-${r.style||"primary"} dm-cta-trigger`,i.dataset.action=r.action||"",r.scope&&(i.dataset.scope=r.scope),i.dataset.entry=f._entryId||"",r.confirm&&(i.dataset.confirm=r.confirm),r.icon){const a=document.createElement("span");a.dataset.icon=r.icon,i.appendChild(a),i.appendChild(document.createTextNode(" "))}return i.appendChild(document.createTextNode(r.label||"Run")),i}})}const p="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=p,A.replaceChildren(m),T.create("#"+p,{data:y,columns:_,search:o,sortable:t,exportable:n,pageSize:s,emptyMessage:e}),r&&I(m),A._dmTable={columns:_,rows:y,slug:d,exportCfg:h,render(b){T.create("#"+p,{data:b,columns:_,search:o,sortable:t,exportable:n,pageSize:s,emptyMessage:e}),r&&I(m)}}})})(),(function(){const g=document.querySelectorAll("[data-form-inline]");if(!g.length||typeof F>"u")return;function A(t){const n=t&&t.logic;return!!(n&&(n.visibility||n.requirement))}function w(t,n){const s={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const r=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),d=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":r?"chooser":e.type,h={...e.formConfig||{}};h.span==="full"&&n&&(h.span=n);const p={type:d,required:A(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...h}};e.minLength!==void 0&&(p.minLength=e.minLength),e.maxLength!==void 0&&(p.maxLength=e.maxLength),e.min!==void 0&&(p.min=e.min),e.max!==void 0&&(p.max=e.max),r&&(e.variant&&(p.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(p.multiple=!0),e.density&&(p.density=e.density),e.columns&&(p.columns=e.columns),e.accent&&(p.accent=e.accent),e.accentStyle&&(p.accentStyle=e.accentStyle),e.glow&&(p.glow=!0),e.glowColour&&(p.glowColour=e.glowColour),e.shadow&&(p.shadow=e.shadow),e.shadowColour&&(p.shadowColour=e.shadowColour)),s[e.name]=p}),s}function _(t){const n={};return(t||[]).forEach(s=>{if(!(!s.name||s.type==="page-break"||s.type==="spacer")&&(s.type==="select"||s.type==="multiselect")&&s.required){const e=(s.options||[])[0];e&&(n[s.name]=typeof e=="object"?e.value:e)}}),n}function y(t,n){(n||[]).forEach(s=>{if(s.type!=="date"||!s.name)return;const e=t.querySelector(`[name="${s.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function o(t,n,s){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=n,e.style.cssText=s?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}g.forEach(t=>{let n;try{n=N(t.dataset.formInline)}catch{return}const s=n.fields||[],e=n.settings||{},r=Number(e.columns)===3?3:2,d=e.layout||"grid",h=s.some(i=>i.type==="page-break"),p=async i=>{if(t.dataset.triggerBlocked==="true"){const a=t._formLogicRuntime,l=a&&a.submitBlock?a.submitBlock().reasons:[];o(t,l.join(" ")||"This form cannot be submitted yet.",!0);const u=new Error("Blocked by a form trigger");throw u.formSubmitFailed=!0,u}try{const a=t.querySelector(".fb-form-honeypot"),l=a?.querySelector('input[type="text"]')||null,u=a?.querySelector('[name="_t"]')||null,C=Object.assign({},i);delete C._t,a?.dataset.hpName&&delete C[a.dataset.hpName],l!==null&&(C._hp=l.value),u!==null&&(C._t=u.value);const v=await H.post(`/api/forms/submit/${n.slug}`,C);if(v&&v.error){o(t,v.error,!0);const q=new Error(v.error);throw q.formSubmitFailed=!0,q}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);o(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(a){throw a.formSubmitFailed||o(t,a.message||"Submission failed. Please try again.",!0),a}},m=Date.now();function b(i){const a=i.querySelector("form");if(!a||a.querySelector(".fb-form-honeypot"))return;const l=document.createElement("div");l.className="fb-form-honeypot",l.setAttribute("aria-hidden","true");const u=document.createElement("input");u.name=a.querySelector('[name="website"]')?"_website":"website",l.dataset.hpName=u.name,u.type="text",u.tabIndex=-1,u.autocomplete="url",u.placeholder="https://",l.appendChild(u);const C=document.createElement("input");C.name="_t",C.type="hidden",C.value=m,l.appendChild(C),a.appendChild(l)}function c(i){if(!window.FormLogicEngine||!s.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const a=new window.FormLogicEngine.FormLogicRuntime(n,t,i?{baseValues:i}:void 0);if(a.init(),t._formLogicRuntime=a,t._formLogicObserved)return a;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(u){for(const C of u)for(const v of C.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=l}return a}let f=!1;if(t.addEventListener("dm-form-end",i=>{const a=i.detail?.validation;if(a&&!a.valid){W(t,a.missing),J(a);return}f||(f=!0,p(i.detail?.values||{}).catch(()=>{}).finally(()=>{f=!1}))}),h&&F.wizard){const i=ee(s,n.title),a=i.map(k=>({title:k.title,description:k.description,fields:w(k.fields,r)})),l=i.map(k=>k.fields);let u=0,C=null,v=null;const q=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const z=L.validateFields(t,l[u]||[]);z.valid||(k.preventDefault(),k.stopImmediatePropagation(),W(t,z.missing),J(z))},M=()=>{const k=l[u]||s;ae(t,e),X(t,e,k),y(t,k),V(t,k),e.honeypot!==!1&&b(t),C&&C.destroy(),C=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",q,!0))};v=F.wizard(t,{schema:{steps:a},layout:d,columns:r,finishText:e.submitText||"Finish",onSubmit:p,onStepChange:k=>{u=k,setTimeout(M,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=a.length||L!==u&&v.goToStep(L)}),Promise.resolve(v).then(M)}else if(F.render){const i=F.render(t,w(s,r),_(s),{submitText:e.submitText||"Submit",layout:d,columns:r,onSubmit:p});Promise.resolve(i).then(function(){te(t,e,d),X(t,e,s),y(t,s),V(t,s),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
1
|
+
import{decodeBase64Json as N}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as O,applyColour as j,applyPill as U,applyFloat as X,applyHighlight as B,applyItemHighlight as G,itemHighlightAttrs as K,isCurrentItem as R,menuAlign as Q,applyClasses as D,cssClasses as P}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{initFloatingMenus as Z}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as V,markInvalidFields as W,showValidationPopup as J}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as ee}from"/public/js/form-steps.mjs";import{applyFormClasses as Y,applySubmitButtons as te,applyWizardButtons as ae}from"/public/js/form-submit.mjs";$(()=>{const h=window.__CMS_NAV__||{},g=window.__CMS_SITE__||{};if(g.autoTheme?.enabled){let t=function(e){const n=(e||"07:00").split(":");return+n[0]*60+(+n[1]||0)},s=function(){const e=new Date,n=e.getHours()*60+e.getMinutes();return n>=t(o.dayStart)&&n<t(o.nightStart)?o.dayTheme:o.nightTheme},i=function(e){const n=o.apply&&o.apply[e]||{theme:e,custom:""};Domma.theme.set(n.theme);for(const r of[...document.body.classList])r.startsWith("dm-custom-")&&document.body.classList.remove(r);n.custom&&document.body.classList.add(n.custom)};const o=g.autoTheme;i(s()),setInterval(()=>i(s()),6e4)}const C=$("#site-navbar");if(C.length&&h.brand){let s=function(m,l=0){return Array.isArray(m)?m.filter(a=>!(a&&(a.type==="spacer"||a.type==="theme-switcher"))).filter(a=>!(a&&a.type==="separator"&&l===0)).map(a=>a&&a.type==="separator"?{divider:!0}:Array.isArray(a?.items)?{...a,items:s(a.items,l+1)}:a):m},i=function(m){return Array.isArray(m)?m.filter(l=>!(l&&(l.type==="separator"||l.type==="spacer"||l.type==="theme-switcher"))):[]};const o={...h.brand},t=o.size&&o.size!=="md"?` navbar-brand-${o.size}`:"";if(o.logo||o.icon||o.tagline){let m="";o.logo?m+=`<img src="${o.logo}" class="navbar-brand-logo" alt="${o.text||""}">`:o.icon&&(m+=`<span data-icon="${o.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),o.text&&(m+=`<span class="navbar-brand-text${t}">${o.text}</span>`),o.tagline&&(m+=`<small class="navbar-brand-tagline">${o.tagline}</small>`),o.html=m}else t&&o.text&&(o.html=`<span class="navbar-brand-text${t}">${o.text}</span>`);const e=h.position==="floating",n=h.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:o,items:s(h.items||[]),variant:h.variant||"dark",position:e?"static":h.position||"sticky",collapsible:!0,appearOnHover:!!h.appearOnHover}),Domma.icons.scan("#site-navbar");const r=C.get(0);r.classList.add(`dm-nav-align-${Q(h)||"centre"}`),n&&C.get(0).classList.add("dm-nav-vertical",h.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const y=h.dock||{};n&&!e&&oe(r,h.side==="right"),!n&&y.hideOnScroll&&ne(r),B(r,h),D(r,h.class),e&&(X(C.get(0),h),Z(C.get(0).parentNode||document));const p=r.querySelector(".navbar-toggle"),u=r.querySelector(".navbar-collapse");if(p&&u){let m=null;const l=()=>{u.classList.contains("show")&&p.click()},a=()=>{m&&(m.remove(),m=null),document.body.classList.remove("dm-drawer-open")},d=()=>{m||(m=document.createElement("div"),m.className="dm-navbar-backdrop",m.addEventListener("click",l),document.body.appendChild(m),document.body.classList.add("dm-drawer-open"))};p.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?d():a()})}),u.addEventListener("click",c=>{c.target.closest("a")&&requestAnimationFrame(a)}),document.addEventListener("keydown",c=>{c.key==="Escape"&&u.classList.contains("show")&&l()})}const b=r.querySelector(".navbar-nav");if(b){const m=Array.from(b.children);let l=0;for(const a of h.items||[])if(!(a&&a.type==="separator")){if(a&&a.type==="spacer"){const d=document.createElement("li"),c=["xs","sm","md","lg","xl","flex"].includes(a.size)?a.size:"md";d.className=`dm-menu-spacer dm-menu-spacer--${c}`,d.setAttribute("aria-hidden","true"),b.insertBefore(d,m[l]||null);continue}if(a&&a.type==="theme-switcher"){const d=document.createElement("li");d.className="dm-menu-theme-switcher";const c=document.createElement("span");c.dataset.themeSwitcher="menu",c.dataset.position="inline",d.appendChild(c),b.insertBefore(d,m[l]||null);continue}l++}window.CMSThemeSwitcher?.scan(b)}const k=i(h.items||[]);r.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(m=>{const l=k[parseInt(m.dataset.index,10)];if(!l)return;const a=m.dataset.subindex!=null,d=a&&Array.isArray(l.items)?l.items[parseInt(m.dataset.subindex,10)]:l;if(!d)return;d.colour&&j(m,d.colour),d.pill&&!a&&U(m,d.pill),G(m,d),D(m.closest("li"),d.class);const c=O(d.badge);c&&m.appendChild(c),R(d.url,location.pathname)&&(m.classList.add("active"),m.setAttribute("aria-current","page"))})}const f=$("#site-footer");if(f.length){let e=function(a){return String(a??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},n=function(a){return e(a).replace(/'/g,"'")},r=function(a){if(a&&a.type==="separator")return'<li class="footer-sep"><hr></li>';if(a&&a.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(a.size)?a.size:"md"}" aria-hidden="true"></li>`;if(a&&a.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const d=n(a.url||"#"),c=e(a.text||""),A=Array.isArray(a.items)&&a.items.length?`<ul>${a.items.map(r).join("")}</ul>`:"",w=K(a),q=[w.hover&&` data-menu-item-hover="${n(w.hover)}"`,w.active&&` data-menu-item-active="${n(w.active)}"`].filter(Boolean).join(""),I=w.accent?` style="--dm-menu-highlight:${n(w.accent)}"`:"",L=P(a.class).join(" ");return`<li${L?` class="${n(L)}"`:""}><a href="${d}"${q}${I}>${c}</a>${A}</li>`},y=function(a,d){return(a||[]).forEach(c=>{c&&(c.type==="separator"||c.type==="spacer"||c.type==="theme-switcher")||(d.push(c),Array.isArray(c.items)&&c.items.length&&y(c.items,d))}),d};const o=g.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const i=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(i.copyright&&(s+=`<p>${e(i.copyright)}</p>`),i.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${i.primary.map(r).join("")}</ul></nav>`),i.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${i.legal.map(r).join("")}</ul></nav>`),g.footer){const a=Object.keys(t).filter(c=>o[c]),d=P(g.footer.socialClass).join(" ");a.length&&(s+='<div class="footer-social">',a.forEach(c=>{const{label:A,svg:w}=t[c];s+=`<a href="${o[c]}" target="_blank" rel="noopener noreferrer" aria-label="${A}" class="footer-social-link${d?` ${n(d)}`:""}">${w}</a>`}),s+="</div>")}s+="</div>",f.html(s),window.CMSThemeSwitcher?.scan(f.get(0)),D(f.get(0),g.footer?.class);const p=[...y(i.primary,[]),...y(i.legal,[])];f.get(0).querySelectorAll(".footer-nav a").forEach((a,d)=>{const c=p[d];if(!c)return;c.colour&&j(a,c.colour);const A=O(c.badge);A&&a.appendChild(A),R(c.url,location.pathname)&&(a.classList.add("is-active"),a.setAttribute("aria-current","page"))}),B(f.get(0).querySelector(".footer-nav--primary"),{highlight:i.primaryHighlight}),B(f.get(0).querySelector(".footer-nav--legal"),{highlight:i.legalHighlight}),D(f.get(0).querySelector(".footer-nav--primary"),i.primaryClass),D(f.get(0).querySelector(".footer-nav--legal"),i.legalClass);const b=g.footer?.showMotionToggle!==!1,k=S.get("reduced_motion"),m=k!==null?!!k:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),l=f.get(0).querySelector(".footer-inner");if(b&&l){const a=document.createElement("input");a.type="checkbox",a.className="form-switch-input",a.id="dm-motion-switch",a.checked=m,a.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const d=document.createElement("span");d.className="form-switch-label",d.textContent="Reduce motion";const c=document.createElement("label");c.className="form-switch footer-motion-switch",c.title="Reduce motion",c.appendChild(a),c.appendChild(d),l.appendChild(c)}}if($("#site-sidebar").length){const o=document.querySelector(".site-content"),t=r=>!r.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),s=r=>o?[...o.querySelectorAll(r)].filter(t):[],i=s("h2").length?s("h2"):s("h3"),e=new Set([...document.querySelectorAll("[id]")].map(r=>r.id)),n=[];for(const r of i){if(!r.id){const y=(r.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let p=y;for(let u=2;e.has(p);u++)p=`${y}-${u}`;e.add(p),r.id=p}n.push({text:r.textContent.trim(),url:`#${r.id}`,section:r.id})}n.length?Domma.elements.sidebar("#site-sidebar",{items:n,fixed:!1,push:!1,collapsible:!1,variant:"theme",scrollSpy:!0,position:document.querySelector(".site-main.sidebar-right")?"right":"left"}):document.querySelector(".site-main.with-sidebar")?.classList.add("no-sidebar-items")}Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const v=$(".page-body");if(v.length){v.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),v.find(".tabs").each(function(){Domma.elements.tabs(this)}),v.find(".carousel").each(function(){const o={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(o.animationDuration=t)}this.dataset.animationEasing&&(o.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=o),this._dmCarousel=Domma.elements.carousel(this,o)}),v.find(".dm-countdown").each(function(){const o={autoStart:!0},t=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),i=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=i?new Date(+i[1],+i[2]-1,+i[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?o.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(o.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const n=/^dd:/i.test(t);o.format=n?"hh:mm:ss":t||(o.duration>=36e5?"hh:mm:ss":"mm:ss");const r=this,y=u=>String(u).padStart(2,"0"),p=u=>{const b=Math.max(0,Math.floor(u/1e3)),k=r.querySelector(".dm-timer-time");k&&(k.textContent=`${y(Math.floor(b/86400))}:${y(Math.floor(b%86400/3600))}:${y(Math.floor(b%3600/60))}:${y(b%60)}`)};n&&(o.onTick=p),Domma.elements.timer(this,o),n&&p(o.duration||0)}),v.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),v.find(".dm-progression").each(function(){const o=Array.from(this.querySelectorAll(".dm-progression-item")).map(i=>{const e={title:i.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:i.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return i.dataset.date&&(e.date=i.dataset.date),i.dataset.status&&(e.status=i.dataset.status),i.dataset.entryId&&(e._entryId=i.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...o.length?{items:o}:{}});o.length&&(this._dmCtx={instance:s,items:o})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(o=>{const t=o.dataset.revealMode||"stagger",s=o.dataset.revealAnimation||"slide-up",i=parseInt(o.dataset.revealDuration,10)||400,e=parseInt(o.dataset.revealStagger,10)||60,n=parseInt(o.dataset.revealDelay,10)||0,r=o.dataset.revealDirection==="rtl",y=Array.from(o.children),p={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};y.forEach((u,b)=>{u.style.opacity="0",u.style.transform=p[s]||"",u.style.transition=`opacity ${i}ms ease, transform ${i}ms ease`;const k=r?y.length-1-b:b;u.style.transitionDelay=t==="stagger"?`${n+k*e}ms`:`${n}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const u=new IntersectionObserver(b=>{b.forEach(k=>{k.isIntersecting&&(k.target.offsetWidth,k.target.style.opacity="1",k.target.style.transform="none",u.unobserve(k.target))})},{threshold:.1});y.forEach(b=>u.observe(b))}))}),v.find(".card[data-collapsible]").each(function(){const o=this.querySelector(".card-header");o&&o.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),v.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const o=this.dataset.soTarget,t=document.getElementById(o);if(!t)return;const s=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",s.setContent(t),s.open()})})}if(typeof $.setup=="function"){const o=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const s=N(t.dataset.config);Object.assign(o,s)}catch{}}),Object.keys(o).length>0){const t={};for(const[s,i]of Object.entries(o)){const e=i?.events?.click,{confirm:n,toast:r,alert:y,prompt:p,...u}=e||{};n||r||y||p?($(s).on("click",async function(k){if(k.preventDefault(),n&&!await E.confirm(n))return;let m=null;if(!(p&&(m=await E.prompt(p,{inputPlaceholder:u.promptPlaceholder||"",inputValue:u.promptDefault||""}),m===null))){if(u.target){const l=$(u.target);u.toggleClass&&l.toggleClass(u.toggleClass),u.addClass&&l.addClass(u.addClass),u.removeClass&&l.removeClass(u.removeClass),m!==null&&(u.setText&&l.text(m),u.setVal&&l.val(m),u.setAttr&&l.attr(u.setAttr,m))}u.href&&(window.location.href=u.href),r&&E.toast(r,{type:u.toastType||"success"}),y&&E.alert(y)}}),Object.keys(u).length&&(t[s]={...i,events:{...i.events,click:u}})):t[s]=i}$.setup(t)}}v.length&&M(v.get(0))}),window.wireCTAButtons=M;function M(h){h.querySelectorAll(".dm-cta-trigger").forEach(g=>{g.__ctaWired||(g.__ctaWired=!0,g.addEventListener("click",async()=>{const C=g.dataset.action,f=g.dataset.entry,x=g.dataset.confirm;let v=S.get("auth_token");if(!v){E.toast("Please log in to perform this action.",{type:"warning"});return}if(x&&!await E.confirm(x))return;const o=Array.from(g.childNodes).map(s=>s.cloneNode(!0));g.disabled=!0,g.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${C}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(g.dataset.scope?{entryId:f,scope:g.dataset.scope}:{entryId:f})});try{let s=await t(v);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const n=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(n.ok){const{token:r}=await n.json();S.set("auth_token",r),v=r,s=await t(v)}}}const i=await s.json().catch(()=>({}));if(!s.ok)throw new Error(i.error||i.message||`Error ${s.status}`);E.toast(i.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{g.disabled=!1,g.textContent="",o.forEach(s=>g.appendChild(s)),Domma.icons.scan(g)}}))})}(function(){const g=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!g.length)return;const C=S.get("auth_token");function f(v,o){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(o){s.appendChild(document.createTextNode("Please "));const i=document.createElement("a");i.href="/login",i.textContent="sign in",s.appendChild(i),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=v;return t.appendChild(s),t}function x(v,o){const t=document.createElement("template");t.innerHTML=o||"",v.replaceWith(t.content)}g.forEach(async v=>{const o=v.dataset.collectionAttrs;if(!o)return;if(!C){v.replaceChildren(f("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:o})});try{let s=C,i=await t(s);if(i.status===401){const n=S.get("auth_refresh_token");if(n){const r=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:n})});if(r.ok){const{token:y}=await r.json();S.set("auth_token",y),s=y,i=await t(s)}}}if(!i.ok){const{error:n}=await i.json().catch(()=>({}));v.replaceChildren(f(n||"Unable to load entries.",!1));return}const{html:e}=await i.json();x(v,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{v.replaceChildren(f("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),M(document.body)},100)})(),(function(){const g=document.querySelectorAll("[data-collection-table]");!g.length||typeof T>"u"||!T.create||g.forEach(C=>{let f;try{f=N(C.dataset.payload)}catch{return}const{columns:x,rows:v,search:o,sortable:t,exportable:s,pageSize:i,empty:e,ctaConfig:n,slug:r,exportCfg:y}=f;if(!x?.length)return;if(n){const b=x.findIndex(k=>k.key==="_cta");b!==-1&&(x[b]={key:"_cta",title:"",render:(k,m)=>{const l=document.createElement("button");if(l.className=`btn btn-${n.style||"primary"} dm-cta-trigger`,l.dataset.action=n.action||"",n.scope&&(l.dataset.scope=n.scope),l.dataset.entry=m._entryId||"",n.confirm&&(l.dataset.confirm=n.confirm),n.icon){const a=document.createElement("span");a.dataset.icon=n.icon,l.appendChild(a),l.appendChild(document.createTextNode(" "))}return l.appendChild(document.createTextNode(n.label||"Run")),l}})}const p="col-table-"+Math.random().toString(36).slice(2,7),u=document.createElement("div");u.id=p,C.replaceChildren(u),T.create("#"+p,{data:v,columns:x,search:o,sortable:t,exportable:s,pageSize:i,emptyMessage:e}),n&&M(u),C._dmTable={columns:x,rows:v,slug:r,exportCfg:y,render(b){T.create("#"+p,{data:b,columns:x,search:o,sortable:t,exportable:s,pageSize:i,emptyMessage:e}),n&&M(u)}}})})(),(function(){const g=document.querySelectorAll("[data-form-inline]");if(!g.length||typeof F>"u")return;function C(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function f(t,s){const i={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const n=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":n?"chooser":e.type,y={...e.formConfig||{}};y.span==="full"&&s&&(y.span=s);const p={type:r,required:C(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...y}};e.minLength!==void 0&&(p.minLength=e.minLength),e.maxLength!==void 0&&(p.maxLength=e.maxLength),e.min!==void 0&&(p.min=e.min),e.max!==void 0&&(p.max=e.max),n&&(e.variant&&(p.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(p.multiple=!0),e.density&&(p.density=e.density),e.columns&&(p.columns=e.columns),e.accent&&(p.accent=e.accent),e.accentStyle&&(p.accentStyle=e.accentStyle),e.glow&&(p.glow=!0),e.glowColour&&(p.glowColour=e.glowColour),e.shadow&&(p.shadow=e.shadow),e.shadowColour&&(p.shadowColour=e.shadowColour)),i[e.name]=p}),i}function x(t){const s={};return(t||[]).forEach(i=>{if(!(!i.name||i.type==="page-break"||i.type==="spacer")&&(i.type==="select"||i.type==="multiselect")&&i.required){const e=(i.options||[])[0];e&&(s[i.name]=typeof e=="object"?e.value:e)}}),s}function v(t,s){(s||[]).forEach(i=>{if(i.type!=="date"||!i.name)return;const e=t.querySelector(`[name="${i.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function o(t,s,i){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=i?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}g.forEach(t=>{let s;try{s=N(t.dataset.formInline)}catch{return}const i=s.fields||[],e=s.settings||{},n=Number(e.columns)===3?3:2,r=e.layout||"grid",y=i.some(l=>l.type==="page-break"),p=async l=>{if(t.dataset.triggerBlocked==="true"){const a=t._formLogicRuntime,d=a&&a.submitBlock?a.submitBlock().reasons:[];o(t,d.join(" ")||"This form cannot be submitted yet.",!0);const c=new Error("Blocked by a form trigger");throw c.formSubmitFailed=!0,c}try{const a=t.querySelector(".fb-form-honeypot"),d=a?.querySelector('input[type="text"]')||null,c=a?.querySelector('[name="_t"]')||null,A=Object.assign({},l);delete A._t,a?.dataset.hpName&&delete A[a.dataset.hpName],d!==null&&(A._hp=d.value),c!==null&&(A._t=c.value);const w=await H.post(`/api/forms/submit/${s.slug}`,A);if(w&&w.error){o(t,w.error,!0);const q=new Error(w.error);throw q.formSubmitFailed=!0,q}if(w?.redirect){window.location.href=w.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);o(t,w?.message||e.successMessage||"Thank you for your submission.",!1)}catch(a){throw a.formSubmitFailed||o(t,a.message||"Submission failed. Please try again.",!0),a}},u=Date.now();function b(l){const a=l.querySelector("form");if(!a||a.querySelector(".fb-form-honeypot"))return;const d=document.createElement("div");d.className="fb-form-honeypot",d.setAttribute("aria-hidden","true");const c=document.createElement("input");c.name=a.querySelector('[name="website"]')?"_website":"website",d.dataset.hpName=c.name,c.type="text",c.tabIndex=-1,c.autocomplete="url",c.placeholder="https://",d.appendChild(c);const A=document.createElement("input");A.name="_t",A.type="hidden",A.value=u,d.appendChild(A),a.appendChild(d)}function k(l){if(!window.FormLogicEngine||!i.some(d=>d.logic||Array.isArray(d.triggers)&&d.triggers.length))return null;const a=new window.FormLogicEngine.FormLogicRuntime(s,t,l?{baseValues:l}:void 0);if(a.init(),t._formLogicRuntime=a,t._formLogicObserved)return a;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const d=new MutationObserver(function(c){for(const A of c)for(const w of A.removedNodes)if(w===t||w.nodeType===1&&w.contains&&w.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),d.disconnect();return}});d.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=d}return a}let m=!1;if(t.addEventListener("dm-form-end",l=>{const a=l.detail?.validation;if(a&&!a.valid){W(t,a.missing),J(a);return}m||(m=!0,p(l.detail?.values||{}).catch(()=>{}).finally(()=>{m=!1}))}),y&&F.wizard){const l=ee(i,s.title),a=l.map(L=>({title:L.title,description:L.description,fields:f(L.fields,n)})),d=l.map(L=>L.fields);let c=0,A=null,w=null;const q=L=>{const _=window.FormLogicEngine;if(!_||!_.validateFields)return;const z=_.validateFields(t,d[c]||[]);z.valid||(L.preventDefault(),L.stopImmediatePropagation(),W(t,z.missing),J(z))},I=()=>{const L=d[c]||i;ae(t,e),Y(t,e,L),v(t,L),V(t,L),e.honeypot!==!1&&b(t),A&&A.destroy(),A=k(w?.getStepData?w.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(_=>_.addEventListener("click",q,!0))};w=F.wizard(t,{schema:{steps:a},layout:r,columns:n,finishText:e.submitText||"Finish",onSubmit:p,onStepChange:L=>{c=L,setTimeout(I,0)}}),t.addEventListener("dm-form-trigger",L=>{if(L.detail?.type!=="goto-step"||!w?.goToStep)return;const _=Number(L.detail.action.step);!Number.isFinite(_)||_<0||_>=a.length||_!==c&&w.goToStep(_)}),Promise.resolve(w).then(I)}else if(F.render){const l=F.render(t,f(i,n),x(i),{submitText:e.submitText||"Submit",layout:r,columns:n,onSubmit:p});Promise.resolve(l).then(function(){te(t,e,r),Y(t,e,i),v(t,i),V(t,i),e.honeypot!==!1&&b(t),k()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();function oe(h,g){const C=document.body,f=C.classList,x=new Set((C.dataset.railSite||"").split(" ").filter(Boolean)),v=()=>window.matchMedia("(min-width: 993px)").matches;h.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(n=>{const r=n.textContent.trim();r&&(n.setAttribute("title",r),n.querySelector("svg, [data-icon]")||(n.dataset.initial=r.charAt(0).toUpperCase()))});const o=document.createElement("button");o.type="button",o.className="dm-nav-collapse-toggle";const t=()=>{const n=f.contains("dm-vnav-collapsed");o.setAttribute("aria-pressed",String(n)),o.setAttribute("aria-label",n?"Expand menu":"Collapse menu"),o.title=o.getAttribute("aria-label");const r=g?"chevrons-left":"chevrons-right",y=g?"chevrons-right":"chevrons-left";o.innerHTML=`<span data-icon="${n?r:y}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(o)},s=n=>{f.toggle("dm-vnav-collapsed",n),S.set("nav_collapsed",n),t()};o.addEventListener("click",()=>s(!f.contains("dm-vnav-collapsed"))),t();const i=h.querySelector(".navbar-container")||h;i.insertBefore(o,i.firstChild?.nextSibling||null);const e=n=>{f.toggle("dm-vnav-autohide",n),f.toggle("dm-vnav-collapsible",!n&&x.has("collapsible")),n?f.remove("dm-vnav-collapsed"):x.has("collapsible")&&S.get("nav_collapsed")===!0&&f.add("dm-vnav-collapsed"),h.classList.remove("dm-nav-revealed"),t()};h.addEventListener("pointerdown",n=>{f.contains("dm-vnav-autohide")&&n.pointerType!=="mouse"&&!h.classList.contains("dm-nav-revealed")&&(h.classList.add("dm-nav-revealed"),n.preventDefault())}),document.addEventListener("pointerdown",n=>{h.contains(n.target)||h.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(h,{items:()=>{const n=f.contains("dm-vnav-autohide"),r=f.contains("dm-vnav-collapsed"),y=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:r?"Expand menu":"Collapse to icons",icon:r?"maximize":"minimize",disabled:!v()||n||!x.has("collapsible"),action:()=>s(!r)},{label:n?"Keep on screen":"Hide when not in use",icon:n?"eye":"eye-off",disabled:!v(),action:()=>{S.set("nav_autohide",!n),e(!n)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!y,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(x.has("autohide")),f.toggle("dm-vnav-collapsed",!x.has("autohide")&&x.has("start-collapsed")),t()}}]}})}function ne(h){h.classList.add("dm-nav-scroll-hide");let g=window.scrollY,C=!1;window.addEventListener("scroll",()=>{C||(C=!0,requestAnimationFrame(()=>{C=!1;const f=window.scrollY,x=h.matches(":focus-within")||h.querySelector(".navbar-dropdown.open, .navbar-collapse.show");f>g&&f>h.offsetHeight&&!x?h.classList.add("dm-nav-scrolled-away"):f<g&&h.classList.remove("dm-nav-scrolled-away"),g=f}))},{passive:!0})}
|
|
@@ -12,7 +12,7 @@ import {fileURLToPath} from 'url';
|
|
|
12
12
|
import {applyTransforms, getSanitizeExtensions, getShortcodeProcessors} from './hooks.js';
|
|
13
13
|
import {getConfig} from '../config.js';
|
|
14
14
|
import {getCollection, listEntries} from './collections.js';
|
|
15
|
-
import {getMenu, resolveLocation, resolveMenuDecorations} from './menus.js';
|
|
15
|
+
import {getMenu, navbarOverrideFromAttrs, resolveLocation, resolveMenuDecorations} from './menus.js';
|
|
16
16
|
import {buildMenuNav} from './menuRender.js';
|
|
17
17
|
import {checkVisibility} from '../middleware/auth.js';
|
|
18
18
|
import {getRoleHierarchy, getRoleLevel} from './roles.js';
|
|
@@ -3618,6 +3618,30 @@ function processSpacerBlocks(markdown) {
|
|
|
3618
3618
|
* @param {string} markdown
|
|
3619
3619
|
* @returns {string}
|
|
3620
3620
|
*/
|
|
3621
|
+
/**
|
|
3622
|
+
* [navbar ... /] - this page's own navbar settings, over the navbar menu's.
|
|
3623
|
+
*
|
|
3624
|
+
* Any Behaviour setting of the menu, as attributes (see NAVBAR_OVERRIDE_ATTRS in
|
|
3625
|
+
* menus.js): position, orientation, side, align, variant, hover-open, hover,
|
|
3626
|
+
* selected, accent, class, font, font-size, font-weight, letter-spacing,
|
|
3627
|
+
* icon-size, width, collapsible, collapsed, autohide, hide-on-scroll and the
|
|
3628
|
+
* float-* panel options. `true` / `false` switch a setting on or off; an empty
|
|
3629
|
+
* value clears it. Leaves a hidden marker the renderer reads (the first tag on
|
|
3630
|
+
* a page counts) - it draws nothing itself.
|
|
3631
|
+
*
|
|
3632
|
+
* [navbar collapsed="true" /]
|
|
3633
|
+
* [navbar autohide="true" width="200" /]
|
|
3634
|
+
* [navbar position="floating" float-anchor="TR" float-collapsible="true" /]
|
|
3635
|
+
*/
|
|
3636
|
+
function processNavbarBlocks(markdown) {
|
|
3637
|
+
const {scrubbed, restore} = scrubCodeRegions(markdown);
|
|
3638
|
+
return restore(scrubbed.replace(/\[navbar(\s[^\]]*?)?\/?\]/gi, (_, attrStr) => {
|
|
3639
|
+
const override = navbarOverrideFromAttrs(parseShortcodeAttrs(attrStr || ''));
|
|
3640
|
+
if (!Object.keys(override).length) return '';
|
|
3641
|
+
return `<span class="dm-navbar-override" hidden data-navbar-override="${escapeAttr(JSON.stringify(override))}"></span>`;
|
|
3642
|
+
}));
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3621
3645
|
export const THEME_SWITCHER_POSITIONS = ['inline', 'top-left', 'top-right', 'left-center', 'right-center', 'bottom-left', 'bottom-right'];
|
|
3622
3646
|
|
|
3623
3647
|
function processThemeSwitcherBlocks(markdown) {
|
|
@@ -4470,7 +4494,7 @@ export async function parseMarkdown(raw, opts = {}) {
|
|
|
4470
4494
|
const withTimeline = processTimelineBlocks(withCountdown);
|
|
4471
4495
|
const withListGroup = processListGroupBlocks(withTimeline);
|
|
4472
4496
|
const withSpacer = processSpacerBlocks(withListGroup);
|
|
4473
|
-
const withSwitcher = processThemeSwitcherBlocks(withSpacer);
|
|
4497
|
+
const withSwitcher = processNavbarBlocks(processThemeSwitcherBlocks(withSpacer));
|
|
4474
4498
|
const withCenter = processCenterBlocks(withSwitcher);
|
|
4475
4499
|
const withIcon = processIconBlocks(withCenter);
|
|
4476
4500
|
const withDemo = processDemoBlocks(withIcon);
|
package/server/services/menus.js
CHANGED
|
@@ -255,6 +255,112 @@ export function spacerSize(item) {
|
|
|
255
255
|
// floating switcher itself is on.
|
|
256
256
|
// ---------------------------------------------------------------------------
|
|
257
257
|
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// Docked menu behaviour - `dock: {width, collapsible, collapsed, autohide, hideOnScroll}`.
|
|
260
|
+
//
|
|
261
|
+
// For the menu in the navbar slot when it is docked (not floating):
|
|
262
|
+
// width a vertical rail's width in px (160-480; 240 when unset)
|
|
263
|
+
// collapsible a vertical rail gets a toggle that shrinks it to its icons;
|
|
264
|
+
// the visitor's choice is remembered in their browser
|
|
265
|
+
// collapsed ...and starts that way until they choose
|
|
266
|
+
// autohide a vertical rail slides off-screen, leaving its edge, and comes
|
|
267
|
+
// back when the pointer reaches it (or focus moves into it)
|
|
268
|
+
// hideOnScroll a horizontal bar slides away while scrolling down and comes
|
|
269
|
+
// back on the way up
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
export const DOCK_WIDTH_MIN = 160;
|
|
272
|
+
export const DOCK_WIDTH_MAX = 480;
|
|
273
|
+
|
|
274
|
+
/** A dock block with only known keys and sane values; null when nothing is set. */
|
|
275
|
+
export function normaliseDock(dock) {
|
|
276
|
+
if (!dock || typeof dock !== 'object' || Array.isArray(dock)) return null;
|
|
277
|
+
const out = {};
|
|
278
|
+
const width = parseInt(dock.width, 10);
|
|
279
|
+
if (Number.isFinite(width)) out.width = Math.min(DOCK_WIDTH_MAX, Math.max(DOCK_WIDTH_MIN, width));
|
|
280
|
+
for (const key of ['collapsible', 'collapsed', 'autohide', 'hideOnScroll']) {
|
|
281
|
+
if (dock[key] === true) out[key] = true;
|
|
282
|
+
}
|
|
283
|
+
if (out.collapsed && !out.collapsible) out.collapsible = true; // starting collapsed needs the toggle back
|
|
284
|
+
return Object.keys(out).length ? out : null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ---------------------------------------------------------------------------
|
|
288
|
+
// Per-page overrides - the `[navbar ... /]` tag.
|
|
289
|
+
//
|
|
290
|
+
// A page can change any of its navbar menu's Behaviour settings for itself
|
|
291
|
+
// alone. The tag's attributes map onto the menu's keys below; `true`/`false`
|
|
292
|
+
// switch a setting on or off (so a page can turn off what the menu turns on),
|
|
293
|
+
// and an empty value clears it back to the default. The renderer merges the
|
|
294
|
+
// override over the menu, then validates the result - an override that would
|
|
295
|
+
// not pass validateMenu is dropped whole rather than half-applied.
|
|
296
|
+
// ---------------------------------------------------------------------------
|
|
297
|
+
export const NAVBAR_OVERRIDE_ATTRS = {
|
|
298
|
+
'variant': ['variant'], 'position': ['position'], 'orientation': ['orientation'],
|
|
299
|
+
'align': ['align'], 'side': ['side'], 'hover-open': ['appearOnHover', 'bool'], 'class': ['class'],
|
|
300
|
+
'hover': ['highlight', 'hover'], 'selected': ['highlight', 'active'], 'accent': ['highlight', 'accent'],
|
|
301
|
+
'font': ['style', 'fontFamily'], 'font-size': ['style', 'fontSize'], 'font-weight': ['style', 'fontWeight'],
|
|
302
|
+
'letter-spacing': ['style', 'letterSpacing'], 'icon-size': ['style', 'iconSize'],
|
|
303
|
+
'width': ['dock', 'width', 'num'], 'collapsible': ['dock', 'collapsible', 'bool'],
|
|
304
|
+
'collapsed': ['dock', 'collapsed', 'bool'], 'autohide': ['dock', 'autohide', 'bool'],
|
|
305
|
+
'hide-on-scroll': ['dock', 'hideOnScroll', 'bool'],
|
|
306
|
+
'float-anchor': ['float', 'anchor'], 'float-x': ['float', 'offsetX', 'num'], 'float-y': ['float', 'offsetY', 'num'],
|
|
307
|
+
'float-width': ['float', 'width', 'num'], 'float-radius': ['float', 'radius', 'num'],
|
|
308
|
+
'float-shadow': ['float', 'shadow'], 'float-accent': ['float', 'accent'], 'float-opacity': ['float', 'opacity', 'num'],
|
|
309
|
+
'float-title': ['float', 'title'], 'float-collapsible': ['float', 'collapsible', 'bool'],
|
|
310
|
+
'float-collapsed': ['float', 'collapsed', 'bool'], 'float-movable': ['float', 'movable', 'bool'],
|
|
311
|
+
'float-resizable': ['float', 'resizable', 'bool']
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* The override a tag's attributes describe: `{key: value}` for top-level settings and
|
|
316
|
+
* `{group: {key: value}}` for float / highlight / style / dock. `null` means "clear".
|
|
317
|
+
*/
|
|
318
|
+
export function navbarOverrideFromAttrs(attrs = {}) {
|
|
319
|
+
const out = {};
|
|
320
|
+
for (const [name, raw] of Object.entries(attrs)) {
|
|
321
|
+
const spec = NAVBAR_OVERRIDE_ATTRS[name];
|
|
322
|
+
if (!spec) continue;
|
|
323
|
+
const [group, keyOrKind, kind] = spec;
|
|
324
|
+
const nested = spec.length === 3 || (spec.length === 2 && !['bool', 'num'].includes(keyOrKind));
|
|
325
|
+
const type = nested ? kind : keyOrKind;
|
|
326
|
+
let value = raw === true ? 'true' : String(raw).trim();
|
|
327
|
+
if (value === '') value = null;
|
|
328
|
+
else if (type === 'bool') value = value !== 'false' && value !== '0' && value !== 'no';
|
|
329
|
+
else if (type === 'num') value = Number.isFinite(Number(value)) ? Number(value) : value;
|
|
330
|
+
if (nested) (out[group] ||= {})[keyOrKind] = value;
|
|
331
|
+
else out[group] = value;
|
|
332
|
+
}
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* A menu with a page's override applied, or the menu as it was when the result would
|
|
338
|
+
* not validate. Groups merge key by key; `null` removes a key, `false` turns a switch off.
|
|
339
|
+
*/
|
|
340
|
+
export function applyMenuOverride(menu, override) {
|
|
341
|
+
if (!menu || !override || !Object.keys(override).length) return menu;
|
|
342
|
+
const next = {...menu};
|
|
343
|
+
for (const [key, value] of Object.entries(override)) {
|
|
344
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
345
|
+
const group = {...(menu[key] || {})};
|
|
346
|
+
for (const [k, v] of Object.entries(value)) {
|
|
347
|
+
if (v === null || v === false) delete group[k]; else group[k] = v;
|
|
348
|
+
}
|
|
349
|
+
if (Object.keys(group).length) next[key] = group; else delete next[key];
|
|
350
|
+
} else if (value === null || value === false) {
|
|
351
|
+
delete next[key];
|
|
352
|
+
} else {
|
|
353
|
+
next[key] = value;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (validateMenu(next).length) return menu;
|
|
357
|
+
if (next.dock) {
|
|
358
|
+
const dock = normaliseDock(next.dock);
|
|
359
|
+
if (dock) next.dock = dock; else delete next.dock;
|
|
360
|
+
}
|
|
361
|
+
return next;
|
|
362
|
+
}
|
|
363
|
+
|
|
258
364
|
/** Items that hold no link: they are drawn, not navigated. */
|
|
259
365
|
export const isStructuralItem = (it) => !!it && (it.type === 'separator' || it.type === 'spacer' || it.type === 'theme-switcher');
|
|
260
366
|
|
|
@@ -501,6 +607,7 @@ export async function createMenu(input) {
|
|
|
501
607
|
...(input.float != null && {float: input.float}),
|
|
502
608
|
...(input.highlight != null && {highlight: input.highlight}),
|
|
503
609
|
...(input.style != null && {style: input.style}),
|
|
610
|
+
...(normaliseDock(input.dock) && {dock: normaliseDock(input.dock)}),
|
|
504
611
|
...(binding != null && {binding}),
|
|
505
612
|
items: Array.isArray(input.items) ? input.items : [],
|
|
506
613
|
meta: {
|
|
@@ -546,6 +653,7 @@ export async function updateMenu(slug, input) {
|
|
|
546
653
|
...(input.float != null && {float: input.float}),
|
|
547
654
|
...(input.highlight != null && {highlight: input.highlight}),
|
|
548
655
|
...(input.style != null && {style: input.style}),
|
|
656
|
+
...(normaliseDock(input.dock) && {dock: normaliseDock(input.dock)}),
|
|
549
657
|
...(binding != null && {binding}),
|
|
550
658
|
items: Array.isArray(input.items) ? input.items : [],
|
|
551
659
|
meta: {
|
|
@@ -662,6 +770,16 @@ export function validateMenu(menu) {
|
|
|
662
770
|
if (menu.side != null && !SIDES.has(menu.side)) {
|
|
663
771
|
errors.push(`Invalid side "${menu.side}" - expected one of: ${[...SIDES].join(', ')}`);
|
|
664
772
|
}
|
|
773
|
+
if (menu.dock != null) {
|
|
774
|
+
if (typeof menu.dock !== 'object' || Array.isArray(menu.dock)) {
|
|
775
|
+
errors.push('dock must be an object');
|
|
776
|
+
} else if (menu.dock.width != null && menu.dock.width !== '') {
|
|
777
|
+
const w = Number(menu.dock.width);
|
|
778
|
+
if (!Number.isFinite(w) || w < DOCK_WIDTH_MIN || w > DOCK_WIDTH_MAX) {
|
|
779
|
+
errors.push(`dock.width must be a number of px from ${DOCK_WIDTH_MIN} to ${DOCK_WIDTH_MAX}`);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
665
783
|
if (menu.style != null) {
|
|
666
784
|
if (typeof menu.style !== 'object' || Array.isArray(menu.style)) {
|
|
667
785
|
errors.push('style must be an object');
|
|
@@ -8,7 +8,7 @@ import {fileURLToPath} from 'url';
|
|
|
8
8
|
import {getConfig} from '../config.js';
|
|
9
9
|
import {getInjectionSnippets} from './plugins.js';
|
|
10
10
|
import {applyTransforms} from './hooks.js';
|
|
11
|
-
import {hasThemeSwitcherItem, resolveLocation, resolveMenuDecorations, resolveOverlaysForPage} from './menus.js';
|
|
11
|
+
import {applyMenuOverride, hasThemeSwitcherItem, resolveLocation, resolveMenuDecorations, resolveOverlaysForPage} from './menus.js';
|
|
12
12
|
import {buildMenuNav} from './menuRender.js';
|
|
13
13
|
import {getProjectForPage} from './projects.js';
|
|
14
14
|
import {resolveContextMenusForPage} from './contextMenus.js';
|
|
@@ -122,6 +122,17 @@ function buildAnalyticsTag() {
|
|
|
122
122
|
* html (body and overlay menus) and the item lists of its navbar and footers
|
|
123
123
|
* @returns {{headTag: string, bodyTag: string}} Empty strings when nothing needs it
|
|
124
124
|
*/
|
|
125
|
+
/** The override a page's [navbar] tag left in its html (the first one), or null. */
|
|
126
|
+
function readNavbarOverride(html) {
|
|
127
|
+
const m = /data-navbar-override="([^"]*)"/.exec(html || '');
|
|
128
|
+
if (!m) return null;
|
|
129
|
+
try {
|
|
130
|
+
return JSON.parse(m[1].replace(/"/g, '"').replace(/'/g, "'").replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&'));
|
|
131
|
+
} catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
125
136
|
function buildThemeSwitcherAssets(themeCfg, page = {}) {
|
|
126
137
|
const sw = themeCfg?.switcher || {};
|
|
127
138
|
const html = page.html || '';
|
|
@@ -235,7 +246,7 @@ export async function renderPage(page, opts = {}) {
|
|
|
235
246
|
project: page.resolvedProject
|
|
236
247
|
|| await getProjectForPage(page.urlPath || page.url || '/', page.project)
|
|
237
248
|
};
|
|
238
|
-
const [template, site, presets, injection, customCss,
|
|
249
|
+
const [template, site, presets, injection, customCss, navMenuOwn, footerPrimary, footerLegal] = await Promise.all([
|
|
239
250
|
getTemplate(),
|
|
240
251
|
Promise.resolve(getConfig('site')),
|
|
241
252
|
Promise.resolve(getConfig('presets')),
|
|
@@ -246,6 +257,8 @@ export async function renderPage(page, opts = {}) {
|
|
|
246
257
|
resolveLocation('footer-legal', opts.user || null, menuCtx)
|
|
247
258
|
]);
|
|
248
259
|
const baseUrl = opts.baseUrl || site.baseUrl || '';
|
|
260
|
+
// The page's own navbar settings ([navbar ... /]) over the menu's, for this page only.
|
|
261
|
+
const navMenu = applyMenuOverride(navMenuOwn, readNavbarOverride(page.html));
|
|
249
262
|
|
|
250
263
|
// Resolve live badge counts (countFrom) before the menus are injected as
|
|
251
264
|
// globals. Static badges/colours/pills pass through unchanged.
|
|
@@ -277,6 +290,9 @@ export async function renderPage(page, opts = {}) {
|
|
|
277
290
|
...(navMenu.align && {align: navMenu.align}),
|
|
278
291
|
...(navMenu.float && {float: navMenu.float}),
|
|
279
292
|
...(navMenu.appearOnHover && {appearOnHover: true}),
|
|
293
|
+
// Docked behaviour (rail width, collapse, autohide, hide on scroll) - site.js
|
|
294
|
+
// wires it; width and autohide also shape the body below, from the first paint.
|
|
295
|
+
...(navMenu.dock && {dock: navMenu.dock}),
|
|
280
296
|
// Item highlighting: the navbar is built in the browser, so the
|
|
281
297
|
// config has to travel to site.js rather than being rendered here.
|
|
282
298
|
...(navMenu.highlight && {highlight: navMenu.highlight}),
|
|
@@ -293,9 +309,7 @@ export async function renderPage(page, opts = {}) {
|
|
|
293
309
|
const layoutWidth = pageWidth || (VALID_LAYOUT_WIDTHS.has(preset.width) ? preset.width : 'normal');
|
|
294
310
|
// A vertical navbar docks as a side rail, so the body needs its gutter from
|
|
295
311
|
// the first paint - stamping the class client-side would shift the layout.
|
|
296
|
-
const verticalNavClass = (navigation
|
|
297
|
-
? `dm-vnav dm-vnav-${navigation.side === 'right' ? 'right' : 'left'}`
|
|
298
|
-
: '';
|
|
312
|
+
const verticalNavClass = railBodyClass(navigation);
|
|
299
313
|
const navbarClass = (navigation.orientation === 'vertical' && navigation.position !== 'floating')
|
|
300
314
|
? `dm-nav-vertical dm-nav-vertical-${navigation.side === 'right' ? 'right' : 'left'}`
|
|
301
315
|
: '';
|
|
@@ -404,6 +418,7 @@ export async function renderPage(page, opts = {}) {
|
|
|
404
418
|
layoutBodyClass,
|
|
405
419
|
pageBodyStyle,
|
|
406
420
|
navbarClass,
|
|
421
|
+
railDocked: /\bdm-vnav\b/.test(verticalNavClass),
|
|
407
422
|
showNavbar: preset.navbar !== false,
|
|
408
423
|
showFooter: preset.footer !== false,
|
|
409
424
|
showSidebar: preset.sidebar === true || page.sidebar === true,
|
|
@@ -819,10 +834,30 @@ function escapeHtml(str) {
|
|
|
819
834
|
.replace(/"/g, '"');
|
|
820
835
|
}
|
|
821
836
|
|
|
837
|
+
/**
|
|
838
|
+
* The body classes a docked vertical rail needs from the first paint: the gutter
|
|
839
|
+
* on its side, none when it autohides (it slides over the page), and a marker
|
|
840
|
+
* for a collapsible one (page.html's boot script adds the visitor's collapsed
|
|
841
|
+
* state before paint, so the gutter is right straight away).
|
|
842
|
+
*/
|
|
843
|
+
function railBodyClass(navigation) {
|
|
844
|
+
if (navigation.orientation !== 'vertical' || navigation.position === 'floating') return '';
|
|
845
|
+
const dock = navigation.dock || {};
|
|
846
|
+
return [
|
|
847
|
+
'dm-vnav', `dm-vnav-${navigation.side === 'right' ? 'right' : 'left'}`,
|
|
848
|
+
dock.autohide ? 'dm-vnav-autohide' : '',
|
|
849
|
+
dock.collapsible && !dock.autohide ? 'dm-vnav-collapsible' : '',
|
|
850
|
+
dock.collapsed && !dock.autohide ? 'dm-vnav-start-collapsed' : ''
|
|
851
|
+
].filter(Boolean).join(' ');
|
|
852
|
+
}
|
|
853
|
+
|
|
822
854
|
function buildNavbarStyleTag(nav) {
|
|
823
855
|
const s = nav?.style || {};
|
|
856
|
+
// A docked rail's width is a token the rail and the body's gutter both read.
|
|
857
|
+
const railWidth = nav?.orientation === 'vertical' && Number.isFinite(nav?.dock?.width)
|
|
858
|
+
? `:root { --dm-vnav-width: ${Math.round(nav.dock.width)}px; }` : '';
|
|
824
859
|
if (!s.fontFamily && !s.fontSize && !s.fontWeight && !s.letterSpacing && !s.iconSize) {
|
|
825
|
-
return {navbarFontLink: '', navbarStyleTag: ''};
|
|
860
|
+
return {navbarFontLink: '', navbarStyleTag: railWidth ? `<style>${railWidth}</style>` : ''};
|
|
826
861
|
}
|
|
827
862
|
let navbarFontLink = '';
|
|
828
863
|
if (s.fontFamily && s.fontFamily !== 'system-ui' && s.fontFamily !== 'inherit') {
|
|
@@ -843,6 +878,7 @@ function buildNavbarStyleTag(nav) {
|
|
|
843
878
|
const iconSel = '#site-navbar .navbar-link [data-icon], #site-navbar .navbar-link svg, #site-navbar .navbar-dropdown-toggle [data-icon], #site-navbar .navbar-dropdown-toggle svg';
|
|
844
879
|
rules.push(`${iconSel} { width: ${s.iconSize} !important; height: ${s.iconSize} !important; }`);
|
|
845
880
|
}
|
|
881
|
+
if (railWidth) rules.push(railWidth);
|
|
846
882
|
const navbarStyleTag = `<style>${rules.join(' ')}</style>`;
|
|
847
883
|
return {navbarFontLink, navbarStyleTag};
|
|
848
884
|
}
|
|
@@ -1014,6 +1050,9 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
|
|
|
1014
1050
|
...(navMenu.orientation === 'vertical' && {orientation: 'vertical', side: navMenu.side === 'right' ? 'right' : 'left'}),
|
|
1015
1051
|
...(navMenu.align && {align: navMenu.align}),
|
|
1016
1052
|
...(navMenu.appearOnHover && {appearOnHover: true}),
|
|
1053
|
+
// Docked behaviour (rail width, collapse, autohide, hide on scroll) - site.js
|
|
1054
|
+
// wires it; width and autohide also shape the body below, from the first paint.
|
|
1055
|
+
...(navMenu.dock && {dock: navMenu.dock}),
|
|
1017
1056
|
// Item highlighting: the navbar is built in the browser, so the
|
|
1018
1057
|
// config has to travel to site.js rather than being rendered here.
|
|
1019
1058
|
...(navMenu.highlight && {highlight: navMenu.highlight}),
|
|
@@ -1119,9 +1158,10 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
|
|
|
1119
1158
|
fontStyleTag,
|
|
1120
1159
|
layout: 'default',
|
|
1121
1160
|
layoutBodyClass: ['dm-layout-normal', navigation.orientation === 'vertical'
|
|
1122
|
-
?
|
|
1161
|
+
? railBodyClass(navigation)
|
|
1123
1162
|
: '', ...cssClasses(site.bodyClass)].filter(Boolean).join(' '),
|
|
1124
1163
|
pageBodyStyle: '',
|
|
1164
|
+
railDocked: navigation.orientation === 'vertical' && /\bdm-vnav\b/.test(railBodyClass(navigation)),
|
|
1125
1165
|
showNavbar: true,
|
|
1126
1166
|
showFooter: true,
|
|
1127
1167
|
showSidebar: false,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
<link rel="stylesheet" href="/dist/domma/themes/domma-themes.css">
|
|
26
26
|
|
|
27
27
|
<!-- Site CSS -->
|
|
28
|
-
<link rel="stylesheet" href="/public/css/site.css?v=20261011-
|
|
28
|
+
<link rel="stylesheet" href="/public/css/site.css?v=20261011-docked-menus">
|
|
29
29
|
<link rel="stylesheet" href="/public/css/forms.css?v=20260927-submit-btn-css">
|
|
30
30
|
<!-- Menu item hover / current-page effects. Loaded after site.css so a
|
|
31
31
|
menu's own highlight wins over the blanket link styling there. -->
|
|
@@ -41,6 +41,25 @@
|
|
|
41
41
|
{{headInjectLate}}
|
|
42
42
|
</head>
|
|
43
43
|
<body class="dm-cloaked dm-theme-{{dommaTheme}} {{customThemeClass}} {{layoutBodyClass}}" data-layout="{{layout}}">
|
|
44
|
+
{{#if railDocked}}
|
|
45
|
+
<script>
|
|
46
|
+
// A docked rail: the visitor's own choices - collapsed, or hidden when not in use
|
|
47
|
+
// (the rail's right-click menu sets them) - over the menu's, before the first paint,
|
|
48
|
+
// so the page's gutter is right straight away. site.js owns the controls.
|
|
49
|
+
(function () {
|
|
50
|
+
var b = document.body, cl = b.classList;
|
|
51
|
+
var get = function (k) { try { return JSON.parse(localStorage.getItem('domma:' + k)); } catch (e) { return null; } };
|
|
52
|
+
b.dataset.railSite = ['autohide', 'collapsible', 'start-collapsed']
|
|
53
|
+
.filter(function (k) { return cl.contains('dm-vnav-' + k); }).join(' ');
|
|
54
|
+
var hide = get('nav_autohide');
|
|
55
|
+
if (hide === true) { cl.add('dm-vnav-autohide'); cl.remove('dm-vnav-collapsible'); }
|
|
56
|
+
if (hide === false) { cl.remove('dm-vnav-autohide'); if (b.dataset.railSite.indexOf('collapsible') !== -1) cl.add('dm-vnav-collapsible'); }
|
|
57
|
+
if (!cl.contains('dm-vnav-collapsible')) return;
|
|
58
|
+
var c = get('nav_collapsed');
|
|
59
|
+
if (c === true || (c === null && cl.contains('dm-vnav-start-collapsed'))) cl.add('dm-vnav-collapsed');
|
|
60
|
+
})();
|
|
61
|
+
</script>
|
|
62
|
+
{{/if}}
|
|
44
63
|
|
|
45
64
|
{{#if showNavbar}}
|
|
46
65
|
<nav id="site-navbar" class="{{navbarClass}}"></nav>
|
|
@@ -137,7 +156,7 @@
|
|
|
137
156
|
</script>
|
|
138
157
|
|
|
139
158
|
<!-- Site initialisation -->
|
|
140
|
-
<script src="/public/js/site.js?v=20261011-
|
|
159
|
+
<script src="/public/js/site.js?v=20261011-docked-menus" type="module"></script>
|
|
141
160
|
<script src="/public/js/collection-context.js?v=20261010-utf8-payloads" type="module"></script>
|
|
142
161
|
{{ctxMenusModule}}
|
|
143
162
|
|