domma-cms 1.8.23 → 1.8.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/admin/css/admin.css +1 -1
- package/admin/js/app.js +1 -1
- package/admin/js/lib/editor-hop-arrange.js +1 -1
- package/admin/js/lib/editor-hop.js +1 -19
- package/admin/js/lib/editor-workspace-arrange.js +1 -0
- package/admin/js/lib/page-blocks-arrange.js +1 -1
- package/admin/js/lib/page-editor-arrange.js +1 -1
- package/admin/js/lib/plain-editor.js +6 -0
- package/admin/js/lib/sidebar-size.js +1 -1
- package/admin/js/lib/syntax-highlight.js +1 -1
- package/admin/js/templates/docs/components-howto.html +2 -2
- package/admin/js/templates/docs/components-walkthrough.html +1 -1
- package/admin/js/templates/docs/usage-blocks.html +19 -15
- package/admin/js/templates/page-editor.html +533 -298
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/page-editor.js +36 -9
- package/docs/DommaFeatures.md +8 -8
- package/docs/configuration.md +13 -12
- package/docs/markdown-shortcodes.md +12 -8
- package/package.json +1 -1
- package/admin/js/templates/block-editor.html +0 -251
- package/admin/js/templates/component-editor.html +0 -150
- package/admin/js/views/block-editor.js +0 -14
- package/admin/js/views/component-editor.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{KINDS as S,keyOf as k}from"./editor-hop-arrange.js";import{SAMPLE_IMAGE as w,sampleValue as b}from"./block-editor-arrange.js";export const LAYOUTS=["split","write","preview"],nextLayout=t=>LAYOUTS[(LAYOUTS.indexOf(t)+1)%LAYOUTS.length],cleanLayout=t=>LAYOUTS.includes(t)?t:"split";export function workspaceKey(t){if(!t||!(t.ctrlKey||t.metaKey)||t.altKey)return null;const n=String(t.key||"").toLowerCase();return!t.shiftKey&&n==="s"?"save":!t.shiftKey&&(n==="\\"||t.code==="Backslash")?"layout":t.shiftKey&&n==="e"?"explorer":null}export const tabId=t=>k(t);export function tabItem(t){const n=String(t||""),r=n.indexOf(":");if(r<0)return null;const e=n.slice(0,r);return S.includes(e)?{kind:e,id:n.slice(r+1)}:null}export function openTab(t,n){return{ids:t.includes(n)?[...t]:[...t,n],active:n}}export function closeTab(t,n,r){const e=t.indexOf(n);if(e<0)return{ids:[...t],active:r};const o=t.filter(i=>i!==n);return r!==n?{ids:o,active:r}:{ids:o,active:o[Math.min(e,o.length-1)]??""}}export function moveTab(t,n,r){const e=t.indexOf(n),o=e+(r<0?-1:1);if(e<0||o<0||o>=t.length)return[...t];const i=[...t];return[i[e],i[o]]=[i[o],i[e]],i}export function tabsToClose(t,n,r){const e=t.indexOf(n);return e<0?[]:r==="others"?t.filter(o=>o!==n):r==="right"?t.slice(e+1):r==="all"?[...t]:[]}export function renameTab(t,n,r,e){return{ids:t.map(i=>i===n?r:i).filter((i,u,c)=>c.indexOf(i)===u),active:e===n?r:e}}export function rememberedTabs(t){const n=(Array.isArray(t?.ids)?t.ids:[]).filter(e=>typeof e=="string"&&tabItem(e)).filter((e,o,i)=>i.indexOf(e)===o).slice(0,40),r=typeof t?.active=="string"&&n.includes(t.active)?t.active:n[0]||"";return{ids:n,active:r}}export function startingTabs(t,n,r){if(!t||!t.id&&t.kind!=="page")return n;const e=tabId(t);return r&&n.active===e?n:openTab(n.ids,e)}export function addressFor(t){return t.kind==="page"?t.id?`/pages/edit${t.id}`:"/pages/new":`/${t.kind==="component"?"components":"blocks"}/edit/${encodeURIComponent(t.id)}`}const p=t=>String(t||"").split("/").filter(Boolean);export function comparePaths(t,n){const r=p(t),e=p(n);for(let o=0;o<Math.min(r.length,e.length);o++)if(r[o]!==e[o])return r[o]<e[o]?-1:1;return r.length-e.length}export function pageRows(t,{filter:n="",folded:r=new Set}={}){const e=(Array.isArray(t)?t:[]).filter(s=>typeof s?.urlPath=="string"&&s.urlPath.startsWith("/")),o=String(n||"").trim().toLowerCase(),i=(s,a,l)=>({key:`page:${s.urlPath}`,kind:"page",id:s.urlPath,label:String(s.title||"").trim()||s.urlPath,meta:s.urlPath,depth:a,folder:l,status:typeof s.status=="string"?s.status:""});if(o)return e.filter(s=>[s.title,s.urlPath].some(a=>String(a||"").toLowerCase().includes(o))).sort((s,a)=>comparePaths(s.urlPath,a.urlPath)).map(s=>i(s,0,!1));const u=new Map(e.map(s=>[s.urlPath,s])),c=new Set;for(const s of e){const a=p(s.urlPath);for(let l=1;l<a.length;l++)c.add("/"+a.slice(0,l).join("/"))}const d=[...new Set([...u.keys(),...c])].sort(comparePaths),y=r instanceof Set?r:new Set(r||[]),f=[];for(const s of d){const a=p(s),l=Math.max(0,a.length-1);let m=!1;for(let g=1;g<a.length;g++)if(y.has("/"+a.slice(0,g).join("/"))){m=!0;break}if(m)continue;const x=c.has(s),h=u.get(s);h?f.push(i(h,l,x)):f.push({key:`folder:${s}`,kind:"folder",id:s,label:a.at(-1)||s,meta:s,depth:l,folder:!0,status:""})}return f}export function blockRows(t,n=""){const r=String(n||"").trim().toLowerCase();return(Array.isArray(t)?t:[]).filter(e=>typeof e?.name=="string"&&e.name).filter(e=>!r||[e.name,e.description].some(o=>String(o||"").toLowerCase().includes(r))).sort((e,o)=>e.name.localeCompare(o.name)).map(e=>({key:`block:${e.name}`,kind:"block",id:e.name,label:e.name,meta:String(e.description||"")}))}export const componentKind=t=>t?.origin==="plugin"?"plugin":t?.bundled?"builtin":"mine";const $={plugin:"Plugin - read only",builtin:"Built in",mine:""};export function componentRows(t,n=""){const r=String(n||"").trim().toLowerCase();return(Array.isArray(t)?t:[]).filter(e=>typeof e?.name=="string"&&e.name).filter(e=>!r||[e.name,...Object.keys(e.props&&typeof e.props=="object"?e.props:{})].some(o=>String(o||"").toLowerCase().includes(r))).sort((e,o)=>e.name.localeCompare(o.name)).map(e=>({key:`component:${e.name}`,kind:"component",id:e.name,label:e.name,meta:$[componentKind(e)],readOnly:componentKind(e)==="plugin"}))}export function componentsInBody(t,n){const r=n instanceof Set?n:new Set(n||[]),e=[];for(const o of String(t||"").matchAll(/<dm-([a-z][a-z0-9-]*)|\[component\s+[^\]]*?name=["']?([a-z][a-z0-9-]*)/g)){const i=o[1]||o[2];r.has(i)&&!e.includes(i)&&e.push(i)}return e}export function componentStatusText({name:t="",readOnly:n=!1,state:r=""}={}){const e=`<dm-${t}>`;if(n)return`${e} \xB7 From a plugin - read only`;const o={compiling:"Compiling\u2026",ok:"Compiles",error:"Does not compile - see the editor"};return o[r]?`${e} \xB7 ${o[r]}`:e}export function blockAloneBody(t,n={}){if(!/^[a-z0-9][a-z0-9-]*$/.test(String(t||"")))return"";const r=[];for(const[e,o]of Object.entries(n||{})){if(!/^[\w_]+$/.test(e)||e==="template")continue;const i=String(o??"").replace(/\s+/g," ");!i||i.includes("]")||(i.includes('"')?i.includes("'")||r.push(`${e}='${i}'`):r.push(`${e}="${i}"`))}return`[block template="${t}"${r.length?" "+r.join(" "):""} /]`}export const SAMPLE_IMAGE_URL="/admin/preview/sample-image.svg";export function sampleRows(t,n,r={},e=new Date,o=SAMPLE_IMAGE_URL){return t.map(i=>({name:i,raw:n.has(i),value:Object.prototype.hasOwnProperty.call(r,i)?String(r[i]):b(i,e,{raw:n.has(i)}).split(w).join(o)}))}export function pageStatusText({urlPath:t="",status:n="draft",isEdit:r=!1}={}){const e=String(t||"").trim()||(r?"":"New page"),o=n==="published"?"Published":n==="review"?"In review":"Draft";return e?`${e} \xB7 ${o}`:o}export function saveAllLabel(t,n){return t.filter(e=>!n.includes(e)).length?`Save all (${t.length})`:""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export function blockTabs(e,t=[],i=null){const
|
|
1
|
+
export function blockTabs(e,t=[],i=null){const s=i?i instanceof Set?i:new Set(i):null,n=[],r=new Set;for(const o of Array.isArray(e)?e:[])typeof o!="string"||r.has(o)||(r.add(o),n.push({name:o,footer:!1}));for(const o of Array.isArray(t)?t:[])typeof o!="string"||r.has(o)||s&&!s.has(o)||(r.add(o),n.push({name:o,footer:!0}));return n}export function otherUses(e,t=""){return!e||typeof e!="object"?null:{pages:(Array.isArray(e.pages)?e.pages:[]).filter(i=>i!==t),views:Array.isArray(e.views)?e.views.filter(Boolean):[],footer:e.footer===!0}}const a=(e,t,i=`${t}s`)=>`${e} ${e===1?t:i}`;export function describeUses(e){if(!e)return"";const t=[];return e.pages.length&&t.push(a(e.pages.length,"other page")),e.views.length&&t.push(a(e.views.length,"view")),e.footer&&t.push("the footer"),t.length<2?t.join(""):`${t.slice(0,-1).join(", ")} and ${t.at(-1)}`}export function usesLine(e){if(!e)return"Where else it is used could not be read - saving changes it everywhere it is.";if(e.footer&&!e.pages.length&&!e.views.length)return"In the footer - on every page. Saving changes it everywhere.";const t=describeUses(e);return t?`Also used by ${t} - saving changes it there too.`:"Only used on this page."}export function notHereLine(e){const t="Not on this page, so the preview cannot show it (right-click \u203A Add block puts it in).";if(!e||typeof e!="object")return`${t} Where else it is used could not be read.`;const i=Array.isArray(e.pages)?e.pages.length:0,s=Array.isArray(e.views)?e.views.filter(Boolean).length:0,n=[];if(i&&n.push(a(i,"page")),s&&n.push(a(s,"view")),e.footer===!0&&n.push("the footer"),!n.length)return`${t} Not used anywhere yet.`;const r=n.length<2?n[0]:`${n.slice(0,-1).join(", ")} and ${n.at(-1)}`;return`${t} Used by ${r} - saving changes it there.`}export function saveQuestion(e,t={},i=new Set){const s=[];for(const n of e){if(i.has(n))continue;if(t[n]==null){s.push(`Where else "${n}" is used could not be read.`);continue}const r=describeUses(t[n]);r&&s.push(`"${n}" is also used by ${r}.`)}return s.length?`${s.join(" ")} Saving changes ${s.length===1?"it":"them"} everywhere ${s.length===1?"it is":"they are"} used. Save anyway?`:""}export function previewBlocks(e={},t=[],i=2e5){const s={...e};for(const n of t){if(!n.dirty){delete s[n.name];continue}n.content.length>i||n.css.length>i||(s[n.name]={content:n.content,css:n.css})}return s}export function savedMessage({page:e=!1,pages:t=0,css:i=!1,blocks:s=[],components:n=[]}={}){const r=[];if(t>1?r.push(`${t} pages`):(e||t===1)&&r.push("Page"),i&&r.push("CSS"),s.length===1?r.push(`block "${s[0]}"`):s.length&&r.push(`${s.length} blocks`),n.length===1?r.push(`component "${n[0]}"`):n.length&&r.push(`${n.length} components`),!r.length)return"Nothing to save.";const o=r.length===1?r[0]:`${r.slice(0,-1).join(", ")} and ${r.at(-1)}`;return`${o[0].toUpperCase()}${o.slice(1)} saved.`}export function outlineBlock(e,t){const i=String(e??"");if(!t||!/^[a-z0-9][a-z0-9-]*$/.test(t))return i;const s=`<style>[data-block="${t}"]{outline:2px dashed var(--dm-primary,#4f6bed);outline-offset:6px}</style>`;return/<\/head>/i.test(i)?i.replace(/<\/head>/i,`${s}</head>`):s+i}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SCREEN=/^\/pages\/(new|edit\/.*?)(\?.*)?$/;export function pageOfPath(t){const e=String(t||"").match(/^\/pages\/edit(\/[^?#]*)/);return e?e[1]:""}export const draftKey=t=>`page-editor.draft.${t||"new"}`,FIELDS=["urlPath","title","description","layout","status","sortOrder","showInNav","sidebar","breadcrumbs","bundled","tags","category","visibility","project","theme","seoTitle","seoDesc","dconfig","body","css"];export function snapshot(t={}){const e=t||{},o={};for(const n of FIELDS){const r=e[n];n==="tags"?o[n]=Array.isArray(r)?r.map(String):[]:typeof r=="boolean"?o[n]=r:n==="css"?o[n]=r==null?null:String(r):o[n]=r==null?"":String(r)}return JSON.stringify(o)}export function makeDraft(t,e,o=new Date().toISOString()){return{state:JSON.parse(snapshot(t)),base:e,at:o}}export function readDraft(t){return!t||typeof t!="object"||!t.state||typeof t.state!="object"?null:{state:JSON.parse(snapshot(t.state)),base:typeof t.base=="string"?t.base:"",at:typeof t.at=="string"?t.at:""}}export const draftIsStale=(t,e)=>!!(t?.base&&e&&t.base!==e);export function problems(t={}){const e=[],o=String(t.urlPath||"").trim();o?o.startsWith("/")?/\s/.test(o)&&e.push({field:"urlPath",text:"The address cannot contain spaces."}):e.push({field:"urlPath",text:"The address starts with / - for example /about."}):e.push({field:"urlPath",text:"The page needs an address - its URL path."});const n=String(t.dconfig||"").trim();if(n)try{const r=JSON.parse(n);(!r||typeof r!="object"||Array.isArray(r))&&e.push({field:"dconfig",text:"DConfig must be a JSON object ({ \u2026 })."})}catch{e.push({field:"dconfig",text:"DConfig is not valid JSON."})}return e}export function bannerSection(t,e,o){return t?String(e||"").trim()||o||"Untitled":"New page"}export function initialProject({isEdit:t,page:e=null,projects:o=[],fromHash:n="",urlPath:r=""}){if(!t&&n)return n;if(!e||e.project===null)return"";if(typeof e.project=="string"&&e.project)return e.project;if(!r)return"";let i="",a=-1;for(const s of o||[])s?.rootUrl&&(r===s.rootUrl||r.startsWith(s.rootUrl+"/"))&&s.rootUrl.length>a&&(i=s.slug,a=s.rootUrl.length);return i}
|
|
1
|
+
export const SCREEN=/^\/(pages\/(new|edit\/.*?)|(blocks|components)\/(new|edit\/[^/?#]+\/?))(\?.*)?$/;export function pageOfPath(t){const e=String(t||"").match(/^\/pages\/edit(\/[^?#]*)/);return e?e[1]:""}export const draftKey=t=>`page-editor.draft.${t||"new"}`,FIELDS=["urlPath","title","description","layout","status","sortOrder","showInNav","sidebar","breadcrumbs","bundled","tags","category","visibility","project","theme","seoTitle","seoDesc","dconfig","body","css"];export function snapshot(t={}){const e=t||{},o={};for(const n of FIELDS){const r=e[n];n==="tags"?o[n]=Array.isArray(r)?r.map(String):[]:typeof r=="boolean"?o[n]=r:n==="css"?o[n]=r==null?null:String(r):o[n]=r==null?"":String(r)}return JSON.stringify(o)}export function makeDraft(t,e,o=new Date().toISOString()){return{state:JSON.parse(snapshot(t)),base:e,at:o}}export function readDraft(t){return!t||typeof t!="object"||!t.state||typeof t.state!="object"?null:{state:JSON.parse(snapshot(t.state)),base:typeof t.base=="string"?t.base:"",at:typeof t.at=="string"?t.at:""}}export const draftIsStale=(t,e)=>!!(t?.base&&e&&t.base!==e);export function problems(t={}){const e=[],o=String(t.urlPath||"").trim();o?o.startsWith("/")?/\s/.test(o)&&e.push({field:"urlPath",text:"The address cannot contain spaces."}):e.push({field:"urlPath",text:"The address starts with / - for example /about."}):e.push({field:"urlPath",text:"The page needs an address - its URL path."});const n=String(t.dconfig||"").trim();if(n)try{const r=JSON.parse(n);(!r||typeof r!="object"||Array.isArray(r))&&e.push({field:"dconfig",text:"DConfig must be a JSON object ({ \u2026 })."})}catch{e.push({field:"dconfig",text:"DConfig is not valid JSON."})}return e}export function bannerSection(t,e,o){return t?String(e||"").trim()||o||"Untitled":"New page"}export function initialProject({isEdit:t,page:e=null,projects:o=[],fromHash:n="",urlPath:r=""}){if(!t&&n)return n;if(!e||e.project===null)return"";if(typeof e.project=="string"&&e.project)return e.project;if(!r)return"";let i="",a=-1;for(const s of o||[])s?.rootUrl&&(r===s.rootUrl||r.startsWith(s.rootUrl+"/"))&&s.rootUrl.length>a&&(i=s.slug,a=s.rootUrl.length);return i}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{attachSmoothCaret as g}from"./smooth-caret.js";import{highlight as C}from"./syntax-highlight.js";export function attachColourLayer(t,E){const s=document.createElement("div");s.className="pe-plain-host";const l=document.createElement("pre");l.className="editor-textarea pe-plain-colours",l.setAttribute("aria-hidden","true"),t.classList.add("pe-plain-coloured"),t.parentNode.insertBefore(s,t),s.append(l,t);let p=null;const d=()=>{const e=getComputedStyle(t);l.style.whiteSpace!==e.whiteSpace&&(l.style.whiteSpace=e.whiteSpace,l.style.overflowWrap=e.overflowWrap),p!==t.value&&(p=t.value,l.innerHTML=C(t.value,E))},o=()=>{l.scrollTop=t.scrollTop,l.scrollLeft=t.scrollLeft},i=()=>{d(),o()};return t.addEventListener("input",i),t.addEventListener("scroll",o),d(),{host:s,colours:l,paint:()=>{d(),o()},destroy(){t.removeEventListener("input",i),t.removeEventListener("scroll",o),t.classList.remove("pe-plain-coloured"),s.parentNode&&(s.parentNode.insertBefore(t,s),s.remove())}}}export function createPlainEditor(t,{initialValue:E="",onChange:s=null,ariaLabel:l="",placeholder:p="",language:d=null}={}){if(!t)throw new Error("createPlainEditor: a mount element is required.");for(;t.firstChild;)t.removeChild(t.firstChild);const o=document.createElement("div");o.className="pe-plain";const i=document.createElement("div");i.className="editor-line-numbers",i.setAttribute("aria-hidden","true");const e=document.createElement("textarea");e.className="editor-textarea",e.spellcheck=!1,e.wrap="off",e.setAttribute("autocomplete","off"),e.setAttribute("autocorrect","off"),e.setAttribute("autocapitalize","off"),l&&e.setAttribute("aria-label",l),p&&(e.placeholder=p);let c=null;if(d){const n=document.createElement("div");n.className="pe-plain-host",c=document.createElement("pre"),c.className="editor-textarea pe-plain-colours",c.setAttribute("aria-hidden","true"),e.classList.add("pe-plain-coloured"),n.append(c,e),o.append(i,n)}else o.append(i,e);t.appendChild(o);let y=0;const L=()=>{const n=e.value.split(`
|
|
2
|
+
`).length||1;n!==y&&(y=n,i.textContent=Array.from({length:n},(r,m)=>m+1).join(`
|
|
3
|
+
`))};let w=null;const b=()=>{c&&w!==e.value&&(w=e.value,c.innerHTML=C(e.value,d))},v=()=>{i.scrollTop=e.scrollTop,c&&(c.scrollTop=e.scrollTop,c.scrollLeft=e.scrollLeft)},T=()=>{L(),b(),v(),s&&s(e.value)},N=n=>{if(n.isComposing)return;const{selectionStart:r,selectionEnd:m,value:u}=e;if(n.key==="Tab"){if(n.preventDefault(),!n.shiftKey)e.setRangeText(" ",r,m,"end");else{const a=u.lastIndexOf(`
|
|
4
|
+
`,r-1)+1,h=u.slice(a,a+2),f=h===" "?2:h[0]===" "?1:0;f&&(e.setRangeText("",a,a+f,"start"),e.selectionStart=e.selectionEnd=Math.max(a,r-f))}e.dispatchEvent(new Event("input",{bubbles:!0}))}else if(n.key==="Enter"){n.preventDefault();const a=u.lastIndexOf(`
|
|
5
|
+
`,r-1)+1,h=(u.slice(a,r).match(/^[ \t]*/)||[""])[0],f=u.slice(0,r).trimEnd().slice(-1);e.setRangeText(`
|
|
6
|
+
`+h+("{[(".includes(f)?" ":""),r,m,"end"),e.dispatchEvent(new Event("input",{bubbles:!0}))}};e.addEventListener("input",T),e.addEventListener("scroll",v),e.addEventListener("keydown",N),e.value=E??"",L(),b();const S=g(e);return{textarea:e,gutter:i,colours:c,getValue(){return e.value},setValue(n){const r=n??"";e.value!==r&&(e.value=r,L(),b(),v(),S.refresh?.())},focus(){e.focus()},destroy(){S.destroy?.(),e.removeEventListener("input",T),e.removeEventListener("scroll",v),e.removeEventListener("keydown",N),o.parentNode===t&&t.removeChild(o)}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{PHONE_QUERY as
|
|
1
|
+
import{PHONE_QUERY as C}from"./sidebar-drawer.js";export const MIN_WIDTH=180,MAX_WIDTH=480,COLLAPSED_WIDTH=56,COLLAPSE_SNAP=120,STEP=16,BIG_STEP=64,WIDTH_KEY="sidebar.width",COLLAPSED_KEY="sidebar.collapsed";export function railShown(e,r){return e===!0&&!r}function _(){return typeof matchMedia=="function"&&matchMedia(C).matches}function D(){try{return S.get(COLLAPSED_KEY)===!0}catch{return!1}}export function clampWidth(e){return Math.max(MIN_WIDTH,Math.min(MAX_WIDTH,Math.round(e)))}export function parseWidth(e){const r=Number.parseInt(e,10);return Number.isFinite(r)&&r>=MIN_WIDTH&&r<=MAX_WIDTH?r:null}export function dragOutcome(e){return e<COLLAPSE_SNAP?{collapsed:!0,width:null}:{collapsed:!1,width:clampWidth(e)}}export function keyOutcome({key:e,shiftKey:r=!1},{width:t,collapsed:i}){const n=r?BIG_STEP:STEP;switch(e){case"ArrowLeft":return i?{collapsed:!0,width:null}:t<=MIN_WIDTH?{collapsed:!0,width:null}:{collapsed:!1,width:clampWidth(t-n)};case"ArrowRight":return i?{collapsed:!1,width:null}:{collapsed:!1,width:clampWidth(t+n)};case"Home":return{collapsed:!1,width:MIN_WIDTH};case"End":return{collapsed:!1,width:MAX_WIDTH};case"Enter":case" ":return{collapsed:!i,width:null};default:return null}}export function collapseButtonMarkup(){return'<button type="button" class="btn btn-sm btn-ghost dm-admin-sidebar-collapse" aria-expanded="true" aria-label="Collapse sidebar" title="Collapse sidebar"><span data-icon="chevrons-left" data-icon-size="16"></span></button>'}export function isCollapsed(e){return e.classList.contains("is-collapsed")}function T(){try{return parseWidth(S.get(WIDTH_KEY))}catch{return null}}function u(e,r){try{r==null?S.remove(e):S.set(e,r)}catch{}}function h(e,r){e.classList.toggle("is-collapsed",r);const t=e.querySelector(".dm-admin-sidebar-collapse");if(t){const i=r?"Expand sidebar":"Collapse sidebar";t.setAttribute("aria-expanded",String(!r)),t.setAttribute("aria-label",i),t.title=i}r?e.querySelector(".dm-admin-sidebar")?.scrollTo?.(0,0):d();for(const i of e.querySelectorAll("details > summary"))r?i.setAttribute("aria-expanded","false"):i.removeAttribute("aria-expanded");I(e)}function m(e){return!!e.querySelector(".dm-admin-sidebar.is-arranging")}function g(e){return isCollapsed(e)?COLLAPSED_WIDTH:parseInt(e.style.width,10)||e.getBoundingClientRect().width}function I(e){const r=e.querySelector(".dm-admin-sidebar-handle");if(r)if(isCollapsed(e))r.setAttribute("aria-valuenow",String(MIN_WIDTH)),r.setAttribute("aria-valuetext","Collapsed");else{const t=Math.round(g(e));if(!t)return;r.setAttribute("aria-valuenow",String(clampWidth(t))),r.setAttribute("aria-valuetext",`${t} pixels`)}}function l(e){I(e),e.__dmGutter?.()}export function setCollapsed(e,r,t=!0){h(e,r),t&&u(COLLAPSED_KEY,r?!0:null),l(e);const i=n=>{n.target!==e||n.propertyName!=="width"||(e.removeEventListener("transitionend",i),l(e))};e.addEventListener("transitionend",i)}function W(e,r){e.style.width=r+"px",u(WIDTH_KEY,r)}let a=null,f=null;function d({restoreFocus:e=!1}={}){if(!a)return;a.remove();const r=f?.querySelector(":scope > summary");r?.setAttribute("aria-expanded","false"),e&&r?.focus(),a=null,f=null}function z(e,r,{focus:t=!1}={}){const i=f===r;if(d(),i)return;const n=r.querySelector(":scope > summary"),o=r.querySelector(":scope > .sidebar-children");if(!n||!o)return;const v=e.querySelector(".dm-admin-sidebar");a=document.createElement("div"),a.className="dm-admin-sidebar-flyout";const c=document.createElement("nav");c.className=v?v.className:"dm-admin-sidebar",c.setAttribute("aria-label",n.querySelector(".sidebar-text")?.textContent.trim()||"Folder");const y=document.createElement("div");y.className="dm-admin-sidebar-flyout-title",y.textContent=c.getAttribute("aria-label"),c.appendChild(y);for(const s of o.children)c.appendChild(s.cloneNode(!0));for(const s of c.querySelectorAll(".sidebar-children"))s.style.maxHeight="";a.appendChild(c);for(const s of["data-menu-hover","data-menu-active"])e.hasAttribute(s)&&a.setAttribute(s,e.getAttribute(s));const x=e.style.getPropertyValue("--dm-menu-highlight");x&&a.style.setProperty("--dm-menu-highlight",x),document.body.appendChild(a);const b=e.getBoundingClientRect(),M=n.getBoundingClientRect(),w=window.innerHeight-8;a.style.maxHeight=`${w-8}px`;const{width:A,height:q}=a.getBoundingClientRect(),P=b.right+4+A<=window.innerWidth-8?b.right+4:b.left-4-A;a.style.left=`${Math.round(Math.max(8,P))}px`,a.style.top=`${Math.round(Math.max(8,Math.min(M.top,w-q)))}px`,f=r,n.setAttribute("aria-expanded","true"),t&&a.querySelector("a, summary")?.focus(),a.addEventListener("click",s=>{s.target.closest("a[href]")&&d()}),a.addEventListener("keydown",s=>{if(s.key==="Escape"){s.preventDefault(),d({restoreFocus:!0});return}if(s.key!=="Tab")return;const L=[...a.querySelectorAll("a[href], summary")].filter(p=>p.offsetParent);if(s.shiftKey&&document.activeElement===L[0])s.preventDefault(),d({restoreFocus:!0});else if(!s.shiftKey&&document.activeElement===L.at(-1)){s.preventDefault();const p=[...e.querySelectorAll('a[href], summary, button, [tabindex="0"]')].filter(N=>N.offsetParent),k=p[p.indexOf(n)+1];d(),(k||n).focus()}}),a.addEventListener("focusout",s=>{!a?.contains(s.relatedTarget)&&!n.contains(s.relatedTarget)&&s.relatedTarget&&d()})}function H(e){if(e.__dmSizeWired)return;e.__dmSizeWired=!0,e.addEventListener("click",t=>{if(!isCollapsed(e))return;const i=t.target.closest("summary");!i||!e.contains(i)||(t.preventDefault(),z(e,i.parentElement,{focus:t.detail===0}))}),e.addEventListener("keydown",t=>{t.key==="Escape"&&a&&d({restoreFocus:!0})}),document.addEventListener("pointerdown",t=>{!a||a.contains(t.target)||f?.querySelector(":scope > summary")?.contains(t.target)||d()}),window.addEventListener("hashchange",()=>d()),window.addEventListener("resize",()=>d()),document.addEventListener("pointermove",t=>{const i=e.__dmDrag;if(!i||t.pointerId!==i.pointerId)return;if(t.pointerType==="mouse"&&t.buttons===0)return r(t);const n=t.clientX-i.x;if(!i.moved&&Math.abs(n)<3)return;i.moved=!0;const o=dragOutcome(i.width+n);o.collapsed!==isCollapsed(e)&&h(e,o.collapsed),o.collapsed||(e.style.width=o.width+"px"),l(e)});const r=t=>{const i=e.__dmDrag;!i||t.pointerId!==i.pointerId||(e.__dmDrag=null,e.classList.remove("is-resizing"),document.body.classList.remove("dm-sidebar-resizing"),i.moved&&(isCollapsed(e)?(e.style.width=i.inline,u(COLLAPSED_KEY,!0)):(u(COLLAPSED_KEY,null),u(WIDTH_KEY,parseInt(e.style.width,10))),l(e)))};document.addEventListener("pointerup",r),document.addEventListener("pointercancel",r),typeof matchMedia=="function"&&matchMedia(C).addEventListener?.("change",t=>{const i=railShown(D(),t.matches);i!==isCollapsed(e)&&h(e,i),l(e)})}export function wireSidebarSize(e){H(e),d();const r=T();r&&(e.style.width=r+"px");const t=document.createElement("div");t.className="dm-admin-sidebar-handle",t.tabIndex=0,t.setAttribute("role","separator"),t.setAttribute("aria-orientation","vertical"),t.setAttribute("aria-label","Resize sidebar"),e.id&&t.setAttribute("aria-controls",e.id),t.setAttribute("aria-valuemin",String(MIN_WIDTH)),t.setAttribute("aria-valuemax",String(MAX_WIDTH)),t.title="Drag to resize - double-click to reset",e.appendChild(t),h(e,railShown(D(),_())),e.querySelector(".dm-admin-sidebar-collapse")?.addEventListener("click",()=>{_()||setCollapsed(e,!isCollapsed(e))}),t.addEventListener("pointerdown",i=>{if(!(i.button!==0||m(e))){e.__dmDrag={pointerId:i.pointerId,x:i.clientX,width:g(e),inline:e.style.width,moved:!1};try{t.setPointerCapture(i.pointerId)}catch{}e.classList.add("is-resizing"),document.body.classList.add("dm-sidebar-resizing"),i.preventDefault()}}),t.addEventListener("dblclick",()=>{m(e)||(e.style.width="",u(WIDTH_KEY,null),setCollapsed(e,!1))}),t.addEventListener("keydown",i=>{if(m(e))return;const n=keyOutcome(i,{width:g(e),collapsed:isCollapsed(e)});n&&(i.preventDefault(),n.collapsed!==isCollapsed(e)&&setCollapsed(e,n.collapsed),n.width!=null&&W(e,n.width),l(e))}),l(e)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export function escapeHtml(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const i=(e,t)=>`<span class="dm-tok-${e}">${escapeHtml(t)}</span>`;function m(e,t){let n="",s=0;const o=t.map(r=>({cls:r.cls,re:new RegExp(r.re.source,r.re.flags.replace("y","")+"y")}));for(;s<e.length;){let r=!1;for(const{cls:l,re:a}of o){a.lastIndex=s;const c=a.exec(e);if(c&&c[0].length>0){n+=i(l,c[0]),s+=c[0].length,r=!0;break}}if(!r){let l=s+1;if(/[A-Za-z0-9_]/.test(e[s]))for(;l<e.length&&/[A-Za-z0-9_]/.test(e[l]);)l++;n+=escapeHtml(e.slice(s,l)),s=l}}return n}const d=/\b(?:async|await|break|case|catch|class|const|continue|default|delete|do|else|export|extends|finally|for|from|function|if|import|in|instanceof|let|new|of|return|static|super|switch|this|throw|try|typeof|var|void|while|yield)\b/,g={js:[{cls:"comment",re:/\/\/[^\n]*/},{cls:"comment",re:/\/\*[\s\S]*?(?:\*\/|$)/},{cls:"string",re:/`(?:[^`\\]|\\[\s\S])*(?:`|$)/},{cls:"string",re:/'(?:[^'\\\n]|\\[\s\S])*(?:'|$)/},{cls:"string",re:/"(?:[^"\\\n]|\\[\s\S])*(?:"|$)/},{cls:"keyword",re:d},{cls:"literal",re:/\b(?:true|false|null|undefined|NaN|Infinity)\b/},{cls:"number",re:/\b0[xXbBoO]?[\da-fA-F_]+n?\b|\b\d[\d_]*(?:\.\d+)?(?:[eE][+-]?\d+)?\b/},{cls:"func",re:/[A-Za-z_$][\w$]*(?=\s*\()/}],json:[{cls:"key",re:/"(?:[^"\\]|\\[\s\S])*"(?=\s*:)/},{cls:"string",re:/"(?:[^"\\]|\\[\s\S])*(?:"|$)/},{cls:"literal",re:/\b(?:true|false|null)\b/},{cls:"number",re:/-?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/}],css:[{cls:"comment",re:/\/\*[\s\S]*?(?:\*\/|$)/},{cls:"string",re:/'(?:[^'\\\n]|\\[\s\S])*(?:'|$)|"(?:[^"\\\n]|\\[\s\S])*(?:"|$)/},{cls:"number",re:/-?\b\d+(?:\.\d+)?(?:px|rem|em|vh|vw|s|ms|deg|fr|%)?\b/},{cls:"key",re:/--?[a-zA-Z][\w-]*(?=\s*:)/},{cls:"keyword",re:/@[a-zA-Z-]+/},{cls:"func",re:/[a-zA-Z-]+(?=\()/},{cls:"literal",re:/#[0-9a-fA-F]{3,8}\b/},{cls:"tag",re:/\.[a-zA-Z_-][\w-]*|#[a-zA-Z_-][\w-]*/}],html:[{cls:"comment",re:/<!--[\s\S]*?(?:-->|$)/},{cls:"string",re:/"(?:[^"]*)(?:"|$)|'(?:[^']*)(?:'|$)/},{cls:"tag",re:/<\/?[a-zA-Z][\w-]*|\/?>/},{cls:"key",re:/\b[a-zA-Z-]+(?==)/}],md:[{cls:"keyword",re:/^#{1,6}[^\n]*/m},{cls:"comment",re:/```[\s\S]*?(?:```|$)/},{cls:"string",re:/`[^`\n]*(?:`|$)/},{cls:"comment",re:/<!--[\s\S]*?(?:-->|$)/},{cls:"comment",re:/^ {0,3}\/\/[^\n]*/m},{cls:"literal",re:/\*\*[^*\n]+\*\*|\*[^*\n]+\*/},{cls:"func",re:/\[[^\]\n]*\]\([^)\n]*\)/},{cls:"tag",re:/^\s*[-*+]\s|^\s*\d+\.\s/m}]};export function languageForFile(e){const t=String(e||"").toLowerCase().split(".").pop();return{js:"js",json:"json",css:"css",html:"html",htm:"html",svg:"html",md:"md",markdown:"md"}[t]||null}export function highlight(e,t){const n=g[t];return(n?m(String(e??""),n):escapeHtml(String(e??"")))+`
|
|
1
|
+
export function escapeHtml(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const i=(e,t)=>`<span class="dm-tok-${e}">${escapeHtml(t)}</span>`;function m(e,t){let n="",s=0;const o=t.map(r=>({cls:r.cls,re:new RegExp(r.re.source,r.re.flags.replace("y","")+"y")}));for(;s<e.length;){let r=!1;for(const{cls:l,re:a}of o){a.lastIndex=s;const c=a.exec(e);if(c&&c[0].length>0){n+=i(l,c[0]),s+=c[0].length,r=!0;break}}if(!r){let l=s+1;if(/[A-Za-z0-9_]/.test(e[s]))for(;l<e.length&&/[A-Za-z0-9_]/.test(e[l]);)l++;n+=escapeHtml(e.slice(s,l)),s=l}}return n}const d=/\b(?:async|await|break|case|catch|class|const|continue|default|delete|do|else|export|extends|finally|for|from|function|if|import|in|instanceof|let|new|of|return|static|super|switch|this|throw|try|typeof|var|void|while|yield)\b/,g={js:[{cls:"comment",re:/\/\/[^\n]*/},{cls:"comment",re:/\/\*[\s\S]*?(?:\*\/|$)/},{cls:"string",re:/`(?:[^`\\]|\\[\s\S])*(?:`|$)/},{cls:"string",re:/'(?:[^'\\\n]|\\[\s\S])*(?:'|$)/},{cls:"string",re:/"(?:[^"\\\n]|\\[\s\S])*(?:"|$)/},{cls:"keyword",re:d},{cls:"literal",re:/\b(?:true|false|null|undefined|NaN|Infinity)\b/},{cls:"number",re:/\b0[xXbBoO]?[\da-fA-F_]+n?\b|\b\d[\d_]*(?:\.\d+)?(?:[eE][+-]?\d+)?\b/},{cls:"func",re:/[A-Za-z_$][\w$]*(?=\s*\()/}],json:[{cls:"key",re:/"(?:[^"\\]|\\[\s\S])*"(?=\s*:)/},{cls:"string",re:/"(?:[^"\\]|\\[\s\S])*(?:"|$)/},{cls:"literal",re:/\b(?:true|false|null)\b/},{cls:"number",re:/-?\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b/}],css:[{cls:"comment",re:/\/\*[\s\S]*?(?:\*\/|$)/},{cls:"string",re:/'(?:[^'\\\n]|\\[\s\S])*(?:'|$)|"(?:[^"\\\n]|\\[\s\S])*(?:"|$)/},{cls:"number",re:/-?\b\d+(?:\.\d+)?(?:px|rem|em|vh|vw|s|ms|deg|fr|%)?\b/},{cls:"key",re:/--?[a-zA-Z][\w-]*(?=\s*:)/},{cls:"keyword",re:/@[a-zA-Z-]+/},{cls:"func",re:/[a-zA-Z-]+(?=\()/},{cls:"literal",re:/#[0-9a-fA-F]{3,8}\b/},{cls:"tag",re:/\.[a-zA-Z_-][\w-]*|#[a-zA-Z_-][\w-]*/}],html:[{cls:"comment",re:/<!--[\s\S]*?(?:-->|$)/},{cls:"string",re:/"(?:[^"]*)(?:"|$)|'(?:[^']*)(?:'|$)/},{cls:"tag",re:/<\/?[a-zA-Z][\w-]*|\/?>/},{cls:"key",re:/\b[a-zA-Z-]+(?==)/}],md:[{cls:"keyword",re:/^#{1,6}[^\n]*/m},{cls:"comment",re:/```[\s\S]*?(?:```|$)/},{cls:"string",re:/`[^`\n]*(?:`|$)/},{cls:"comment",re:/<!--[\s\S]*?(?:-->|$)/},{cls:"comment",re:/^ {0,3}\/\/[^\n]*/m},{cls:"literal",re:/\*\*[^*\n]+\*\*|\*[^*\n]+\*/},{cls:"func",re:/\[[^\]\n]*\]\([^)\n]*\)/},{cls:"key",re:/\[\/?[a-z][\w-]*(?:\s[^\]\n]*)?\/?\]/},{cls:"tag",re:/^\s*[-*+]\s|^\s*\d+\.\s/m}]};export function languageForFile(e){const t=String(e||"").toLowerCase().split(".").pop();return{js:"js",json:"json",css:"css",html:"html",htm:"html",svg:"html",md:"md",markdown:"md"}[t]||null}export function highlight(e,t){const n=g[t];return(n?m(String(e??""),n):escapeHtml(String(e??"")))+`
|
|
2
2
|
`}
|
|
@@ -155,7 +155,7 @@ onMount() { this.set({ count: this.props.initial }); }</code></pre>
|
|
|
155
155
|
<ol>
|
|
156
156
|
<li>On <a href="#/components">Components</a>, right-click the row (or use its menu) and choose
|
|
157
157
|
<span data-icon="download"></span> <strong>Export .dmcomponent.json</strong> - you'll download
|
|
158
|
-
<code>name.dmcomponent.json</code
|
|
158
|
+
<code>name.dmcomponent.json</code>.</li>
|
|
159
159
|
<li>On the other site, click <strong>Import</strong> in the Components banner and pick that file. On a
|
|
160
160
|
name clash you'll be asked to confirm an overwrite.</li>
|
|
161
161
|
</ol>
|
|
@@ -163,7 +163,7 @@ onMount() { this.set({ count: this.props.initial }); }</code></pre>
|
|
|
163
163
|
<hr>
|
|
164
164
|
|
|
165
165
|
<h2>File it under a project</h2>
|
|
166
|
-
<p>In the editor, set the <strong>Project</strong> dropdown. That writes <code>project</code> to the
|
|
166
|
+
<p>In the editor's dock (the <strong>Component</strong> panel), set the <strong>Project</strong> dropdown. That writes <code>project</code> to the
|
|
167
167
|
component's <code>.meta.json</code> sidecar, so it shows in that project's Components list
|
|
168
168
|
(<code>#/projects/<slug>/components</code>).</p>
|
|
169
169
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
We'll build one component end-to-end: a <strong>star rating</strong> widget you can drop onto any
|
|
20
20
|
page with <code>[component name="star-rating" max="5" value="3" /]</code>. By the end you'll have
|
|
21
21
|
used every section of a <code>.dmc</code> file, reactive state, an event listener, a custom event,
|
|
22
|
-
and the live preview. Follow along in a real <strong>New component</strong> editor.
|
|
22
|
+
and the live preview. Follow along in a real component - <strong>New component</strong> in the Components banner opens one as a tab in the editor.
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
25
|
<hr>
|
|
@@ -187,23 +187,27 @@
|
|
|
187
187
|
<p><em>In use</em> is worked out from page sources and view settings. A Tool that draws a block from its own code
|
|
188
188
|
is not counted, so check before deleting a block marked unused.</p>
|
|
189
189
|
|
|
190
|
-
<h3>
|
|
190
|
+
<h3>Editing a block</h3>
|
|
191
|
+
<p>A block opens as a tab in the page editor's workspace, beside pages and components - from the Blocks list,
|
|
192
|
+
from the list on the editor's left, or from a page's <em>This page</em> section (the blocks that page uses).</p>
|
|
191
193
|
<ul>
|
|
192
|
-
<li><strong>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
<li><strong>
|
|
203
|
-
|
|
194
|
+
<li><strong>HTML</strong> and <strong>CSS</strong>: the two parts of the block, in the editor pane, with
|
|
195
|
+
<strong>Format</strong> (tidies the indentation). The toolbar's three buttons - or <kbd>Ctrl</kbd>+<kbd>\</kbd> -
|
|
196
|
+
choose editor and preview, editor only or preview only.</li>
|
|
197
|
+
<li><strong>Preview</strong>: the block drawn on the open page that uses it, outlined, with your changes as you
|
|
198
|
+
type - or, when no open page uses it, on its own inside your site's page shell, with its theme, fonts and
|
|
199
|
+
Custom CSS. Preview only has full, tablet and mobile widths.</li>
|
|
200
|
+
<li><strong>The dock</strong> (the sliders button): <strong>Block</strong> - its short tag and shortcode, an
|
|
201
|
+
optional project, <strong>Bundled</strong> (ships the block with fresh installs) and where it is used;
|
|
202
|
+
<strong>Samples</strong> - one box per placeholder the template uses, filled in for the on-its-own preview
|
|
203
|
+
only. Nothing in them is saved. Right-click one to insert its placeholder into the template.</li>
|
|
204
|
+
<li><strong>New block</strong>: the <strong>+</strong> by Blocks in the editor's list, or <strong>New
|
|
205
|
+
block</strong> in the Blocks banner - a name (lowercase letters, digits and hyphens, fixed once created),
|
|
206
|
+
then its tab.</li>
|
|
204
207
|
</ul>
|
|
205
|
-
<p><kbd>Ctrl</kbd>+<kbd>S</kbd> saves
|
|
206
|
-
|
|
208
|
+
<p><kbd>Ctrl</kbd>+<kbd>S</kbd> saves the tab you are on; <strong>Save all</strong> saves every open page, block
|
|
209
|
+
and component. A block used elsewhere changes there too - you are asked the first time. Closing a tab, or
|
|
210
|
+
leaving with unsaved changes, keeps your work as a draft for that block until you open it again.</p>
|
|
207
211
|
|
|
208
212
|
<h3>Copying blocks between sites</h3>
|
|
209
213
|
<p><strong>Export</strong> on a block's right-click menu downloads it as a <code><name>.dmblock.json</code>
|