domma-cms 0.25.9 → 0.25.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/js/lib/sidebar-renderer.js +2 -2
- package/bin/cli.js +7 -0
- package/bin/update.js +15 -9
- package/package.json +5 -1
- package/plugins/analytics/plugin.json +8 -0
- package/plugins/analytics/daily.json +0 -8
- package/plugins/analytics/journeys.json +0 -18
- package/plugins/analytics/lifetime.json +0 -25
- package/plugins/analytics/stats.json +0 -24
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{api as c}from"../api.js";import{colourToCss as F}from"/public/js/menu-decor.mjs";import{groupPluginItems as W,stripItemByUrl as D,insertFoldersBeforeSystem as _,pruneEmptySynthesisedFolders as K,MANAGE_PLUGINS_URL as X}from"./sidebar-grouping.js";function f(e){return String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const G=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Menus",url:"#/menus",icon:"menu"}];function B(e,i){return i?!e||!e.length?!1:e.includes(i)?!0:["read","create","update","delete"].some(t=>e.includes(`${i}.${t}`)):!0}function
|
|
1
|
+
import{api as c}from"../api.js";import{colourToCss as F}from"/public/js/menu-decor.mjs";import{groupPluginItems as W,stripItemByUrl as D,insertFoldersBeforeSystem as _,pruneEmptySynthesisedFolders as K,MANAGE_PLUGINS_URL as X}from"./sidebar-grouping.js";function f(e){return String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const G=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Menus",url:"#/menus",icon:"menu"}];function B(e,i){return i?!e||!e.length?!1:e.includes(i)?!0:["read","create","update","delete"].some(t=>e.includes(`${i}.${t}`)):!0}function I(e,i){const t=[];for(const n of e){if(n.hidden||n.permission&&!B(i,n.permission))continue;const s=Array.isArray(n.items)&&n.items.length?I(n.items,i):[];t.push({...n,items:s})}return t}function O(e,i){if(!i||!i.length)return e;const t=(n,s)=>{for(const d of n){if((d.text||"").toLowerCase()===s.toLowerCase())return d;if(Array.isArray(d.items)){const a=t(d.items,s);if(a)return a}}return null};for(const n of i)if(n.parent){const s=t(e,n.parent);s?(s.items=Array.isArray(s.items)?s.items:[],s.items.push(n.item)):e.push(n.item)}else e.push(n.item);return e}async function V(e){if(!B(e,"projects"))return[];let i=[];try{i=await c.projects.list()}catch{return[]}const t={};await Promise.all(i.map(async s=>{try{const d=await c.projects.artefacts(s.slug);t[s.slug]=d}catch{t[s.slug]={}}}));const n=[{key:"pages",text:"Pages",icon:"file-text",path:"/pages"},{key:"collections",text:"Collections",icon:"database",path:"/collections"},{key:"forms",text:"Forms",icon:"layout",path:"/forms"},{key:"actions",text:"Actions",icon:"zap",path:"/actions"},{key:"menus",text:"Menus",icon:"menu",path:"/menus"},{key:"blocks",text:"Blocks",icon:"box",path:"/blocks"},{key:"components",text:"Components",icon:"component",path:"/components"},{key:"views",text:"Views",icon:"eye",path:"/views"},{key:"roles",text:"Roles",icon:"shield",path:"/roles"},{key:"users",text:"Users",icon:"users",path:"/users"},{key:"apis",text:"APIs",icon:"code",path:"/apis"}];return i.map(s=>{const a="#/projects/"+encodeURIComponent(s.slug),p=t[s.slug]||{},u=[{text:"Overview",url:a,icon:s.icon||"folder"}];for(const l of n){const h=p[l.key],g=Array.isArray(h)?h.length:0;g<=0||u.push({text:`${l.text} (${g})`,url:a+l.path,icon:l.icon})}return u.push({text:"Settings",url:a+"/settings",icon:"settings"}),{text:s.name||s.slug,icon:s.icon||"folder",items:u}})}function Y(e,i){for(const t of e)if((t.text||"").toLowerCase()==="projects"){t.items=Array.isArray(t.items)?t.items.slice():[],t.items.push(...i);return}}function J(e,i){if(!e.url||!i)return"";const t=i[e.url];return t==null||t<=0?"":`<span class="sidebar-badge">${f(String(t))}</span>`}function Q(e){const i=(e.text||"").replace(/\s*\(\d+\)\s*$/,"").toLowerCase().replace(/\s+/g,"-"),t=(e.url||"").match(/^#\/projects\/([^/]+)/);return`sidebar.expanded.${t?`project-${decodeURIComponent(t[1])}.`:""}${i}`}function z(e,i){if(e&&e.type==="separator")return'<hr class="sidebar-divider">';const t=e.icon?`<span data-icon="${f(e.icon)}"></span>`:"",n=f(e.text||""),s=e.url?f(e.url):"",d=Array.isArray(e.items)&&e.items.length>0,a=e.colour?F(e.colour):"",p=a?` style="color:${f(a)}"`:"";let u="";if(e.badge&&e.badge.text!=null&&e.badge.text!==""){const l=e.badge.variant?F(e.badge.variant):"";u=`<span class="dm-menu-badge"${l?` style="background:${f(l)};color:#fff"`:""}>${f(String(e.badge.text))}</span>`}if(d){const l=Q(e),h=S.get(l)!==!1,g=e.items.map(y=>z(y,i)).join("");return`<details data-state-key="${f(l)}"${h?" open":""}>
|
|
2
2
|
<summary${p}>${t} <span class="sidebar-text">${n}</span>${u}</summary>
|
|
3
3
|
<div class="sidebar-children">${g}</div>
|
|
4
|
-
</details>`}return`<a href="${s}" class="sidebar-link" data-url="${s}"${p}>${t} <span class="sidebar-text">${n}</span>${J(e,i)}${u}</a>`}async function Z(){const e=y=>y.then(b=>Array.isArray(b)?b.length:Array.isArray(b?.entries)?b.entries.length:0).catch(()=>0),[i,t,n,s,d,a,p,u,l,h,g]=await Promise.all([e(c.pages.list()),e(c.media.list()),e(c.collections.list()),e(c.forms.list()),e(c.views.list()),e(c.actions.list()),e(c.blocks.list()),e(c.components.list()),e(c.users.list()),e(c.plugins.list()),c.system?.notifications?.unreadCount?.().then(y=>y?.count??0).catch(()=>0)??Promise.resolve(0)]);return{"#/pages":i,"#/media":t,"#/collections":n,"#/forms":s,"#/views":d,"#/actions":a,"#/blocks":p,"#/components":u,"#/users":l,"#/plugins":h,"#/system/notifications":g}}async function ee(){try{const e=await c.settings.get();return e?.adminBrand?.title||e?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:e,permissions:i}){const t=$(e).get(0);if(!t)return;let n,s=null,d=null,a=null;try{const r=await c.menus.get("admin-sidebar");n=Array.isArray(r?.items)?r.items:null,s=r?.variant||null,d=r?.position||null,a=r?.style||null}catch{n=null}(!n||!n.length)&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),n=G.slice());let p=[];try{p=await H.get("/api/sidebar/registered-items")||[]}catch{}n=D(n,X);const{toolsFolder:u,pluginsFolder:l,parented:h}=W(p);n=O(n,h),n=_(n,[u,l]);const g=await V(i);g.length&&Y(n,g),n=
|
|
4
|
+
</details>`}return`<a href="${s}" class="sidebar-link" data-url="${s}"${p}>${t} <span class="sidebar-text">${n}</span>${J(e,i)}${u}</a>`}async function Z(){const e=y=>y.then(b=>Array.isArray(b)?b.length:Array.isArray(b?.entries)?b.entries.length:0).catch(()=>0),[i,t,n,s,d,a,p,u,l,h,g]=await Promise.all([e(c.pages.list()),e(c.media.list()),e(c.collections.list()),e(c.forms.list()),e(c.views.list()),e(c.actions.list()),e(c.blocks.list()),e(c.components.list()),e(c.users.list()),e(c.plugins.list()),c.system?.notifications?.unreadCount?.().then(y=>y?.count??0).catch(()=>0)??Promise.resolve(0)]);return{"#/pages":i,"#/media":t,"#/collections":n,"#/forms":s,"#/views":d,"#/actions":a,"#/blocks":p,"#/components":u,"#/users":l,"#/plugins":h,"#/system/notifications":g}}async function ee(){try{const e=await c.settings.get();return e?.adminBrand?.title||e?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:e,permissions:i}){const t=$(e).get(0);if(!t)return;let n,s=null,d=null,a=null;try{const r=await c.menus.get("admin-sidebar");n=Array.isArray(r?.items)?r.items:null,s=r?.variant||null,d=r?.position||null,a=r?.style||null}catch{n=null}(!n||!n.length)&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),n=G.slice());let p=[];try{p=await H.get("/api/sidebar/registered-items")||[]}catch{}n=D(n,X);const{toolsFolder:u,pluginsFolder:l,parented:h}=W(p);n=O(n,h),n=_(n,[u,l]);const g=await V(i);g.length&&Y(n,g),n=I(n,i),n=K(n);const[y,b]=await Promise.all([Z().catch(()=>({})),ee()]),R=s?` dm-admin-sidebar--${f(s)}`:"";function w(r,m="px"){if(r==null)return r;const o=String(r).trim();return/^\d+(\.\d+)?$/.test(o)?`${o}${m}`:o}let C="";if(a){const r=[];a.fontFamily&&r.push(`font-family: ${a.fontFamily}, sans-serif`),a.fontSize&&r.push(`font-size: ${w(a.fontSize)}`),a.fontWeight&&r.push(`font-weight: ${a.fontWeight}`),a.letterSpacing&&r.push(`letter-spacing: ${w(a.letterSpacing,"em")}`);const m=[];if(r.length&&m.push(`#admin-sidebar .dm-admin-sidebar, #admin-sidebar .dm-admin-sidebar .sidebar-link, #admin-sidebar .dm-admin-sidebar summary, #admin-sidebar .dm-admin-sidebar .sidebar-text { ${r.join("; ")} }`),a.iconSize){const o=w(a.iconSize);m.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${o} !important; height: ${o} !important; }`)}m.length&&(C=`<style data-admin-sidebar-style>${m.join(" ")}</style>`)}const N=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span> ${f(b)}</div>`,U=`${C}<nav class="dm-admin-sidebar${R}">${N}${n.map(r=>z(r,y)).join("")}</nav>`,j=document.createRange();j.selectNodeContents(t);const q=j.createContextualFragment(U);t.replaceChildren(q),Domma.icons.scan(t);const x=Number.parseInt(S.get("sidebar.width"),10);Number.isFinite(x)&&x>=180&&x<=480&&(t.style.width=x+"px");const A=document.createElement("div");A.className="dm-admin-sidebar-handle",A.setAttribute("aria-label","Resize sidebar"),t.appendChild(A),t.querySelectorAll("details").forEach(r=>{r.addEventListener("toggle",function(){const m=this.getAttribute("data-state-key");m&&S.set(m,this.open);const o=this.querySelector(":scope > .sidebar-children");if(o)if(this.open){const k=o.scrollHeight;o.style.maxHeight="0",requestAnimationFrame(()=>{o.style.maxHeight=k+"px",o.addEventListener("transitionend",function T(){o.style.maxHeight="none",o.removeEventListener("transitionend",T)})})}else{const k=o.scrollHeight;o.style.maxHeight=k+"px",requestAnimationFrame(()=>{o.style.maxHeight="0"})}})});let v=!1,P=0,E=0;A.addEventListener("mousedown",r=>{v=!0,P=r.clientX,E=t.getBoundingClientRect().width,document.body.style.cursor="col-resize",document.body.style.userSelect="none",r.preventDefault()}),document.addEventListener("mousemove",r=>{if(!v)return;const m=Math.max(180,Math.min(480,E+(r.clientX-P)));t.style.width=m+"px"}),document.addEventListener("mouseup",()=>{v&&(v=!1,document.body.style.cursor="",document.body.style.userSelect="",S.set("sidebar.width",parseInt(t.style.width,10)))});function L(){const r=location.hash||"#/";$(t).find(".sidebar-link").removeClass("active"),$(t).find(`.sidebar-link[data-url="${r}"]`).addClass("active")}L(),M.subscribe("router:afterChange",L)}
|
package/bin/cli.js
CHANGED
|
@@ -321,6 +321,13 @@ content/users/
|
|
|
321
321
|
content/media/
|
|
322
322
|
*.log
|
|
323
323
|
.domma-backups/
|
|
324
|
+
|
|
325
|
+
# Analytics plugin runtime counters — written on every page hit. Never track:
|
|
326
|
+
# committing them resets live analytics on every checkout/pull/update.
|
|
327
|
+
plugins/analytics/stats.json
|
|
328
|
+
plugins/analytics/daily.json
|
|
329
|
+
plugins/analytics/lifetime.json
|
|
330
|
+
plugins/analytics/journeys.json
|
|
324
331
|
`;
|
|
325
332
|
|
|
326
333
|
step('Writing .gitignore');
|
package/bin/update.js
CHANGED
|
@@ -467,18 +467,24 @@ export default async function update(_positional, flags) {
|
|
|
467
467
|
done();
|
|
468
468
|
|
|
469
469
|
// -------------------------------------------------------------------------
|
|
470
|
-
// 11. Ensure
|
|
470
|
+
// 11. Ensure runtime state is in .gitignore (self-heal existing installs)
|
|
471
|
+
// .domma-backups/ + analytics counters — tracking the latter resets
|
|
472
|
+
// live analytics on every checkout/pull/update (recurring bug).
|
|
471
473
|
// -------------------------------------------------------------------------
|
|
472
474
|
|
|
473
475
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
476
|
+
const requiredIgnores = [
|
|
477
|
+
'.domma-backups/',
|
|
478
|
+
'plugins/analytics/stats.json',
|
|
479
|
+
'plugins/analytics/daily.json',
|
|
480
|
+
'plugins/analytics/lifetime.json',
|
|
481
|
+
'plugins/analytics/journeys.json',
|
|
482
|
+
];
|
|
483
|
+
const current = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf8') : '';
|
|
484
|
+
const missing = requiredIgnores.filter(entry => !current.split(/\r?\n/).includes(entry));
|
|
485
|
+
if (missing.length) {
|
|
486
|
+
const prefix = current ? current.trimEnd() + '\n' : '';
|
|
487
|
+
writeFileSync(gitignorePath, prefix + missing.join('\n') + '\n', 'utf8');
|
|
482
488
|
}
|
|
483
489
|
|
|
484
490
|
// -------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domma-cms",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.11",
|
|
4
4
|
"description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/server.js",
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"config/",
|
|
21
21
|
"!config/connections.json",
|
|
22
22
|
"plugins/",
|
|
23
|
+
"!plugins/analytics/stats.json",
|
|
24
|
+
"!plugins/analytics/daily.json",
|
|
25
|
+
"!plugins/analytics/lifetime.json",
|
|
26
|
+
"!plugins/analytics/journeys.json",
|
|
23
27
|
"scripts/",
|
|
24
28
|
"docs/",
|
|
25
29
|
"CHANGELOG.md",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"2026-05-06": [
|
|
3
|
-
{
|
|
4
|
-
"sid": "test-controller",
|
|
5
|
-
"t": 1778084386121,
|
|
6
|
-
"url": "/test-from-controller",
|
|
7
|
-
"ref": "/"
|
|
8
|
-
}
|
|
9
|
-
],
|
|
10
|
-
"2026-05-22": [
|
|
11
|
-
{
|
|
12
|
-
"sid": "test-sid-123",
|
|
13
|
-
"t": 1779450391054,
|
|
14
|
-
"url": "/about",
|
|
15
|
-
"ref": ""
|
|
16
|
-
}
|
|
17
|
-
]
|
|
18
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"/": 162,
|
|
3
|
-
"/about": 89,
|
|
4
|
-
"/blog": 42,
|
|
5
|
-
"/contact": 31,
|
|
6
|
-
"/resources/typography": 4,
|
|
7
|
-
"/resources": 13,
|
|
8
|
-
"/resources/shortcodes": 14,
|
|
9
|
-
"/resources/cards": 19,
|
|
10
|
-
"/resources/interactive": 13,
|
|
11
|
-
"/resources/grid": 6,
|
|
12
|
-
"/forms": 14,
|
|
13
|
-
"/resources/effects": 6,
|
|
14
|
-
"/blog/hello-world": 28,
|
|
15
|
-
"/feedback": 42,
|
|
16
|
-
"/resources/dependencies": 2,
|
|
17
|
-
"/resources/components": 6,
|
|
18
|
-
"/gdpr": 3,
|
|
19
|
-
"/scratch": 84,
|
|
20
|
-
"/getting-started": 3,
|
|
21
|
-
"/resources/pro": 1,
|
|
22
|
-
"/todo": 23,
|
|
23
|
-
"/thank-you": 1,
|
|
24
|
-
"/test-from-controller": 1
|
|
25
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"/": 162,
|
|
3
|
-
"/about": 88,
|
|
4
|
-
"/blog": 42,
|
|
5
|
-
"/contact": 31,
|
|
6
|
-
"/resources/typography": 4,
|
|
7
|
-
"/resources": 13,
|
|
8
|
-
"/resources/shortcodes": 14,
|
|
9
|
-
"/resources/cards": 19,
|
|
10
|
-
"/resources/interactive": 13,
|
|
11
|
-
"/resources/grid": 6,
|
|
12
|
-
"/forms": 14,
|
|
13
|
-
"/resources/effects": 6,
|
|
14
|
-
"/blog/hello-world": 28,
|
|
15
|
-
"/feedback": 42,
|
|
16
|
-
"/resources/dependencies": 2,
|
|
17
|
-
"/resources/components": 6,
|
|
18
|
-
"/gdpr": 3,
|
|
19
|
-
"/scratch": 84,
|
|
20
|
-
"/getting-started": 3,
|
|
21
|
-
"/resources/pro": 1,
|
|
22
|
-
"/todo": 23,
|
|
23
|
-
"/thank-you": 1
|
|
24
|
-
}
|