domma-cms 0.90.4 → 0.91.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +3 -2
- package/admin/js/lib/editor-folding.js +2 -2
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +1 -1
- package/admin/js/lib/media-picker.js +24 -0
- package/admin/js/lib/page-editor-reference.js +7 -3
- package/admin/js/lib/seo-settings.js +2 -2
- package/admin/js/lib/shortcode-context-menu.js +1 -1
- package/admin/js/lib/shortcode-registry.js +3 -1
- package/admin/js/lib/tool-kit.js +1 -1
- package/admin/js/templates/docs/usage-shortcodes.html +53 -2
- package/admin/js/templates/seo.html +2 -0
- package/admin/js/views/seo.js +42 -39
- package/package.json +1 -1
- package/public/css/site.css +1 -1
- package/server/services/markdown.js +36 -2
package/CLAUDE.md
CHANGED
|
@@ -65,13 +65,14 @@ Processing order (innermost first):
|
|
|
65
65
|
|
|
66
66
|
1. `[dconfig]` - always first
|
|
67
67
|
2. `[grid]` / `[row]` / `[col]`
|
|
68
|
-
3. `[card]`
|
|
68
|
+
3. `[card]` (and `[box]` - a headerless card, handled at the top of `processCardBlocks`)
|
|
69
69
|
4. `[tabs]`, `[accordion]`, `[carousel]`, `[hero]`, `[table]`, `[badge]`, `[countdown]`, `[timeline]`, `[spacer]`,
|
|
70
70
|
`[center]`, `[icon]`, `[cta]`, `[block]`, `[view]`, `[collection]`, `[text]`, `[button]`, `[link]`,
|
|
71
71
|
`[listgroup]`, `[form]`, `[banner]`, `[celebrate]`
|
|
72
72
|
5. `[slideover]` - always last (can contain anything above)
|
|
73
73
|
|
|
74
|
-
Safe nesting: `[card]` inside `[slideover]`, `[grid]` inside `[slideover]`, `[col]` inside `[grid]
|
|
74
|
+
Safe nesting: `[card]` inside `[slideover]`, `[grid]` inside `[slideover]`, `[col]` inside `[grid]`, `[card]` inside
|
|
75
|
+
`[box]` and `[box]` inside `[card]`.
|
|
75
76
|
Do NOT nest `[slideover]` inside another `[slideover]`.
|
|
76
77
|
|
|
77
78
|
## Public Site Patterns
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const
|
|
1
|
+
const _=["card","box","grid","row","tabs","accordion","carousel","hero","timeline","slideover","dconfig"],b=new RegExp(`^\\[(${_.join("|")})(\\s[^\\]]*)?\\]`,"i"),k="\u2026",G="\u200B";function j(n,f,o){return`${n.trimEnd()} ${k} [/${f}]${G}${o}`}function $(n,f,o){const c=new RegExp(`^\\[\\/${o}\\]`,"i"),h=new RegExp(`^\\[${o}(\\s[^\\]]*)?\\]`,"i");let d=1;for(let u=f+1;u<n.length;u++){const g=n[u].trimStart();if(h.test(g)&&d++,c.test(g)&&(d--,d===0))return u}return-1}function F(n){const f=[];for(let o=0;o<n.length;o++){const h=n[o].trimStart().match(b);if(!h)continue;const d=h[1].toLowerCase(),u=$(n,o,d);u>o&&f.push({lineIndex:o,tag:d,closeIndex:u})}return f}function B(n){for(;n.firstChild;)n.removeChild(n.firstChild)}export function createFoldingManager(n,f,o={}){const c=new Map;let h=0,d=null;function u(e){d&&d(!0),e(),d&&d(!1)}function g(){return n.value.split(`
|
|
2
2
|
`)}function p(){const e=g(),t=F(e),i=new Set(t.map(s=>s.lineIndex)),l=new Set;e.forEach((s,r)=>{c.has(s)&&l.add(r)}),B(f),e.forEach((s,r)=>{const m=document.createElement("span");m.className="editor-line-number-row";const a=document.createElement("span");l.has(r)?(a.className="fold-toggle fold-toggle--folded",a.setAttribute("title","Unfold block"),a.textContent="\u25B8",a.addEventListener("click",()=>w(r))):i.has(r)?(a.className="fold-toggle fold-toggle--open",a.setAttribute("title","Fold block"),a.textContent="\u25BE",a.addEventListener("click",()=>C(r))):a.className="fold-toggle fold-toggle--empty",m.appendChild(a);const E=document.createElement("span");E.className="editor-line-num",E.textContent=String(r+1),m.appendChild(E),f.appendChild(m)}),f.scrollTop=n.scrollTop}function C(e){const t=g(),i=t[e].trimStart().match(b);if(!i)return;const l=i[1].toLowerCase(),s=$(t,e,l);if(s<=e)return;const r=t.slice(e,s+1).join(`
|
|
3
3
|
`),m=j(t[e],l,++h);c.set(m,r);const a=[...t.slice(0,e),m,...t.slice(s+1)];u(()=>{n.value=a.join(`
|
|
4
4
|
`)}),p(),o.onFoldChange&&o.onFoldChange()}function w(e){const t=g(),i=t[e],l=c.get(i);if(!l)return;c.delete(i);const s=l.split(`
|
|
5
5
|
`),r=[...t.slice(0,e),...s,...t.slice(e+1)];u(()=>{n.value=r.join(`
|
|
6
|
-
`)}),p(),o.onFoldChange&&o.onFoldChange()}function S(){let e=0;for(;e++<200;){const t=g(),l=F(t).find(s=>!c.has(t[s.lineIndex]));if(!l)break;C(l.lineIndex)}}function L(){let e=0;for(;c.size>0&&e++<200;){const i=g().findIndex(l=>c.has(l));if(i===-1)break;w(i)}}function v(){if(c.size===0)return n.value;let e=n.value,t=!0,i=0;for(;t&&i++<20;){t=!1;for(const[l,s]of c){const r=l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),m=e.replace(new RegExp(`^${r}$`,"m"),()=>s);m!==e&&(e=m,t=!0)}}return e}function y(e){const t=g();return t[e]!==void 0&&c.has(t[e])}function A(e){d=e}function R(){p()}function
|
|
6
|
+
`)}),p(),o.onFoldChange&&o.onFoldChange()}function S(){let e=0;for(;e++<200;){const t=g(),l=F(t).find(s=>!c.has(t[s.lineIndex]));if(!l)break;C(l.lineIndex)}}function L(){let e=0;for(;c.size>0&&e++<200;){const i=g().findIndex(l=>c.has(l));if(i===-1)break;w(i)}}function v(){if(c.size===0)return n.value;let e=n.value,t=!0,i=0;for(;t&&i++<20;){t=!1;for(const[l,s]of c){const r=l.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),m=e.replace(new RegExp(`^${r}$`,"m"),()=>s);m!==e&&(e=m,t=!0)}}return e}function y(e){const t=g();return t[e]!==void 0&&c.has(t[e])}function A(e){d=e}function R(){p()}function x(){L()}return p(),{foldAt:C,unfoldAt:w,foldAll:S,unfoldAll:L,getUnfoldedContent:v,isFolded:y,setGuard:A,refresh:R,destroy:x}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const EFFECTS=[{name:"reveal",label:"Reveal",category:"Entrance",description:"Scroll-triggered entrance animation when the element enters the viewport.",attrs:[{name:"animation",label:"Animation",type:"select",default:"fade",options:[["fade","Fade"],["slide-up","Slide up"],["slide-down","Slide down"],["zoom","Zoom"],["flip","Flip"]]},{name:"duration",label:"Duration (ms)",type:"number",default:600},{name:"delay",label:"Delay (ms)",type:"number",default:0},{name:"threshold",label:"Threshold",type:"number",default:.1,step:.05,min:0,max:1},{name:"once",label:"Animate once",type:"checkbox",default:!0}],hosts:["card","hero","banner","col"],previewable:!0},{name:"breathe",label:"Breathe",category:"Animation",description:"Continuous gentle scaling - makes elements feel alive.",attrs:[{name:"amplitude",label:"Amplitude (px)",type:"number",default:8},{name:"duration",label:"Duration (ms)",type:"number",default:3e3}],hosts:["card","hero","col","button"],previewable:!0},{name:"pulse",label:"Pulse",category:"Animation",description:"A repeating scale pulse - stronger than breathe.",attrs:[{name:"scale",label:"Scale",type:"number",default:1.05,step:.01},{name:"duration",label:"Duration (ms)",type:"number",default:1e3}],hosts:["card","hero","banner","button"],previewable:!0},{name:"shake",label:"Shake",category:"Animation",description:"One-shot horizontal or vertical shake.",attrs:[{name:"intensity",label:"Intensity (px)",type:"number",default:5},{name:"duration",label:"Duration (ms)",type:"number",default:500},{name:"direction",label:"Direction",type:"select",default:"horizontal",options:[["horizontal","Horizontal"],["vertical","Vertical"]]}],hosts:["card","banner","button"],previewable:!0},{name:"animate",label:"CSS Animate",category:"Animation",description:"Applies a Domma CSS animation utility class - no JavaScript.",attrs:[{name:"type",label:"Type",type:"select",default:"fade-in-up",options:[["fade-in","fade-in"],["fade-in-up","fade-in-up"],["fade-in-down","fade-in-down"],["fade-in-left","fade-in-left"],["fade-in-right","fade-in-right"],["slide-in-up","slide-in-up"],["slide-in-down","slide-in-down"],["zoom-in","zoom-in"],["zoom-out","zoom-out"],["bounce","bounce"],["pulse","pulse"],["shake","shake"],["spin","spin"],["flip","flip"]]},{name:"duration",label:"Duration",type:"select",default:"normal",options:[["fast","fast"],["normal","normal"],["slow","slow"],["slower","slower"]]},{name:"delay",label:"Delay (ms)",type:"number",default:0},{name:"repeat",label:"Repeat",type:"select",default:"once",options:[["once","Once"],["infinite","Infinite"]]}],hosts:["card","hero","banner","col","button"],previewable:!0},{name:"scribe",label:"Scribe (typewriter)",category:"Text",description:"Types text character by character. Simple mode only - for the action-script composer use Insert \u2192 Scribe.",attrs:[{name:"speed",label:"Speed (ms/char)",type:"number",default:50},{name:"cursor",label:"Show cursor",type:"checkbox",default:!0},{name:"loop",label:"Loop",type:"checkbox",default:!1}],hosts:[],previewable:!0},{name:"scramble",label:"Scramble",category:"Text",description:"Reveals text through a character-scramble animation.",attrs:[{name:"speed",label:"Speed (ms/char)",type:"number",default:50},{name:"loop",label:"Loop",type:"checkbox",default:!1}],hosts:[],previewable:!0},{name:"counter",label:"Counter",category:"Text",description:"Animates a number from a starting value to a target. Self-closing shortcode.",attrs:[{name:"to",label:"To",type:"number",default:100},{name:"from",label:"From",type:"number",default:0},{name:"duration",label:"Duration (ms)",type:"number",default:2e3},{name:"prefix",label:"Prefix",type:"text",default:""},{name:"suffix",label:"Suffix",type:"text",default:""},{name:"decimals",label:"Decimal places",type:"number",default:0},{name:"separator",label:"Thousand separator",type:"text",default:""}],hosts:[],previewable:!0,selfClosing:!0},{name:"ripple",label:"Ripple",category:"Visual",description:"Click-triggered ripple effect on the element.",attrs:[{name:"colour",label:"Colour",type:"colour",default:"#7c6af7"},{name:"duration",label:"Duration (ms)",type:"number",default:600},{name:"opacity",label:"Opacity",type:"number",default:.3,step:.05,min:0,max:1}],hosts:["card","col","button"],previewable:!0},{name:"twinkle",label:"Twinkle",category:"Visual",description:"Generates animated particle effects inside the element.",attrs:[{name:"count",label:"Particle count",type:"number",default:80},{name:"shape",label:"Shape",type:"select",default:"star",options:[["star","Star"],["circle","Circle"],["square","Square"]]},{name:"colour",label:"Colour",type:"colour",default:"#ffffff"},{name:"min-size",label:"Min size (px)",type:"number",default:2},{name:"max-size",label:"Max size (px)",type:"number",default:6}],hosts:["card","hero"],previewable:!0},{name:"ambient",label:"Ambient background",category:"Visual",description:"Applies an animated CSS background class to the element.",attrs:[{name:"type",label:"Type",type:"select",default:"float-blobs",options:[["float-blobs","Float blobs"],["float-orbs","Float orbs"],["float-particles","Float particles"],["rotate-glow","Rotate glow"],["rotate-dual","Rotate dual"],["rotate-spotlight","Rotate spotlight"],["wave","Wave"],["ripple","Ripple"],["aurora","Aurora"]]},{name:"speed",label:"Speed",type:"select",default:"normal",options:[["slow","Slow"],["normal","Normal"],["fast","Fast"]]},{name:"intensity",label:"Intensity",type:"select",default:"subtle",options:[["subtle","Subtle"],["intense","Intense"]]}],hosts:["card","hero","banner"],previewable:!0},{name:"firework",label:"Firework",category:"Celebrations",description:"CSS-only firework particle. Self-closing or wrapping form.",attrs:[{name:"type",label:"Type",type:"select",default:"burst",options:[["burst","Burst"],["sparkle","Sparkle"],["trail","Trail"]]},{name:"colour",label:"Colour theme",type:"select",default:"rainbow",options:[["rainbow","Rainbow"],["primary","Primary"],["info","Info"],["success","Success"],["warning","Warning"],["danger","Danger"]]},{name:"size",label:"Size",type:"select",default:"md",options:[["sm","Small"],["md","Medium"],["lg","Large"]]},{name:"continuous",label:"Continuous",type:"checkbox",default:!1},{name:"hover",label:"On hover only",type:"checkbox",default:!1}],hosts:[],previewable:!0},{name:"fireworks",label:"Fireworks show",category:"Celebrations",description:"A container with multiple firework particles inside.",attrs:[],hosts:[],previewable:!1},{name:"celebrate",label:"Celebrate",category:"Celebrations",description:"Canvas-based seasonal particle system. Runs full-page on the published site.",attrs:[{name:"theme",label:"Theme",type:"select",default:"auto",options:[["auto","Auto (date-detected)"],["christmas","Christmas"],["halloween","Halloween"],["valentines","Valentines"],["guy-fawkes","Guy Fawkes"],["st-patricks","St Patrick's"],["st-davids","St David's"],["st-georges","St George's"],["st-andrews","St Andrew's"]]},{name:"intensity",label:"Intensity",type:"select",default:"medium",options:[["light","Light"],["medium","Medium"],["heavy","Heavy"]]}],hosts:[],previewable:!1,selfClosing:!0},{name:"ticker-tape",label:"Ticker tape",category:"Celebrations",description:"Coloured rectangular strips fall from the top, sway, rotate, and fade. Inserted self-closing (full-page); hand-write the wrapping form for container-scoped.",attrs:[{name:"palette",label:"Palette",type:"select",default:"theme",options:[["theme","Theme"],["rainbow","Rainbow"],["gold","Gold"],["silver","Silver"],["festive","Festive"],["pastel","Pastel"],["mono","Mono"]]},{name:"density",label:"Density",type:"number",default:50},{name:"speed",label:"Speed multiplier",type:"number",default:1,step:.1},{name:"sway",label:"Sway (px)",type:"number",default:60},{name:"burst",label:"Burst mode (one-shot)",type:"checkbox",default:!1},{name:"burst-count",label:"Burst count",type:"number",default:150}],hosts:["hero"],previewable:!0,selfClosing:!0},{name:"butterflies",label:"Butterflies",category:"Celebrations",description:"Procedurally drawn butterflies wander and rise with flapping wings. Self-closing for full-page; wrapping form for container-scoped.",attrs:[{name:"palette",label:"Palette",type:"select",default:"meadow",options:[["meadow","Meadow"],["theme","Theme"],["rainbow","Rainbow"],["pastel","Pastel"],["festive","Festive"],["gold","Gold"],["silver","Silver"],["mono","Mono"],["sunset","Sunset"],["ocean","Ocean"],["forest","Forest"],["bridal","Bridal"],["firefly","Firefly"]]},{name:"density",label:"Density",type:"number",default:18},{name:"speed",label:"Speed multiplier",type:"number",default:1,step:.1},{name:"wander",label:"Wander",type:"number",default:1,step:.1,hint:"Steering erraticness"},{name:"rise-speed",label:"Rise speed",type:"number",default:.4,step:.1,hint:"Upward drift bias"},{name:"flap-speed",label:"Flap speed",type:"number",default:1,step:.1},{name:"min-size",label:"Min wingspan (px)",type:"number",default:14},{name:"max-size",label:"Max wingspan (px)",type:"number",default:26},{name:"two-tone",label:"Two-tone wings",type:"checkbox",default:!0},{name:"burst",label:"Burst mode (one-shot)",type:"checkbox",default:!1},{name:"burst-count",label:"Burst count",type:"number",default:40}],hosts:["hero"],previewable:!0},{name:"strobe",label:"Strobe lighting",category:"Celebrations",description:"Light beams sweep from the corners and brighten where they cross - club, concert, or searchlight moods. Self-closing for full-page; wrapping form for container-scoped.",attrs:[{name:"preset",label:"Preset",type:"select",default:"club",options:[["club","Club"],["concert","Concert"],["police","Police"],["searchlight","Searchlight"],["scanner","Scanner"],["mood","Mood"]],hint:"Other fields override the preset when changed"},{name:"motion",label:"Motion",type:"select",default:"sweep",options:[["sweep","Sweep (fan back and forth)"],["rotate","Rotate (full circle)"]]},{name:"speed",label:"Speed multiplier",type:"number",default:1,step:.1},{name:"sweep-arc",label:"Sweep arc (deg)",type:"number",default:100},{name:"beam-width",label:"Beam width (deg)",type:"number",default:16},{name:"intensity",label:"Intensity",type:"number",default:.7,step:.05,min:0,max:1},{name:"flicker",label:"Flicker",type:"checkbox",default:!0},{name:"hz",label:"Flicker rate (Hz)",type:"number",default:10,hint:"Rates above 5 flashes/sec can trigger photosensitive seizures"},{name:"colours",label:"Colours",type:"text",default:"",placeholder:"#ffffff, #38bdf8",hint:"Comma-separated hex colours - overrides the preset palette"},{name:"duration",label:"Auto-stop (ms)",type:"number",default:"",hint:"Stop after this many ms - blank runs forever"}],hosts:["hero"],previewable:!0}];export function getEffect(t){return EFFECTS.find(e=>e.name===t)||null}export function effectsByCategory(){return["Entrance","Animation","Text","Visual","Celebrations"].map(e=>({category:e,effects:EFFECTS.filter(a=>a.category===e)}))}export function effectsInjectableInto(t){return EFFECTS.filter(e=>e.hosts.includes(t))}
|
|
1
|
+
export const EFFECTS=[{name:"reveal",label:"Reveal",category:"Entrance",description:"Scroll-triggered entrance animation when the element enters the viewport.",attrs:[{name:"animation",label:"Animation",type:"select",default:"fade",options:[["fade","Fade"],["slide-up","Slide up"],["slide-down","Slide down"],["zoom","Zoom"],["flip","Flip"]]},{name:"duration",label:"Duration (ms)",type:"number",default:600},{name:"delay",label:"Delay (ms)",type:"number",default:0},{name:"threshold",label:"Threshold",type:"number",default:.1,step:.05,min:0,max:1},{name:"once",label:"Animate once",type:"checkbox",default:!0}],hosts:["card","box","hero","banner","col"],previewable:!0},{name:"breathe",label:"Breathe",category:"Animation",description:"Continuous gentle scaling - makes elements feel alive.",attrs:[{name:"amplitude",label:"Amplitude (px)",type:"number",default:8},{name:"duration",label:"Duration (ms)",type:"number",default:3e3}],hosts:["card","box","hero","col","button"],previewable:!0},{name:"pulse",label:"Pulse",category:"Animation",description:"A repeating scale pulse - stronger than breathe.",attrs:[{name:"scale",label:"Scale",type:"number",default:1.05,step:.01},{name:"duration",label:"Duration (ms)",type:"number",default:1e3}],hosts:["card","box","hero","banner","button"],previewable:!0},{name:"shake",label:"Shake",category:"Animation",description:"One-shot horizontal or vertical shake.",attrs:[{name:"intensity",label:"Intensity (px)",type:"number",default:5},{name:"duration",label:"Duration (ms)",type:"number",default:500},{name:"direction",label:"Direction",type:"select",default:"horizontal",options:[["horizontal","Horizontal"],["vertical","Vertical"]]}],hosts:["card","box","banner","button"],previewable:!0},{name:"animate",label:"CSS Animate",category:"Animation",description:"Applies a Domma CSS animation utility class - no JavaScript.",attrs:[{name:"type",label:"Type",type:"select",default:"fade-in-up",options:[["fade-in","fade-in"],["fade-in-up","fade-in-up"],["fade-in-down","fade-in-down"],["fade-in-left","fade-in-left"],["fade-in-right","fade-in-right"],["slide-in-up","slide-in-up"],["slide-in-down","slide-in-down"],["zoom-in","zoom-in"],["zoom-out","zoom-out"],["bounce","bounce"],["pulse","pulse"],["shake","shake"],["spin","spin"],["flip","flip"]]},{name:"duration",label:"Duration",type:"select",default:"normal",options:[["fast","fast"],["normal","normal"],["slow","slow"],["slower","slower"]]},{name:"delay",label:"Delay (ms)",type:"number",default:0},{name:"repeat",label:"Repeat",type:"select",default:"once",options:[["once","Once"],["infinite","Infinite"]]}],hosts:["card","box","hero","banner","col","button"],previewable:!0},{name:"scribe",label:"Scribe (typewriter)",category:"Text",description:"Types text character by character. Simple mode only - for the action-script composer use Insert \u2192 Scribe.",attrs:[{name:"speed",label:"Speed (ms/char)",type:"number",default:50},{name:"cursor",label:"Show cursor",type:"checkbox",default:!0},{name:"loop",label:"Loop",type:"checkbox",default:!1}],hosts:[],previewable:!0},{name:"scramble",label:"Scramble",category:"Text",description:"Reveals text through a character-scramble animation.",attrs:[{name:"speed",label:"Speed (ms/char)",type:"number",default:50},{name:"loop",label:"Loop",type:"checkbox",default:!1}],hosts:[],previewable:!0},{name:"counter",label:"Counter",category:"Text",description:"Animates a number from a starting value to a target. Self-closing shortcode.",attrs:[{name:"to",label:"To",type:"number",default:100},{name:"from",label:"From",type:"number",default:0},{name:"duration",label:"Duration (ms)",type:"number",default:2e3},{name:"prefix",label:"Prefix",type:"text",default:""},{name:"suffix",label:"Suffix",type:"text",default:""},{name:"decimals",label:"Decimal places",type:"number",default:0},{name:"separator",label:"Thousand separator",type:"text",default:""}],hosts:[],previewable:!0,selfClosing:!0},{name:"ripple",label:"Ripple",category:"Visual",description:"Click-triggered ripple effect on the element.",attrs:[{name:"colour",label:"Colour",type:"colour",default:"#7c6af7"},{name:"duration",label:"Duration (ms)",type:"number",default:600},{name:"opacity",label:"Opacity",type:"number",default:.3,step:.05,min:0,max:1}],hosts:["card","box","col","button"],previewable:!0},{name:"twinkle",label:"Twinkle",category:"Visual",description:"Generates animated particle effects inside the element.",attrs:[{name:"count",label:"Particle count",type:"number",default:80},{name:"shape",label:"Shape",type:"select",default:"star",options:[["star","Star"],["circle","Circle"],["square","Square"]]},{name:"colour",label:"Colour",type:"colour",default:"#ffffff"},{name:"min-size",label:"Min size (px)",type:"number",default:2},{name:"max-size",label:"Max size (px)",type:"number",default:6}],hosts:["card","box","hero"],previewable:!0},{name:"ambient",label:"Ambient background",category:"Visual",description:"Applies an animated CSS background class to the element.",attrs:[{name:"type",label:"Type",type:"select",default:"float-blobs",options:[["float-blobs","Float blobs"],["float-orbs","Float orbs"],["float-particles","Float particles"],["rotate-glow","Rotate glow"],["rotate-dual","Rotate dual"],["rotate-spotlight","Rotate spotlight"],["wave","Wave"],["ripple","Ripple"],["aurora","Aurora"]]},{name:"speed",label:"Speed",type:"select",default:"normal",options:[["slow","Slow"],["normal","Normal"],["fast","Fast"]]},{name:"intensity",label:"Intensity",type:"select",default:"subtle",options:[["subtle","Subtle"],["intense","Intense"]]}],hosts:["card","box","hero","banner"],previewable:!0},{name:"firework",label:"Firework",category:"Celebrations",description:"CSS-only firework particle. Self-closing or wrapping form.",attrs:[{name:"type",label:"Type",type:"select",default:"burst",options:[["burst","Burst"],["sparkle","Sparkle"],["trail","Trail"]]},{name:"colour",label:"Colour theme",type:"select",default:"rainbow",options:[["rainbow","Rainbow"],["primary","Primary"],["info","Info"],["success","Success"],["warning","Warning"],["danger","Danger"]]},{name:"size",label:"Size",type:"select",default:"md",options:[["sm","Small"],["md","Medium"],["lg","Large"]]},{name:"continuous",label:"Continuous",type:"checkbox",default:!1},{name:"hover",label:"On hover only",type:"checkbox",default:!1}],hosts:[],previewable:!0},{name:"fireworks",label:"Fireworks show",category:"Celebrations",description:"A container with multiple firework particles inside.",attrs:[],hosts:[],previewable:!1},{name:"celebrate",label:"Celebrate",category:"Celebrations",description:"Canvas-based seasonal particle system. Runs full-page on the published site.",attrs:[{name:"theme",label:"Theme",type:"select",default:"auto",options:[["auto","Auto (date-detected)"],["christmas","Christmas"],["halloween","Halloween"],["valentines","Valentines"],["guy-fawkes","Guy Fawkes"],["st-patricks","St Patrick's"],["st-davids","St David's"],["st-georges","St George's"],["st-andrews","St Andrew's"]]},{name:"intensity",label:"Intensity",type:"select",default:"medium",options:[["light","Light"],["medium","Medium"],["heavy","Heavy"]]}],hosts:[],previewable:!1,selfClosing:!0},{name:"ticker-tape",label:"Ticker tape",category:"Celebrations",description:"Coloured rectangular strips fall from the top, sway, rotate, and fade. Inserted self-closing (full-page); hand-write the wrapping form for container-scoped.",attrs:[{name:"palette",label:"Palette",type:"select",default:"theme",options:[["theme","Theme"],["rainbow","Rainbow"],["gold","Gold"],["silver","Silver"],["festive","Festive"],["pastel","Pastel"],["mono","Mono"]]},{name:"density",label:"Density",type:"number",default:50},{name:"speed",label:"Speed multiplier",type:"number",default:1,step:.1},{name:"sway",label:"Sway (px)",type:"number",default:60},{name:"burst",label:"Burst mode (one-shot)",type:"checkbox",default:!1},{name:"burst-count",label:"Burst count",type:"number",default:150}],hosts:["hero"],previewable:!0,selfClosing:!0},{name:"butterflies",label:"Butterflies",category:"Celebrations",description:"Procedurally drawn butterflies wander and rise with flapping wings. Self-closing for full-page; wrapping form for container-scoped.",attrs:[{name:"palette",label:"Palette",type:"select",default:"meadow",options:[["meadow","Meadow"],["theme","Theme"],["rainbow","Rainbow"],["pastel","Pastel"],["festive","Festive"],["gold","Gold"],["silver","Silver"],["mono","Mono"],["sunset","Sunset"],["ocean","Ocean"],["forest","Forest"],["bridal","Bridal"],["firefly","Firefly"]]},{name:"density",label:"Density",type:"number",default:18},{name:"speed",label:"Speed multiplier",type:"number",default:1,step:.1},{name:"wander",label:"Wander",type:"number",default:1,step:.1,hint:"Steering erraticness"},{name:"rise-speed",label:"Rise speed",type:"number",default:.4,step:.1,hint:"Upward drift bias"},{name:"flap-speed",label:"Flap speed",type:"number",default:1,step:.1},{name:"min-size",label:"Min wingspan (px)",type:"number",default:14},{name:"max-size",label:"Max wingspan (px)",type:"number",default:26},{name:"two-tone",label:"Two-tone wings",type:"checkbox",default:!0},{name:"burst",label:"Burst mode (one-shot)",type:"checkbox",default:!1},{name:"burst-count",label:"Burst count",type:"number",default:40}],hosts:["hero"],previewable:!0},{name:"strobe",label:"Strobe lighting",category:"Celebrations",description:"Light beams sweep from the corners and brighten where they cross - club, concert, or searchlight moods. Self-closing for full-page; wrapping form for container-scoped.",attrs:[{name:"preset",label:"Preset",type:"select",default:"club",options:[["club","Club"],["concert","Concert"],["police","Police"],["searchlight","Searchlight"],["scanner","Scanner"],["mood","Mood"]],hint:"Other fields override the preset when changed"},{name:"motion",label:"Motion",type:"select",default:"sweep",options:[["sweep","Sweep (fan back and forth)"],["rotate","Rotate (full circle)"]]},{name:"speed",label:"Speed multiplier",type:"number",default:1,step:.1},{name:"sweep-arc",label:"Sweep arc (deg)",type:"number",default:100},{name:"beam-width",label:"Beam width (deg)",type:"number",default:16},{name:"intensity",label:"Intensity",type:"number",default:.7,step:.05,min:0,max:1},{name:"flicker",label:"Flicker",type:"checkbox",default:!0},{name:"hz",label:"Flicker rate (Hz)",type:"number",default:10,hint:"Rates above 5 flashes/sec can trigger photosensitive seizures"},{name:"colours",label:"Colours",type:"text",default:"",placeholder:"#ffffff, #38bdf8",hint:"Comma-separated hex colours - overrides the preset palette"},{name:"duration",label:"Auto-stop (ms)",type:"number",default:"",hint:"Stop after this many ms - blank runs forever"}],hosts:["hero"],previewable:!0}];export function getEffect(t){return EFFECTS.find(e=>e.name===t)||null}export function effectsByCategory(){return["Entrance","Animation","Text","Visual","Celebrations"].map(e=>({category:e,effects:EFFECTS.filter(a=>a.category===e)}))}export function effectsInjectableInto(t){return EFFECTS.filter(e=>e.hosts.includes(t))}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{EFFECTS as _,effectsByCategory as z,effectsInjectableInto as A,getEffect as u}from"./effect-defs.js";import{insertAtCursor as R,replaceRange as x}from"./markdown-toolbar.js";let g=null;function j(e,t,r=14){e.textContent="";const o=document.createElement("span");return o.setAttribute("data-icon",t),o.setAttribute("data-icon-size",String(r)),o.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;",e.appendChild(o),I.scan(e),e}function L(e,t,r,o=14){return j(e,t,o),e.appendChild(document.createTextNode(" "+r)),e}export const EffectsBuilder={open(e){if(g)return;const t={textarea:e,activeEffect:S.get("effects-builder-last")||"reveal",scope:"standalone",host:null,editing:null,fieldValues:{}};if(t.host=F(e),t.host&&A(t.host.name).map(c=>c.name).includes(t.activeEffect)&&!(t.activeEffect in t.host.attrs)&&(t.scope="inject"),t.editing=q(e),t.editing){t.activeEffect=t.editing.name,t.scope="standalone";const a=u(t.editing.name);for(const c of a.attrs)if(c.name in t.editing.attrs){const s=t.editing.attrs[c.name];c.type==="number"?t.fieldValues[c.name]=Number(s):c.type==="checkbox"?t.fieldValues[c.name]=s==="true":t.fieldValues[c.name]=s}}const r=E.slideover({title:"Effects",size:"lg",position:"right",onClose:()=>{g=null}}),o=O(t,r);r.element.appendChild(o),r.open(),I.scan(o),g={state:t,slideover:r}},close(){g&&(g.slideover.close(),g=null)}};function O(e,t){const r=document.createElement("div");r.style.cssText="display:grid;grid-template-columns:170px 1fr;height:100%;min-height:520px;";const o=document.createElement("div");o.className="effects-rail",o.style.cssText="background:var(--dm-background-alt,#15152a);border-right:1px solid var(--dm-border,#2a2a40);padding:.5rem .35rem;font-size:.8rem;overflow-y:auto;";const a=document.createElement("div");a.className="effects-pane",a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;overflow-y:auto;";function c(){H(a,e,t)}return b(o,e,c),c(),r.appendChild(o),r.appendChild(a),r}function b(e,t,r){e.replaceChildren();for(const o of z()){const a=document.createElement("div");a.style.cssText="color:var(--dm-text-muted,#888);text-transform:uppercase;font-size:.65rem;letter-spacing:.05em;margin:.4rem .35rem .25rem;",a.textContent=o.category,e.appendChild(a);for(const c of o.effects){const s=document.createElement("button");s.type="button",s.dataset.effect=c.name,s.style.cssText="display:block;width:100%;text-align:left;padding:.3rem .5rem;border:none;background:transparent;color:var(--dm-text,#ddd);border-radius:3px;font-size:.8rem;cursor:pointer;margin-bottom:.1rem;",s.textContent=c.label,c.name===t.activeEffect&&(s.style.background="var(--dm-primary,#4338ca)",s.style.color="var(--dm-primary-text,#fff)"),s.addEventListener("click",()=>{t.activeEffect=c.name,S.set("effects-builder-last",c.name),t.fieldValues={},b(e,t,r),r()}),e.appendChild(s)}}}function V(e,t){if(e.type==="select"){const o=document.createElement("select");o.style.cssText="width:100%;padding:.35rem .5rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text,#eee);font-size:.85rem;";for(const[a,c]of e.options){const s=document.createElement("option");s.value=a,s.textContent=c,o.appendChild(s)}return o.value=t??e.default??"",o}if(e.type==="checkbox"){const o=document.createElement("input");return o.type="checkbox",o.checked=t??e.default??!1,o}const r=document.createElement("input");return r.type=e.type==="number"?"number":e.type==="colour"?"color":"text",r.value=t??e.default??"",e.placeholder&&(r.placeholder=e.placeholder),e.type==="number"&&(e.min!=null&&(r.min=e.min),e.max!=null&&(r.max=e.max),e.step!=null&&(r.step=e.step)),r.style.cssText="width:100%;padding:.35rem .5rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text,#eee);font-size:.85rem;",r}function v(e,t){return t.type==="checkbox"?e.checked:t.type==="number"?e.value===""?"":Number(e.value):e.value}function N(e,t,r){const o=u(t.activeEffect);if(e.replaceChildren(),o.attrs.length===0){const c=document.createElement("div");c.style.cssText="color:var(--dm-text-muted,#888);font-size:.8rem;font-style:italic;",c.textContent="This effect takes no parameters.",e.appendChild(c);return}const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:.6rem .7rem;";for(const c of o.attrs){const s=document.createElement("div"),d=document.createElement("label");d.style.cssText="display:block;color:var(--dm-text-muted,#888);font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.2rem;",d.textContent=c.label,s.appendChild(d);const i=V(c,t.fieldValues[c.name]);if(i.addEventListener("input",()=>{t.fieldValues[c.name]=v(i,c),r()}),i.addEventListener("change",()=>{t.fieldValues[c.name]=v(i,c),r()}),s.appendChild(i),c.hint){const n=document.createElement("div");n.style.cssText="color:var(--dm-text-muted,#666);font-size:.7rem;margin-top:.15rem;",n.textContent=c.hint,s.appendChild(n)}a.appendChild(s)}e.appendChild(a)}function y(e){const t={},r=/(\w[\w-]*)(?:\s*=\s*"([^"]*)"|\s*=\s*'([^']*)'|\s*=\s*(\S+))?/g;for(const o of e.matchAll(r)){const a=o[1],c=o[2]??o[3]??o[4]??"";t[a]=c}return t}const B=_.filter(e=>!e.selfClosing).map(e=>e.name);function q(e){const t=e.value,r=e.selectionStart;for(const o of B){const a=new RegExp(`\\[${o}([^\\]]*)\\]`,"g"),c=new RegExp(`\\[/${o}\\]`,"g"),s=[];for(const n of t.matchAll(a)){if(n.index>=r)break;s.push({type:"open",start:n.index,end:n.index+n[0].length,attrStr:n[1]})}for(const n of t.matchAll(c)){if(n.index>=r)break;s.push({type:"close",start:n.index,end:n.index+n[0].length})}s.sort((n,l)=>n.start-l.start);let d=0,i=null;for(const n of s)n.type==="open"?(d++,i=n):(d--,d<0&&(d=0,i=null));if(d>0&&i){const n=new RegExp(`\\[/${o}\\]`,"g"),l=t.slice(r),m=l.match(n);if(m){const f=r+l.indexOf(m[0]);return{name:o,blockStart:i.start,blockEnd:f+m[0].length,openTagEnd:i.end,attrs:y(i.attrStr)}}}}return null}const P=["card","hero","banner","col","button"];function F(e){const t=e.value,r=e.selectionStart;for(const o of P){const a=new RegExp(`\\[${o}([^\\]]*)\\]`,"g"),c=new RegExp(`\\[/${o}\\]`,"g"),s=[];for(const n of t.matchAll(a)){if(n.index>=r)break;s.push({type:"open",start:n.index,end:n.index+n[0].length,attrStr:n[1]})}for(const n of t.matchAll(c)){if(n.index>=r)break;s.push({type:"close",start:n.index,end:n.index+n[0].length})}s.sort((n,l)=>n.start-l.start);let d=0,i=null;for(const n of s)n.type==="open"?(d++,i=n):(d--,d<0&&(d=0,i=null));if(d>0&&i){const n=new RegExp(`\\[/${o}\\]`,"g"),l=t.slice(r),m=l.match(n);if(m){const f=r+l.indexOf(m[0]);return{name:o,openTagStart:i.start,openTagEnd:i.end,closeTagStart:f,closeTagEnd:f+m[0].length,attrs:y(i.attrStr)}}}}return null}function C(e,t){const r=[];for(const o of t.attrs){const a=e.fieldValues[o.name];a===void 0||a===""||a===null||a!==o.default&&(o.type==="checkbox"?r.push(`${o.name}="${a?"true":"false"}"`):r.push(`${o.name}="${String(a).replace(/"/g,""")}"`))}return r.join(" ")}function k(e){const t=u(e.activeEffect),r=C(e,t),o=r?" ":"";if(e.scope==="inject"&&e.host){const a=e.host.attrs,c=t.name,s=[];for(const d of Object.keys(a)){if(d===c||d.startsWith(c+"-"))continue;const i=a[d];s.push(i===""?d:`${d}="${String(i).replace(/"/g,""")}"`)}s.push(c);for(const d of t.attrs){const i=e.fieldValues[d.name];if(i===void 0||i===""||i===null||i===d.default)continue;const n=d.type==="checkbox"?i?"true":"false":String(i).replace(/"/g,""");s.push(`${c}-${d.name}="${n}"`)}return`[${e.host.name} ${s.join(" ")}]\u2026[/${e.host.name}]`}return t.selfClosing?`[${t.name}${o}${r} /]`:`[${t.name}${o}${r}]
|
|
1
|
+
import{EFFECTS as _,effectsByCategory as z,effectsInjectableInto as A,getEffect as u}from"./effect-defs.js";import{insertAtCursor as R,replaceRange as x}from"./markdown-toolbar.js";let g=null;function j(e,t,r=14){e.textContent="";const o=document.createElement("span");return o.setAttribute("data-icon",t),o.setAttribute("data-icon-size",String(r)),o.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;",e.appendChild(o),I.scan(e),e}function L(e,t,r,o=14){return j(e,t,o),e.appendChild(document.createTextNode(" "+r)),e}export const EffectsBuilder={open(e){if(g)return;const t={textarea:e,activeEffect:S.get("effects-builder-last")||"reveal",scope:"standalone",host:null,editing:null,fieldValues:{}};if(t.host=F(e),t.host&&A(t.host.name).map(c=>c.name).includes(t.activeEffect)&&!(t.activeEffect in t.host.attrs)&&(t.scope="inject"),t.editing=q(e),t.editing){t.activeEffect=t.editing.name,t.scope="standalone";const a=u(t.editing.name);for(const c of a.attrs)if(c.name in t.editing.attrs){const s=t.editing.attrs[c.name];c.type==="number"?t.fieldValues[c.name]=Number(s):c.type==="checkbox"?t.fieldValues[c.name]=s==="true":t.fieldValues[c.name]=s}}const r=E.slideover({title:"Effects",size:"lg",position:"right",onClose:()=>{g=null}}),o=O(t,r);r.element.appendChild(o),r.open(),I.scan(o),g={state:t,slideover:r}},close(){g&&(g.slideover.close(),g=null)}};function O(e,t){const r=document.createElement("div");r.style.cssText="display:grid;grid-template-columns:170px 1fr;height:100%;min-height:520px;";const o=document.createElement("div");o.className="effects-rail",o.style.cssText="background:var(--dm-background-alt,#15152a);border-right:1px solid var(--dm-border,#2a2a40);padding:.5rem .35rem;font-size:.8rem;overflow-y:auto;";const a=document.createElement("div");a.className="effects-pane",a.style.cssText="padding:1rem;display:flex;flex-direction:column;gap:.75rem;overflow-y:auto;";function c(){H(a,e,t)}return b(o,e,c),c(),r.appendChild(o),r.appendChild(a),r}function b(e,t,r){e.replaceChildren();for(const o of z()){const a=document.createElement("div");a.style.cssText="color:var(--dm-text-muted,#888);text-transform:uppercase;font-size:.65rem;letter-spacing:.05em;margin:.4rem .35rem .25rem;",a.textContent=o.category,e.appendChild(a);for(const c of o.effects){const s=document.createElement("button");s.type="button",s.dataset.effect=c.name,s.style.cssText="display:block;width:100%;text-align:left;padding:.3rem .5rem;border:none;background:transparent;color:var(--dm-text,#ddd);border-radius:3px;font-size:.8rem;cursor:pointer;margin-bottom:.1rem;",s.textContent=c.label,c.name===t.activeEffect&&(s.style.background="var(--dm-primary,#4338ca)",s.style.color="var(--dm-primary-text,#fff)"),s.addEventListener("click",()=>{t.activeEffect=c.name,S.set("effects-builder-last",c.name),t.fieldValues={},b(e,t,r),r()}),e.appendChild(s)}}}function V(e,t){if(e.type==="select"){const o=document.createElement("select");o.style.cssText="width:100%;padding:.35rem .5rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text,#eee);font-size:.85rem;";for(const[a,c]of e.options){const s=document.createElement("option");s.value=a,s.textContent=c,o.appendChild(s)}return o.value=t??e.default??"",o}if(e.type==="checkbox"){const o=document.createElement("input");return o.type="checkbox",o.checked=t??e.default??!1,o}const r=document.createElement("input");return r.type=e.type==="number"?"number":e.type==="colour"?"color":"text",r.value=t??e.default??"",e.placeholder&&(r.placeholder=e.placeholder),e.type==="number"&&(e.min!=null&&(r.min=e.min),e.max!=null&&(r.max=e.max),e.step!=null&&(r.step=e.step)),r.style.cssText="width:100%;padding:.35rem .5rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text,#eee);font-size:.85rem;",r}function v(e,t){return t.type==="checkbox"?e.checked:t.type==="number"?e.value===""?"":Number(e.value):e.value}function N(e,t,r){const o=u(t.activeEffect);if(e.replaceChildren(),o.attrs.length===0){const c=document.createElement("div");c.style.cssText="color:var(--dm-text-muted,#888);font-size:.8rem;font-style:italic;",c.textContent="This effect takes no parameters.",e.appendChild(c);return}const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:1fr 1fr;gap:.6rem .7rem;";for(const c of o.attrs){const s=document.createElement("div"),d=document.createElement("label");d.style.cssText="display:block;color:var(--dm-text-muted,#888);font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.2rem;",d.textContent=c.label,s.appendChild(d);const i=V(c,t.fieldValues[c.name]);if(i.addEventListener("input",()=>{t.fieldValues[c.name]=v(i,c),r()}),i.addEventListener("change",()=>{t.fieldValues[c.name]=v(i,c),r()}),s.appendChild(i),c.hint){const n=document.createElement("div");n.style.cssText="color:var(--dm-text-muted,#666);font-size:.7rem;margin-top:.15rem;",n.textContent=c.hint,s.appendChild(n)}a.appendChild(s)}e.appendChild(a)}function y(e){const t={},r=/(\w[\w-]*)(?:\s*=\s*"([^"]*)"|\s*=\s*'([^']*)'|\s*=\s*(\S+))?/g;for(const o of e.matchAll(r)){const a=o[1],c=o[2]??o[3]??o[4]??"";t[a]=c}return t}const B=_.filter(e=>!e.selfClosing).map(e=>e.name);function q(e){const t=e.value,r=e.selectionStart;for(const o of B){const a=new RegExp(`\\[${o}([^\\]]*)\\]`,"g"),c=new RegExp(`\\[/${o}\\]`,"g"),s=[];for(const n of t.matchAll(a)){if(n.index>=r)break;s.push({type:"open",start:n.index,end:n.index+n[0].length,attrStr:n[1]})}for(const n of t.matchAll(c)){if(n.index>=r)break;s.push({type:"close",start:n.index,end:n.index+n[0].length})}s.sort((n,l)=>n.start-l.start);let d=0,i=null;for(const n of s)n.type==="open"?(d++,i=n):(d--,d<0&&(d=0,i=null));if(d>0&&i){const n=new RegExp(`\\[/${o}\\]`,"g"),l=t.slice(r),m=l.match(n);if(m){const f=r+l.indexOf(m[0]);return{name:o,blockStart:i.start,blockEnd:f+m[0].length,openTagEnd:i.end,attrs:y(i.attrStr)}}}}return null}const P=["card","box","hero","banner","col","button"];function F(e){const t=e.value,r=e.selectionStart;for(const o of P){const a=new RegExp(`\\[${o}([^\\]]*)\\]`,"g"),c=new RegExp(`\\[/${o}\\]`,"g"),s=[];for(const n of t.matchAll(a)){if(n.index>=r)break;s.push({type:"open",start:n.index,end:n.index+n[0].length,attrStr:n[1]})}for(const n of t.matchAll(c)){if(n.index>=r)break;s.push({type:"close",start:n.index,end:n.index+n[0].length})}s.sort((n,l)=>n.start-l.start);let d=0,i=null;for(const n of s)n.type==="open"?(d++,i=n):(d--,d<0&&(d=0,i=null));if(d>0&&i){const n=new RegExp(`\\[/${o}\\]`,"g"),l=t.slice(r),m=l.match(n);if(m){const f=r+l.indexOf(m[0]);return{name:o,openTagStart:i.start,openTagEnd:i.end,closeTagStart:f,closeTagEnd:f+m[0].length,attrs:y(i.attrStr)}}}}return null}function C(e,t){const r=[];for(const o of t.attrs){const a=e.fieldValues[o.name];a===void 0||a===""||a===null||a!==o.default&&(o.type==="checkbox"?r.push(`${o.name}="${a?"true":"false"}"`):r.push(`${o.name}="${String(a).replace(/"/g,""")}"`))}return r.join(" ")}function k(e){const t=u(e.activeEffect),r=C(e,t),o=r?" ":"";if(e.scope==="inject"&&e.host){const a=e.host.attrs,c=t.name,s=[];for(const d of Object.keys(a)){if(d===c||d.startsWith(c+"-"))continue;const i=a[d];s.push(i===""?d:`${d}="${String(i).replace(/"/g,""")}"`)}s.push(c);for(const d of t.attrs){const i=e.fieldValues[d.name];if(i===void 0||i===""||i===null||i===d.default)continue;const n=d.type==="checkbox"?i?"true":"false":String(i).replace(/"/g,""");s.push(`${c}-${d.name}="${n}"`)}return`[${e.host.name} ${s.join(" ")}]\u2026[/${e.host.name}]`}return t.selfClosing?`[${t.name}${o}${r} /]`:`[${t.name}${o}${r}]
|
|
2
2
|
Content
|
|
3
3
|
[/${t.name}]`}function T(e,t){e.replaceChildren();const r=document.createElement("div");r.style.cssText="color:var(--dm-text-muted,#888);font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem;",r.textContent="Shortcode (live)",e.appendChild(r);const o=document.createElement("pre");o.style.cssText="background:var(--dm-code-bg,#000);border:1px solid var(--dm-border,#333);padding:.5rem .65rem;border-radius:3px;font-family:var(--dm-font-mono,monospace);font-size:.75rem;color:var(--dm-code-text,#7c6af7);line-height:1.5;white-space:pre-wrap;word-break:break-all;margin:0;",o.textContent=k(t),e.appendChild(o)}function D(e,t,r){if(e.replaceChildren(),t.editing)return;const o=u(t.activeEffect),a=t.host&&o.hosts.includes(t.host.name),c=document.createElement("div");c.style.cssText="background:var(--dm-background-alt,#15152a);border:1px solid var(--dm-border,#2a2a40);border-radius:4px;padding:.5rem .6rem;";const s=document.createElement("div");if(s.style.cssText="color:var(--dm-text-muted,#888);text-transform:uppercase;font-size:.65rem;letter-spacing:.05em;margin-bottom:.3rem;",s.textContent="Apply as",c.appendChild(s),!a){const n=document.createElement("div");n.style.cssText="color:var(--dm-text-muted,#888);font-size:.75rem;font-style:italic;",t.host?n.textContent=`Inserted as a standalone block (${o.label} cannot be injected into [${t.host.name}]).`:n.textContent="Inserted as a standalone block.",c.appendChild(n),e.appendChild(c),t.scope="standalone";return}const d=document.createElement("div");d.style.cssText="display:flex;gap:.3rem;";function i(n,l){const m=document.createElement("button");return m.type="button",m.style.cssText="flex:1;padding:.35rem;border:1px solid var(--dm-border,#333);border-radius:3px;font-size:.75rem;font-weight:600;cursor:pointer;",t.scope===n?(m.style.background="var(--dm-primary,#4338ca)",m.style.color="var(--dm-primary-text,#fff)",m.style.borderColor="var(--dm-primary,#4338ca)"):(m.style.background="transparent",m.style.color="var(--dm-text-muted,#bbb)"),m.textContent=l,m.addEventListener("click",()=>{t.scope=n,r()}),m}d.appendChild(i("standalone","Standalone block")),d.appendChild(i("inject",`Inject into [${t.host.name}]`)),c.appendChild(d),e.appendChild(c)}let h=0;function $(e){return e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase())}function w(e,t){e.replaceChildren();const r=u(t.activeEffect),o=document.createElement("div");o.style.cssText="display:flex;justify-content:space-between;align-items:center;margin-bottom:.25rem;";const a=document.createElement("div");if(a.style.cssText="color:var(--dm-text-muted,#888);text-transform:uppercase;font-size:.65rem;letter-spacing:.05em;",a.textContent="Live preview",o.appendChild(a),!r.previewable){const i=document.createElement("div");i.style.cssText="background:var(--dm-background-alt,#15152a);border:1px solid var(--dm-border,#2a2a40);border-radius:4px;padding:.6rem;color:var(--dm-text-muted,#888);font-size:.8rem;font-style:italic;text-align:center;",i.textContent="Runs full-page on the published site - no inline preview.",e.appendChild(i);return}const c=document.createElement("button");c.type="button",c.style.cssText="background:transparent;border:1px solid var(--dm-border,#333);color:var(--dm-text-muted,#888);font-size:.65rem;padding:.15rem .4rem;border-radius:2px;cursor:pointer;",L(c,"refresh-cw","Replay",12),o.appendChild(c),e.appendChild(o);const s=document.createElement("div");s.style.cssText="background:var(--dm-background-alt,#1a1a2e);border:1px solid var(--dm-border,#2a2a40);border-radius:4px;padding:1rem;text-align:center;min-height:80px;position:relative;overflow:hidden;",e.appendChild(s);function d(){h++;const i=h;s.replaceChildren();const n=document.createElement("div");n.style.cssText="background:linear-gradient(135deg,#6366f1,#a855f7);color:#fff;padding:.6rem;border-radius:4px;font-size:.8rem;font-weight:600;",n.textContent="Sample content",s.appendChild(n);const l=window.Domma&&window.Domma.effects;if(!l)return;const m={};for(const f of r.attrs){const p=t.fieldValues[f.name];p===void 0||p===""||p===null||(m[$(f.name)]=p)}try{const f=l[$(r.name)];if(typeof f=="function"){if(i!==h)return;f(n,m)}}catch(f){console.warn("Effects preview failed:",f)}}c.addEventListener("click",d),d()}function H(e,t,r){const o=u(t.activeEffect);e.replaceChildren();const a=document.createElement("h3");a.style.cssText="margin:0;font-size:1rem;color:var(--dm-text,#eee);",a.textContent=o.label,e.appendChild(a);const c=document.createElement("p");c.style.cssText="margin:0;color:var(--dm-text-muted,#999);font-size:.8rem;line-height:1.4;",c.textContent=o.description,e.appendChild(c);const s=document.createElement("div");e.appendChild(s);const d=document.createElement("div");e.appendChild(d);const i=document.createElement("div");e.appendChild(i);const n=document.createElement("div");e.appendChild(n);function l(){D(s,t,l),N(d,t,()=>{T(i,t),w(n,t)}),T(i,t),w(n,t)}l();const m=document.createElement("div");m.style.cssText="display:flex;gap:.5rem;margin-top:auto;padding-top:.75rem;border-top:1px solid var(--dm-border,#2a2a40);";const f=document.createElement("button");f.type="button",f.className="btn btn-ghost",f.textContent="Cancel",f.addEventListener("click",()=>r.close()),m.appendChild(f);const p=document.createElement("button");p.type="button",p.className="btn btn-primary",p.style.flex="2",p.textContent=t.editing?"Update":"Insert effect",p.addEventListener("click",()=>K(t,r)),m.appendChild(p),e.appendChild(m)}function K(e,t){const r=e.textarea,o=k(e);if(e.editing){const a=u(e.editing.name),c=r.value,s=`[/${a.name}]`.length,d=e.editing.openTagEnd,i=e.editing.blockEnd-s,n=c.substring(d,i),l=C(e,a),m=l?" ":"",f=a.selfClosing?`[${a.name}${m}${l} /]`:`[${a.name}${m}${l}]${n}[/${a.name}]`;x(r,e.editing.blockStart,e.editing.blockEnd,f);const p=a.selfClosing?e.editing.blockStart+f.length:e.editing.blockStart+f.indexOf("]")+1;r.setSelectionRange(p,p),t.close();return}if(e.scope==="inject"&&e.host){const a=u(e.activeEffect),c=e.host.attrs,s=a.name,d=[];for(const n of Object.keys(c)){if(n===s||n.startsWith(s+"-"))continue;const l=c[n];d.push(l===""?n:`${n}="${String(l).replace(/"/g,""")}"`)}d.push(s);for(const n of a.attrs){const l=e.fieldValues[n.name];if(l===void 0||l===""||l===null||l===n.default)continue;const m=n.type==="checkbox"?l?"true":"false":String(l).replace(/"/g,""");d.push(`${s}-${n.name}="${m}"`)}const i=`[${e.host.name} ${d.join(" ")}]`;x(r,e.host.openTagStart,e.host.openTagEnd,i),t.close();return}R(r,o),t.close()}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{api as q}from"../api.js";import{onceClosed as S}from"./tool-kit.js";const $=/\.(png|jpe?g|gif|webp|avif|svg)$/i;export function pickable(l,{query:s="",accept:p=$}={}){const r=String(s).trim().toLowerCase();return(Array.isArray(l)?l:[]).map(e=>({name:e.name||e.filename||"",url:e.url||(e.name?`/media/${e.name}`:"")})).filter(e=>e.url&&p.test(e.name||e.url)&&(!r||e.name.toLowerCase().includes(r)))}export function pickMedia({title:l="Choose an image",current:s=""}={}){return new Promise(p=>{let r=!1;const e=a=>{r||(r=!0,p(a))},i=E.slideover({title:l,size:"lg",position:"right"}),m=document.createElement("template");m.innerHTML=`<div class="mp-picker">
|
|
2
|
+
<div class="mp-bar">
|
|
3
|
+
<input type="search" class="form-input" placeholder="Search Media\u2026" aria-label="Search Media" data-model="query.value">
|
|
4
|
+
<label class="btn btn-sm btn-ghost mp-upload"><span data-icon="upload"></span> Upload
|
|
5
|
+
<input type="file" accept="image/*" hidden></label>
|
|
6
|
+
</div>
|
|
7
|
+
<p class="mp-note" data-bind-hidden="!note.value" data-bind-text="note.value"></p>
|
|
8
|
+
<div class="media-picker-grid mp-grid" data-each="shown.value key=url">
|
|
9
|
+
<button type="button" class="media-picker-item" data-bind-data-url="url" data-bind-title="name">
|
|
10
|
+
<img data-bind-src="url" data-bind-alt="name" loading="lazy"><span data-bind-text="name"></span>
|
|
11
|
+
</button>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
<style>
|
|
15
|
+
.mp-picker { padding: 1rem; display: flex; flex-direction: column; gap: .75rem; }
|
|
16
|
+
.mp-bar { display: flex; gap: .5rem; align-items: center; }
|
|
17
|
+
.mp-bar .form-input { flex: 1; }
|
|
18
|
+
.mp-upload { cursor: pointer; white-space: nowrap; }
|
|
19
|
+
.mp-note { margin: 0; font-size: .85rem; opacity: .75; }
|
|
20
|
+
.mp-picker [hidden] { display: none !important; }
|
|
21
|
+
.mp-grid { max-height: none; }
|
|
22
|
+
.mp-grid .media-picker-item { background: none; padding: 0; text-align: left; color: inherit; font: inherit; }
|
|
23
|
+
.mp-grid .media-picker-item.is-current { border-color: var(--dm-primary); }
|
|
24
|
+
</style>`;const o=m.content.firstElementChild,h=m.content.querySelector("style"),d=M.observable([]),u=M.observable(""),t=M.observable("Loading\u2026"),g=M.computed(()=>pickable(d.value,{query:u.value})),x=M.effect(()=>{t.peek()==="Loading\u2026"&&!d.value.length||(t.value=g.value.length?"":u.value.trim()?"No picture matches.":"No pictures in Media yet - upload one.")}),b=async()=>{try{d.value=await q.media.list(),t.value="",pickable(d.peek()).length||(t.value="No pictures in Media yet - upload one.")}catch(a){t.value=`Could not load Media: ${a.message||a}`}},y=o.querySelector(".mp-grid"),k=a=>{const n=a.target.closest("[data-url]");n&&(e(n.dataset.url),i.close())};y.addEventListener("click",k);const v=o.querySelector("input[type=file]");v.addEventListener("change",async()=>{const a=v.files?.[0];if(a){t.value=`Uploading ${a.name}\u2026`;try{const n=new FormData;n.append("file",a);const f=await q.media.upload(n),c=Array.isArray(f)?f[0]:f,w=c?.url||(c?.name?`/media/${c.name}`:"");if(E.toast(`${c?.name||a.name} is in Media.`,{type:"success"}),w){e(w),i.close();return}await b()}catch(n){t.value="",E.toast(`Not uploaded: ${n.message||n}`,{type:"error"})}finally{v.value=""}}}),i.element.appendChild(o),h&&i.element.appendChild(h);const L=M.applyBindings({query:u,note:t,shown:g},o),C=M.effect(()=>{g.value,queueMicrotask(()=>y.querySelectorAll("[data-url]").forEach(a=>a.classList.toggle("is-current",!!s&&a.dataset.url===s)))});S(i,()=>{L.dispose(),x?.(),C?.(),y.removeEventListener("click",k),e(null)}),Domma.icons?.scan?.(o),i.open(),b(),setTimeout(()=>o.querySelector("input[type=search]")?.focus(),50)})}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{onceClosed as p}from"./tool-kit.js";const m=([o,a,
|
|
1
|
+
import{onceClosed as p}from"./tool-kit.js";const m=([o,a,n])=>n===void 0?{code:o,where:"",text:a}:{code:o,where:a,text:n},e=(o,a,n="")=>({title:o,code:a,note:n||""}),t=(o,{intro:a="",head:n=null,rows:s=[],block:l="",examples:i=[],outro:r=""}={})=>({title:o,intro:a,head:(n||[]).map((d,c)=>({i:c,text:d})),rows:s.map(m),block:l,examples:i,outro:r}),u=[t("Markdown Basics",{head:["Syntax","Result"],rows:[["**bold**","bold (rendered bold)"],["_italic_","italic (rendered italic)"],["## Heading","Heading (h2)"],["[text](url)","Link"],["","Image"],["- item","Bullet list"],["`code`","Inline code"],["---","Divider"]]}),t("Keyboard Shortcuts",{rows:[["Ctrl + B","Bold selected text"],["Ctrl + I","Italic selected text"],["Ctrl + K","Insert link dialog"],["Tab","Indent 2 spaces at cursor"],["Shift + Tab","Dedent 2 spaces on current line"],["Ctrl + X","Cut current line (no selection) or cut selection"],["Ctrl + C","Copy current line (no selection) or copy selection"],["Ctrl + V","Paste from clipboard"],["Ctrl + Z","Undo"],["Ctrl + Y","Redo"]]}),t("Tips",{rows:[['class="text-center"',"Centre text and inline elements on any shortcode"],['class="mx-auto"',"Centre a block element horizontally"],["[center]...[/center]","Shorthand wrapper for centred content"]],outro:"Most shortcodes accept a class attribute for custom styling."})],g=[t("Grid & Columns",{rows:[['cols="N"',"[grid] only","Number of columns (1-12)"],['gap="N"',"[grid], [row]","Gap between columns/rows (1-6)"],['span="N"',"[col] only","How many columns this cell spans"],['fullwidth="true"',"[grid] only","Break out of page container to span full viewport"],['class="x"',"all","Add extra CSS classes"]],examples:[e("Equal columns",`[grid cols="3" gap="4"]
|
|
2
2
|
[col]One[/col]
|
|
3
3
|
[col]Two[/col]
|
|
4
4
|
[col]Three[/col]
|
|
@@ -22,7 +22,11 @@ import{onceClosed as p}from"./tool-kit.js";const m=([o,a,i])=>i===void 0?{code:o
|
|
|
22
22
|
[col]
|
|
23
23
|
[card title="Three"]Content[/card]
|
|
24
24
|
[/col]
|
|
25
|
-
[/grid]`)]}),t("
|
|
25
|
+
[/grid]`)]}),t("Box",{intro:"A card with no header - a plain container. No shadow and a 2px corner radius unless you say otherwise.",rows:[['shadow="none|md|lg"',"Shadow (default: none)"],['rounded="xs|none|sm|lg|full"',"Corners (default: xs = 2px)"],['padding="compact|spacious"',"Inner padding"],["borderless","Flag: no border"],['footer="..."',"Footer strip text"],['class="..."',"Extra CSS classes (the box also carries dm-box)"]],examples:[e("Basic box",`[box]
|
|
26
|
+
Any content - text, buttons, a grid or a card.
|
|
27
|
+
[/box]`),e("With a shadow and rounder corners",`[box shadow="md" rounded="lg"]
|
|
28
|
+
Lifted off the page.
|
|
29
|
+
[/box]`,"Title, icon and image are ignored - a box never has a header. A [card] can go inside a [box], and a [box] inside a [card].")]}),t("Spacer",{intro:"Self-closing shortcode that inserts a fixed-height blank gap.",rows:[['size="N"',"Height in px (default: 8)"],['class="..."',"Extra CSS class on the spacer div"]],examples:[e("32px gap",'[spacer size="32" /]')]}),t("Center",{intro:"Wraps content in a centred div. Works with any content including cards, grids, and text.",examples:[e("Example","[center]Centred content here[/center]",'Accepts an optional class="..." attribute for extra styling.')]}),t("Hero",{intro:"Full-width hero sections - no plugin required. Uses Domma's built-in Hero CSS component.",rows:[['title="..."',"Heading text"],['tagline="..."',"Subtitle text"],['size="sm|lg|full"',"Height variant (default: normal)"],['variant="dark|primary|gradient-blue|gradient-purple|gradient-sunset|gradient-ocean"',"Colour / gradient preset"],['image="url"',"Background image URL (adds cover mode)"],['overlay="light|dark|darker|gradient|gradient-reverse"',"Image overlay style"],['align="center|left"',"Content alignment (default: center)"],['fullwidth="true"',"Break out of the page container to span full viewport width"],['bg="..."',"Background colour CSS value"],["twinkle","Flag: adds particle overlay (requires Effects plugin)"],['twinkle-count="N"',"Number of particles"],['twinkle-colour="..."',"Particle colour CSS value"],["blobs","Flag: adds ambient blob background"],['blobs-type="..."',"Blob animation type (default: float-blobs)"],['class="..."',"Extra CSS classes"],['id="..."',"Element id"]],examples:[e("Basic hero",'[hero title="Welcome" tagline="Build something great"][/hero]'),e("Gradient with body content",`[hero title="Get Started" tagline="Everything you need." size="lg" variant="gradient-blue" align="center"]
|
|
26
30
|
Some introductory **Markdown** content here.
|
|
27
31
|
[/hero]`),e("Background image with overlay",'[hero title="Our Story" image="/media/hero.jpg" overlay="dark" size="full"][/hero]',"Combine image + overlay for text legibility over photos.")]})],h=[t("Cards",{examples:[e("Basic card",`[card title="Optional Title"]
|
|
28
32
|
Markdown **works** here.
|
|
@@ -150,4 +154,4 @@ pre.per-block { padding-right: .75rem; margin-bottom: .5rem; }
|
|
|
150
154
|
.per-copy { position: absolute; top: .3rem; right: .3rem; background: none; border: none; cursor: pointer; opacity: .45; padding: .15rem;
|
|
151
155
|
line-height: 1; color: inherit; }
|
|
152
156
|
.per-copy:hover, .per-copy:focus-visible { opacity: 1; }
|
|
153
|
-
</style>`;async function w(o){try{return await navigator.clipboard.writeText(o),!0}catch{const a=document.createElement("textarea");a.value=o,a.style.cssText="position:fixed;opacity:0;",document.body.appendChild(a),a.select();let
|
|
157
|
+
</style>`;async function w(o){try{return await navigator.clipboard.writeText(o),!0}catch{const a=document.createElement("textarea");a.value=o,a.style.cssText="position:fixed;opacity:0;",document.body.appendChild(a),a.select();let n=!1;try{n=document.execCommand("copy")}catch{}return a.remove(),n}}export function openEditorReference(){const o=E.slideover({title:"Editor Reference",size:"md",position:"right"}),a=document.createElement("div");a.innerHTML=y;const n=M.observable("basics"),s=M.applyBindings({tabs:REFERENCE,tab:n,show:i=>{n.value=i},copy:async i=>{const r=await w(i);E.toast(r?"Copied!":"Could not copy - select the code and copy it.",{type:r?"success":"warning",duration:1200})}},a);o.element.appendChild(a);const l=M.effect(()=>{n.value,requestAnimationFrame(()=>I.scan(a))});p(o,()=>{try{l()}catch{}try{s.dispose()}catch{}}),o.open()}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{LIMITS as h}from"./seo-analyse.js";export const ORG_TYPES=["Organization","LocalBusiness","Person"],DEFAULT_SETTINGS={organisation:{enabled:!1,type:"Organization",name:"",logo:"",url:"",email:"",phone:"",sameAs:[],address:{street:"",locality:"",region:"",postcode:"",country:""}},articles:!0,sitemap:{exclude:[],sources:{}},robots:{blockAll:!1,extra:""},redirects:{onRename:!0},audit:{everyHours:24,...h}};const f=(e,i=300)=>String(e??"").trim().slice(0,i),c=(e,i)=>e===void 0?i:e===!0||e==="true",m=e=>(Array.isArray(e)?e:String(e??"").split(/[\n,]+/)).map(i=>String(i).trim()).filter(Boolean),p=(e,i,n)=>{const r=Number(e);return Number.isInteger(r)&&r>=i&&r<=n?r:null},g=e=>{try{return["http:","https:"].includes(new URL(e).protocol)}catch{return!1}};export function checkSettings(e={},i=DEFAULT_SETTINGS){const n={},r=JSON.parse(JSON.stringify(mergeDefaults(i))),
|
|
2
|
-
`).map(a=>a.trim()).filter(a=>a&&!a.startsWith("#")&&!/^[A-Za-z-]+\s*:/.test(a));t.length?n["robots.extra"]=`Each line is "Field: value" (or a # comment): ${t[0].slice(0,40)}`:r.robots.extra=
|
|
1
|
+
import{LIMITS as h}from"./seo-analyse.js";export const ORG_TYPES=["Organization","LocalBusiness","Person"],DEFAULT_SETTINGS={organisation:{enabled:!1,type:"Organization",name:"",logo:"",url:"",email:"",phone:"",sameAs:[],address:{street:"",locality:"",region:"",postcode:"",country:""}},articles:!0,sitemap:{exclude:[],sources:{}},robots:{blockAll:!1,extra:""},redirects:{onRename:!0},audit:{everyHours:24,...h}};const f=(e,i=300)=>String(e??"").trim().slice(0,i),c=(e,i)=>e===void 0?i:e===!0||e==="true",m=e=>(Array.isArray(e)?e:String(e??"").split(/[\n,]+/)).map(i=>String(i).trim()).filter(Boolean),p=(e,i,n)=>{const r=Number(e);return Number.isInteger(r)&&r>=i&&r<=n?r:null},g=e=>{try{return["http:","https:"].includes(new URL(e).protocol)}catch{return!1}};export function checkSettings(e={},i=DEFAULT_SETTINGS){const n={},r=JSON.parse(JSON.stringify(mergeDefaults(i))),s=e.organisation;if(s&&typeof s=="object"){const o=r.organisation;s.enabled!==void 0&&(o.enabled=c(s.enabled,!1)),s.type!==void 0&&(ORG_TYPES.includes(s.type)?o.type=s.type:n["organisation.type"]="Organisation, local business or person.");for(const t of["name","email","phone"])s[t]!==void 0&&(o[t]=f(s[t],200));for(const t of["logo","url"]){if(s[t]===void 0)continue;const a=f(s[t],500);a&&!g(a)&&!a.startsWith("/")?n[`organisation.${t}`]=`${t==="logo"?"The logo":"The address"}: a full web address, or a path like /media/logo.png.`:o[t]=a}if(s.sameAs!==void 0){const t=m(s.sameAs),a=t.filter(l=>!g(l));a.length?n["organisation.sameAs"]=`Not web addresses: ${a.slice(0,2).join(", ")}`:o.sameAs=[...new Set(t)].slice(0,20)}if(s.address&&typeof s.address=="object")for(const t of Object.keys(DEFAULT_SETTINGS.organisation.address))s.address[t]!==void 0&&(o.address[t]=f(s.address[t],200))}if(e.articles!==void 0&&(r.articles=c(e.articles,!0)),e.sitemap&&typeof e.sitemap=="object"){if(e.sitemap.exclude!==void 0){const o=m(e.sitemap.exclude),t=o.filter(a=>!a.startsWith("/"));t.length?n["sitemap.exclude"]=`Each starts with "/": ${t.slice(0,3).join(", ")}`:r.sitemap.exclude=[...new Set(o)].slice(0,200)}if(e.sitemap.sources&&typeof e.sitemap.sources=="object")for(const[o,t]of Object.entries(e.sitemap.sources))/^[a-z0-9][a-z0-9:-]*$/.test(o)&&(r.sitemap.sources[o]=c(t,!0))}if(e.robots&&typeof e.robots=="object"&&(e.robots.blockAll!==void 0&&(r.robots.blockAll=c(e.robots.blockAll,!1)),e.robots.extra!==void 0)){const o=String(e.robots.extra??"").replace(/\r/g,"").slice(0,5e3),t=o.split(`
|
|
2
|
+
`).map(a=>a.trim()).filter(a=>a&&!a.startsWith("#")&&!/^[A-Za-z-]+\s*:/.test(a));t.length?n["robots.extra"]=`Each line is "Field: value" (or a # comment): ${t[0].slice(0,40)}`:r.robots.extra=o.trim()}e.redirects&&e.redirects.onRename!==void 0&&(r.redirects.onRename=c(e.redirects.onRename,!0));const d=e.audit;if(d&&typeof d=="object"){const o=(t,a,l,b)=>{if(d[t]===void 0)return;const u=p(d[t],a,l);u===null?n[`audit.${t}`]=`${b}: a whole number, ${a} to ${l}.`:r.audit[t]=u};o("everyHours",0,168,"Check every (hours)"),o("titleMin",10,70,"Shortest title"),o("titleMax",30,100,"Longest title"),o("descMin",30,160,"Shortest description"),o("descMax",80,320,"Longest description"),o("minWords",0,5e3,"Words a page should have"),r.audit.titleMax<r.audit.titleMin&&(n["audit.titleMax"]="The longest title cannot be shorter than the shortest."),r.audit.descMax<r.audit.descMin&&(n["audit.descMax"]="The longest description cannot be shorter than the shortest.")}return{errors:n,settings:r}}export function mergeDefaults(e={}){const i=DEFAULT_SETTINGS;return{organisation:{...i.organisation,...e.organisation||{},address:{...i.organisation.address,...e.organisation?.address||{}},sameAs:Array.isArray(e.organisation?.sameAs)?e.organisation.sameAs:[]},articles:e.articles??i.articles,sitemap:{exclude:Array.isArray(e.sitemap?.exclude)?e.sitemap.exclude:[],sources:{...e.sitemap?.sources||{}}},robots:{...i.robots,...e.robots||{}},redirects:{...i.redirects,...e.redirects||{}},audit:{...i.audit,...e.audit||{}}}}export function excluded(e,i=[]){const n=String(e||"").toLowerCase();return i.some(r=>{const s=String(r).toLowerCase().replace(/\*$/,"");return s.endsWith("/")?n===s.slice(0,-1)||n.startsWith(s):n===s})}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{SHORTCODES as $}from"./shortcode-registry.js";import{EFFECTS as C}from"./effect-defs.js";import{boolState as V,boolValue as G,findEnclosingShortcode as M,setAttr as N,setAttrs as X,effectAttrKeys as q}from"./shortcode-tags.js";import{insertAtCursor as J}from"./markdown-toolbar.js";import{clearLookupCache as Q,lookupOptions as Z}from"./shortcode-lookups.js";import{insertMenuGroups as ee,insertShortcodeByName as te}from"./shortcode-insert.js";import{openShortcodeForm as R}from"./shortcode-form.js";function ne(e){return Z(e,c?.span?.attrs||{})}const oe=$.map(e=>({name:e.name,selfClosing:!!e.selfClosing})),se=new Map($.map(e=>[e.name,e])),ie=new Map(C.map(e=>[e.name,e])),ce=C.map(e=>({name:e.name,selfClosing:!!e.selfClosing})),z=[...oe,...ce],D=new Set(["card","hero","banner","col","button"]);let c=null;const P="position:fixed;z-index:10000;min-width:210px;max-height:70vh;overflow-y:auto;background:var(--dm-surface,#1c1c30);border:1px solid var(--dm-border,#2a2a40);border-radius:6px;box-shadow:var(--dm-shadow-lg);padding:.3rem;font-size:.83rem;color:var(--dm-text,#e5e5e5);",p="display:flex;align-items:center;gap:.5rem;width:100%;text-align:left;padding:.35rem .55rem;border:none;background:transparent;color:inherit;border-radius:4px;cursor:pointer;font-size:.83rem;",S="padding:.3rem .55rem;color:var(--dm-text-muted,#8a8a9a);font-size:.68rem;text-transform:uppercase;letter-spacing:.06em;",H="flex:1;min-width:0;padding:.2rem .4rem;background:var(--dm-input-bg,#12121e);border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text,#eee);font-size:.8rem;",ae="height:1px;background:var(--dm-border,#2a2a40);margin:.3rem .2rem;";function m(e){return e.addEventListener("mouseenter",()=>{e.style.background="var(--dm-primary,#4338ca)",e.style.color="var(--dm-primary-text,#fff)"}),e.addEventListener("mouseleave",()=>{e.style.background="transparent",e.style.color="inherit"}),e}export function attachContextMenu(e){return typeof Domma>"u"||!Domma.elements?.contextMenu?(e.addEventListener("contextmenu",n=>{n.preventDefault(),f();const t=M(e,z);F(e,t,n.clientX,n.clientY)}),null):Domma.elements.contextMenu(e,{inherit:!1,cursor:!1,render:n=>{f();const t=M(e,z);F(e,t,n.x,n.y)}})}function f(){c&&(v(),c.root.remove(),document.removeEventListener("mousedown",W,!0),document.removeEventListener("keydown",j,!0),window.removeEventListener("scroll",Y,!0),c=null)}const W=e=>{c&&!c.root.contains(e.target)&&!(c.submenu&&c.submenu.contains(e.target))&&f()},Y=e=>{c&&!c.root.contains(e.target)&&!(c.submenu&&c.submenu.contains(e.target))&&f()},j=e=>{e.key==="Escape"&&f()};function F(e,n,t,o){Q();const s=document.createElement("div");s.className="dm-sc-menu",s.style.cssText=P,c={root:s,textarea:e,span:n,submenu:null};const i=n&&(se.get(n.name)||ie.get(n.name)),l=n&&D.has(n.name)?C.filter(r=>r.name in n.attrs):[];i&&re(s,i);for(const r of l)xe(s,r);(i||l.length)&&s.appendChild(le()),s.appendChild(y("Add effect\u2026",()=>be())),s.appendChild(y("Insert\u2026",()=>ye()));const a=e.selectionStart!==e.selectionEnd;(n||a)&&s.appendChild(y(a?"Wrap selection in\u2026":"Wrap in\u2026",()=>Ee())),document.body.appendChild(s),U(s,t,o),document.addEventListener("mousedown",W,!0),document.addEventListener("keydown",j,!0),window.addEventListener("scroll",Y,!0),window.I&&I.scan(s)}function le(){const e=document.createElement("div");return e.style.cssText=ae,e}function k(e){const n=document.createElement("div");return n.style.cssText=S,n.textContent=e,n}function re(e,n){e.appendChild(k(`${n.label} options`));const t=m(document.createElement("button"));t.type="button",t.style.cssText=p,t.innerHTML='<span data-icon="edit" data-icon-size="13" style="display:inline-flex;align-items:center;"></span>',t.appendChild(document.createTextNode(`Edit ${n.label}\u2026`)),t.addEventListener("click",()=>{const{textarea:o,span:s}=c;f(),R(o,n,{span:s})}),e.appendChild(t);for(const o of n.attrs||[])e.appendChild(O(o))}function O(e,n=e.name){const t=c.span.attrs[n];switch(e.type){case"checkbox":return de(e,n,V(t,e.default));case"select":return me(e,n,t);case"lookup":return he(e,n,t);case"colour":return pe(e,n,t);case"icon":return fe(e,n,t);default:return ue(e,n,t)}}function b(e,n){c.span=N(c.textarea,c.span,e,n)}function de(e,n,t){const o=m(document.createElement("label"));o.style.cssText=p;const s=document.createElement("input");return s.type="checkbox",s.checked=t,s.addEventListener("change",()=>b(n,G(e,s.checked))),o.appendChild(s),o.appendChild(document.createTextNode(e.label)),o}function ue(e,n,t){const o=document.createElement("div");o.style.cssText=p+"cursor:default;";const s=document.createElement("span");s.textContent=e.label,s.style.cssText="white-space:nowrap;color:var(--dm-text-muted,#9a9aac);";const i=document.createElement("input");i.type=e.type==="number"?"number":"text",i.value=t===!0||t==null?"":t,e.default!=null&&e.default!==""&&(i.placeholder=String(e.default)),i.style.cssText=H;let l=null;return i.addEventListener("input",()=>{clearTimeout(l),l=setTimeout(()=>b(n,i.value.trim()),180)}),i.addEventListener("mousedown",a=>a.stopPropagation()),o.appendChild(s),o.appendChild(i),o}function pe(e,n,t){const o=document.createElement("div");o.style.cssText=p+"cursor:default;";const s=document.createElement("span");s.textContent=e.label,s.style.flex="1";const i=document.createElement("input");return i.type="color",typeof t=="string"&&/^#/.test(t)?i.value=t:typeof e.default=="string"&&/^#/.test(e.default)&&(i.value=e.default),i.addEventListener("input",()=>b(n,i.value)),o.appendChild(s),o.appendChild(i),o}function me(e,n,t){const o=t==null||t===!0?e.default??"":t;return y(`${e.label}${o!==""?`: ${o}`:""}`,()=>{const s=g();for(const[i,l]of e.options||[]){const a=m(document.createElement("button"));a.type="button",a.style.cssText=p,a.textContent=l,i===o&&(a.style.fontWeight="700"),a.addEventListener("click",()=>{b(n,i),v()}),s.appendChild(a)}return s})}function fe(e,n,t){const o=t==null||t===!0?"":String(t),s=o?`${e.label}: ${o}`:e.label;return y(s,()=>{const i=g();i.style.width="232px";const l=document.createElement("input");l.type="text",l.placeholder="Search icons\u2026",l.style.cssText=H+"margin:6px;width:calc(100% - 12px);",l.addEventListener("mousedown",T=>T.stopPropagation()),i.appendChild(l);const a=m(document.createElement("button"));a.type="button",a.style.cssText=p,a.textContent="- none -",o||(a.style.fontWeight="700"),a.addEventListener("click",()=>{b(n,null),v()}),i.appendChild(a);const r=document.createElement("div");r.style.cssText="display:flex;flex-wrap:wrap;gap:2px;padding:4px 6px;max-height:220px;overflow-y:auto;",i.appendChild(r);const u=96,w=()=>{const T=typeof I<"u"&&typeof I.list=="function"?I.list():[],A=l.value.trim().toLowerCase(),_=A?T.filter(d=>d.toLowerCase().includes(A)):T;r.replaceChildren();for(const d of _.slice(0,u)){const x=m(document.createElement("button"));x.type="button",x.title=d,x.style.cssText="width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;background:none;border:1px solid transparent;border-radius:4px;cursor:pointer;color:inherit;",d===o&&(x.style.borderColor="var(--dm-primary,#5b8cff)");const L=document.createElement("span");L.setAttribute("data-icon",d),L.setAttribute("data-icon-size","15"),L.style.cssText="display:inline-flex;align-items:center;",x.appendChild(L),x.addEventListener("click",()=>{b(n,d),v()}),r.appendChild(x)}if(_.length>u){const d=document.createElement("div");d.style.cssText=S,d.textContent=`${_.length-u} more - refine search`,r.appendChild(d)}if(!_.length){const d=document.createElement("div");d.style.cssText=S,d.textContent="No icons match",r.appendChild(d)}window.I&&I.scan(r)};let h=null;return l.addEventListener("input",()=>{clearTimeout(h),h=setTimeout(w,120)}),w(),setTimeout(()=>l.focus(),0),i})}function he(e,n,t){const o=t==null||t===!0?e.default??"":t;return y(`${e.label}${o!==""?`: ${o}`:""}`,()=>{const s=g();s.style.minHeight="48px";const i=typeof E<"u"&&E.loader?E.loader(s,{type:"dots"}):null;return ne(e.source).then(l=>{if(i&&i.destroy(),!c||c.submenu!==s)return;if(s.style.minHeight="",!l.length){const u=document.createElement("div");u.style.cssText=S,u.textContent="Nothing found",s.appendChild(u)}const a=l.some(([u])=>u===o),r=[["","- none -"],...l];o!==""&&!a&&r.push([o,`${o} (missing)`]);for(const[u,w]of r){const h=m(document.createElement("button"));h.type="button",h.style.cssText=p,h.textContent=w,u===o&&(h.style.fontWeight="700"),h.addEventListener("click",()=>{b(n,u===""?null:u),v()}),s.appendChild(h)}}),s})}function xe(e,n){e.appendChild(k(`Effect: ${n.label}`));for(const o of n.attrs||[])e.appendChild(O(o,`${n.name}-${o.name}`));const t=m(document.createElement("button"));t.type="button",t.style.cssText=p,t.innerHTML='<span data-icon="trash" data-icon-size="13" style="display:inline-flex;align-items:center;"></span> Remove effect',t.addEventListener("click",()=>{const o={};for(const s of q(c.span.attrs,n.name))o[s]=null;X(c.textarea,c.span,o),f()}),e.appendChild(t)}function be(){const e=g(),n=c.span,t=n&&D.has(n.name)?n.name:null;for(const o of[...new Set(C.map(s=>s.category))]){const s=C.filter(i=>i.category===o);if(s.length){e.appendChild(k(o));for(const i of s){const l=t&&(i.hosts||[]).includes(t)&&!(i.name in n.attrs),a=m(document.createElement("button"));if(a.type="button",a.style.cssText=p+"justify-content:space-between;",a.appendChild(document.createTextNode(i.label)),l){const r=document.createElement("span");r.textContent=`inject \u2192 [${t}]`,r.style.cssText="opacity:.6;font-size:.7rem;",a.appendChild(r)}a.addEventListener("click",()=>{if(l)N(c.textarea,c.span,i.name,!0);else{const r=i.selfClosing?`[${i.name} /]`:`[${i.name}]
|
|
1
|
+
import{SHORTCODES as $}from"./shortcode-registry.js";import{EFFECTS as C}from"./effect-defs.js";import{boolState as V,boolValue as G,findEnclosingShortcode as M,setAttr as N,setAttrs as X,effectAttrKeys as q}from"./shortcode-tags.js";import{insertAtCursor as J}from"./markdown-toolbar.js";import{clearLookupCache as Q,lookupOptions as Z}from"./shortcode-lookups.js";import{insertMenuGroups as ee,insertShortcodeByName as te}from"./shortcode-insert.js";import{openShortcodeForm as R}from"./shortcode-form.js";function ne(e){return Z(e,c?.span?.attrs||{})}const oe=$.map(e=>({name:e.name,selfClosing:!!e.selfClosing})),se=new Map($.map(e=>[e.name,e])),ie=new Map(C.map(e=>[e.name,e])),ce=C.map(e=>({name:e.name,selfClosing:!!e.selfClosing})),z=[...oe,...ce],D=new Set(["card","box","hero","banner","col","button"]);let c=null;const P="position:fixed;z-index:10000;min-width:210px;max-height:70vh;overflow-y:auto;background:var(--dm-surface,#1c1c30);border:1px solid var(--dm-border,#2a2a40);border-radius:6px;box-shadow:var(--dm-shadow-lg);padding:.3rem;font-size:.83rem;color:var(--dm-text,#e5e5e5);",p="display:flex;align-items:center;gap:.5rem;width:100%;text-align:left;padding:.35rem .55rem;border:none;background:transparent;color:inherit;border-radius:4px;cursor:pointer;font-size:.83rem;",S="padding:.3rem .55rem;color:var(--dm-text-muted,#8a8a9a);font-size:.68rem;text-transform:uppercase;letter-spacing:.06em;",H="flex:1;min-width:0;padding:.2rem .4rem;background:var(--dm-input-bg,#12121e);border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text,#eee);font-size:.8rem;",ae="height:1px;background:var(--dm-border,#2a2a40);margin:.3rem .2rem;";function m(e){return e.addEventListener("mouseenter",()=>{e.style.background="var(--dm-primary,#4338ca)",e.style.color="var(--dm-primary-text,#fff)"}),e.addEventListener("mouseleave",()=>{e.style.background="transparent",e.style.color="inherit"}),e}export function attachContextMenu(e){return typeof Domma>"u"||!Domma.elements?.contextMenu?(e.addEventListener("contextmenu",n=>{n.preventDefault(),f();const t=M(e,z);F(e,t,n.clientX,n.clientY)}),null):Domma.elements.contextMenu(e,{inherit:!1,cursor:!1,render:n=>{f();const t=M(e,z);F(e,t,n.x,n.y)}})}function f(){c&&(v(),c.root.remove(),document.removeEventListener("mousedown",W,!0),document.removeEventListener("keydown",j,!0),window.removeEventListener("scroll",Y,!0),c=null)}const W=e=>{c&&!c.root.contains(e.target)&&!(c.submenu&&c.submenu.contains(e.target))&&f()},Y=e=>{c&&!c.root.contains(e.target)&&!(c.submenu&&c.submenu.contains(e.target))&&f()},j=e=>{e.key==="Escape"&&f()};function F(e,n,t,o){Q();const s=document.createElement("div");s.className="dm-sc-menu",s.style.cssText=P,c={root:s,textarea:e,span:n,submenu:null};const i=n&&(se.get(n.name)||ie.get(n.name)),l=n&&D.has(n.name)?C.filter(r=>r.name in n.attrs):[];i&&re(s,i);for(const r of l)xe(s,r);(i||l.length)&&s.appendChild(le()),s.appendChild(y("Add effect\u2026",()=>be())),s.appendChild(y("Insert\u2026",()=>ye()));const a=e.selectionStart!==e.selectionEnd;(n||a)&&s.appendChild(y(a?"Wrap selection in\u2026":"Wrap in\u2026",()=>Ee())),document.body.appendChild(s),U(s,t,o),document.addEventListener("mousedown",W,!0),document.addEventListener("keydown",j,!0),window.addEventListener("scroll",Y,!0),window.I&&I.scan(s)}function le(){const e=document.createElement("div");return e.style.cssText=ae,e}function k(e){const n=document.createElement("div");return n.style.cssText=S,n.textContent=e,n}function re(e,n){e.appendChild(k(`${n.label} options`));const t=m(document.createElement("button"));t.type="button",t.style.cssText=p,t.innerHTML='<span data-icon="edit" data-icon-size="13" style="display:inline-flex;align-items:center;"></span>',t.appendChild(document.createTextNode(`Edit ${n.label}\u2026`)),t.addEventListener("click",()=>{const{textarea:o,span:s}=c;f(),R(o,n,{span:s})}),e.appendChild(t);for(const o of n.attrs||[])e.appendChild(O(o))}function O(e,n=e.name){const t=c.span.attrs[n];switch(e.type){case"checkbox":return de(e,n,V(t,e.default));case"select":return me(e,n,t);case"lookup":return he(e,n,t);case"colour":return pe(e,n,t);case"icon":return fe(e,n,t);default:return ue(e,n,t)}}function b(e,n){c.span=N(c.textarea,c.span,e,n)}function de(e,n,t){const o=m(document.createElement("label"));o.style.cssText=p;const s=document.createElement("input");return s.type="checkbox",s.checked=t,s.addEventListener("change",()=>b(n,G(e,s.checked))),o.appendChild(s),o.appendChild(document.createTextNode(e.label)),o}function ue(e,n,t){const o=document.createElement("div");o.style.cssText=p+"cursor:default;";const s=document.createElement("span");s.textContent=e.label,s.style.cssText="white-space:nowrap;color:var(--dm-text-muted,#9a9aac);";const i=document.createElement("input");i.type=e.type==="number"?"number":"text",i.value=t===!0||t==null?"":t,e.default!=null&&e.default!==""&&(i.placeholder=String(e.default)),i.style.cssText=H;let l=null;return i.addEventListener("input",()=>{clearTimeout(l),l=setTimeout(()=>b(n,i.value.trim()),180)}),i.addEventListener("mousedown",a=>a.stopPropagation()),o.appendChild(s),o.appendChild(i),o}function pe(e,n,t){const o=document.createElement("div");o.style.cssText=p+"cursor:default;";const s=document.createElement("span");s.textContent=e.label,s.style.flex="1";const i=document.createElement("input");return i.type="color",typeof t=="string"&&/^#/.test(t)?i.value=t:typeof e.default=="string"&&/^#/.test(e.default)&&(i.value=e.default),i.addEventListener("input",()=>b(n,i.value)),o.appendChild(s),o.appendChild(i),o}function me(e,n,t){const o=t==null||t===!0?e.default??"":t;return y(`${e.label}${o!==""?`: ${o}`:""}`,()=>{const s=g();for(const[i,l]of e.options||[]){const a=m(document.createElement("button"));a.type="button",a.style.cssText=p,a.textContent=l,i===o&&(a.style.fontWeight="700"),a.addEventListener("click",()=>{b(n,i),v()}),s.appendChild(a)}return s})}function fe(e,n,t){const o=t==null||t===!0?"":String(t),s=o?`${e.label}: ${o}`:e.label;return y(s,()=>{const i=g();i.style.width="232px";const l=document.createElement("input");l.type="text",l.placeholder="Search icons\u2026",l.style.cssText=H+"margin:6px;width:calc(100% - 12px);",l.addEventListener("mousedown",T=>T.stopPropagation()),i.appendChild(l);const a=m(document.createElement("button"));a.type="button",a.style.cssText=p,a.textContent="- none -",o||(a.style.fontWeight="700"),a.addEventListener("click",()=>{b(n,null),v()}),i.appendChild(a);const r=document.createElement("div");r.style.cssText="display:flex;flex-wrap:wrap;gap:2px;padding:4px 6px;max-height:220px;overflow-y:auto;",i.appendChild(r);const u=96,w=()=>{const T=typeof I<"u"&&typeof I.list=="function"?I.list():[],A=l.value.trim().toLowerCase(),_=A?T.filter(d=>d.toLowerCase().includes(A)):T;r.replaceChildren();for(const d of _.slice(0,u)){const x=m(document.createElement("button"));x.type="button",x.title=d,x.style.cssText="width:26px;height:26px;display:inline-flex;align-items:center;justify-content:center;background:none;border:1px solid transparent;border-radius:4px;cursor:pointer;color:inherit;",d===o&&(x.style.borderColor="var(--dm-primary,#5b8cff)");const L=document.createElement("span");L.setAttribute("data-icon",d),L.setAttribute("data-icon-size","15"),L.style.cssText="display:inline-flex;align-items:center;",x.appendChild(L),x.addEventListener("click",()=>{b(n,d),v()}),r.appendChild(x)}if(_.length>u){const d=document.createElement("div");d.style.cssText=S,d.textContent=`${_.length-u} more - refine search`,r.appendChild(d)}if(!_.length){const d=document.createElement("div");d.style.cssText=S,d.textContent="No icons match",r.appendChild(d)}window.I&&I.scan(r)};let h=null;return l.addEventListener("input",()=>{clearTimeout(h),h=setTimeout(w,120)}),w(),setTimeout(()=>l.focus(),0),i})}function he(e,n,t){const o=t==null||t===!0?e.default??"":t;return y(`${e.label}${o!==""?`: ${o}`:""}`,()=>{const s=g();s.style.minHeight="48px";const i=typeof E<"u"&&E.loader?E.loader(s,{type:"dots"}):null;return ne(e.source).then(l=>{if(i&&i.destroy(),!c||c.submenu!==s)return;if(s.style.minHeight="",!l.length){const u=document.createElement("div");u.style.cssText=S,u.textContent="Nothing found",s.appendChild(u)}const a=l.some(([u])=>u===o),r=[["","- none -"],...l];o!==""&&!a&&r.push([o,`${o} (missing)`]);for(const[u,w]of r){const h=m(document.createElement("button"));h.type="button",h.style.cssText=p,h.textContent=w,u===o&&(h.style.fontWeight="700"),h.addEventListener("click",()=>{b(n,u===""?null:u),v()}),s.appendChild(h)}}),s})}function xe(e,n){e.appendChild(k(`Effect: ${n.label}`));for(const o of n.attrs||[])e.appendChild(O(o,`${n.name}-${o.name}`));const t=m(document.createElement("button"));t.type="button",t.style.cssText=p,t.innerHTML='<span data-icon="trash" data-icon-size="13" style="display:inline-flex;align-items:center;"></span> Remove effect',t.addEventListener("click",()=>{const o={};for(const s of q(c.span.attrs,n.name))o[s]=null;X(c.textarea,c.span,o),f()}),e.appendChild(t)}function be(){const e=g(),n=c.span,t=n&&D.has(n.name)?n.name:null;for(const o of[...new Set(C.map(s=>s.category))]){const s=C.filter(i=>i.category===o);if(s.length){e.appendChild(k(o));for(const i of s){const l=t&&(i.hosts||[]).includes(t)&&!(i.name in n.attrs),a=m(document.createElement("button"));if(a.type="button",a.style.cssText=p+"justify-content:space-between;",a.appendChild(document.createTextNode(i.label)),l){const r=document.createElement("span");r.textContent=`inject \u2192 [${t}]`,r.style.cssText="opacity:.6;font-size:.7rem;",a.appendChild(r)}a.addEventListener("click",()=>{if(l)N(c.textarea,c.span,i.name,!0);else{const r=i.selfClosing?`[${i.name} /]`:`[${i.name}]
|
|
2
2
|
Content
|
|
3
3
|
[/${i.name}]`;J(c.textarea,r)}f()}),e.appendChild(a)}}}return e}function y(e,n){const t=m(document.createElement("button"));t.type="button",t.style.cssText=p+"justify-content:space-between;",t.appendChild(document.createTextNode(e));const o=document.createElement("span");return o.setAttribute("data-icon","chevron-right"),o.setAttribute("data-icon-size","12"),o.style.cssText="opacity:.6;display:inline-flex;align-items:center;flex-shrink:0;",t.appendChild(o),t.addEventListener("mouseenter",()=>B(t,n)),t.addEventListener("click",s=>{s.stopPropagation(),B(t,n)}),t}function g(){const e=document.createElement("div");return e.className="dm-sc-submenu",e.style.cssText=P,e}function B(e,n){v();const t=n();c.submenu=t,document.body.appendChild(t);const o=e.getBoundingClientRect();U(t,o.right+2,o.top,o.left-2),window.I&&I.scan(t)}function v(){c&&c.submenu&&(c.submenu.remove(),c.submenu=null)}function K(e){const n=m(document.createElement("button"));if(n.type="button",n.style.cssText=p,e.icon){const t=document.createElement("span");t.setAttribute("data-icon",e.icon),t.setAttribute("data-icon-size","14"),t.style.cssText="opacity:.75;display:inline-flex;align-items:center;flex-shrink:0;",n.appendChild(t)}return n.appendChild(document.createTextNode(e.label)),n}function ye(){const e=g();for(const{category:n,items:t}of ee()){e.appendChild(k(n));for(const o of t){const s=K(o);s.addEventListener("click",()=>{const i=c.textarea;f(),te(o.name,i)}),e.appendChild(s)}}return e}function Ee(){const e=g();for(const n of $.filter(t=>t.wrappable||t.container)){const t=K(n);t.addEventListener("click",()=>{const o=c.textarea;f(),R(o,n)}),e.appendChild(t)}return e}function U(e,n,t,o){e.style.left="0px",e.style.top="0px";const s=e.getBoundingClientRect();let i=n;n+s.width>window.innerWidth-8&&(i=o!=null?o-s.width:n-s.width);let l=t;t+s.height>window.innerHeight-8&&(l=Math.max(8,window.innerHeight-s.height-8)),e.style.left=`${Math.max(8,i)}px`,e.style.top=`${Math.max(8,l)}px`}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const SHORTCODES=[{name:"card",label:"Card",icon:"card",category:"Layout",selfClosing:!1,container:!0,wrappable:!0,template:`[card title="Title"]
|
|
2
2
|
Content
|
|
3
|
-
[/card]`,custom:"card",attrs:[{name:"title",type:"text",label:"Title"},{name:"subtitle",type:"text",label:"Subtitle"},{name:"icon",type:"icon",label:"Icon"},{name:"icon-layout",type:"select",label:"Icon layout",options:[["inline","Inline"],["stacked","Stacked"]]},{name:"footer",type:"text",label:"Footer"},{name:"variant",type:"select",label:"Variant",options:[["","Default"],["primary","Primary"]]},{name:"collapsible",type:"checkbox",label:"Collapsible"},{name:"hover",type:"checkbox",label:"Hover highlight"},{name:"class",type:"text",label:"CSS class"},{name:"id",type:"text",label:"ID"}]},{name:"
|
|
3
|
+
[/card]`,custom:"card",attrs:[{name:"title",type:"text",label:"Title"},{name:"subtitle",type:"text",label:"Subtitle"},{name:"icon",type:"icon",label:"Icon"},{name:"icon-layout",type:"select",label:"Icon layout",options:[["inline","Inline"],["stacked","Stacked"]]},{name:"footer",type:"text",label:"Footer"},{name:"variant",type:"select",label:"Variant",options:[["","Default"],["primary","Primary"]]},{name:"collapsible",type:"checkbox",label:"Collapsible"},{name:"hover",type:"checkbox",label:"Hover highlight"},{name:"class",type:"text",label:"CSS class"},{name:"id",type:"text",label:"ID"}]},{name:"box",label:"Box",icon:"square",category:"Layout",selfClosing:!1,container:!0,wrappable:!0,template:`[box]
|
|
4
|
+
Content
|
|
5
|
+
[/box]`,attrs:[{name:"shadow",type:"select",label:"Shadow",options:[["","None (default)"],["md","Medium"],["lg","Large"]]},{name:"rounded",type:"select",label:"Corners",options:[["","2px (default)"],["none","Square"],["sm","Small"],["lg","Large"],["full","Pill"]]},{name:"padding",type:"select",label:"Padding",options:[["","Normal"],["compact","Compact"],["spacious","Spacious"]]},{name:"borderless",type:"checkbox",label:"No border"},{name:"footer",type:"text",label:"Footer"},{name:"class",type:"text",label:"CSS class"},{name:"id",type:"text",label:"ID"}]},{name:"grid",label:"Grid",icon:"columns",category:"Layout",selfClosing:!1,container:!0,wrappable:!1,template:`[grid cols="2" gap="3"]
|
|
4
6
|
[col]
|
|
5
7
|
Left
|
|
6
8
|
[/col]
|
package/admin/js/lib/tool-kit.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export function onceClosed(t,e=()=>{}){const n=t.close.bind(t);let
|
|
1
|
+
export function onceClosed(t,e=()=>{}){const n=t.close.bind(t),o=t.close;let c=!1;t.close=(...r)=>{const s=n(...r);return c||(c=!0,e(),setTimeout(()=>{t.close=o;try{t.destroy?.()}catch{}t.element?.remove()},400)),s}}export function openMenuAt(t){const e=t.getBoundingClientRect();t.dispatchEvent(new MouseEvent("contextmenu",{bubbles:!0,cancelable:!0,clientX:e.left,clientY:e.bottom,view:window}))}export function settingsStore(t,e){return{read(){try{return e(S.get(t))}catch{return e(null)}},write(n){try{S.set(t,n)}catch{}}}}export function viewLifetime(t){let e=[];const n=()=>{const c=e;e=[],c.forEach(r=>{try{r?.()}catch{}})},o=()=>{t.test(location.hash)||n()};return{add(c){e.push(c)},reset(){n(),window.addEventListener("hashchange",o),e.push(()=>window.removeEventListener("hashchange",o))}}}export function sidebarCount(t,e={}){try{window.dispatchEvent(new CustomEvent("dm:sidebar-count",{detail:{url:t,...e}}))}catch{}}
|
|
@@ -51,6 +51,12 @@
|
|
|
51
51
|
<strong>Cards</strong> subsection below.
|
|
52
52
|
</td>
|
|
53
53
|
</tr>
|
|
54
|
+
<tr>
|
|
55
|
+
<td><code>[box]...[/box]</code></td>
|
|
56
|
+
<td>A card with no header - a plain container. No shadow and a 2px corner radius unless
|
|
57
|
+
<code>shadow</code> / <code>rounded</code> say otherwise. See <strong>Box</strong> below.
|
|
58
|
+
</td>
|
|
59
|
+
</tr>
|
|
54
60
|
<tr>
|
|
55
61
|
<td><code>[tabs]...[/tabs]</code></td>
|
|
56
62
|
<td>Tab group; use <code>[tab title="..."]...[/tab]</code> inside</td>
|
|
@@ -88,6 +94,51 @@
|
|
|
88
94
|
</tbody>
|
|
89
95
|
</table>
|
|
90
96
|
|
|
97
|
+
<h3>Box - a plain container</h3>
|
|
98
|
+
<p><code>[box]</code> wraps content in a card with no header. Without attributes it has
|
|
99
|
+
<strong>no shadow</strong> and a <strong>2px corner radius</strong>; give <code>shadow</code> or
|
|
100
|
+
<code>rounded</code> to change either.</p>
|
|
101
|
+
<pre><code>[box]
|
|
102
|
+
Any content - text, a button, a [grid] or a [card].
|
|
103
|
+
[/box]
|
|
104
|
+
|
|
105
|
+
[box shadow="md" rounded="lg" padding="spacious"]
|
|
106
|
+
Lifted off the page, with rounder corners.
|
|
107
|
+
[/box]</code></pre>
|
|
108
|
+
<table class="table table-sm">
|
|
109
|
+
<thead>
|
|
110
|
+
<tr>
|
|
111
|
+
<th>Attribute</th>
|
|
112
|
+
<th>Values</th>
|
|
113
|
+
<th>Effect</th>
|
|
114
|
+
</tr>
|
|
115
|
+
</thead>
|
|
116
|
+
<tbody>
|
|
117
|
+
<tr>
|
|
118
|
+
<td><code>shadow</code></td>
|
|
119
|
+
<td><code>none</code> (default) · <code>md</code> · <code>lg</code></td>
|
|
120
|
+
<td>Drop-shadow depth</td>
|
|
121
|
+
</tr>
|
|
122
|
+
<tr>
|
|
123
|
+
<td><code>rounded</code></td>
|
|
124
|
+
<td><code>xs</code> (2px, default) · <code>none</code> · <code>sm</code> ·
|
|
125
|
+
<code>lg</code> · <code>full</code></td>
|
|
126
|
+
<td>Corner radius</td>
|
|
127
|
+
</tr>
|
|
128
|
+
<tr>
|
|
129
|
+
<td><code>padding</code>, <code>borderless</code>, <code>variant</code>, <code>footer</code>,
|
|
130
|
+
<code>class</code>, <code>id</code></td>
|
|
131
|
+
<td>as on <code>[card]</code></td>
|
|
132
|
+
<td>The box carries <code>card</code> and <code>dm-box</code> classes for your own CSS</td>
|
|
133
|
+
</tr>
|
|
134
|
+
</tbody>
|
|
135
|
+
</table>
|
|
136
|
+
<p>A box never has a header: <code>title</code>, <code>subtitle</code>, <code>icon</code>,
|
|
137
|
+
<code>image</code> and <code>layout</code> are ignored. Card effects (<code>reveal</code>,
|
|
138
|
+
<code>pulse</code>, …) work on a box too. A <code>[card]</code> can go inside a
|
|
139
|
+
<code>[box]</code> and a <code>[box]</code> inside a <code>[card]</code>, but a box cannot hold
|
|
140
|
+
another box.</p>
|
|
141
|
+
|
|
91
142
|
<h3>Cards - variants, gradients & layouts</h3>
|
|
92
143
|
<p>The <code>[card]</code> shortcode is the most configurable component in the system. It has three
|
|
93
144
|
layers you can mix freely: <strong>variant</strong> (the overall visual style), <strong>gradient</strong>
|
|
@@ -224,8 +275,8 @@ Body content in **Markdown** is supported.
|
|
|
224
275
|
</tr>
|
|
225
276
|
<tr>
|
|
226
277
|
<td><code>rounded</code></td>
|
|
227
|
-
<td><code>none</code> · <code>
|
|
228
|
-
<code>full</code></td>
|
|
278
|
+
<td><code>none</code> · <code>xs</code> (2px) · <code>sm</code> ·
|
|
279
|
+
<code>lg</code> · <code>full</code></td>
|
|
229
280
|
<td>Corner radius</td>
|
|
230
281
|
</tr>
|
|
231
282
|
<tr>
|
|
@@ -186,6 +186,8 @@
|
|
|
186
186
|
.sox-form h4 { margin: 0 0 .5rem; font-size: var(--dm-text-base); display: flex; align-items: center; gap: .5rem; }
|
|
187
187
|
.sox-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); gap: .7rem 1rem; }
|
|
188
188
|
.sox-wide { grid-column: 1 / -1; }
|
|
189
|
+
.sox-pick { display: flex; gap: .4rem; align-items: center; }
|
|
190
|
+
.sox-pick .form-input { flex: 1; min-width: 0; }
|
|
189
191
|
.sox-err { color: var(--dm-danger); font-size: var(--dm-text-xs); }
|
|
190
192
|
.sox-actions { display: flex; align-items: center; gap: .5rem; border-top: 1px solid var(--dm-border); padding-top: .8rem; }
|
|
191
193
|
.sox-meter { display: flex; align-items: center; gap: .5rem; font-size: var(--dm-text-xs); color: var(--dm-text-muted); margin-top: .25rem; }
|