domma-cms 1.8.44 → 1.8.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/admin/js/lib/code-format.js +50 -40
- package/admin/js/templates/docs/usage-blocks.html +29 -0
- package/admin/js/views/page-editor.js +10 -8
- package/docs/configuration.md +19 -7
- package/docs/starter-blocks.md +203 -0
- package/package.json +1 -1
- package/server/blocks/catalog.json +98 -0
- package/server/blocks/domma-block-banner.css +65 -0
- package/server/blocks/domma-block-banner.html +22 -0
- package/server/blocks/domma-block-banner.meta.json +7 -0
- package/server/blocks/domma-block-contact.css +18 -0
- package/server/blocks/domma-block-contact.html +15 -0
- package/server/blocks/domma-block-contact.meta.json +7 -0
- package/server/blocks/domma-block-cta.css +8 -0
- package/server/blocks/domma-block-cta.html +17 -0
- package/server/blocks/domma-block-cta.meta.json +7 -0
- package/server/blocks/domma-block-faq.css +13 -0
- package/server/blocks/domma-block-faq.html +17 -0
- package/server/blocks/domma-block-faq.meta.json +7 -0
- package/server/blocks/domma-block-features.css +18 -0
- package/server/blocks/domma-block-features.html +19 -0
- package/server/blocks/domma-block-features.meta.json +7 -0
- package/server/blocks/domma-block-hero.css +15 -0
- package/server/blocks/domma-block-hero.html +13 -0
- package/server/blocks/domma-block-hero.meta.json +7 -0
- package/server/blocks/domma-block-image.css +8 -0
- package/server/blocks/domma-block-image.html +12 -0
- package/server/blocks/domma-block-image.meta.json +7 -0
- package/server/blocks/domma-block-logos.css +13 -0
- package/server/blocks/domma-block-logos.html +18 -0
- package/server/blocks/domma-block-logos.meta.json +7 -0
- package/server/blocks/domma-block-pricing-card.css +20 -0
- package/server/blocks/domma-block-pricing-card.html +15 -0
- package/server/blocks/domma-block-pricing-card.meta.json +7 -0
- package/server/blocks/domma-block-service-card.css +17 -0
- package/server/blocks/domma-block-service-card.html +15 -0
- package/server/blocks/domma-block-service-card.meta.json +7 -0
- package/server/blocks/domma-block-split.css +26 -0
- package/server/blocks/domma-block-split.html +22 -0
- package/server/blocks/domma-block-split.meta.json +7 -0
- package/server/blocks/domma-block-stats.css +20 -0
- package/server/blocks/domma-block-stats.html +16 -0
- package/server/blocks/domma-block-stats.meta.json +7 -0
- package/server/blocks/domma-block-steps.css +19 -0
- package/server/blocks/domma-block-steps.html +17 -0
- package/server/blocks/domma-block-steps.meta.json +7 -0
- package/server/blocks/domma-block-team-card.css +13 -0
- package/server/blocks/domma-block-team-card.html +14 -0
- package/server/blocks/domma-block-team-card.meta.json +7 -0
- package/server/blocks/domma-block-testimonial.css +13 -0
- package/server/blocks/domma-block-testimonial.html +12 -0
- package/server/blocks/domma-block-testimonial.meta.json +7 -0
- package/server/blocks/domma-block-text.css +9 -0
- package/server/blocks/domma-block-text.html +11 -0
- package/server/blocks/domma-block-text.meta.json +7 -0
- package/server/services/blocks.js +2 -0
- package/server/services/starter-blocks.js +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.46] - 2026-10-23
|
|
4
|
+
|
|
5
|
+
- **Format lays HTML out properly.** Shift+Alt+F used to re-indent HTML line by line and nothing more, so `<div><h2>…</h2><p>…</p></div>` stayed on one line and a closer trailing a line threw the rest out. It now puts every block element (div, p, li, h2, section, custom elements…) on a line of its own, indented by nesting, with `{{#if}}` sections the same; text and inline tags (`<a>`, `<strong>`, `<span>`) keep the lines they were written on, so no space appears or goes on the page. Tags get one space between attributes, a tag wider than 120 columns an attribute a line. HTML blocks in the page body are laid out too (new setting *Lay out HTML in the page body*, on), and Enter after an opening block tag in the body goes one deeper. Checked across the fleet's pages (all render the same) and the CMS's own 150 templates.
|
|
6
|
+
|
|
7
|
+
## [1.8.45] - 2026-10-23
|
|
8
|
+
|
|
9
|
+
- Include a free library of 16 editable `domma-block-*` Custom Blocks with every site: introductions, image/text sections, features, services, testimonials, figures, steps, FAQs, contact details, pricing, team profiles, images, logos and calls to action. Each includes scoped responsive styling and examples. Startup adds missing blocks while preserving site customisations.
|
|
10
|
+
|
|
3
11
|
## [1.8.44] - 2026-10-23
|
|
4
12
|
|
|
5
13
|
- **Blocks with empty fields no longer show raw HTML.** A block placeholder on its own line with nothing to fill it (`{{bio}}` when there is no bio) left a blank line, which ended the block's HTML in the Markdown, and what followed showed on the page as code - the About page's team card printed its contact links as raw tags. Such a line is now dropped when it fills empty (`fillTemplateLines()` in `markdown.js`), for collection displays and block short tags alike; a template's own blank lines stay, since they are how it hands a Markdown value to marked.
|
|
@@ -1,44 +1,54 @@
|
|
|
1
|
-
let
|
|
2
|
-
`).filter(
|
|
3
|
-
`)
|
|
4
|
-
|
|
1
|
+
let C=" ";export const DEFAULT_CODE_PREFS=Object.freeze({indent:"spaces",size:2,detect:!0,autoIndent:!0,continueLists:!0,shortTags:!0,tables:!0,html:!0,formatOnSave:!1}),INDENT_SIZES=Object.freeze([2,4,8]);export function cleanCodePrefs(t={}){const n=DEFAULT_CODE_PREFS,e=s=>typeof t?.[s]=="boolean"?t[s]:n[s];return{indent:t?.indent==="tabs"?"tabs":"spaces",size:INDENT_SIZES.includes(Number(t?.size))?Number(t.size):n.size,detect:e("detect"),autoIndent:e("autoIndent"),continueLists:e("continueLists"),shortTags:e("shortTags"),tables:e("tables"),html:e("html"),formatOnSave:e("formatOnSave")}}let E=cleanCodePrefs();export function setCodePrefs(t){E=cleanCodePrefs(t)}export const codePrefs=()=>E,prefUnit=()=>E.indent==="tabs"?" ":" ".repeat(E.size),unitFor=t=>E.detect?detectIndent(t,prefUnit()):prefUnit();export function detectIndent(t,n=" "){const e=String(t).split(`
|
|
2
|
+
`).filter(r=>r.trim()),s=e.filter(r=>r.startsWith(" ")).length,o=e.filter(r=>r.startsWith(" ")).length;if(s>o)return" ";const l=e.map(r=>r.match(/^ */)[0].length).filter(r=>r>0);return l.length?l.filter(r=>r%4===2).length>l.length/5?" ":n===" ".repeat(8)&&l.every(r=>r%8===0)?n:" ":n}export function isFormatKey(t){return!t||!t.altKey||!t.shiftKey||t.ctrlKey||t.metaKey?!1:t.code==="KeyF"||String(t.key||"").toLowerCase()==="f"}export function formatCode(t,n){const e=String(t??"").replace(/\r\n?/g,`
|
|
3
|
+
`),s=e.split(`
|
|
4
|
+
`).filter(o=>/^[ \t]+\S/.test(o)).length;C=n==="md"||n==="html"&&s<3?prefUnit():unitFor(e);try{switch(n){case"json":return{text:formatJson(e)};case"css":return{text:formatCss(e)};case"js":return{text:formatJs(e)};case"html":return{text:formatHtml(e)};case"md":return{text:formatMarkdown(e)};default:return{error:"Nothing to format here."}}}catch(o){return{error:o.message||"Could not format this."}}}export function formatJson(t){if(!t.trim())return t;try{JSON.parse(t)}catch(o){throw new Error(`Not valid JSON: ${o.message}`)}let n="",e=0;const s=()=>`
|
|
5
|
+
`+C.repeat(e);for(let o=0;o<t.length;o++){const l=t[o];if(l==='"'){let a=o+1;for(;t[a]!=='"';)a+=t[a]==="\\"?2:1;n+=t.slice(o,a+1),o=a}else if(l==="{"||l==="["){const a=l==="{"?"}":"]",r=t.slice(o+1).search(/\S/);if(t[o+1+r]===a){n+=l+a,o+=r+1;continue}e++,n+=l+s()}else l==="}"||l==="]"?(e--,n+=s()+l):l===","?n+=","+s():l===":"?n+=": ":/\s/.test(l)||(n+=l)}return n+(t.endsWith(`
|
|
5
6
|
`)?`
|
|
6
|
-
`:"")}export function formatCss(t){if(!t.trim())return t;if(/\{\{\{?\s*[#/^\w]/.test(t))throw new Error("This CSS has {{placeholders}} in it - left as it is.");const
|
|
7
|
-
`);
|
|
8
|
-
`;)
|
|
7
|
+
`:"")}export function formatCss(t){if(!t.trim())return t;if(/\{\{\{?\s*[#/^\w]/.test(t))throw new Error("This CSS has {{placeholders}} in it - left as it is.");const n=[];let e=0,s="",o=!1,l="",a=!1,r=0;const i=()=>C.repeat(e),f=u=>{o&&n.length&&n[n.length-1]!==""&&!n[n.length-1].endsWith("{")&&n.push(""),o=!1,n.push(u)},p=()=>{a&&e===0?(o=!0,a=!1):(l.match(/\n/g)||[]).length>=2&&(o=!0),l=""},d=u=>{const g=u.match(/^(--[\w-]+|[-\w]+)\s*:\s*([\s\S]*)$/);return!g||u.startsWith("@")?u:`${g[1]}: ${g[2]}`},m=u=>{const g=s.trim();if(s="",!!g){if(u==="{"){const y=g.startsWith("@")?[g]:Z(g,",");y.forEach((b,$)=>f(i()+b.trim()+($<y.length-1?",":" {")));return}f(i()+d(g)+";")}};for(let u=0;u<t.length;u++){const g=t[u];if(g==="/"&&t[u+1]==="*"){const y=t.indexOf("*/",u+2),b=y<0?t.length:y+2,$=t.slice(u,b);if(s.trim())s+=$;else{p();const c=$.split(`
|
|
8
|
+
`);f(i()+c[0]),n.push(...c.slice(1))}u=b-1;continue}if(g==='"'||g==="'"){s.trim()||p();let y=u+1;for(;y<t.length&&t[y]!==g&&t[y]!==`
|
|
9
|
+
`;)y+=t[y]==="\\"?2:1;s+=t.slice(u,y+1),u=y;continue}if(/\s/.test(g)){s.trim()?s.endsWith(" ")||(s+=" "):l+=g;continue}if(s.trim()||p(),g==="("?r++:g===")"&&(r=Math.max(0,r-1)),r===0&&g==="{"){m("{"),e++,l="";continue}if(r===0&&g===";"){m(";");continue}if(r===0&&g==="}"){if(m(";"),e--,e<0)throw new Error("There is a } with no { before it.");o=!1,n.push(i()+"}"),l="",e===0&&(a=!0);continue}s+=g}if(s.trim()&&m(";"),e!==0)throw new Error(`${e} { left without a closing }.`);return n.join(`
|
|
9
10
|
`)+`
|
|
10
|
-
`}function
|
|
11
|
-
`),s={comment:!1,str:null,stack:[]},
|
|
12
|
-
`)}const
|
|
13
|
-
`),
|
|
14
|
-
`);let
|
|
15
|
-
`))
|
|
16
|
-
`)
|
|
17
|
-
|
|
18
|
-
`)
|
|
19
|
-
`)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`)
|
|
11
|
+
`}function Z(t,n){const e=[];let s=0,o=null,l="";for(const a of t){if(o)a===o&&(o=null);else if(a==='"'||a==="'")o=a;else if("([{".includes(a))s++;else if(")]}".includes(a))s--;else if(a===n&&s===0){e.push(l),l="";continue}l+=a}return e.push(l),e}const v=/(^|[(,=:[!&|?{};+\-*%<>~^]|\b(?:return|typeof|case|do|else|in|of|new|delete|void|throw|yield|await))\s*$/;function q(t,n,e){let s=0;if(n.str){let o=0;for(;o<t.length&&t[o]!==n.str;)o+=t[o]==="\\"?2:1;if(o>=t.length){t.endsWith("\\")||(n.str=null);return}n.str=null,s=o+1}for(;s<t.length;){const o=n.stack[n.stack.length-1];if(n.comment){const a=t.indexOf("*/",s);if(a<0)return;n.comment=!1,s=a+2;continue}if(o==="`"){const a=t[s];if(a==="\\"){s+=2;continue}if(a==="`"){n.stack.pop(),s++;continue}if(a==="$"&&t[s+1]==="{"){n.stack.push("${"),s+=2;continue}s++;continue}const l=t[s];if(l==="/"&&t[s+1]==="/")return;if(l==="/"&&t[s+1]==="*"){n.comment=!0,s+=2;continue}if(l==='"'||l==="'"){let a=s+1;for(;a<t.length&&t[a]!==l;)a+=t[a]==="\\"?2:1;if(a>=t.length&&t.endsWith("\\")){n.str=l;return}s=a+1;continue}if(l==="`"){n.stack.push("`"),s++;continue}if(l==="/"&&v.test(t.slice(0,s))){let a=s+1,r=!1;for(;a<t.length;){const i=t[a];if(i==="\\"){a+=2;continue}if(i==="[")r=!0;else if(i==="]")r=!1;else if(i==="/"&&!r)break;a++}s=a+1;continue}if(l==="}"&&o==="${"){n.stack.pop(),s++;continue}l==="{"&&n.stack.length?n.stack.push("{"):l==="}"&&o==="{"&&n.stack.pop(),"{[(".includes(l)?e(l,s,!0):"}])".includes(l)&&e(l,s,!1),s++}}function L(t){return t.replace(/(["'`])(?:\\.|(?!\1).)*\1/g,'""').replace(/\/\*.*?(\*\/|$)/g,"").replace(/\/\/.*$/,"").trimEnd()}export function formatJs(t,n=0){const e=t.split(`
|
|
12
|
+
`),s={comment:!1,str:null,stack:[]},o=[],l=[];let a="";const r=()=>{const i=o[o.length-1];return i?i.at+1+(i.sw&&i.inCase?1:0):0};if(e.forEach((i,f)=>{const p=s.stack[s.stack.length-1]==="`"||!!s.str,d=s.comment,m=i.trim();let u=i;if(p)u=i;else if(!m)u="";else if(d)u=C.repeat(n+r())+(m.startsWith("*")?" ":"")+m;else{const y=Math.min(o.length,(m.match(/^[}\])]+/)||[""])[0].length),b=o[o.length-1],$=/^(case\b.*|default\s*):/.test(m);let c;y?c=o[o.length-y].at:b?.sw&&$?c=b.at+1:c=r();const h=L(m),w=/^(\.(?!\.\.)|\?\.|[+\-*/%]|&&|\|\||\?\?|\?(?!\.)|:(?!:))/.test(h)&&!$||/(=>|[^=!<>]=|[+\-*/%]|&&|\|\||\?\?|\?)$/.test(a)&&!y&&!/^[{[(]/.test(h),x=h.startsWith("/")&&v.test(a);w&&!x&&!/^[}\])]/.test(m)&&c++,u=C.repeat(n+c)+m}l.push(u);const g=Math.round(u.match(/^[ \t]*/)[0].length/C.length)-n;if(p||d||m){const y=o[o.length-1];q(i,s,(b,$,c)=>{if(c){const h=b==="{"&&/\bswitch\s*\(.*\)\s*$/.test(L(i.slice(0,$)));o.push({at:p||d?r():g,sw:h,inCase:!1})}else o.pop()}),y?.sw&&!p&&!d&&/^(case\b.*|default\s*):/.test(m)&&(y.inCase=!0),!p&&!d&&(a=L(m))}}),s.comment||s.str||s.stack.some(i=>i!=="{"))throw new Error("A comment, string or template is left open.");return l.join(`
|
|
13
|
+
`)}const _=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),P=new Set(["pre","textarea","script","style"]),z=new Set(["address","article","aside","blockquote","body","caption","center","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","legend","li","main","menu","nav","ol","optgroup","option","p","pre","search","section","summary","table","tbody","td","tfoot","th","thead","tr","ul"]),D=new Set(["base","link","meta","noscript","param","script","source","style","template","title","track"]),H=new Set(["address","article","aside","blockquote","details","dialog","div","dl","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","hr","main","menu","nav","ol","p","pre","search","section","table","ul"]),J=120;export function formatHtml(t,{templates:n=!0}={}){if(!t.trim())return t;const e=[],s=c=>c.includes(`
|
|
14
|
+
`)?`\0${e.push(c)-1}\0`:c,o=c=>C.repeat(c),l=c=>c?.type==="el"&&z.has(c.name)||c?.type==="raw"&&c.name==="pre"||c?.type==="decl",a=c=>{if(c.type!=="el"||!c.open.lineStart||!c.close?.lineEnd)return!1;const h=c.children.map(d).join("");return/^[ \t]*\n/.test(h)&&/\n\s*$/.test(h)},r=(c,h)=>!c||!h||l(c)||l(h)||c.type==="text"&&/\s$/.test(c.text)||h.type==="text"&&/^\s/.test(h.text),i=new WeakSet,f=c=>{c.forEach((h,w)=>{const x=h.type==="el"||h.type==="sec"?h.children:null;if(x&&f(x),l(h)){i.add(h);return}if(!(!(x&&x.some(k=>i.has(k))||a(h)||h.type==="sec"&&h.open.lineStart||h.type==="comment"&&h.lineStart||(h.type==="el"||h.type==="raw"||h.type==="stray")&&(D.has(h.name)||z.has(h.name)))||!r(c[w-1],h)||!r(h,c[w+1]))){if(x&&x.length){const k=(T,j)=>l(T)||T.type==="text"&&j.test(T.text);if(!k(x[0],/^\s/)||!k(x[x.length-1],/\s$/)||x.some((T,j)=>T.type==="else"&&(!r(x[j-1],T)||!r(T,x[j+1]))))return}i.add(h)}})},p=c=>i.has(c),d=c=>{switch(c.type){case"text":return c.text;case"el":return m(c.open.text,-1)[0]+(c.close?""+c.children.map(d).join("")+""+c.close.text:c.children.map(d).join(""));case"sec":return c.open.text+c.children.map(d).join("")+(c.close?.text??"");case"raw":return s(c.open+c.body+c.close);default:return s(c.text)}},m=(c,h)=>{const w=X(c);if(!w)return[s(c)];const x=w.slash?w.attrs.length||w.spaced?" />":"/>":">",S=`<${w.name}${w.attrs.map(k=>" "+k).join("")}${x}`;return h<0||w.attrs.length<2||o(h).length+S.length<=J?[h<0?S:o(h)+S]:[o(h)+"<"+w.name,...w.attrs.map((k,T)=>o(h+1)+k+(T===w.attrs.length-1?x.trim()===">"?">":x:""))]},u=c=>c.type==="text"&&!c.text.trim(),g=(c,h)=>{const w=[];let x=!1;const S=j=>{x&&w.length&&w.push(""),x=!1,w.push(j)};let k=[];const T=()=>{if(!k.length)return;const j=k.map(d).join("").split(`
|
|
15
|
+
`).map(O=>O.trim());k=[];let N=0;j.forEach((O,A)=>{const F=(O.match(/^(?:\u0002<\/[^>]*>)+/)||[""])[0].split("").length-1,K=Math.max(0,N-F);N+=O.split("").length-O.split("").length,O=O.replace(/[\u0001\u0002]/g,""),O?S(o(h+K)+O):A>0&&A<j.length-1&&!j[A-1]&&(x=!0)})};for(const j of c){if(!p(j)){k.push(j);continue}T(),y(j,h).forEach(S)}return T(),w},y=(c,h)=>{if(c.type==="el"){const w=m(c.open.text,h),x=c.close?c.close.text:"";if(c.children.every(u))return w.length===1&&x?[w[0]+x]:x?[...w,o(h)+x]:w;if(w.length===1&&!c.children.some(p)){const S=c.children.map(d).join("").replace(c.close?/$^/:/\s+$/,"");if(!S.includes(`
|
|
16
|
+
`))return[w[0]+S.replace(/[\u0001\u0002]/g,"")+x]}return[...w,...g(c.children,h+1),...x?[o(h)+x]:[]]}if(c.type==="sec"){const w=[o(h)+c.open.text];let x=[];for(const S of c.children){if(S.type!=="else"){x.push(S);continue}w.push(...g(x,h+1),o(h)+S.text),x=[]}return w.push(...g(x,h+1)),c.close&&w.push(o(h)+c.close.text),w}if(c.type==="raw"){if(c.name==="pre"||!c.body.includes(`
|
|
17
|
+
`)||!c.close)return[o(h)+s(c.open+c.body+c.close)];const w=c.body.replace(/^[ \t]*\n/,"").replace(/\n[ \t]*$/,"");let x=null;try{const S=(c.open.match(/\btype\s*=\s*["']?([^"'\s>]*)/i)||[])[1]||"";c.name==="script"&&(!S||/module|javascript|ecmascript/i.test(S))?x=formatJs(w,h+1):c.name==="style"&&(x=Y(formatCss(Q(w)).replace(/\n$/,""),h+1))}catch{x=null}return[o(h)+s(c.open),...(x??s(w)).split(`
|
|
18
|
+
`),o(h)+c.close]}return[o(h)+s(c.text)]},b=V(G(t,n));return f(b),g(b,0).join(`
|
|
19
|
+
`).replace(/[\u0001\u0002]/g,"").replace(/\u0000(\d+)\u0000/g,(c,h)=>e[Number(h)])+(t.endsWith(`
|
|
20
|
+
`)?`
|
|
21
|
+
`:"")}function U(t,n){let e=null;for(let s=n+1;s<t.length;s++){const o=t[s];if(e){o===e&&(e=null);continue}if(o==='"'||o==="'")e=o;else if(o==="{"&&t[s+1]==="{"){const l=t.indexOf("}}",s+2);if(l<0)return-1;s=l+1}else{if(o===">")return s+1;if(o==="<")return-1}}return-1}function G(t,n){const e=[];let s=0,o=0;const l=(a,r)=>{s>o&&e.push({type:"text",text:t.slice(o,s)}),a.lineStart=!t.slice(t.lastIndexOf(`
|
|
22
|
+
`,s-1)+1,s).trim(),a.lineEnd=/^[ \t]*(\n|$)/.test(t.slice(r,r+200)),e.push(a),s=o=r};for(;s<t.length;){const a=t[s],r=t[s+1]||"";if(a==="<"&&t.startsWith("<!--",s)){const i=t.indexOf("-->",s+4);l({type:"comment",text:t.slice(s,i<0?t.length:i+3)},i<0?t.length:i+3);continue}if(a==="<"&&r==="!"){const i=t.indexOf(">",s);if(i>=0){l({type:"decl",text:t.slice(s,i+1)},i+1);continue}}if(a==="<"&&r==="/"){const i=/^<\/([a-zA-Z][\w:.-]*)\s*>/.exec(t.slice(s,s+200));if(i){l({type:"close",name:i[1].toLowerCase(),text:i[0]},s+i[0].length);continue}}if(a==="<"&&/[a-zA-Z]/.test(r)){const i=U(t,s);if(i>0){const f=t.slice(s,i),p=/^<([a-zA-Z][\w:.-]*)/.exec(f)[1].toLowerCase(),d=_.has(p)||B(f);if(P.has(p)&&!d){const m=new RegExp(`</${p}\\s*>`,"i").exec(t.slice(i)),u=m?i+m.index:t.length;l({type:"raw",name:p,open:f,body:t.slice(i,u),close:m?m[0]:""},m?u+m[0].length:u);continue}l({type:"open",name:p,text:f,self:d},i);continue}}if(n&&a==="{"&&r==="{"){if(t.startsWith("{{!--",s)){const f=t.indexOf("--}}",s);s=f<0?t.length:f+4;continue}const i=t.indexOf("}}",s+2);if(i>=0){const f=t.slice(s+2,i).trim();let p,d=null;if((p=/^[#^]\s*([\w.-]+)/.exec(f))?d={type:"hb",kind:"open",name:p[1]}:(p=/^\/\s*([\w.-]+)$/.exec(f))?d={type:"hb",kind:"close",name:p[1]}:/^(else\b|\^$)/.test(f)&&(d={type:"hb",kind:"else"}),d){d.text=t.slice(s,i+2),l(d,i+2);continue}s=i+2;continue}}s++}return s>o&&e.push({type:"text",text:t.slice(o,s)}),e}function V(t){const n={type:"root",children:[]},e=[n],s=()=>e[e.length-1],o=r=>s().children.push(r),l=r=>{for(let i=e.length-1;i>0;i--)if(e[i].type==="sec"&&(!r||e[i].name===r))return i;return-1},a=r=>{const i=s();if(i.type!=="el")return;const f=p=>p==="td"||p==="th";(r==="li"&&i.name==="li"||r==="option"&&i.name==="option"||(r==="dt"||r==="dd")&&(i.name==="dt"||i.name==="dd")||f(r)&&f(i.name)||r==="tr"&&(i.name==="tr"||f(i.name))||i.name==="p"&&H.has(r))&&(e.pop(),r==="tr"&&s().type==="el"&&s().name==="tr"&&e.pop())};for(const r of t)if(r.type==="open"){a(r.name);const i={type:"el",name:r.name,open:r,children:[],close:null};o(i),r.self||e.push(i)}else if(r.type==="close"){let i=e.length-1;for(;i>0&&e[i].type==="el"&&e[i].name!==r.name;)i--;i>0&&e[i].type==="el"?(e[i].close=r,e.length=i):o({type:"stray",name:r.name,text:r.text})}else if(r.type==="hb"){if(r.kind==="open"){const f={type:"sec",name:r.name,open:r,children:[],close:null};o(f),e.push(f);continue}const i=l(r.kind==="close"?r.name:null);if(i<0){o({type:"text",text:r.text});continue}r.kind==="else"?(e.length=i+1,o({type:"else",text:r.text})):(e[i].close=r,e.length=i)}else o(r);return n.children}function B(t){const n=/^<[a-zA-Z][\w:.-]*([\s\S]*?)\/\s*>$/.exec(t);return!!n&&(!n[1].trim()||/[\s"'}]$/.test(n[1])||!/=\s*[^\s"'=]+$/.test(n[1]))}function X(t){const n=/^<([a-zA-Z][\w:.-]*)/.exec(t);if(!n)return null;let e=t.slice(n[0].length,-1);const s=B(t);if(s&&(e=e.replace(/\/\s*$/,"")),e&&!/^\s/.test(e))return null;const o=[];let l="",a=null;for(let r=0;r<e.length;r++){const i=e[r];if(a){if(i===`
|
|
23
|
+
`)return null;l+=i,i===a&&(a=null);continue}if(i==='"'||i==="'"){a=i,l+=i;continue}if(i==="{"&&e[r+1]==="{"){const f=e.indexOf("}}",r+2),p=e.slice(r,f+2);if(p.includes(`
|
|
24
|
+
`))return null;l+=p,r=f+1;continue}if(/\s/.test(i)){const f=e.slice(r).match(/^\s+/)[0];if(l&&(l.endsWith("=")||e[r+f.length]==="=")){r+=f.length-1;continue}l&&o.push(l),l="",r+=f.length-1;continue}l+=i}return a?null:(l&&o.push(l),{name:n[1],attrs:o,slash:s,spaced:/\s\/\s*>$/.test(t)})}function Q(t){const n=t.split(`
|
|
25
|
+
`),e=n.filter(o=>o.trim()).map(o=>o.match(/^[ \t]*/)[0].length),s=e.length?Math.min(...e):0;return n.map(o=>o.slice(Math.min(s,o.match(/^[ \t]*/)[0].length))).join(`
|
|
26
|
+
`).replace(/^\n+|\n+$/g,"")}function Y(t,n){return t.split(`
|
|
27
|
+
`).map(e=>e&&C.repeat(n)+e).join(`
|
|
28
|
+
`)}export const SHORT_TAG_CONTAINERS=new Set(["grid","row","col","card","box","header","footer","tabs","tab","accordion","item","carousel","slide","timeline","event","hero","banner","slideover","center","listgroup","table","dconfig","reveal","animate","pulse","shake","scramble","ripple","breathe","ambient","twinkle","fireworks","scribe","wait","render","redraw"]);export function shortTagLine(t){const n=String(t).trim().match(/^\[(\/?)([a-z][\w-]*)(?:\s[^\]]*)?\]$/i);return!n||!SHORT_TAG_CONTAINERS.has(n[2].toLowerCase())||!n[1]&&/\/\]$/.test(t.trim())?null:{name:n[2].toLowerCase(),close:!!n[1]}}export function shortTagLayout(t){const n=t.map(()=>({tag:!1,depth:0,block:-1,fence:!1})),e=new Set;let s=null;t.forEach((r,i)=>{if(s){e.add(i);const p=r.match(/^\s*(`{3,}|~{3,})\s*$/);p&&p[1][0]===s[0]&&p[1].length>=s.length&&(s=null);return}const f=r.match(/^\s*(`{3,}|~{3,})/);f&&(s=f[1])});const o=(r,i)=>{let f=0;const p=new RegExp(`\\[(\\/?)${r}(?:[\\s\\]])`,"gi");for(let d=i;d<t.length;d++)if(!e.has(d))for(const m of t[d].matchAll(p))if(!m[1])f++;else{if(f===0)return!0;f--}return!1},l=[];t.forEach((r,i)=>{const f=l[l.length-1];if(n[i].depth=l.length,n[i].block=f?f.at:-1,e.has(i)){n[i].fence=!0;return}const p=shortTagLine(r);if(p)if(p.close){const d=l.map(m=>m.name).lastIndexOf(p.name);if(d<0)return;l.length=d,Object.assign(n[i],{tag:!0,depth:l.length})}else o(p.name,i+1)&&(n[i].tag=!0,l.push({name:p.name,at:i}))});const a=new Map;return t.forEach((r,i)=>{const f=n[i];if(f.tag||f.fence||f.block<0||!r.trim())return;const p=r.match(/^[ \t]*/)[0].length;a.set(f.block,Math.min(a.get(f.block)??1/0,p))}),n.map((r,i)=>{const f=t[i].match(/^[ \t]*/)[0].length,p=r.tag?f:r.block<0?0:Math.min(f,a.get(r.block)??0);return{...r,cut:p}})}function tt(t){const n=shortTagLayout(t);return t.map((e,s)=>n[s].cut?e.slice(n[s].cut):e)}function et(t){const n=shortTagLayout(t);return t.map((e,s)=>{const o=n[s];return o.tag?C.repeat(o.depth)+e.trim():!o.depth||!e.trim()?e:C.repeat(o.depth)+e})}export function formatMarkdown(t){if(!t.trim())return t;const n=E.shortTags?tt(t.split(`
|
|
23
29
|
`)):t.split(`
|
|
24
|
-
`),
|
|
30
|
+
`),e=[];let s=null,o=!1;const l=r=>/^( {4}|\t)/.test(r),a=r=>{for(let i=r+1;i<n.length;i++)if(n[i].trim())return n[i];return""};for(let r=0;r<n.length;r++){const i=n[r];if(s){e.push(i);const u=i.match(/^ {0,3}(`{3,}|~{3,})\s*$/);u&&u[1][0]===s[0]&&u[1].length>=s.length&&(s=null);continue}if(o||/^\s*<pre[\s>]/i.test(i)){e.push(i),o=!/<\/pre\s*>/i.test(i);continue}const f=i.match(/^ {0,3}(`{3,}|~{3,})/);if(f){s=f[1],e.push(i.trimEnd());continue}if(E.html&&nt.test(i)){let u=r;for(;u<n.length&&n[u].trim()&&!shortTagLine(n[u]);)u++;const g=n.slice(r,u);if(!g.some(y=>st.test(y))){const y=i.match(/^ */)[0];e.push(...formatHtml(g.join(`
|
|
31
|
+
`),{templates:!1}).split(`
|
|
32
|
+
`).map(b=>b&&y+b)),r=u-1;continue}}if(E.tables&&it(n,r)){let u=r+2;for(;u<n.length&&/\|/.test(n[u])&&n[u].trim();)u++;e.push(...rt(n.slice(r,u))),r=u-1;continue}if(!i.trim()){const u=e.length?e[e.length-1]:"",g=[...e].reverse().find(y=>y.trim())||"";if(!u.trim()&&!(l(g)&&l(a(r))))continue;e.push("");continue}if(l(i)){e.push(i);continue}const p=i.match(/[ \t]*$/)[0],d=i.slice(0,i.length-p.length),m=/ {2,}$/.test(p)&&(n[r+1]||"").trim()&&!/^\s*#/.test(d);e.push(m?d+" ":d)}for(;e.length&&!e[0].trim();)e.shift();for(;e.length&&!e[e.length-1].trim();)e.pop();return(E.shortTags?et(e):e).join(`
|
|
25
33
|
`)+`
|
|
26
|
-
`}const
|
|
27
|
-
`,
|
|
28
|
-
`,
|
|
29
|
-
`):
|
|
30
|
-
`+
|
|
31
|
-
`+
|
|
32
|
-
`+(
|
|
33
|
-
|
|
34
|
-
`+
|
|
35
|
-
|
|
36
|
-
`+
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
`)
|
|
40
|
-
|
|
41
|
-
`)
|
|
42
|
-
`).length
|
|
43
|
-
`)[
|
|
44
|
-
`)
|
|
34
|
+
`}const nt=/^ {0,3}<(?:address|article|aside|blockquote|body|caption|center|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|h[1-6]|header|html|legend|li|main|menu|nav|ol|p|search|section|summary|table|tbody|td|tfoot|th|thead|tr|ul)(?=[\s/>]|$)/i,st=/<\/?(?:pre|textarea|script|style)\b|^\s*(?:`{3,}|~{3,})/i,ot=/^\s*:?-+:?\s*$/;function W(t){let n=t.trim();n.startsWith("|")&&(n=n.slice(1)),n.endsWith("|")&&!n.endsWith("\\|")&&(n=n.slice(0,-1));const e=[];let s="";for(let o=0;o<n.length;o++){if(n[o]==="\\"&&n[o+1]==="|"){s+="\\|",o++;continue}if(n[o]==="|"){e.push(s.trim()),s="";continue}s+=n[o]}return e.push(s.trim()),e}function it(t,n){const e=t[n],s=t[n+1];if(!e||!s||!e.includes("|")||!s.includes("|")||/^\s{4,}/.test(e))return!1;const o=W(s);if(!(o.length>0&&o.every(l=>ot.test(l))&&W(e).length===o.length))return!1;for(let l=n+2;l<t.length&&t[l].includes("|")&&t[l].trim();l++)if(W(t[l]).length>o.length)return!1;return!0}function rt(t){const n=t[0].match(/^\s*/)[0],e=t.map(W),s=Math.max(...e.map(r=>r.length)),o=e[1].map(r=>r.startsWith(":")&&r.endsWith(":")?"c":r.endsWith(":")?"r":r.startsWith(":")?"l":""),l=r=>[...r].length,a=Array.from({length:s},(r,i)=>Math.max(3,...e.map((f,p)=>p===1?3:l(f[i]??""))));return e.map((r,i)=>{const f=Array.from({length:s},(p,d)=>{const m=a[d];if(i===1){const y=o[d]||"",b="-".repeat(m-(y==="c"?2:y?1:0));return y==="c"?`:${b}:`:y==="r"?`${b}:`:y==="l"?`:${b}`:b}const u=r[d]??"",g=m-l(u);return o[d]==="r"?" ".repeat(g)+u:o[d]==="c"?" ".repeat(Math.floor(g/2))+u+" ".repeat(Math.ceil(g/2)):u+" ".repeat(g)});return`${n}| ${f.join(" | ")} |`})}const M=(t,n)=>t.lastIndexOf(`
|
|
35
|
+
`,n-1)+1,I=(t,n)=>{const e=t.indexOf(`
|
|
36
|
+
`,n);return e<0?t.length:e};export function enterEdit(t,n,e,s){const o=M(t,n),l=t.slice(o,I(t,n)),a=t.slice(o,n),r=t.slice(e,I(t,e)),i=(a.match(/^[ \t]*/)||[""])[0],f=(b,$=b.length)=>({start:n,end:e,text:b,selStart:n+$,selEnd:n+$});if(s==="md"||!s){const b=shortTagLine(l);if(b&&n===e&&!r.trim()&&!R(t,o))return!E.shortTags||!E.autoIndent?f(`
|
|
37
|
+
`):f(`
|
|
38
|
+
`+i+(b.close?"":prefUnit()));const $=a.match(/<([a-zA-Z][\w-]*)(?:\s[^<>]*)?>\s*$/);if($&&E.autoIndent&&n===e&&(z.has($[1].toLowerCase())||$[1].includes("-"))&&!_.has($[1].toLowerCase())&&!/\/\s*>\s*$/.test(a)&&!R(t,o)){const c=`
|
|
39
|
+
`+i+prefUnit();if(new RegExp(`^\\s*</${$[1]}\\s*>`,"i").test(r)){const h=(t.slice(e).match(/^[ \t]*/)||[""])[0].length;return{start:n,end:e+h,text:c+`
|
|
40
|
+
`+i,selStart:n+c.length,selEnd:n+c.length}}return f(c)}if(E.continueLists&&!R(t,o)){const c=a.match(/^([ \t]*)((?:>[ \t]?)+)?([ \t]*)([-*+]|(\d+)([.)]))?([ \t]+)(\[[ xX]\][ \t]+)?/),h=c?.[2]||"",w=c?.[4]||"",x=/^\s*([-*_])(\s*\1){2,}\s*$/.test(l);if(c&&(h||w)&&!x&&c[0].length<=a.length){if(!l.slice(c[0].length).trim()&&n===e&&n>=o+c[0].length)return{start:o,end:I(t,n),text:c[1],selStart:o+c[1].length,selEnd:o+c[1].length};if(n>=o+c[0].length-(c[7]?.length||0)){const k=c[5]?`${Number(c[5])+1}${c[6]}`:w,T=`
|
|
41
|
+
`+c[1]+h+(c[3]||"")+(w?k+(c[7]||" ")+(c[8]?"[ ] ":""):c[7]||"");return f(T)}}}return f(`
|
|
42
|
+
`+(E.autoIndent?i:""))}if(!E.autoIndent)return f(`
|
|
43
|
+
`);const p=(s==="html"?a:L(a)).trimEnd().slice(-1),d=r.trimStart()[0]||"",m={"{":"}","[":"]","(":")"};let u=!!m[p],g=u&&d===m[p];if(s==="html"||s==="css"){const b=a.match(/<([a-zA-Z][\w:-]*)(?:\s[^<>]*)?>\s*$/);b&&!_.has(b[1].toLowerCase())&&!/\/\s*>\s*$/.test(a)&&(u=!0,g=new RegExp(`^\\s*</${b[1]}\\s*>`,"i").test(r)),/\{\{\s*#\w+[^}]*\}\}\s*$/.test(a)&&(u=!0,g=/^\s*\{\{\s*\//.test(r))}if(!u)return f(`
|
|
44
|
+
`+i);const y=`
|
|
45
|
+
`+i+unitFor(t);if(g){const b=(t.slice(e).match(/^[ \t]*/)||[""])[0].length;return{start:n,end:e+b,text:y+`
|
|
46
|
+
`+i,selStart:n+y.length,selEnd:n+y.length}}return f(y)}function R(t,n){let e=null;for(const s of t.slice(0,n).split(`
|
|
47
|
+
`)){const o=s.match(/^\s*(`{3,}|~{3,})/);o&&(e?o[1][0]===e[0]&&o[1].length>=e.length&&!s.trim().slice(o[1].length).trim()&&(e=null):e=o[1])}return!!e}export function indentEdit(t,n,e,s,o=" "){const l=M(t,n),a=e>n&&t[e-1]===`
|
|
48
|
+
`?e-1:e,r=I(t,a);if(!t.slice(n,e).includes(`
|
|
49
|
+
`)&&!(s&&n===e))return null;const i=t.slice(l,r),f=i.split(`
|
|
50
|
+
`),p=f.map(m=>s?m.startsWith(o)?m.slice(o.length):m.startsWith(" ")?m.slice(2):m.startsWith(" ")?m.slice(1):m.replace(/^ /,""):m.trim()?o+m:m),d=p.join(`
|
|
51
|
+
`);if(d===i)return null;if(n===e){const m=f[0].length-p[0].length,u=Math.max(l,n-m);return{start:l,end:r,text:d,selStart:u,selEnd:u}}return{start:l,end:r,text:d,selStart:l,selEnd:l+d.length}}export function closerEdit(t,n,e,s,o=""){if(n!==e)return null;const l=M(t,n);let a=t.slice(l,n),r=s;if(o==="html"&&s==="/"&&/^[ \t]*<$/.test(a))a=a.slice(0,-1),r="</";else if(!"}])".includes(s))return null;if(!E.autoIndent)return null;const i=unitFor(t);if(!a||a.trim()||!a.endsWith(i))return null;const f=a.slice(0,-i.length),p=l+f.length+r.length;return{start:l,end:n,text:f+r,selStart:p,selEnd:p}}export const tabUnit=(t,n)=>n==="md"?prefUnit():unitFor(t);export function changedSpan(t,n){let e=0;const s=Math.min(t.length,n.length);for(;e<s&&t[e]===n[e];)e++;let o=0;for(;o<s-e&&t[t.length-1-o]===n[n.length-1-o];)o++;return{start:e,end:t.length-o,text:n.slice(e,n.length-o)}}export function caretAfterFormat(t,n,e){const s=t.slice(0,e).split(`
|
|
52
|
+
`).length-1,o=t.split(`
|
|
53
|
+
`)[s]??"",l=e-M(t,e),a=Math.max(0,l-o.match(/^[ \t]*/)[0].length),r=n.split(`
|
|
54
|
+
`),i=Math.min(s,r.length-1);let f=0;for(let m=0;m<i;m++)f+=r[m].length+1;const p=r[i],d=p.match(/^[ \t]*/)[0].length;return f+Math.min(p.length,d+a)}export function applyEdit(t,n){const{start:e,end:s,text:o}=n;let l=!1;if(typeof document<"u"&&typeof document.execCommand=="function"){t.focus(),t.setSelectionRange(e,s);try{l=o?document.execCommand("insertText",!1,o):e===s||document.execCommand("delete")}catch{l=!1}}l||(t.value=t.value.slice(0,e)+o+t.value.slice(s),t.dispatchEvent(new Event("input",{bubbles:!0}))),t.setSelectionRange(n.selStart,n.selEnd)}export function formatTextarea(t,n){const e=t.value,s=formatCode(e,n);if(s.error)return s;if(s.text===e)return{text:e,unchanged:!0};const o=caretAfterFormat(e,s.text,t.selectionStart),l=changedSpan(e,s.text),a=t.scrollTop;return applyEdit(t,{...l,selStart:o,selEnd:o}),t.scrollTop=a,s}
|
|
@@ -16,6 +16,35 @@
|
|
|
16
16
|
<code><name>.html</code> holds the template, <code><name>.css</code> its styles (optional) and
|
|
17
17
|
<code><name>.meta.json</code> its project and bundled flag (optional).</p>
|
|
18
18
|
|
|
19
|
+
<h3>A free library to start your site</h3>
|
|
20
|
+
<p>Every site includes 16 editable <code>domma-block-*</code> blocks. Search for
|
|
21
|
+
<code>domma-block-</code> in Blocks or use <strong>Add block</strong> in the editor.
|
|
22
|
+
Each includes its own styling, documented parameters and an example to copy.</p>
|
|
23
|
+
<table class="table table-sm"><thead><tr><th>Block</th><th>Use it for</th></tr></thead><tbody>
|
|
24
|
+
<tr><td><code>domma-block-banner</code></td><td>A photo banner with a readable overlay across its left half.</td></tr>
|
|
25
|
+
<tr><td><code>domma-block-split</code></td><td>An image beside a section heading and introduction.</td></tr>
|
|
26
|
+
<tr><td><code>domma-block-cta</code></td><td>A welcoming call to action using your site theme.</td></tr>
|
|
27
|
+
<tr><td><code>domma-block-hero</code></td><td>A centred page introduction with an optional button.</td></tr>
|
|
28
|
+
<tr><td><code>domma-block-text</code></td><td>A readable text section for your story or an introduction.</td></tr>
|
|
29
|
+
<tr><td><code>domma-block-features</code></td><td>An introduction and up to three feature cards.</td></tr>
|
|
30
|
+
<tr><td><code>domma-block-service-card</code></td><td>A reusable service card with an optional photo and button.</td></tr>
|
|
31
|
+
<tr><td><code>domma-block-testimonial</code></td><td>A customer quotation with an optional attribution.</td></tr>
|
|
32
|
+
<tr><td><code>domma-block-stats</code></td><td>Up to three useful figures with clear labels.</td></tr>
|
|
33
|
+
<tr><td><code>domma-block-steps</code></td><td>A clear, numbered process with up to three steps.</td></tr>
|
|
34
|
+
<tr><td><code>domma-block-faq</code></td><td>Up to three questions and answers, readable without JavaScript.</td></tr>
|
|
35
|
+
<tr><td><code>domma-block-contact</code></td><td>Contact details, an address and opening hours.</td></tr>
|
|
36
|
+
<tr><td><code>domma-block-pricing-card</code></td><td>A clear price or package card with an optional enquiry button.</td></tr>
|
|
37
|
+
<tr><td><code>domma-block-team-card</code></td><td>A team member photo, role and short introduction.</td></tr>
|
|
38
|
+
<tr><td><code>domma-block-image</code></td><td>An uncropped image with an optional caption.</td></tr>
|
|
39
|
+
<tr><td><code>domma-block-logos</code></td><td>A responsive row of up to four organisation logos.</td></tr>
|
|
40
|
+
</tbody></table>
|
|
41
|
+
<p>Start with a banner or hero, add sections and cards, then finish with a call to action.
|
|
42
|
+
Change the text and choose your own pictures from Media. Use one main heading per page.
|
|
43
|
+
Leave optional buttons and unused feature, FAQ, step, figure or logo slots empty to hide them.</p>
|
|
44
|
+
<pre><code>[domma-block-hero header="Welcome to our business" blurb="A short introduction to what we do." link="/contact" label="Get in touch" /]</code></pre>
|
|
45
|
+
<p>Blocks follow your theme and adapt to smaller screens. You can edit or duplicate them;
|
|
46
|
+
updates add missing library files without replacing your existing customisations.</p>
|
|
47
|
+
|
|
19
48
|
<h3>Three ways to place a block</h3>
|
|
20
49
|
<table class="table table-sm">
|
|
21
50
|
<thead>
|