domma-cms 0.10.0 → 0.13.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.
Files changed (121) hide show
  1. package/CLAUDE.md +248 -159
  2. package/admin/css/admin.css +1 -1
  3. package/admin/js/api.js +1 -1
  4. package/admin/js/app.js +7 -3
  5. package/admin/js/config/sidebar-config.js +1 -1
  6. package/admin/js/http-interceptor.js +1 -0
  7. package/admin/js/lib/safe-html.js +1 -0
  8. package/admin/js/templates/documentation.html +611 -2
  9. package/admin/js/templates/layouts.html +5 -4
  10. package/admin/js/templates/notifications.html +14 -0
  11. package/admin/js/templates/plugin-marketplace.html +16 -0
  12. package/admin/js/templates/plugins.html +17 -5
  13. package/admin/js/views/index.js +1 -1
  14. package/admin/js/views/layouts.js +1 -16
  15. package/admin/js/views/notifications.js +1 -0
  16. package/admin/js/views/plugin-marketplace.js +1 -0
  17. package/admin/js/views/plugins.js +16 -16
  18. package/config/navigation.json +5 -72
  19. package/config/plugins.json +10 -14
  20. package/config/presets.json +50 -13
  21. package/config/site.json +11 -63
  22. package/package.json +2 -1
  23. package/plugins/_template/admin/templates/index.html +17 -0
  24. package/plugins/_template/admin/views/index.js +19 -0
  25. package/plugins/_template/config.js +8 -0
  26. package/plugins/_template/plugin.js +23 -0
  27. package/plugins/_template/plugin.json +34 -0
  28. package/plugins/analytics/plugin.json +41 -31
  29. package/plugins/blog/admin/templates/blog.html +22 -0
  30. package/plugins/blog/admin/templates/categories.html +7 -0
  31. package/plugins/blog/admin/templates/comments.html +11 -0
  32. package/plugins/blog/admin/templates/post-editor.html +97 -0
  33. package/plugins/blog/admin/templates/settings.html +11 -0
  34. package/plugins/blog/admin/views/blog.js +183 -0
  35. package/plugins/blog/admin/views/categories.js +235 -0
  36. package/plugins/blog/admin/views/comments.js +187 -0
  37. package/plugins/blog/admin/views/post-editor.js +291 -0
  38. package/plugins/blog/admin/views/settings.js +100 -0
  39. package/plugins/blog/collections/categories/schema.json +12 -0
  40. package/plugins/blog/collections/comments/schema.json +16 -0
  41. package/plugins/blog/collections/posts/schema.json +19 -0
  42. package/plugins/blog/config.js +8 -0
  43. package/plugins/blog/plugin.js +352 -0
  44. package/plugins/blog/plugin.json +96 -0
  45. package/plugins/blog/roles/blog-author.json +10 -0
  46. package/plugins/blog/roles/blog-editor.json +12 -0
  47. package/plugins/blog/templates/author.html +9 -0
  48. package/plugins/blog/templates/category.html +9 -0
  49. package/plugins/blog/templates/index.html +9 -0
  50. package/plugins/blog/templates/post.html +17 -0
  51. package/plugins/blog/templates/tag.html +9 -0
  52. package/plugins/contacts/collections/user-contact-groups/schema.json +1 -1
  53. package/plugins/contacts/collections/user-contacts/schema.json +1 -1
  54. package/plugins/contacts/plugin.js +4 -10
  55. package/plugins/contacts/plugin.json +13 -3
  56. package/plugins/notes/collections/user-notes/schema.json +1 -1
  57. package/plugins/notes/plugin.js +3 -9
  58. package/plugins/notes/plugin.json +13 -3
  59. package/plugins/site-search/plugin.json +5 -2
  60. package/plugins/theme-switcher/plugin.json +1 -1
  61. package/plugins/todo/collections/todos/schema.json +1 -1
  62. package/plugins/todo/plugin.js +3 -9
  63. package/plugins/todo/plugin.json +13 -3
  64. package/public/css/site.css +1 -1
  65. package/scripts/build.js +48 -0
  66. package/scripts/create-plugin.js +113 -0
  67. package/scripts/fresh.js +6 -7
  68. package/scripts/gen-instance-secret.js +46 -0
  69. package/scripts/reset.js +3 -3
  70. package/scripts/setup.js +31 -13
  71. package/server/middleware/auth.js +48 -0
  72. package/server/middleware/managerAuth.js +36 -0
  73. package/server/routes/api/actions.js +1 -1
  74. package/server/routes/api/auth.js +4 -3
  75. package/server/routes/api/layouts.js +173 -49
  76. package/server/routes/api/notifications.js +155 -0
  77. package/server/routes/api/plugin-marketplace.js +75 -0
  78. package/server/routes/api/users.js +1 -1
  79. package/server/routes/api/views.js +1 -1
  80. package/server/routes/public.js +4 -9
  81. package/server/server.js +32 -3
  82. package/server/services/actions.js +1 -1
  83. package/server/services/managerClient.js +182 -0
  84. package/server/services/markdown.js +52 -14
  85. package/server/services/permissionRegistry.js +245 -173
  86. package/server/services/pluginInstaller.js +301 -0
  87. package/server/services/plugins.js +117 -10
  88. package/server/services/presetCollections.js +66 -251
  89. package/server/services/renderer.js +99 -0
  90. package/server/services/roles.js +191 -39
  91. package/server/services/users.js +1 -1
  92. package/server/services/views.js +1 -1
  93. package/server/templates/page.html +2 -2
  94. package/plugins/docs/admin/templates/docs.html +0 -69
  95. package/plugins/docs/admin/views/docs.js +0 -276
  96. package/plugins/docs/config.js +0 -8
  97. package/plugins/docs/data/documents/57e003f0-68f2-47dc-9c36-ed4b10ed3deb.json +0 -11
  98. package/plugins/docs/data/folders.json +0 -9
  99. package/plugins/docs/data/templates.json +0 -1
  100. package/plugins/docs/data/versions/57e003f0-68f2-47dc-9c36-ed4b10ed3deb/1.json +0 -5
  101. package/plugins/docs/plugin.js +0 -375
  102. package/plugins/docs/plugin.json +0 -23
  103. package/plugins/form-builder/data/forms/contacts.json +0 -66
  104. package/plugins/form-builder/data/forms/enquiries.json +0 -103
  105. package/plugins/form-builder/data/forms/feedback.json +0 -131
  106. package/plugins/form-builder/data/forms/notes.json +0 -79
  107. package/plugins/form-builder/data/forms/to-do.json +0 -100
  108. package/plugins/form-builder/data/submissions/contacts.json +0 -1
  109. package/plugins/form-builder/data/submissions/enquiries.json +0 -1
  110. package/plugins/form-builder/data/submissions/feedback.json +0 -1
  111. package/plugins/form-builder/data/submissions/notes.json +0 -1
  112. package/plugins/form-builder/data/submissions/to-do.json +0 -1
  113. package/plugins/garage/admin/templates/garage.html +0 -111
  114. package/plugins/garage/admin/views/garage.js +0 -622
  115. package/plugins/garage/collections/garage-vehicles/schema.json +0 -101
  116. package/plugins/garage/config.js +0 -18
  117. package/plugins/garage/data/vehicles.json +0 -70
  118. package/plugins/garage/plugin.js +0 -398
  119. package/plugins/garage/plugin.json +0 -33
  120. package/scripts/seed.js +0 -1996
  121. package/server/services/userTypes.js +0 -227
package/admin/js/app.js CHANGED
@@ -1,7 +1,11 @@
1
- import{getSidebarConfig as Y}from"./config/sidebar-config.js";import{views as q}from"./views/index.js?v=4";import{api as n,getUser as m,isAuthenticated as c,logout as z}from"./api.js";$(()=>{(async()=>{try{const t=c()?await n.settings.get():null;Domma.theme.init({theme:t?.adminTheme||"charcoal-dark",persist:!0})}catch{Domma.theme.init({theme:"charcoal-dark",persist:!0})}})();const N=["jb-company","jb-agent","jb-candidate"],W=["/job-board","/my-profile"];function b(t){return t&&N.includes(t.role)}function w(t){return W.some(e=>t===e||t.startsWith(e+"/"))}R.use(async(t,e,a)=>{if(t.path==="/login"||t.path==="/reset-password")return a();if(!c()){R.navigate("/login");return}if(b(m())&&!w(t.path)){R.navigate("/job-board");return}a()});let p=null;async function I(){if(!c())return{};try{const[t,e,a,i,s,o,h,g,u,C,r,d,F]=await Promise.all([n.pages.list().catch(()=>[]),n.media.list().catch(()=>[]),n.users.list().catch(()=>[]),n.plugins.list().catch(()=>[]),n.collections.list().catch(()=>[]),n.forms.list().catch(()=>[]),n.themes.list().catch(()=>[]),n.views.list().catch(()=>[]),n.actions.list().catch(()=>[]),n.blocks.list().catch(()=>[]),n.navigation.get().catch(()=>({})),n.layouts.get().catch(()=>({})),n.get("/collections/roles/entries?limit=100").catch(()=>({entries:[]}))]),T=r.items||[],J=T.filter(D=>!D.hidden).length,L=T.length,H=i.filter(D=>D.enabled).length,B=i.length;return{pages:t.length,media:e.length,users:a.length,plugins:B>0?`${H}/${B}`:null,collections:s.length,forms:o.length,themes:h.length,views:g.length,actions:u.length,blocks:C.length,navigation:L>0?`${J}/${L}`:null,layouts:Object.keys(d).length,roles:(F.entries||[]).length}}catch{return{}}}async function y(){try{return(await n.get("/auth/permissions")).permissions||[]}catch{return[]}}async function V(){try{return await n.get("/settings/db-status")}catch{return{configured:!1}}}async function k(t){p&&$("#admin-sidebar").empty();const[e,a,i]=await Promise.all([I(),V(),c()?n.settings.get().catch(()=>({})):Promise.resolve({})]),s=i.adminBrand||{},o=s.title||"CMS Admin",h=s.icon||"layout",g=s.logo||"",u=$("#admin-topbar .topbar-brand");g?u.html(`<img src="${l(g)}" class="topbar-brand-logo" alt="${l(o)}"><span class="topbar-brand-text">${l(o)}</span>`):u.html(`<span data-icon="${l(h)}"></span><span class="topbar-brand-text">${l(o)}</span>`),Domma.icons.scan("#admin-topbar .topbar-brand");const C=A.map(r=>{if(!r.countKey)return r;const d=e[r.countKey];return{...r,badge:d!=null&&d>0?String(d):null}});if(p=Domma.elements.sidebar("#admin-sidebar",{header:{title:o,icon:h},items:Y(t,e,C),collapsible:!0,collapseAt:992,push:!0,contentSelector:".dashboard-main",top:"60px"}),K(),O(),a?.configured){const r=$("#admin-sidebar").find(".sidebar-header-title").first();r.length&&!r.find(".db-badge").length&&r.append('<span class="db-badge" title="MongoDB connected" style="display:inline-flex;align-items:center;background:#16a34a;color:#fff;font-size:10px;font-weight:700;padding:2px 6px;border-radius:9999px;letter-spacing:.5px;margin-left:6px;vertical-align:middle;line-height:1;">DB</span>')}}function K(){$("#admin-sidebar .sidebar-link").each(function(){const t=$(this).find(".sidebar-text").text().trim();t&&E.tooltip(this,{content:t,position:"right"})})}function O(){const t="sidebar_collapsed_sections",e=new Set(S.get(t)||[]);$("#admin-sidebar .sidebar-heading").each(function(){const a=$(this);a.addClass("sidebar-heading--collapsible"),a.append('<span class="sidebar-heading-toggle"><span data-icon="chevron-down"></span></span>');const i=a.text().trim();if(e.has(i)){a.addClass("is-collapsed");let s=a.next();for(;s.length&&!s.hasClass("sidebar-heading")&&!s.hasClass("sidebar-divider");)s.hide(),s=s.next()}a.on("click",function(){const s=!a.hasClass("is-collapsed");a.toggleClass("is-collapsed",s);let o=a.next();for(;o.length&&!o.hasClass("sidebar-heading")&&!o.hasClass("sidebar-divider");)o.toggle(!s),o=o.next();s?e.add(i):e.delete(i),S.set(t,[...e])})}),Domma.icons.scan("#admin-sidebar")}M.subscribe("router:afterChange",({to:t})=>{p&&t.path!=="/login"&&t.path!=="/reset-password"&&p.setActive("#"+t.path)});const U=[{path:"/",view:"dashboard",title:"Dashboard - Domma CMS"},{path:"/pages",view:"pages",title:"Pages - Domma CMS"},{path:"/pages/new",view:"pageEditor",title:"New Page - Domma CMS"},{path:"/pages/edit/*",view:"pageEditor",title:"Edit Page - Domma CMS"},{path:"/media",view:"media",title:"Media - Domma CMS"},{path:"/navigation",view:"navigation",title:"Navigation - Domma CMS"},{path:"/layouts",view:"layouts",title:"Layouts - Domma CMS"},{path:"/settings",view:"settings",title:"Settings - Domma CMS"},{path:"/users",view:"users",title:"Users - Domma CMS"},{path:"/users/new",view:"userEditor",title:"New User - Domma CMS"},{path:"/users/edit/:id",view:"userEditor",title:"Edit User - Domma CMS"},{path:"/plugins",view:"plugins",title:"Plugins - Domma CMS"},{path:"/documentation",view:"documentation",title:"Usage - Domma CMS"},{path:"/tutorials",view:"tutorials",title:"Tutorials - Domma CMS"},{path:"/api-reference",view:"apiReference",title:"API Reference - Domma CMS"},{path:"/collections",view:"collections",title:"Collections - Domma CMS"},{path:"/collections/new",view:"collectionEditor",title:"New Collection - Domma CMS"},{path:"/collections/edit/:slug",view:"collectionEditor",title:"Edit Collection - Domma CMS"},{path:"/collections/:slug/entries",view:"collectionEntries",title:"Entries - Domma CMS"},{path:"/forms",view:"forms",title:"Forms - Domma CMS"},{path:"/forms/new",view:"formEditor",title:"New Form - Domma CMS"},{path:"/forms/edit/:slug",view:"formEditor",title:"Edit Form - Domma CMS"},{path:"/forms/:slug/submissions",view:"formSubmissions",title:"Submissions - Domma CMS"},{path:"/views",view:"viewsList",title:"Views - Domma CMS"},{path:"/views/new",view:"viewEditor",title:"New View - Domma CMS"},{path:"/views/edit/:slug",view:"viewEditor",title:"Edit View - Domma CMS"},{path:"/views/:slug/preview",view:"viewPreview",title:"View Preview - Domma CMS"},{path:"/actions",view:"actionsList",title:"Actions - Domma CMS"},{path:"/actions/new",view:"actionEditor",title:"New Action - Domma CMS"},{path:"/actions/edit/:slug",view:"actionEditor",title:"Edit Action - Domma CMS"},{path:"/pro/docs",view:"proDocs",title:"Pro Documentation - Domma CMS"},{path:"/blocks",view:"blocks",title:"Blocks - Domma CMS"},{path:"/blocks/new",view:"blockEditor",title:"New Block - Domma CMS"},{path:"/blocks/edit/:name",view:"blockEditor",title:"Edit Block - Domma CMS"},{path:"/my-profile",view:"myProfile",title:"My Profile - Domma CMS"},{path:"/roles",view:"roles",title:"Roles & Permissions - Domma CMS"},{path:"/roles/edit/:id",view:"roleEditor",title:"Edit Role - Domma CMS"},{path:"/effects",view:"effects",title:"Effects - Domma CMS"},{path:"/login",view:"login",title:"Sign in - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}},{path:"/reset-password",view:"login",title:"Reset Password - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}}];M.subscribe("router:afterChange",async({to:t,from:e})=>{if(!(t.path==="/login"||t.path==="/reset-password")){if(b(m())&&!w(t.path)){R.navigate("/job-board");return}if($("#admin-sidebar").show(),$("#admin-topbar").show(),e?.path==="/login"||e?.path==="/reset-password"){$("#topbar-user-name").remove(),await j();const a=await y();k(a)}_()}}),M.subscribe("router:afterChange",()=>{setTimeout(()=>{$(".btn-primary, .btn-danger").length&&Domma.effects.reveal(".btn-primary, .btn-danger",{animation:"fade",stagger:40,duration:300})},50)});const x="cms_card_states",f=S.get(x)||{};M.subscribe("router:afterChange",()=>{setTimeout(()=>{$("#view-container .card-collapsible").each(function(){const t=$(this).find(".card-header h2, .card-header h3").first().text().trim();t&&f[t]==="collapsed"&&$(this).addClass("card-collapsed")})},200)}),$("#view-container").on("click",".card-collapsible .card-header",function(t){if($(t.target).closest("button, a").length)return;const e=$(this).closest(".card");e.toggleClass("card-collapsed");const a=$(this).find("h2, h3").first().text().trim();a&&(f[a]=e.hasClass("card-collapsed")?"collapsed":"open",S.set(x,f))}),document.addEventListener("keydown",t=>{if(!(t.ctrlKey||t.metaKey)||t.key!=="s"||window.location.hash==="#/login"||window.location.hash.startsWith("#/reset-password"))return;const e=document.querySelector("#view-container .view-header button.btn-primary");e&&(t.preventDefault(),e.click())});const P={...q},v=[...U];let A=[];async function j(){if(c())try{const t=await n.plugins.adminConfig();A=t.sidebar||[],t.routes?.length&&v.push(...t.routes);for(const[e,a]of Object.entries(t.views||{}))try{const i=await import(`/plugins/${a.entry}`);P[e]=i[a.exportName]}catch{}}catch{}}function _(){const t=m();if(!t||$("#topbar-user-name").length)return;const a={admin:"Admin",manager:"Manager",editor:"Editor",subscriber:"Subscriber","jb-company":"Company","jb-agent":"Agent","jb-candidate":"Candidate"}[t.role]||t.role;$("#topbar-user").html(`
1
+ import{getSidebarConfig as G}from"./config/sidebar-config.js";import{views as Q}from"./views/index.js?v=4";import{api as o,getUser as u,isAuthenticated as c,logout as X}from"./api.js";import{installHttpInterceptor as Z}from"./http-interceptor.js";$(()=>{Z(),(async()=>{try{const t=c()?await o.settings.get():null;Domma.theme.init({theme:t?.adminTheme||"charcoal-dark",persist:!0})}catch{Domma.theme.init({theme:"charcoal-dark",persist:!0})}})();const W=["jb-company","jb-agent","jb-candidate"],U=["/job-board","/my-profile"];function f(t){return t&&W.includes(t.role)}function w(t){return U.some(e=>t===e||t.startsWith(e+"/"))}R.use(async(t,e,i)=>{if(t.path==="/login"||t.path==="/reset-password")return i();if(!c()){R.navigate("/login");return}if(f(u())&&!w(t.path)){R.navigate("/job-board");return}i()});let g=null;async function V(){if(!c())return{};try{const[t,e,i,a,n,s,d,p,b,y,r,h,J,q]=await Promise.all([o.pages.list().catch(()=>[]),o.media.list().catch(()=>[]),o.users.list().catch(()=>[]),o.plugins.list().catch(()=>[]),o.collections.list().catch(()=>[]),o.forms.list().catch(()=>[]),o.themes.list().catch(()=>[]),o.views.list().catch(()=>[]),o.actions.list().catch(()=>[]),o.blocks.list().catch(()=>[]),o.navigation.get().catch(()=>({})),o.layouts.get().catch(()=>({})),o.get("/collections/roles/entries?limit=100").catch(()=>({entries:[]})),o.system.notifications.unreadCount().catch(()=>({count:0}))]),T=r.items||[],Y=T.filter(D=>!D.hidden).length,L=T.length,z=a.filter(D=>D.enabled).length,j=a.length;return{pages:t.length,media:e.length,users:i.length,plugins:j>0?`${z}/${j}`:null,collections:n.length,forms:s.length,themes:d.length,views:p.length,actions:b.length,blocks:y.length,navigation:L>0?`${Y}/${L}`:null,layouts:Object.keys(h).length,roles:(J.entries||[]).length,unreadNotifications:q.count||0}}catch{return{}}}async function k(){try{return(await o.get("/auth/permissions")).permissions||[]}catch{return[]}}async function K(){try{return await o.get("/settings/db-status")}catch{return{configured:!1}}}async function x(t){g&&$("#admin-sidebar").empty();const[e,i,a]=await Promise.all([V(),K(),c()?o.settings.get().catch(()=>({})):Promise.resolve({})]),n=a.adminBrand||{},s=n.title||"CMS Admin",d=n.icon||"layout",p=n.logo||"",b=$("#admin-topbar .topbar-brand");p?b.html(`<img src="${l(p)}" class="topbar-brand-logo" alt="${l(s)}"><span class="topbar-brand-text">${l(s)}</span>`):b.html(`<span data-icon="${l(d)}"></span><span class="topbar-brand-text">${l(s)}</span>`),Domma.icons.scan("#admin-topbar .topbar-brand");const y=N.map(r=>{if(!r.countKey)return r;const h=e[r.countKey];return{...r,badge:h!=null&&h>0?String(h):null}});if(g=Domma.elements.sidebar("#admin-sidebar",{header:{title:s,icon:d},items:G(t,e,y),collapsible:!0,collapseAt:992,push:!0,contentSelector:".dashboard-main",top:"60px"}),O(),F(),i?.configured){const r=$("#admin-sidebar").find(".sidebar-header-title").first();r.length&&!r.find(".db-badge").length&&r.append('<span class="db-badge" title="MongoDB connected" style="display:inline-flex;align-items:center;background:#16a34a;color:#fff;font-size:10px;font-weight:700;padding:2px 6px;border-radius:9999px;letter-spacing:.5px;margin-left:6px;vertical-align:middle;line-height:1;">DB</span>')}}function O(){$("#admin-sidebar .sidebar-link").each(function(){const t=$(this).find(".sidebar-text").text().trim();t&&E.tooltip(this,{content:t,position:"right"})})}function F(){const t="sidebar_collapsed_sections",e=new Set(S.get(t)||[]);$("#admin-sidebar .sidebar-heading").each(function(){const i=$(this);i.addClass("sidebar-heading--collapsible"),i.append('<span class="sidebar-heading-toggle"><span data-icon="chevron-down"></span></span>');const a=i.text().trim();if(e.has(a)){i.addClass("is-collapsed");let n=i.next();for(;n.length&&!n.hasClass("sidebar-heading")&&!n.hasClass("sidebar-divider");)n.hide(),n=n.next()}i.on("click",function(){const n=!i.hasClass("is-collapsed");i.toggleClass("is-collapsed",n);let s=i.next();for(;s.length&&!s.hasClass("sidebar-heading")&&!s.hasClass("sidebar-divider");)s.toggle(!n),s=s.next();n?e.add(a):e.delete(a),S.set(t,[...e])})}),Domma.icons.scan("#admin-sidebar")}M.subscribe("router:afterChange",({to:t})=>{(t.path==="/login"||t.path==="/reset-password")&&m&&(clearInterval(m),m=null),g&&t.path!=="/login"&&t.path!=="/reset-password"&&g.setActive("#"+t.path)});const H=[{path:"/",view:"dashboard",title:"Dashboard - Domma CMS"},{path:"/pages",view:"pages",title:"Pages - Domma CMS"},{path:"/pages/new",view:"pageEditor",title:"New Page - Domma CMS"},{path:"/pages/edit/*",view:"pageEditor",title:"Edit Page - Domma CMS"},{path:"/media",view:"media",title:"Media - Domma CMS"},{path:"/navigation",view:"navigation",title:"Navigation - Domma CMS"},{path:"/layouts",view:"layouts",title:"Layouts - Domma CMS"},{path:"/settings",view:"settings",title:"Settings - Domma CMS"},{path:"/users",view:"users",title:"Users - Domma CMS"},{path:"/users/new",view:"userEditor",title:"New User - Domma CMS"},{path:"/users/edit/:id",view:"userEditor",title:"Edit User - Domma CMS"},{path:"/plugins",view:"plugins",title:"Plugins - Domma CMS"},{path:"/documentation",view:"documentation",title:"Usage - Domma CMS"},{path:"/tutorials",view:"tutorials",title:"Tutorials - Domma CMS"},{path:"/api-reference",view:"apiReference",title:"API Reference - Domma CMS"},{path:"/collections",view:"collections",title:"Collections - Domma CMS"},{path:"/collections/new",view:"collectionEditor",title:"New Collection - Domma CMS"},{path:"/collections/edit/:slug",view:"collectionEditor",title:"Edit Collection - Domma CMS"},{path:"/collections/:slug/entries",view:"collectionEntries",title:"Entries - Domma CMS"},{path:"/forms",view:"forms",title:"Forms - Domma CMS"},{path:"/forms/new",view:"formEditor",title:"New Form - Domma CMS"},{path:"/forms/edit/:slug",view:"formEditor",title:"Edit Form - Domma CMS"},{path:"/forms/:slug/submissions",view:"formSubmissions",title:"Submissions - Domma CMS"},{path:"/views",view:"viewsList",title:"Views - Domma CMS"},{path:"/views/new",view:"viewEditor",title:"New View - Domma CMS"},{path:"/views/edit/:slug",view:"viewEditor",title:"Edit View - Domma CMS"},{path:"/views/:slug/preview",view:"viewPreview",title:"View Preview - Domma CMS"},{path:"/actions",view:"actionsList",title:"Actions - Domma CMS"},{path:"/actions/new",view:"actionEditor",title:"New Action - Domma CMS"},{path:"/actions/edit/:slug",view:"actionEditor",title:"Edit Action - Domma CMS"},{path:"/pro/docs",view:"proDocs",title:"Pro Documentation - Domma CMS"},{path:"/blocks",view:"blocks",title:"Blocks - Domma CMS"},{path:"/blocks/new",view:"blockEditor",title:"New Block - Domma CMS"},{path:"/blocks/edit/:name",view:"blockEditor",title:"Edit Block - Domma CMS"},{path:"/my-profile",view:"myProfile",title:"My Profile - Domma CMS"},{path:"/roles",view:"roles",title:"Roles & Permissions - Domma CMS"},{path:"/roles/edit/:id",view:"roleEditor",title:"Edit Role - Domma CMS"},{path:"/effects",view:"effects",title:"Effects - Domma CMS"},{path:"/system/notifications",view:"notifications",title:"Notifications - Domma CMS"},{path:"/login",view:"login",title:"Sign in - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}},{path:"/reset-password",view:"login",title:"Reset Password - Domma CMS",onEnter:()=>{$("#admin-sidebar").hide(),$("#admin-topbar").hide()}}];M.subscribe("router:afterChange",async({to:t,from:e})=>{if(!(t.path==="/login"||t.path==="/reset-password")){if(f(u())&&!w(t.path)){R.navigate("/job-board");return}if($("#admin-sidebar").show(),$("#admin-topbar").show(),e?.path==="/login"||e?.path==="/reset-password"){$("#topbar-user-name").remove(),await _();const i=await k();x(i);try{const a=await o.system.notifications.list().catch(()=>[]),n=(Array.isArray(a)?a:[]).filter(s=>s.unread&&["warning","critical"].includes(s.data?.severity)).slice(0,3);for(const s of n){const d=l(s.data?.title||""),p=l((s.data?.body||"").slice(0,120));E.toast(`${d} \u2014 ${p}`,{type:s.data?.severity==="critical"?"error":"warning",duration:0})}}catch{}}B()}}),M.subscribe("router:afterChange",()=>{setTimeout(()=>{$(".btn-primary, .btn-danger").length&&Domma.effects.reveal(".btn-primary, .btn-danger",{animation:"fade",stagger:40,duration:300})},50)});const P="cms_card_states",v=S.get(P)||{};M.subscribe("router:afterChange",()=>{setTimeout(()=>{$("#view-container .card-collapsible").each(function(){const t=$(this).find(".card-header h2, .card-header h3").first().text().trim();t&&v[t]==="collapsed"&&$(this).addClass("card-collapsed")})},200)}),$("#view-container").on("click",".card-collapsible .card-header",function(t){if($(t.target).closest("button, a").length)return;const e=$(this).closest(".card");e.toggleClass("card-collapsed");const i=$(this).find("h2, h3").first().text().trim();i&&(v[i]=e.hasClass("card-collapsed")?"collapsed":"open",S.set(P,v))}),document.addEventListener("keydown",t=>{if(!(t.ctrlKey||t.metaKey)||t.key!=="s"||window.location.hash==="#/login"||window.location.hash.startsWith("#/reset-password"))return;const e=document.querySelector("#view-container .view-header button.btn-primary");e&&(t.preventDefault(),e.click())});const A={...Q},C=[...H];let N=[];async function _(){if(c())try{const t=await o.plugins.adminConfig();N=t.sidebar||[],t.routes?.length&&C.push(...t.routes);for(const[e,i]of Object.entries(t.views||{}))try{const a=await import(`/plugins/${i.entry}`);A[e]=a[i.exportName]}catch{}for(const{id:e,href:i}of t.css||[])if(!document.getElementById(e)){const a=document.createElement("link");a.id=e,a.rel="stylesheet",a.href=i,document.head.appendChild(a)}}catch{}}function B(){const t=u();if(!t||$("#topbar-user-name").length)return;const i={"super-admin":"Super Admin",admin:"Admin",user:"User"}[t.role]||t.role;$("#topbar-user").html(`
2
2
  <span id="topbar-user-name" class="topbar-user-name">${l(t.name)}</span>
3
- <span class="topbar-role-badge topbar-role-badge--${l(t.role)}">${a}</span>
3
+ <span class="topbar-role-badge topbar-role-badge--${l(t.role)}">${i}</span>
4
4
  `),$("#topbar-actions").html(`
5
+ <a href="#/system/notifications" id="topbar-bell" class="topbar-action-link" data-tooltip="Notifications" data-tooltip-placement="bottom" hidden>
6
+ <span data-icon="bell"></span>
7
+ <span id="topbar-bell-badge" class="topbar-bell-badge" hidden></span>
8
+ </a>
5
9
  <a href="#/my-profile" class="topbar-action-link" data-tooltip="My Profile" data-tooltip-placement="bottom">
6
10
  <span data-icon="user"></span>
7
11
  <span>My Profile</span>
@@ -14,4 +18,4 @@ import{getSidebarConfig as Y}from"./config/sidebar-config.js";import{views as q}
14
18
  <span data-icon="log-out"></span>
15
19
  <span>Sign out</span>
16
20
  </a>
17
- `),$("#topbar-logout-btn").on("click",i=>{i.preventDefault(),z()}),Domma.icons.scan("#admin-topbar"),E.tooltip("#topbar-actions [data-tooltip]",{placement:"bottom"})}function l(t){return String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}(async()=>{if(!c()&&!window.location.hash.startsWith("#/reset-password"))window.location.hash="#/login";else{const i=(window.location.hash||"#/").slice(1)||"/";if(b(m())&&!w(i)&&(window.location.hash="#/job-board"),await j(),m()){const o=await y();await k(o),_()}}R.init({container:"#view-container",routes:v,views:P,default:"/",transitions:{enter:"fadeIn",leave:"fadeOut",duration:150}});const t=R._extractParams.bind(R);R._extractParams=function(i,s){if(i.endsWith("/*")){const o=i.slice(0,-2);return s.startsWith(o+"/")?{}:null}return t(i,s)};const e=(window.location.hash||"#/").slice(1)||"/";v.filter(i=>i.path.endsWith("/*")).some(i=>e.startsWith(i.path.slice(0,-2)+"/"))&&R._handleRouteChange()})()});
21
+ `),$("#topbar-logout-btn").on("click",a=>{a.preventDefault(),X()}),Domma.icons.scan("#admin-topbar"),E.tooltip("#topbar-actions [data-tooltip]",{placement:"bottom"}),I(),m||(m=setInterval(I,6e4))}function l(t){return String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}let m=null;async function I(){if(c())try{const{count:t}=await o.system.notifications.unreadCount();$("#topbar-bell").removeAttr("hidden");const e=$("#topbar-bell-badge");t>0?e.text(t>99?"99+":String(t)).removeAttr("hidden"):e.attr("hidden","").text("")}catch{}}(async()=>{if(!c()&&!window.location.hash.startsWith("#/reset-password"))window.location.hash="#/login";else{const a=(window.location.hash||"#/").slice(1)||"/";if(f(u())&&!w(a)&&(window.location.hash="#/job-board"),await _(),u()){const s=await k();await x(s),B()}}R.init({container:"#view-container",routes:C,views:A,default:"/",transitions:{enter:"fadeIn",leave:"fadeOut",duration:150}});const t=R._extractParams.bind(R);R._extractParams=function(a,n){if(a.endsWith("/*")){const s=a.slice(0,-2);return n.startsWith(s+"/")?{}:null}return t(a,n)};const e=(window.location.hash||"#/").slice(1)||"/";C.filter(a=>a.path.endsWith("/*")).some(a=>e.startsWith(a.path.slice(0,-2)+"/"))&&R._handleRouteChange()})()});
@@ -1 +1 @@
1
- export function getSidebarConfig(o=[],t={},r=[]){const e=n=>o.includes(n)||["read","create","update","delete"].some(l=>o.includes(`${n}.${l}`)),s=n=>n==null?null:typeof n=="string"?n.length>0?n:null:n>0?String(n):null,i=[],u=o.length>0&&o.every(n=>n.startsWith("jb-"));u||i.push({heading:"Overview"},{id:"dashboard",text:"Dashboard",icon:"home",url:"#/",section:"#/"},{divider:!0}),(e("navigation")||e("layouts"))&&i.push({heading:"Structure"},...e("navigation")?[{id:"navigation",text:"Navigation",icon:"menu",url:"#/navigation",section:"#/navigation",badge:s(t.navigation)}]:[],...e("layouts")?[{id:"layouts",text:"Layouts",icon:"layout",url:"#/layouts",section:"#/layouts",badge:s(t.layouts)}]:[],{divider:!0}),(e("pages")||e("media"))&&(i.push({heading:"Content"}),e("pages")&&i.push({id:"pages",text:"Pages",icon:"file-text",url:"#/pages",section:"#/pages",badge:s(t.pages)}),e("media")&&i.push({id:"media",text:"Media",icon:"image",url:"#/media",section:"#/media",badge:s(t.media)})),(e("collections")||e("views")||e("actions"))&&(i.push({divider:!0},{heading:"Data"}),e("collections")&&(i.push({id:"collections",text:"Collections",icon:"database",url:"#/collections",section:"#/collections",badge:s(t.collections)}),i.push({id:"forms",text:"Forms",icon:"layout",url:"#/forms",section:"#/forms",badge:s(t.forms)})),e("views")&&i.push({id:"views",text:"Views",icon:"eye",url:"#/views",section:"#/views",badge:s(t.views)}),e("actions")&&i.push({id:"actions",text:"Actions",icon:"zap",url:"#/actions",section:"#/actions",badge:s(t.actions)}),e("pages")&&i.push({id:"blocks",text:"Blocks",icon:"box",url:"#/blocks",section:"#/blocks",badge:s(t.blocks)})),(e("plugins")||e("users")||e("settings"))&&(i.push({divider:!0},{heading:"Configuration"}),e("plugins")&&i.push({id:"roles",text:"Roles",icon:"shield",url:"#/roles",section:"#/roles",badge:s(t.roles)}),e("users")&&i.push({id:"users",text:"Users",icon:"users",url:"#/users",section:"#/users",badge:s(t.users)}),e("settings")&&(i.push({id:"settings",text:"Site Settings",icon:"settings",url:"#/settings",section:"#/settings"}),i.push({id:"effects",text:"Effects",icon:"sparkles",url:"#/effects",section:"#/effects"})));const a=r.filter(n=>n.permissions?.length?n.permissions.some(l=>o.includes(l)):!0);return e("plugins")?i.push({divider:!0},{heading:"Plugins"},{id:"plugins",text:"Plugins",icon:"package",url:"#/plugins",section:"#/plugins",badge:s(t.plugins)},...a):a.length&&i.push({divider:!0},...a),i.push({divider:!0},{heading:"Account"},{id:"my-profile",text:"My Profile",icon:"user",url:"#/my-profile",section:"#/my-profile"}),u||i.push({divider:!0},{heading:"View Site"},{id:"view-site",text:"View Site",icon:"external-link",url:"/",section:"/"}),(e("pages")||e("collections")||e("plugins")||e("settings"))&&i.push({divider:!0},{heading:"Documentation"},{id:"documentation",text:"Usage",icon:"book",url:"#/documentation",section:"#/documentation",badge:s(t.documents)},{id:"tutorials",text:"Tutorials",icon:"document",url:"#/tutorials",section:"#/documentation",badge:s(t.tutorials)},{id:"api-reference",text:"API Reference",icon:"code",url:"#/api-reference",section:"#/documentation"}),i}
1
+ export function getSidebarConfig(n=[],t={},u=[]){const i=o=>n.includes(o)||["read","create","update","delete"].some(a=>n.includes(`${o}.${a}`)),s=o=>o==null?null:typeof o=="string"?o.length>0?o:null:o>0?String(o):null,e=[];e.push({heading:"Overview"},{id:"dashboard",text:"Dashboard",icon:"home",url:"#/",section:"#/"});const l=u.filter(o=>o.permissions?.length?o.permissions.some(a=>n.includes(a)):!0);return l.length&&e.push(...l),e.push({divider:!0}),(i("navigation")||i("layouts"))&&e.push({heading:"Structure"},...i("navigation")?[{id:"navigation",text:"Navigation",icon:"menu",url:"#/navigation",section:"#/navigation",badge:s(t.navigation)}]:[],...i("layouts")?[{id:"layouts",text:"Layouts",icon:"layout",url:"#/layouts",section:"#/layouts",badge:s(t.layouts)}]:[],{divider:!0}),(i("pages")||i("media"))&&(e.push({heading:"Content"}),i("pages")&&e.push({id:"pages",text:"Pages",icon:"file-text",url:"#/pages",section:"#/pages",badge:s(t.pages)}),i("media")&&e.push({id:"media",text:"Media",icon:"image",url:"#/media",section:"#/media",badge:s(t.media)})),(i("collections")||i("views")||i("actions"))&&(e.push({divider:!0},{heading:"Data"}),i("collections")&&(e.push({id:"collections",text:"Collections",icon:"database",url:"#/collections",section:"#/collections",badge:s(t.collections)}),e.push({id:"forms",text:"Forms",icon:"layout",url:"#/forms",section:"#/forms",badge:s(t.forms)})),i("views")&&e.push({id:"views",text:"Views",icon:"eye",url:"#/views",section:"#/views",badge:s(t.views)}),i("actions")&&e.push({id:"actions",text:"Actions",icon:"zap",url:"#/actions",section:"#/actions",badge:s(t.actions)}),i("pages")&&e.push({id:"blocks",text:"Blocks",icon:"box",url:"#/blocks",section:"#/blocks",badge:s(t.blocks)})),e.push({divider:!0},{heading:"System"}),i("notifications")&&e.push({id:"notifications",text:"Notifications",icon:"bell",url:"#/system/notifications",section:"#/system/notifications",badge:s(t.unreadNotifications)}),i("plugins")&&e.push({id:"roles",text:"Roles",icon:"shield",url:"#/roles",section:"#/roles",badge:s(t.roles)}),i("users")&&e.push({id:"users",text:"Users",icon:"users",url:"#/users",section:"#/users",badge:s(t.users)}),i("settings")&&(e.push({id:"settings",text:"Site Settings",icon:"settings",url:"#/settings",section:"#/settings"}),e.push({id:"effects",text:"Effects",icon:"sparkles",url:"#/effects",section:"#/effects"})),i("plugins")&&e.push({id:"plugins",text:"Plugins",icon:"package",url:"#/plugins",section:"#/plugins",badge:s(t.plugins)}),e.push({id:"my-profile",text:"My Profile",icon:"user",url:"#/my-profile",section:"#/my-profile"}),e.push({divider:!0},{heading:"Documentation"},{id:"documentation",text:"Usage",icon:"book",url:"#/documentation",section:"#/documentation",badge:s(t.documents)},{id:"tutorials",text:"Tutorials",icon:"document",url:"#/tutorials",section:"#/documentation",badge:s(t.tutorials)},{id:"api-reference",text:"API Reference",icon:"code",url:"#/api-reference",section:"#/documentation"}),e}
@@ -0,0 +1 @@
1
+ import{clearAuth as p,getToken as u,refreshAccessToken as l}from"./api.js";let i=null;export function installHttpInterceptor(){if(!window.Domma?.http||Domma.http.__intercepted)return;const n=Domma.http.request.bind(Domma.http);Domma.http.request=async function(s,e,a,r={}){if(!(typeof e=="string"&&e.startsWith("/api/")))return n(s,e,a,r);const o=t=>({...r.headers||{},...t?{Authorization:`Bearer ${t}`}:{}});try{return await n(s,e,a,{...r,headers:o(u())})}catch(t){const c=t&&t.message||"";if(!(c.includes("Invalid or missing authentication token")||c.includes("HTTP Error: 401")))throw t;i||(i=l().catch(m=>{throw p(),R.navigate("/login"),m}).finally(()=>{i=null}));let h;try{h=await i}catch{return}return n(s,e,a,{...r,headers:o(h)})}},Domma.http.__intercepted=!0}
@@ -0,0 +1 @@
1
+ const o={ADD_ATTR:["style","target"],ADD_TAGS:["button"],ALLOW_DATA_ATTR:!0},s=new DOMParser;export function safeSetHTML(t,e){const r=DOMPurify.sanitize(e,o),n=s.parseFromString(r,"text/html");t.replaceChildren(...Array.from(n.body.childNodes))}