domma-cms 1.8.37 → 1.8.39
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 +12 -0
- package/admin/css/admin.css +1 -1
- package/admin/index.html +2 -2
- package/admin/js/app.js +35 -9
- package/admin/js/lib/avatar.js +1 -1
- package/admin/js/lib/sidebar-count-cache.js +1 -0
- package/admin/js/lib/sidebar-renderer.js +4 -4
- package/admin/js/lib/site-settings-arrange.js +1 -1
- package/admin/js/lib/topbar-account.js +1 -0
- package/admin/js/lib/topbar-navigation.js +1 -0
- package/admin/js/lib/topbar-project.js +1 -0
- package/admin/js/lib/update-notice.js +1 -1
- package/admin/js/templates/docs/api-settings.html +2 -0
- package/admin/js/templates/docs/usage-site-settings.html +31 -0
- package/admin/js/templates/settings.html +83 -19
- package/admin/js/views/settings.js +3 -5
- package/docs/api-reference.md +1 -1
- package/docs/configuration.md +18 -0
- package/docs/screenshots/admin-navigation.png +0 -0
- package/docs/screenshots/admin-versions.png +0 -0
- package/docs/screenshots/site-settings-navigation.png +0 -0
- package/package.json +1 -1
- package/public/js/btt.js +1 -1
- package/public/js/cookie-consent.js +1 -1
- package/public/js/google-analytics.js +1 -0
- package/public/js/site.js +1 -1
- package/server/routes/api/auth.js +2 -1
- package/server/routes/api/settings.js +19 -3
- package/server/server.js +6 -3
- package/server/services/frameworkVersions.js +11 -0
- package/server/services/googleAnalytics.js +82 -0
- package/server/services/renderer.js +37 -4
- package/server/templates/page.html +1 -1
package/admin/js/app.js
CHANGED
|
@@ -1,23 +1,49 @@
|
|
|
1
|
-
import{installSmoothCarets as K}from"./lib/smooth-caret.js";import{views as J}from"./views/index.js";import{withPluginChrome as O}from"./lib/plugin-chrome.js";import{api as c,getUser as x,isAuthenticated as m,logout as Y,sendToLogin as Q}from"./api.js";import{claimDrafts as X}from"./lib/draft-owner.js";import{isAuthScreen as b,loginHashFor as Z}from"./lib/login-arrange.js";import{installHttpInterceptor as tt}from"./http-interceptor.js";import{installResizableSlideovers as et}from"./lib/slideover-resizable.js";import{installActivityThrobber as it}from"./lib/activity-throbber.js";import{installUpdateNotice as ot}from"./lib/update-notice.js";import{isPathAllowed as at,redirectFor as st}from"./lib/admin-scope.js";import{deliverDesktop as nt,desktopActive as rt,notificationSettings as lt}from"./lib/desktop-notify.js";import{avatarUrl as ct}from"./lib/avatar.js";import{installCalculator as mt}from"./lib/calculator.js";import{takeOverviewPass as pt,withDashboardStrip as _}from"./lib/dashboards-strip.js";import{installHotkeys as dt}from"./lib/hotkeys-ui.js";import{applyAdminBrand as V}from"./lib/admin-brand.js";import{installRouterCatchUp as ut}from"./lib/router-catch-up.js";import{installSidebarDrawer as ht}from"./lib/sidebar-drawer.js";$(()=>{K(document),tt(),mt(),ot(),it(),et(),ht(),(async()=>{const{applyAdminTheme:t,refreshAdminTheme:i}=await import("./lib/admin-theme.js");m()?await i(c,{init:!0}):t({dommaTheme:"charcoal-dark"},{init:!0})})();let p=null,h=null,l="/",w=!1,g=null;function D(t){if(P[t])return E.toast(`${P[t]} is switched off on this site.`,{type:"info"}),"/";if(t.split("?")[0]==="/my-dashboard")return"/dashboards";const i=y[t]||st(p,t);return i||((t.split("?")[0]||"/")==="/"&&l&&l!=="/"&&!pt()?y[l]||l:null)}const y={},P={};R.use(async(t,i,e)=>{if(b(t.path))return e();if(!m()){Q();return}const o=D(t.path);if(o){R.navigate(o);return}e()});async function f(){try{const t=await c.get("/auth/permissions");p=t.adminScope||null,h=t.adminBrand||null,V(h),l=t.adminHome||"/";const i=t.permissions||[];return w=at(p,"/settings")&&i.some(e=>e==="settings"||e.startsWith("settings.")),g=i.some(e=>e==="notifications"||e.startsWith("notifications.")),i}catch{return p=null,l="/",h||V(null),w=!1,g=null,[]}}document.addEventListener("dm:admin-home-changed",()=>{f()});let N=null,A=!1;document.addEventListener("dm:sidebar-rebuild",()=>{if(N){A=!0;return}N=(async()=>{do{A=!1;try{await j(await f())}catch{}}while(A)})().finally(()=>{N=null})});async function j(t){const{renderAdminSidebar:i}=await import("./lib/sidebar-renderer.js");await i({mount:"#admin-sidebar",permissions:t,adminScope:p,brand:h})}M.subscribe("router:afterChange",({to:t})=>{b(t.path)&&(u&&(clearInterval(u),u=null),p=null,l="/",w=!1,g=null)});const W=[{path:"/",view:"dashboard",title:"Dashboard - Domma CMS"},{path:"/dashboards",view:"dashboards",title:"Dashboards - Domma CMS"},{path:"/my-dashboard",view:"dashboards",title:"Dashboards - 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:"/menus",view:"menus",title:"Menus - Domma CMS"},{path:"/context-menus",view:"contextMenus",title:"Context Menus - Domma CMS"},{path:"/context-menus/new",view:"contextMenuEditor",title:"New Context Menu - Domma CMS"},{path:"/context-menus/edit/:slug",view:"contextMenuEditor",title:"Edit Context Menu - Domma CMS"},{path:"/menus/new",view:"menuEditor",title:"New Menu - Domma CMS"},{path:"/menus/edit/:slug",view:"menuEditor",title:"Edit Menu - Domma CMS"},{path:"/menu-locations",view:"menuLocations",title:"Menu Locations - Domma CMS"},{path:"/navigation",view:"menusRedirect",title:"Menus - Domma CMS"},{path:"/layouts",view:"layouts",title:"Layouts - Domma CMS"},{path:"/settings",view:"settings",title:"Settings - Domma CMS"},{path:"/theme",view:"theme",title:"Theme - 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:"/plugins/code/:name",view:"pluginCode",title:"Plugin Code - Domma CMS"},{path:"/documentation",view:"documentation",title:"Usage - Domma CMS"},{path:"/tutorials",view:"tutorials",title:"Tutorials - Domma CMS"},{path:"/tutorials/crud",view:"tutorialCrud",title:"Building a CRUD App - Domma CMS"},{path:"/tutorials/editor",view:"tutorialEditor",title:"The Editor - Domma CMS"},{path:"/tutorials/plugin",view:"tutorialPlugin",title:"Writing a Tool - Domma CMS"},{path:"/tutorials/forms",view:"tutorialForms",title:"Form Follow-Up - Domma CMS"},{path:"/docs/components",view:"componentsReference",title:"Components Reference - Domma CMS"},{path:"/docs/components-howto",view:"componentsHowto",title:"Components How-To - Domma CMS"},{path:"/docs/components-walkthrough",view:"componentsWalkthrough",title:"Components Walkthrough - Domma CMS"},{path:"/docs/components-rules",view:"componentsRules",title:"Components Rules - Domma CMS"},{path:"/docs/usage/pages",view:"usagePages",title:"Pages - Usage - Domma CMS"},{path:"/docs/usage/media",view:"usageMedia",title:"Media - Usage - Domma CMS"},{path:"/docs/usage/navigation",view:"usageNavigation",title:"Navigation - Usage - Domma CMS"},{path:"/docs/usage/dconfig",view:"usageDconfig",title:"DConfig - Usage - Domma CMS"},{path:"/docs/usage/shortcodes",view:"usageShortcodes",title:"Shortcodes - Usage - Domma CMS"},{path:"/docs/usage/site-settings",view:"usageSiteSettings",title:"Site Settings - Usage - Domma CMS"},{path:"/docs/usage/plugins",view:"usagePlugins",title:"Plugins - Usage - Domma CMS"},{path:"/docs/usage/users-roles",view:"usageUsersRoles",title:"Users & Roles - Usage - Domma CMS"},{path:"/docs/usage/views",view:"usageViews",title:"Views - Usage - Domma CMS"},{path:"/docs/usage/actions",view:"usageActions",title:"Actions - Usage - Domma CMS"},{path:"/docs/usage/cta-shortcode",view:"usageCtaShortcode",title:"CTA Shortcode - Usage - Domma CMS"},{path:"/docs/usage/editions",view:"usageEditions",title:"Editions & Licences - Usage - Domma CMS"},{path:"/docs/usage/collections",view:"usageCollections",title:"Collections & Forms - Usage - Domma CMS"},{path:"/docs/usage/blocks",view:"usageBlocks",title:"Blocks - Usage - Domma CMS"},{path:"/docs/usage/tools",view:"usageTools",title:"Built-in Tools - Usage - Domma CMS"},{path:"/docs/usage/dashboard",view:"usageDashboard",title:"Dashboard - Usage - Domma CMS"},{path:"/docs/usage/search-engines",view:"usageSearchEngines",title:"Search Engines & AI - Usage - Domma CMS"},{path:"/docs/plugins",view:"pluginGuides",title:"Plugin Guides - Domma CMS"},{path:"/docs/plugins/*",view:"pluginGuide",title:"Plugin Guide - Domma CMS"},{path:"/docs/api/authentication",view:"apiRefAuthentication",title:"Authentication - API - Domma CMS"},{path:"/docs/api/pages",view:"apiRefPages",title:"Pages - API - Domma CMS"},{path:"/docs/api/settings",view:"apiRefSettings",title:"Settings - API - Domma CMS"},{path:"/docs/api/layouts",view:"apiRefLayouts",title:"Layouts - API - Domma CMS"},{path:"/docs/api/navigation",view:"apiRefNavigation",title:"Navigation - API - Domma CMS"},{path:"/docs/api/media",view:"apiRefMedia",title:"Media - API - Domma CMS"},{path:"/docs/api/users",view:"apiRefUsers",title:"Users - API - Domma CMS"},{path:"/docs/api/plugins",view:"apiRefPlugins",title:"Plugins - API - Domma CMS"},{path:"/docs/api/collections",view:"apiRefCollections",title:"Collections - API - Domma CMS"},{path:"/docs/api/views",view:"apiRefViews",title:"Views API - Domma CMS"},{path:"/docs/api/actions",view:"apiRefActions",title:"Actions API - Domma CMS"},{path:"/docs/api/forms",view:"apiRefForms",title:"Forms API - Domma CMS"},{path:"/docs/api/scaffold",view:"apiRefScaffold",title:"Scaffold API - Domma CMS"},{path:"/docs/api/external",view:"apiRefExternal",title:"External API & Tokens - Domma CMS"},{path:"/docs/api/content",view:"apiRefContent",title:"Content API - Domma CMS"},{path:"/docs/api/builder",view:"apiRefBuilder",title:"API Builder - 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:"pageEditor",title:"New Block - Domma CMS"},{path:"/blocks/edit/:name",view:"pageEditor",title:"Edit Block - Domma CMS"},{path:"/components",view:"components",title:"Components - Domma CMS"},{path:"/components/new",view:"pageEditor",title:"New Component - Domma CMS"},{path:"/components/edit/:name",view:"pageEditor",title:"Edit Component - 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:"/search",view:"search",title:"Search - Domma CMS"},{path:"/content-api",view:"contentApi",title:"Content API - Domma CMS"},{path:"/notes",view:"notes",title:"Notes - Domma CMS"},{path:"/todo",view:"todo",title:"Todo - Domma CMS"},{path:"/calculator",view:"calculator",title:"Calculator - Domma CMS"},{path:"/analytics",view:"analytics",title:"Analytics - Domma CMS"},{path:"/seo",view:"seo",title:"SEO - Domma CMS"},{path:"/seo/:tab",view:"seo",title:"SEO - Domma CMS"},{path:"/wordpress-import",view:"wordpressImport",title:"Import from WordPress - Domma CMS"},{path:"/contacts",view:"contacts",title:"Contacts - Domma CMS"},{path:"/calls/new",view:"callNew",title:"Call now - Domma CMS"},{path:"/system/notifications",view:"notifications",title:"Notifications - Domma CMS"},{path:"/api-tokens",view:"apiTokens",title:"API Tokens - Domma CMS"},{path:"/api-endpoints",view:"apiEndpoints",title:"API Builder - Domma CMS"},{path:"/api-endpoints/new",view:"apiEndpointEditor",title:"New API Endpoint - Domma CMS"},{path:"/api-endpoints/edit/:id",view:"apiEndpointEditor",title:"Edit API Endpoint - Domma CMS"},{path:"/projects",view:"projects",title:"Projects - Domma CMS"},{path:"/projects/new",view:"projects",title:"New Project - Domma CMS"},{path:"/projects/edit/:slug",view:"projects",title:"Edit Project - Domma CMS"},{path:"/projects/:slug/settings",view:"projectSettings",title:"Project settings - Domma CMS"},{path:"/projects/:slug/pages",view:"pages",title:"Project pages - Domma CMS"},{path:"/projects/:slug/collections",view:"collections",title:"Project collections - Domma CMS"},{path:"/projects/:slug/forms",view:"forms",title:"Project forms - Domma CMS"},{path:"/projects/:slug/actions",view:"actionsList",title:"Project actions - Domma CMS"},{path:"/projects/:slug/menus",view:"menus",title:"Project menus - Domma CMS"},{path:"/projects/:slug/blocks",view:"blocks",title:"Project blocks - Domma CMS"},{path:"/projects/:slug/components",view:"components",title:"Project components - Domma CMS"},{path:"/projects/:slug/views",view:"viewsList",title:"Project views - Domma CMS"},{path:"/projects/:slug/roles",view:"roles",title:"Project roles - Domma CMS"},{path:"/projects/:slug/users",view:"users",title:"Project users - Domma CMS"},{path:"/projects/:slug/apis",view:"apiEndpoints",title:"Project APIs - Domma CMS"},{path:"/projects/:slug",view:"projectDetail",title:"Project - 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:i})=>{if(!b(t.path)){if($("#admin-sidebar").show(),$("#admin-topbar").show(),b(i?.path)){$("#topbar-user-name").remove(),import("./lib/admin-theme.js").then(a=>a.refreshAdminTheme(c)),await U();const e=await f(),o=D(t.path);if(o&&R.navigate(o),j(e),lt.read().signInToasts)try{const a=await c.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 v=d(s.data?.title||""),T=d((s.data?.body||"").slice(0,120));E.toast(`${v} - ${T}`,{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 H=["#field-project","#menu-project","#collection-project","#endpoint-project","#action-project","#view-project","#block-project","#component-project","#role-project",'[name="project"]','[name="ownedByProject"]'];function q(t){return/^\/(pages|menus|context-menus|collections|forms|actions|views|blocks|components|users|roles|api-endpoints)\/(new|edit\/)/.test(t)}M.subscribe("router:afterChange",({to:t})=>{const i=t?String(t.path).split("?")[0]:"";if(!t||!q(i))return;const o=new URLSearchParams(location.hash.split("?")[1]||"").get("project");if(!o||!/\/new$/.test(i))return;let a=0;const n=60,s=1500,v=()=>{a+=n;for(const T of H){const C=document.querySelector(T);if(!C)continue;if(Array.from(C.options||[]).find(z=>z.value===o)){C.value=o,C.dispatchEvent(new Event("change",{bubbles:!0}));return}}a<s&&setTimeout(v,n)};setTimeout(v,n)});const L="cms_card_states",k=S.get(L)||{};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&&k[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 i=$(this).closest(".card");i.toggleClass("card-collapsed");const e=$(this).find("h2, h3").first().text().trim();e&&(k[e]=i.hasClass("card-collapsed")?"collapsed":"open",S.set(L,k))}),dt(),document.addEventListener("keydown",t=>{if(!(t.ctrlKey||t.metaKey)||t.key!=="s"||window.location.hash.startsWith("#/login")||window.location.hash.startsWith("#/reset-password"))return;const i=document.querySelector("#view-container .view-header button.btn-primary");i&&(t.preventDefault(),i.click())});const r={...J},G={notes:{displayName:"Notes",icon:"edit-3"},todo:{displayName:"Todo",icon:"check-square"},calculator:{displayName:"Calculator",icon:"calculator"},analytics:{displayName:"Analytics",icon:"chart-bar"},seo:{displayName:"SEO",icon:"search"},wordpressImport:{displayName:"Import from WordPress",icon:"download"},contacts:{displayName:"Contacts",icon:"users"},projects:{displayName:"Projects",icon:"folder"},pages:{displayName:"Pages",icon:"file-text"},media:{displayName:"Media",icon:"image"},menus:{displayName:"Site menus",icon:"menu"},contextMenus:{displayName:"Context Menus",icon:"menu"},theme:{displayName:"Theme",icon:"droplet"},collections:{displayName:"Collections",icon:"database"},forms:{displayName:"Forms",icon:"layout"},viewsList:{displayName:"Views",icon:"eye"},actionsList:{displayName:"Actions",icon:"zap"},apiEndpoints:{displayName:"API Builder",icon:"code"},blocks:{displayName:"Blocks",icon:"box"},components:{displayName:"Components",icon:"component"},notifications:{displayName:"Notifications",icon:"bell"},roles:{displayName:"Roles",icon:"shield"},users:{displayName:"Users",icon:"users"},settings:{displayName:"Site Settings",icon:"settings"},effects:{displayName:"Effects",icon:"sparkles"},layouts:{displayName:"Layouts",icon:"layout"},plugins:{displayName:"Marketplace",icon:"store"},myProfile:{displayName:"My Profile",icon:"user"},apiTokens:{displayName:"API Tokens",icon:"key"},search:{displayName:"Search",icon:"search"},contentApi:{displayName:"Content API",icon:"file-text"},dashboard:{displayName:"Dashboard",icon:"home"},dashboards:{displayName:"Dashboards",icon:"home"},pageEditor:{displayName:"Pages",section:"Edit",icon:"file-text"},menuEditor:{displayName:"Site menus",section:"Edit",icon:"menu"},menuLocations:{displayName:"Site menus",section:"Locations",icon:"map-pin"},contextMenuEditor:{displayName:"Context Menus",section:"Edit",icon:"menu"},collectionEditor:{displayName:"Collections",section:"Edit",icon:"database"},collectionEntries:{displayName:"Collections",section:"Entries",icon:"database"},formEditor:{displayName:"Forms",section:"Edit",icon:"layout"},formSubmissions:{displayName:"Forms",section:"Submissions",icon:"inbox"},viewEditor:{displayName:"Views",section:"Edit",icon:"eye"},viewPreview:{displayName:"Views",section:"Preview",icon:"eye"},actionEditor:{displayName:"Actions",section:"Edit",icon:"zap"},apiEndpointEditor:{displayName:"API Builder",section:"Edit",icon:"code"},roleEditor:{displayName:"Roles",section:"Edit",icon:"shield"},userEditor:{displayName:"Users",section:"Edit",icon:"users"},projectDetail:{displayName:"Projects",section:"Overview",icon:"folder"},projectSettings:{displayName:"Projects",section:"Settings",icon:"folder"},pluginCode:{displayName:"Marketplace",section:"Code",icon:"code"}};for(const[t,i]of Object.entries(G))r[t]&&(r[t]=O(r[t],{plugin:t,licence:"Built in",...i}));r.dashboard=_(r.dashboard);const I=[...W];async function U(){if(m())try{const t=await c.plugins.adminConfig(),i=new Set(I.map(e=>e.path));for(const e of t.routes||[])i.has(e.path)||I.push(e);for(const[e,o]of Object.entries(t.views||{}))try{const a=await import(`/plugins/${o.entry}`);r[e]=O(a[o.exportName],(t.meta||{})[e])}catch{}r.dashboard=_(r.dashboard);for(const[e,{route:o}]of Object.entries(t.takeovers||{}))o&&(y[`/${e}`]=o);for(const[e,{enabled:o,displayName:a}]of Object.entries(t.tools||{}))o===!1&&(P[`/${e}`]=a);for(const{id:e,href:o}of t.css||[])if(!document.getElementById(e)){const a=document.createElement("link");a.id=e,a.rel="stylesheet",a.href=o,document.head.appendChild(a)}}catch{}}function B(){const t=x();if(!t||$("#topbar-user-name").length)return;const e={"super-admin":"Super Admin",admin:"Admin",user:"User"}[t.role]||t.role,o=ct(t);$("#topbar-user").html(`
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import{installSmoothCarets as Y}from"./lib/smooth-caret.js";import{views as Q}from"./views/index.js";import{withPluginChrome as V}from"./lib/plugin-chrome.js";import{api as r,getUser as x,isAuthenticated as m,logout as X,sendToLogin as Z}from"./api.js";import{claimDrafts as tt}from"./lib/draft-owner.js";import{isAuthScreen as C,loginHashFor as et}from"./lib/login-arrange.js";import{installHttpInterceptor as it}from"./http-interceptor.js";import{installResizableSlideovers as at}from"./lib/slideover-resizable.js";import{installActivityThrobber as ot}from"./lib/activity-throbber.js";import{installUpdateNotice as st,renderCmsVersion as nt}from"./lib/update-notice.js";import{renderFrameworkVersions as _,wireAccountMenu as rt}from"./lib/topbar-account.js";import{refreshTopbarProject as L}from"./lib/topbar-project.js";import{isPathAllowed as lt,redirectFor as ct}from"./lib/admin-scope.js";import{deliverDesktop as mt,desktopActive as pt,notificationSettings as dt}from"./lib/desktop-notify.js";import{avatarUrl as ut,installAccountAvatar as ht}from"./lib/avatar.js";import{installCalculator as wt}from"./lib/calculator.js";import{takeOverviewPass as gt,withDashboardStrip as W}from"./lib/dashboards-strip.js";import{installHotkeys as ft}from"./lib/hotkeys-ui.js";import{applyAdminBrand as H}from"./lib/admin-brand.js";import{installRouterCatchUp as vt}from"./lib/router-catch-up.js";import{installSidebarDrawer as bt}from"./lib/sidebar-drawer.js";$(()=>{Y(document),it(),wt(),st(),ot(),at(),bt(),(async()=>{const{applyAdminTheme:t,refreshAdminTheme:i}=await import("./lib/admin-theme.js");m()?await i(r,{init:!0}):t({dommaTheme:"charcoal-dark"},{init:!0})})();let p=null,h=null,c="/",w=!1,g=null;function D(t){if(P[t])return E.toast(`${P[t]} is switched off on this site.`,{type:"info"}),"/";if(t.split("?")[0]==="/my-dashboard")return"/dashboards";const i=y[t]||ct(p,t);return i||((t.split("?")[0]||"/")==="/"&&c&&c!=="/"&&!gt()?y[c]||c:null)}const y={},P={};R.use(async(t,i,e)=>{if(C(t.path))return e();if(!m()){Z();return}const a=D(t.path);if(a){R.navigate(a);return}e()});async function f(){try{const t=await r.get("/auth/permissions");p=t.adminScope||null,h=t.adminBrand||null,H(h),c=t.adminHome||"/",_(t.versions);const i=t.permissions||[];return w=lt(p,"/settings")&&i.some(e=>e==="settings"||e.startsWith("settings.")),g=i.some(e=>e==="notifications"||e.startsWith("notifications.")),i}catch{return p=null,c="/",h||H(null),w=!1,g=null,[]}}document.addEventListener("dm:admin-home-changed",()=>{f()});let N=null,A=!1;document.addEventListener("dm:sidebar-rebuild",()=>{if(L(r),N){A=!0;return}N=(async()=>{do{A=!1;try{await j(await f())}catch{}}while(A)})().finally(()=>{N=null})});async function j(t){const{renderAdminSidebar:i}=await import("./lib/sidebar-renderer.js");await i({mount:"#admin-sidebar",permissions:t,adminScope:p,brand:h})}M.subscribe("router:afterChange",({to:t})=>{C(t.path)&&(u&&(clearInterval(u),u=null),p=null,c="/",w=!1,g=null)});const q=[{path:"/",view:"dashboard",title:"Dashboard - Domma CMS"},{path:"/dashboards",view:"dashboards",title:"Dashboards - Domma CMS"},{path:"/my-dashboard",view:"dashboards",title:"Dashboards - 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:"/menus",view:"menus",title:"Menus - Domma CMS"},{path:"/context-menus",view:"contextMenus",title:"Context Menus - Domma CMS"},{path:"/context-menus/new",view:"contextMenuEditor",title:"New Context Menu - Domma CMS"},{path:"/context-menus/edit/:slug",view:"contextMenuEditor",title:"Edit Context Menu - Domma CMS"},{path:"/menus/new",view:"menuEditor",title:"New Menu - Domma CMS"},{path:"/menus/edit/:slug",view:"menuEditor",title:"Edit Menu - Domma CMS"},{path:"/menu-locations",view:"menuLocations",title:"Menu Locations - Domma CMS"},{path:"/navigation",view:"menusRedirect",title:"Menus - Domma CMS"},{path:"/layouts",view:"layouts",title:"Layouts - Domma CMS"},{path:"/settings",view:"settings",title:"Settings - Domma CMS"},{path:"/theme",view:"theme",title:"Theme - 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:"/plugins/code/:name",view:"pluginCode",title:"Plugin Code - Domma CMS"},{path:"/documentation",view:"documentation",title:"Usage - Domma CMS"},{path:"/tutorials",view:"tutorials",title:"Tutorials - Domma CMS"},{path:"/tutorials/crud",view:"tutorialCrud",title:"Building a CRUD App - Domma CMS"},{path:"/tutorials/editor",view:"tutorialEditor",title:"The Editor - Domma CMS"},{path:"/tutorials/plugin",view:"tutorialPlugin",title:"Writing a Tool - Domma CMS"},{path:"/tutorials/forms",view:"tutorialForms",title:"Form Follow-Up - Domma CMS"},{path:"/docs/components",view:"componentsReference",title:"Components Reference - Domma CMS"},{path:"/docs/components-howto",view:"componentsHowto",title:"Components How-To - Domma CMS"},{path:"/docs/components-walkthrough",view:"componentsWalkthrough",title:"Components Walkthrough - Domma CMS"},{path:"/docs/components-rules",view:"componentsRules",title:"Components Rules - Domma CMS"},{path:"/docs/usage/pages",view:"usagePages",title:"Pages - Usage - Domma CMS"},{path:"/docs/usage/media",view:"usageMedia",title:"Media - Usage - Domma CMS"},{path:"/docs/usage/navigation",view:"usageNavigation",title:"Navigation - Usage - Domma CMS"},{path:"/docs/usage/dconfig",view:"usageDconfig",title:"DConfig - Usage - Domma CMS"},{path:"/docs/usage/shortcodes",view:"usageShortcodes",title:"Shortcodes - Usage - Domma CMS"},{path:"/docs/usage/site-settings",view:"usageSiteSettings",title:"Site Settings - Usage - Domma CMS"},{path:"/docs/usage/plugins",view:"usagePlugins",title:"Plugins - Usage - Domma CMS"},{path:"/docs/usage/users-roles",view:"usageUsersRoles",title:"Users & Roles - Usage - Domma CMS"},{path:"/docs/usage/views",view:"usageViews",title:"Views - Usage - Domma CMS"},{path:"/docs/usage/actions",view:"usageActions",title:"Actions - Usage - Domma CMS"},{path:"/docs/usage/cta-shortcode",view:"usageCtaShortcode",title:"CTA Shortcode - Usage - Domma CMS"},{path:"/docs/usage/editions",view:"usageEditions",title:"Editions & Licences - Usage - Domma CMS"},{path:"/docs/usage/collections",view:"usageCollections",title:"Collections & Forms - Usage - Domma CMS"},{path:"/docs/usage/blocks",view:"usageBlocks",title:"Blocks - Usage - Domma CMS"},{path:"/docs/usage/tools",view:"usageTools",title:"Built-in Tools - Usage - Domma CMS"},{path:"/docs/usage/dashboard",view:"usageDashboard",title:"Dashboard - Usage - Domma CMS"},{path:"/docs/usage/search-engines",view:"usageSearchEngines",title:"Search Engines & AI - Usage - Domma CMS"},{path:"/docs/plugins",view:"pluginGuides",title:"Plugin Guides - Domma CMS"},{path:"/docs/plugins/*",view:"pluginGuide",title:"Plugin Guide - Domma CMS"},{path:"/docs/api/authentication",view:"apiRefAuthentication",title:"Authentication - API - Domma CMS"},{path:"/docs/api/pages",view:"apiRefPages",title:"Pages - API - Domma CMS"},{path:"/docs/api/settings",view:"apiRefSettings",title:"Settings - API - Domma CMS"},{path:"/docs/api/layouts",view:"apiRefLayouts",title:"Layouts - API - Domma CMS"},{path:"/docs/api/navigation",view:"apiRefNavigation",title:"Navigation - API - Domma CMS"},{path:"/docs/api/media",view:"apiRefMedia",title:"Media - API - Domma CMS"},{path:"/docs/api/users",view:"apiRefUsers",title:"Users - API - Domma CMS"},{path:"/docs/api/plugins",view:"apiRefPlugins",title:"Plugins - API - Domma CMS"},{path:"/docs/api/collections",view:"apiRefCollections",title:"Collections - API - Domma CMS"},{path:"/docs/api/views",view:"apiRefViews",title:"Views API - Domma CMS"},{path:"/docs/api/actions",view:"apiRefActions",title:"Actions API - Domma CMS"},{path:"/docs/api/forms",view:"apiRefForms",title:"Forms API - Domma CMS"},{path:"/docs/api/scaffold",view:"apiRefScaffold",title:"Scaffold API - Domma CMS"},{path:"/docs/api/external",view:"apiRefExternal",title:"External API & Tokens - Domma CMS"},{path:"/docs/api/content",view:"apiRefContent",title:"Content API - Domma CMS"},{path:"/docs/api/builder",view:"apiRefBuilder",title:"API Builder - 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:"pageEditor",title:"New Block - Domma CMS"},{path:"/blocks/edit/:name",view:"pageEditor",title:"Edit Block - Domma CMS"},{path:"/components",view:"components",title:"Components - Domma CMS"},{path:"/components/new",view:"pageEditor",title:"New Component - Domma CMS"},{path:"/components/edit/:name",view:"pageEditor",title:"Edit Component - 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:"/search",view:"search",title:"Search - Domma CMS"},{path:"/content-api",view:"contentApi",title:"Content API - Domma CMS"},{path:"/notes",view:"notes",title:"Notes - Domma CMS"},{path:"/todo",view:"todo",title:"Todo - Domma CMS"},{path:"/calculator",view:"calculator",title:"Calculator - Domma CMS"},{path:"/analytics",view:"analytics",title:"Analytics - Domma CMS"},{path:"/seo",view:"seo",title:"SEO - Domma CMS"},{path:"/seo/:tab",view:"seo",title:"SEO - Domma CMS"},{path:"/wordpress-import",view:"wordpressImport",title:"Import from WordPress - Domma CMS"},{path:"/contacts",view:"contacts",title:"Contacts - Domma CMS"},{path:"/calls/new",view:"callNew",title:"Call now - Domma CMS"},{path:"/system/notifications",view:"notifications",title:"Notifications - Domma CMS"},{path:"/api-tokens",view:"apiTokens",title:"API Tokens - Domma CMS"},{path:"/api-endpoints",view:"apiEndpoints",title:"API Builder - Domma CMS"},{path:"/api-endpoints/new",view:"apiEndpointEditor",title:"New API Endpoint - Domma CMS"},{path:"/api-endpoints/edit/:id",view:"apiEndpointEditor",title:"Edit API Endpoint - Domma CMS"},{path:"/projects",view:"projects",title:"Projects - Domma CMS"},{path:"/projects/new",view:"projects",title:"New Project - Domma CMS"},{path:"/projects/edit/:slug",view:"projects",title:"Edit Project - Domma CMS"},{path:"/projects/:slug/settings",view:"projectSettings",title:"Project settings - Domma CMS"},{path:"/projects/:slug/pages",view:"pages",title:"Project pages - Domma CMS"},{path:"/projects/:slug/collections",view:"collections",title:"Project collections - Domma CMS"},{path:"/projects/:slug/forms",view:"forms",title:"Project forms - Domma CMS"},{path:"/projects/:slug/actions",view:"actionsList",title:"Project actions - Domma CMS"},{path:"/projects/:slug/menus",view:"menus",title:"Project menus - Domma CMS"},{path:"/projects/:slug/blocks",view:"blocks",title:"Project blocks - Domma CMS"},{path:"/projects/:slug/components",view:"components",title:"Project components - Domma CMS"},{path:"/projects/:slug/views",view:"viewsList",title:"Project views - Domma CMS"},{path:"/projects/:slug/roles",view:"roles",title:"Project roles - Domma CMS"},{path:"/projects/:slug/users",view:"users",title:"Project users - Domma CMS"},{path:"/projects/:slug/apis",view:"apiEndpoints",title:"Project APIs - Domma CMS"},{path:"/projects/:slug",view:"projectDetail",title:"Project - 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:i})=>{if(!C(t.path)){if($("#admin-sidebar").show(),$("#admin-topbar").show(),C(i?.path)){$("#topbar-user-name").remove(),import("./lib/admin-theme.js").then(o=>o.refreshAdminTheme(r)),await T();const e=await f(),a=D(t.path);if(a&&R.navigate(a),j(e),dt.read().signInToasts)try{const o=await r.system.notifications.list().catch(()=>[]),n=(Array.isArray(o)?o:[]).filter(s=>s.unread&&["warning","critical"].includes(s.data?.severity)).slice(0,3);for(const s of n){const v=d(s.data?.title||""),U=d((s.data?.body||"").slice(0,120));E.toast(`${v} - ${U}`,{type:s.data?.severity==="critical"?"error":"warning",duration:0})}}catch{}}F()}}),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 G=["#field-project","#menu-project","#collection-project","#endpoint-project","#action-project","#view-project","#block-project","#component-project","#role-project",'[name="project"]','[name="ownedByProject"]'];function z(t){return/^\/(pages|menus|context-menus|collections|forms|actions|views|blocks|components|users|roles|api-endpoints)\/(new|edit\/)/.test(t)}M.subscribe("router:afterChange",({to:t})=>{const i=t?String(t.path).split("?")[0]:"";if(!t||!z(i))return;const a=new URLSearchParams(location.hash.split("?")[1]||"").get("project");if(!a||!/\/new$/.test(i))return;let o=0;const n=60,s=1500,v=()=>{o+=n;for(const U of G){const b=document.querySelector(U);if(!b)continue;if(Array.from(b.options||[]).find(J=>J.value===a)){b.value=a,b.dispatchEvent(new Event("change",{bubbles:!0}));return}}o<s&&setTimeout(v,n)};setTimeout(v,n)});const B="cms_card_states",k=S.get(B)||{};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&&k[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 i=$(this).closest(".card");i.toggleClass("card-collapsed");const e=$(this).find("h2, h3").first().text().trim();e&&(k[e]=i.hasClass("card-collapsed")?"collapsed":"open",S.set(B,k))}),ft(),document.addEventListener("keydown",t=>{if(!(t.ctrlKey||t.metaKey)||t.key!=="s"||window.location.hash.startsWith("#/login")||window.location.hash.startsWith("#/reset-password"))return;const i=document.querySelector("#view-container .view-header button.btn-primary");i&&(t.preventDefault(),i.click())});const l={...Q},K={notes:{displayName:"Notes",icon:"edit-3"},todo:{displayName:"Todo",icon:"check-square"},calculator:{displayName:"Calculator",icon:"calculator"},analytics:{displayName:"Analytics",icon:"chart-bar"},seo:{displayName:"SEO",icon:"search"},wordpressImport:{displayName:"Import from WordPress",icon:"download"},contacts:{displayName:"Contacts",icon:"users"},projects:{displayName:"Projects",icon:"folder"},pages:{displayName:"Pages",icon:"file-text"},media:{displayName:"Media",icon:"image"},menus:{displayName:"Site menus",icon:"menu"},contextMenus:{displayName:"Context Menus",icon:"menu"},theme:{displayName:"Theme",icon:"droplet"},collections:{displayName:"Collections",icon:"database"},forms:{displayName:"Forms",icon:"layout"},viewsList:{displayName:"Views",icon:"eye"},actionsList:{displayName:"Actions",icon:"zap"},apiEndpoints:{displayName:"API Builder",icon:"code"},blocks:{displayName:"Blocks",icon:"box"},components:{displayName:"Components",icon:"component"},notifications:{displayName:"Notifications",icon:"bell"},roles:{displayName:"Roles",icon:"shield"},users:{displayName:"Users",icon:"users"},settings:{displayName:"Site Settings",icon:"settings"},effects:{displayName:"Effects",icon:"sparkles"},layouts:{displayName:"Layouts",icon:"layout"},plugins:{displayName:"Marketplace",icon:"store"},myProfile:{displayName:"My Profile",icon:"user"},apiTokens:{displayName:"API Tokens",icon:"key"},search:{displayName:"Search",icon:"search"},contentApi:{displayName:"Content API",icon:"file-text"},dashboard:{displayName:"Dashboard",icon:"home"},dashboards:{displayName:"Dashboards",icon:"home"},pageEditor:{displayName:"Pages",section:"Edit",icon:"file-text"},menuEditor:{displayName:"Site menus",section:"Edit",icon:"menu"},menuLocations:{displayName:"Site menus",section:"Locations",icon:"map-pin"},contextMenuEditor:{displayName:"Context Menus",section:"Edit",icon:"menu"},collectionEditor:{displayName:"Collections",section:"Edit",icon:"database"},collectionEntries:{displayName:"Collections",section:"Entries",icon:"database"},formEditor:{displayName:"Forms",section:"Edit",icon:"layout"},formSubmissions:{displayName:"Forms",section:"Submissions",icon:"inbox"},viewEditor:{displayName:"Views",section:"Edit",icon:"eye"},viewPreview:{displayName:"Views",section:"Preview",icon:"eye"},actionEditor:{displayName:"Actions",section:"Edit",icon:"zap"},apiEndpointEditor:{displayName:"API Builder",section:"Edit",icon:"code"},roleEditor:{displayName:"Roles",section:"Edit",icon:"shield"},userEditor:{displayName:"Users",section:"Edit",icon:"users"},projectDetail:{displayName:"Projects",section:"Overview",icon:"folder"},projectSettings:{displayName:"Projects",section:"Settings",icon:"folder"},pluginCode:{displayName:"Marketplace",section:"Code",icon:"code"}};for(const[t,i]of Object.entries(K))l[t]&&(l[t]=V(l[t],{plugin:t,licence:"Built in",...i}));l.dashboard=W(l.dashboard);const I=[...q];async function T(){if(m())try{const t=await r.plugins.adminConfig(),i=new Set(I.map(e=>e.path));for(const e of t.routes||[])i.has(e.path)||I.push(e);for(const[e,a]of Object.entries(t.views||{}))try{const o=await import(`/plugins/${a.entry}`);l[e]=V(o[a.exportName],(t.meta||{})[e])}catch{}l.dashboard=W(l.dashboard);for(const[e,{route:a}]of Object.entries(t.takeovers||{}))a&&(y[`/${e}`]=a);for(const[e,{enabled:a,displayName:o}]of Object.entries(t.tools||{}))a===!1&&(P[`/${e}`]=o);for(const{id:e,href:a}of t.css||[])if(!document.getElementById(e)){const o=document.createElement("link");o.id=e,o.rel="stylesheet",o.href=a,document.head.appendChild(o)}}catch{}}function F(){const t=x();if(!t)return;if($("#topbar-user-name").length){L(r);return}const e={"super-admin":"Super Admin",admin:"Admin",user:"User"}[t.role]||t.role,a=ut(t);$("#topbar-user").get(0).innerHTML=`
|
|
2
|
+
<a id="topbar-project" class="topbar-action-link topbar-project" hidden>
|
|
3
|
+
<span data-icon="folder"></span>
|
|
4
|
+
<span id="topbar-project-name" class="topbar-project-name"></span>
|
|
5
|
+
</a>
|
|
6
|
+
<div id="topbar-versions-menu" class="topbar-account">
|
|
7
|
+
<button type="button" class="topbar-action-link" aria-label="Versions and layout" aria-expanded="false" aria-controls="topbar-versions-panel">
|
|
8
|
+
<span data-icon="layers"></span><span class="topbar-action-label">Versions</span><span data-icon="chevron-down"></span>
|
|
9
|
+
</button>
|
|
10
|
+
<div id="topbar-versions-panel" class="topbar-account-menu topbar-versions-panel" hidden>
|
|
11
|
+
<div class="topbar-versions" aria-label="Domma versions">
|
|
12
|
+
<span class="topbar-version-item" hidden>Domma Reactive <span id="topbar-reactive-version" class="topbar-version-badge"></span></span>
|
|
13
|
+
<span class="topbar-version-item" hidden>Domma JS <span id="topbar-js-version" class="topbar-version-badge"></span></span>
|
|
14
|
+
<span class="topbar-version-item" hidden>Domma CMS <span id="topbar-cms-version" class="topbar-version-badge"></span></span>
|
|
15
|
+
</div>
|
|
16
|
+
<label class="topbar-sidebar-choice"><input type="checkbox" id="topbar-show-sidebar"> Show side admin menu</label>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
`,$("#topbar-actions").get(0).innerHTML=`
|
|
6
20
|
<a href="#/system/notifications" id="topbar-bell" class="topbar-action-link" data-tooltip="Notifications" data-tooltip-placement="bottom" hidden>
|
|
7
21
|
<span data-icon="bell"></span>
|
|
8
22
|
<span class="topbar-action-label">Notifications</span>
|
|
9
23
|
<span id="topbar-bell-badge" class="topbar-bell-badge" hidden></span>
|
|
10
24
|
</a>
|
|
25
|
+
<div id="topbar-account" class="topbar-account">
|
|
26
|
+
<button type="button" class="topbar-action-link" aria-label="Account menu" aria-expanded="false" aria-controls="topbar-account-menu">
|
|
27
|
+
<span id="topbar-account-avatar" class="topbar-account-avatar" aria-hidden="true"></span><span class="topbar-action-label">Account</span><span data-icon="chevron-down"></span>
|
|
28
|
+
</button>
|
|
29
|
+
<div id="topbar-account-menu" class="topbar-account-menu" hidden>
|
|
30
|
+
<div class="topbar-account-identity">
|
|
31
|
+
${a?`<img id="topbar-avatar" class="topbar-avatar" src="${d(a)}" alt="">`:""}
|
|
32
|
+
<span id="topbar-user-name" class="topbar-user-name">${d(t.name)}</span>
|
|
33
|
+
<span class="topbar-role-badge topbar-role-badge--${d(t.role)}">${d(e)}</span>
|
|
34
|
+
</div>
|
|
11
35
|
<a href="#/my-profile" class="topbar-action-link" data-tooltip="My Profile" data-tooltip-placement="bottom">
|
|
12
36
|
<span data-icon="user"></span>
|
|
13
|
-
<span
|
|
37
|
+
<span>My Profile</span>
|
|
14
38
|
</a>
|
|
15
39
|
<a href="#/settings" id="topbar-settings" class="topbar-action-link" data-tooltip="Settings" data-tooltip-placement="bottom" hidden>
|
|
16
40
|
<span data-icon="settings"></span>
|
|
17
|
-
<span
|
|
41
|
+
<span>Settings</span>
|
|
18
42
|
</a>
|
|
19
43
|
<a href="#" id="topbar-logout-btn" class="topbar-action-link topbar-signout" data-tooltip="Sign out" data-tooltip-placement="bottom">
|
|
20
44
|
<span data-icon="log-out"></span>
|
|
21
|
-
<span
|
|
45
|
+
<span>Sign out</span>
|
|
22
46
|
</a>
|
|
23
|
-
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
`;const o=$("#topbar-bell").get(0);o&&(o.hidden=!0);const n=$("#topbar-settings").get(0);n&&(n.hidden=!w),$("#topbar-logout-btn").on("click",s=>{s.preventDefault(),X()}),Domma.icons.scan("#admin-topbar"),E.tooltip("#topbar-actions [data-tooltip]",{placement:"bottom"}),rt(t),ht(t),_(),nt(),L(r),O(),u||(u=setInterval(O,6e4))}function d(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}let u=null;async function O(){if(!(!m()||g===!1))try{const{count:t}=await r.system.notifications.unreadCount();$("#topbar-bell").removeAttr("hidden");const i=$("#topbar-bell-badge");t>0?i.text(t>99?"99+":String(t)).removeAttr("hidden"):i.attr("hidden","").text(""),t>0&&pt()&&mt(await r.system.notifications.list().catch(()=>[]))}catch{}}(async()=>{if(!m()&&!window.location.hash.startsWith("#/reset-password"))window.location.hash.startsWith("#/login")||(window.location.hash=et(window.location.hash));else if(tt(x()?.id),await T(),x()){const o=await f(),n=(window.location.hash||"#/").slice(1)||"/",s=D(n);s&&(window.location.hash=`#${s}`),await j(o),F()}const t=R._extractParams.bind(R);R._extractParams=function(a,o){const n=o.indexOf("?");if(n!==-1&&(o=o.slice(0,n)),a.endsWith("/*")){const s=a.slice(0,-2);return o.startsWith(s+"/")?{}:null}return t(a,o)};const i=R._renderNotFound.bind(R);let e="";R._renderNotFound=async function(a){return m()&&e!==a&&(e=a,await T(),R._matchRoute(a).route)?(e="",R._handleRouteChange()):(e="",m()&&$("#admin-sidebar").get(0)?.style.display==="none"?(E.toast("That link goes nowhere - here is your home page.",{type:"warning"}),R.navigate("/")):i(a))},vt(R),R.init({container:"#view-container",routes:I,views:l,default:"/",transitions:{enter:"fadeIn",leave:"fadeOut",duration:150}})})()});
|
package/admin/js/lib/avatar.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
import{initials as o}from"./users-arrange.js";const u=/^\/api\/auth\/avatar\/[A-Za-z0-9_-]{1,80}-[a-f0-9]{16}\.webp$/;export function avatarUrl(a){const e=String(a?.avatar||"");return u.test(e)?e:""}export function showTopbarAvatar(a){try{S.set("auth_user",{...S.get("auth_user")||{},avatar:a})}catch{}const e=document.getElementById("topbar-user-name");if(!e)return;let t=document.getElementById("topbar-avatar");if(!a){t?.remove();return}t||(t=document.createElement("img"),t.id="topbar-avatar",t.className="topbar-avatar",t.alt="",e.before(t)),t.src=a}let c;export function installAccountAvatar(a){const e=()=>{let r=a;try{r=S.get("auth_user")||a}catch{}renderAccountAvatar(r)};e(),c?.disconnect();const t=document.querySelector(".topbar-account-identity");t&&(c=new MutationObserver(e),c.observe(t,{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:["src"]}))}export function renderAccountAvatar(a){const e=document.getElementById("topbar-account-avatar");if(!e)return;const t=o(a),r=avatarUrl(a);if(!r){e.textContent=t;return}const n=document.createElement("img");n.className="topbar-avatar",n.alt="",n.addEventListener("error",()=>{e.textContent=t},{once:!0}),n.src=r,e.replaceChildren(n)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{renderTopbarNavigation as y,updateTopbarCounts as h}from"./topbar-navigation.js";export const COUNT_CACHE_MAX_AGE=5*6e4;const f=new Map,u=new Map;let a;export function countCacheKey(o,r,t,c=[]){const n=[],s=e=>{if(e){e.url&&e.countUrl&&n.push([e.url,e.countUrl,!!e.inventory]);for(const i of[...e.items||[],...e.children||[]])s(i)}};return c.forEach(e=>s(e.item||e)),"admin.counts.v1."+JSON.stringify([o?.id||"",[...r].sort(),t,n.sort()])}export function readCountCache(o,r=Date.now()){let t=f.get(o);if(!t)try{t=JSON.parse(sessionStorage.getItem(o))}catch{}return!t||!Number.isFinite(t.at)||r<t.at||r-t.at>COUNT_CACHE_MAX_AGE||!t.counts||typeof t.counts!="object"||Array.isArray(t.counts)?null:t.counts}export function writeCountCache(o,r,t=Date.now()){const c={};for(const[s,e]of Object.entries(r))!e||!Number.isFinite(e.count)||e.count<0||(c[s]={count:e.count,label:String(e.label||""),tone:e.tone||"info",showZero:e.showZero===!0,inventory:e.inventory===!0});const n={at:t,counts:c};f.set(o,n);try{sessionStorage.setItem(o,JSON.stringify(n))}catch{}}export function loadCountSnapshot(o,r){return u.has(o)||u.set(o,Promise.resolve().then(r).then(t=>(writeCountCache(o,t),t)).finally(()=>u.delete(o))),u.get(o)}export function countSnapshot(o,r){const t=new Map,c=n=>{if(n){n.url&&n.countUrl&&t.set(n.url,!!n.inventory);for(const s of[...n.items||[],...n.children||[]])c(s)}};return r.forEach(n=>c(n.item||n)),Object.fromEntries(Object.entries(o).map(([n,s])=>[n,s?{...s,aggregate:t.has(n)&&!t.get(n)&&!s.inventory}:null]))}export async function beginSidebarCounts({user:o,permissions:r,adminScope:t,registered:c,tree:n,actions:s,fetcher:e}){const i={key:countCacheKey(o,r,t,c),registered:c};a=i;const l=readCountCache(i.key)||{};y(n,{...s,counts:countSnapshot(l,c)});try{const p=await loadCountSnapshot(i.key,e);return a===i&&h(countSnapshot(p,c),{replace:!0}),p}catch{return l}}export function publishSidebarCount(o,r){if(!a)return;h(countSnapshot({[o]:r},a.registered));const t=readCountCache(a.key)||{};r?t[o]=r:delete t[o];const c=f.get(a.key)?.at||Date.now();writeCountCache(a.key,t,c)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{api as
|
|
1
|
+
import{api as h,getUser as F}from"../api.js";import{beginSidebarCounts as ye,publishSidebarCount as ve}from"./sidebar-count-cache.js";import{isPathAllowed as xe}from"./admin-scope.js";import{colourToCss as J,applyFloat as $e,applyHighlight as we,itemHighlightAttrs as Se}from"/public/js/menu-decor.mjs?v=20261014-menu-entrance";import{placeTools as ke,ensureLockedTools as Ce,managePluginsItem as qe,stripItemByUrl as Ae,insertFoldersBeforeSystem as Fe,pruneEmptyToolsFolder as Le,sidebarStateKey as Q,canAny as z,filterByPermission as Ee,MANAGE_PLUGINS_URL as ee}from"./sidebar-grouping.js";import{arrangeButtonMarkup as Be,canArrange as Me,startArrange as Te}from"./sidebar-arrange.js";import{collapseButtonMarkup as He,wireSidebarSize as je,COLLAPSED_WIDTH as Ne}from"./sidebar-size.js";import{FREQUENT_MAX as te,addFrequent as Oe,frequentFolder as Pe,moveFrequent as ne,readFrequent as G,readFrequentHidden as Ie,removeFrequent as Re,saveFrequent as _e,syncFrequent as Ue,writeFrequent as ze,writeFrequentHidden as se}from"./sidebar-frequent.js";import{hotkeyFor as oe,hotkeyTitle as We,setHotkeyTree as De}from"./hotkeys-ui.js";import{hotkeyLabel as Ge}from"./hotkeys.js";function f(e){return String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const Ke=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Site menus",url:"#/menus",icon:"menu",permission:"menus"}];async function Ve(e){if(!z(e,"projects"))return[];let t=[];try{t=await h.projects.listWithCounts()}catch{return[]}if(!Array.isArray(t))return[];const s=[{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:"Site 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 t.map(o=>{const d="#/projects/"+encodeURIComponent(o.slug),i=o.counts||{},l=[{text:"Overview",url:d,icon:o.icon||"folder"}];for(const a of s){const r=Number(i[a.key])||0;r<=0||l.push({text:`${a.text} (${r})`,url:d+a.path,icon:a.icon})}l.push({text:"Settings",url:d+"/settings",icon:"settings"});const u=o.enabled===!1;return{text:o.name||o.slug,key:`project.${o.slug}`,icon:o.icon||"folder",items:l,...u&&{colour:"neutral",badge:{text:"off"}}}})}function Xe(e,t){for(const s of e)if(!s.hidden&&(s.key==="projects"||!s.key&&(s.text||"").toLowerCase()==="projects")){s.items=Array.isArray(s.items)?s.items.slice():[],s.items.push(...t);return}}function ie(e,t){const s=re.includes(t.tone)?t.tone:"info",o=t.label||String(t.count);t.details?I.set(e,t.details):I.delete(e);const n=!t.inventory&&L.some(d=>d.url===e&&!d.inventory)?" data-live":"";return`<span class="sidebar-badge sidebar-badge--${s}" data-count-for="${f(e)}"${n} data-badge-label="${f(o)}" aria-label="${f(o)}">${f(String(t.count))}</span>`}function ae(e){for(const t of e.querySelectorAll("details")){const s=t.querySelector(":scope > summary");if(!s)continue;let o=0,n=!1;const d=[];for(const r of t.querySelectorAll(":scope > .sidebar-children .sidebar-badge[data-live]")){const m=Number(r.textContent)||0;m&&(o+=m,n||(n=r.classList.contains("sidebar-badge--danger")),d.push({text:r.closest("a")?.querySelector(".sidebar-text")?.textContent.trim()??"",meta:r.dataset.badgeLabel,tone:r.classList.contains("sidebar-badge--danger")?"danger":void 0}))}const i=`folder:${t.dataset.stateKey||s.textContent.trim()}`;let l=s.querySelector(":scope > .sidebar-badge--sum");if(!o){l?.remove(),I.delete(i);continue}l||(l=document.createElement("span"),s.querySelector(".sidebar-text")?.after(l));const u=s.querySelector(".sidebar-text")?.textContent.trim()||"This folder",a=d.map(r=>`${r.text}: ${r.meta}`).join(" \xB7 ");l.className=`sidebar-badge sidebar-badge--sum sidebar-badge--${n?"danger":"info"}`,l.dataset.countFor=i,l.dataset.badgeLabel=a,l.setAttribute("aria-label",a),l.textContent=String(o),I.set(i,{title:u,items:d})}}const I=new Map;function Ze(e,t){if(!e.url||!t)return"";const s=t[e.url];return!s||!(s.count>0)&&!s.showZero?"":ie(e.url,s)}const re=["info","attention","danger","live"],Ye={"#/pages":["page","pages"],"#/media":["file in the media library","files in the media library"],"#/menus":["menu","menus"],"#/context-menus":["context menu","context menus"],"#/theme":["element override in the theme","element overrides in the theme"],"#/collections":["collection","collections"],"#/forms":["form","forms"],"#/views":["view","views"],"#/actions":["action","actions"],"#/blocks":["block","blocks"],"#/components":["component","components"],"#/users":["user","users"],"#/plugins":["plugin installed","plugins installed"],"#/system/notifications":["unread notification","unread notifications"]};function K(e,{fallbackLabel:t="",tone:s="info"}={}){const o=Number(typeof e=="object"&&e!==null?e.count:e);if(!Number.isFinite(o)||o<0)return null;const n=typeof e?.label=="string"&&e.label||(t?`${o} - ${t}`:String(o)),d={count:Math.round(o),label:n,tone:re.includes(e?.tone)?e.tone:s};return e?.details&&typeof e.details=="object"&&(d.details=e.details),e?.inventory===!0&&(d.inventory=!0),e?.showZero===!0&&(d.showZero=!0),d}function le(e,t,s=null,{inFrequent:o=!1}={}){if(e&&e.type==="separator")return'<hr class="sidebar-divider">';if(e&&e.type==="theme-switcher")return"";if(e&&e.type==="spacer"){const b=["xs","sm","md","lg","xl","flex"].includes(e.size)?e.size:"md";return`<div class="sidebar-spacer sidebar-spacer--${f(b)}" aria-hidden="true"></div>`}const n=String(e.text||"?").trim().charAt(0).toUpperCase()||"?",d=e.icon?`<span data-icon="${f(e.icon)}"></span>`:`<span class="sidebar-initial" aria-hidden="true">${f(n)}</span>`,i=f(e.text||""),l=e.url?f(e.url):"",u=Array.isArray(e.items)&&e.items.length>0,a=e.colour?J(e.colour):"",r=Se(e),m=[r.hover&&` data-menu-item-hover="${f(r.hover)}"`,r.active&&` data-menu-item-active="${f(r.active)}"`].filter(Boolean).join(""),y=[a&&`color:${f(a)}`,r.accent&&`--dm-menu-highlight:${f(r.accent)}`].filter(Boolean).join(";"),v=y?` style="${y}"`:"",w=e.url?We(e.url,e.text||"",{inFrequent:o}):"",k=w?` title="${f(w)}"`:"";let q="";if(e.badge&&e.badge.text!=null&&e.badge.text!==""){const b=e.badge.variant?J(e.badge.variant):"";q=`<span class="dm-menu-badge"${b?` style="background:${f(b)};color:var(--dm-text-inverse,#fff)"`:""}>${f(String(e.badge.text))}</span>`}if(e.frequent&&e.empty){const b=Q(e,s),A=S.get(b)!==!1;return`<details data-state-key="${f(b)}"${A?" open":""} data-frequent data-frequent-empty>
|
|
2
2
|
<summary${v}>${d} <span class="sidebar-text">${i}</span></summary>
|
|
3
3
|
<div class="sidebar-children"><p class="sidebar-frequent-empty">Right-click any Tool and choose <strong>Add to Frequent</strong> to keep it here.</p></div>
|
|
4
|
-
</details>`}if(u){const
|
|
5
|
-
<summary${v}${k}>${d} <span class="sidebar-text">${i}</span>${
|
|
4
|
+
</details>`}if(u){const b=Q(e,s),A=S.get(b)!==!1,B=e.items.map(N=>le(N,t,b,{inFrequent:!!e.frequent})).join(""),j=e.frequent?' data-frequent title="Your Frequent Tools - right-click any Tool to add or remove it"':"";return`<details data-state-key="${f(b)}"${A?" open":""}${j}>
|
|
5
|
+
<summary${v}${k}>${d} <span class="sidebar-text">${i}</span>${q}</summary>
|
|
6
6
|
<div class="sidebar-children">${B}</div>
|
|
7
|
-
</details>`}return`<a href="${c}" class="sidebar-link" data-url="${c}"${v}${m}${k}>${d} <span class="sidebar-text">${i}</span>${De(e,t)}${A}</a>`}async function Ke(e=[],t=[],s=null){const o=p=>p.then(x=>Array.isArray(x)?x.length:Array.isArray(x?.entries)?x.entries.length:0).catch(()=>0);F=Ze(e,s);const n=new Set(F.map(p=>p.url)),d={pages:"#/pages",media:"#/media",menus:"#/menus","context-menus":"#/context-menus",theme:"#/theme",collections:"#/collections",forms:"#/forms",views:"#/views",actions:"#/actions",blocks:"#/blocks",components:"#/components",users:"#/users",plugins:"#/plugins",notifications:"#/system/notifications"},i=(p,x)=>z(t,p)&&!n.has(d[p])?x():Promise.resolve(0),[c,u,r,a,m,b,v,w,k,A,y,C,B,_]=await Promise.all([i("pages",()=>o(g.pages.list())),i("media",()=>o(g.media.list())),i("menus",()=>o(g.menus.list())),i("context-menus",()=>o(g.contextMenus.list())),i("theme",()=>g.theme.get().then(p=>(p?.overrides||[]).length).catch(()=>0)),i("collections",()=>o(g.collections.list())),i("forms",()=>o(g.forms.list())),i("views",()=>o(g.views.list())),i("actions",()=>o(g.actions.list())),i("blocks",()=>o(g.blocks.list())),i("components",()=>o(g.components.list())),i("users",()=>o(g.users.list())),i("plugins",()=>o(g.plugins.list())),i("notifications",()=>g.system?.notifications?.unreadCount?.().then(p=>p?.count??0).catch(()=>0)??Promise.resolve(0))]),L={};await Promise.all(F.map(async p=>{const x=await ce(p);x&&(L[p.url]=x)}));const O={"#/pages":c,"#/media":u,"#/menus":r,"#/context-menus":a,"#/theme":m,"#/collections":b,"#/forms":v,"#/views":w,"#/actions":k,"#/blocks":A,"#/components":y,"#/users":C,"#/plugins":B,"#/system/notifications":_},W={};for(const[p,x]of Object.entries(O)){if(n.has(p))continue;const[D,U]=Ge[p]??["item","items"],j=K(x);j&&(W[p]={...j,label:`${j.count} ${j.count===1?D:U}`})}return{...W,...L}}let F=[];const Ve="dm:sidebar-count",Xe=6e4;function Ze(e=[],t=null){const s=[],o=n=>{if(n&&!(t&&typeof n.url=="string"&&n.url.startsWith("#/")&&!he(t,n.url.slice(1)))){n.url&&typeof n.countUrl=="string"&&n.countUrl&&s.push({url:n.url,countUrl:n.countUrl,text:n.text||"",countLabel:n.countLabel||"",inventory:n.inventory===!0});for(const d of[...n.children||[],...n.items||[]])o(d)}};for(const n of e??[])o(n?.item??n);return s}async function ce(e){try{const t=new Date,s=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,o=e.countUrl+(e.countUrl.includes("?")?"&":"?")+`today=${s}`;return K(await H.get(o),{fallbackLabel:e.countLabel||e.text})}catch{return null}}function de(e,t,s){const o=[...e.querySelectorAll("a.sidebar-link")].filter(n=>n.dataset.url===t);if(o.length){for(const n of o){const d=n.querySelector(".sidebar-badge[data-count-for]");if(!s||!(s.count>0)&&!s.showZero)d?.remove();else{const i=document.createRange();i.selectNodeContents(n);const c=i.createContextualFragment(ie(t,s)).firstElementChild;d?d.replaceWith(c):n.querySelector(".sidebar-text")?.after(c)}}V.set(t,s),ae(e)}}const V=new Map;async function X(e,t=null){const s=t?F.filter(o=>o.url===t):F;await Promise.all(s.map(async o=>{const n=await ce(o),d=V.get(o.url);JSON.stringify(d??null)!==JSON.stringify(n)&&de(e,o.url,n)}))}function Ye(e){e.dataset.liveCounts||(e.dataset.liveCounts="1",window.addEventListener(Ve,t=>{const s=t.detail||{};if(s.url)if(s.count!==void 0){const o=F.find(n=>n.url===s.url);de(e,s.url,K(s,{fallbackLabel:o?.countLabel||o?.text||""}))}else X(e,s.url)}),setInterval(()=>{!document.hidden&&document.body.contains(e)&&X(e)},Xe),document.addEventListener("visibilitychange",()=>{document.hidden||X(e)}),Je(e))}function ue(e,t,s){const o=(i,c,u)=>{const r=document.createElement(i);return c&&(r.className=c),u!=null&&(r.textContent=String(u)),r};if(!s){e.textContent=t;return}e.appendChild(o("strong","dm-badge-pop-title",s.title||t)),(s.rows?.length||!s.items?.length)&&e.appendChild(o("p","dm-badge-pop-sub",t));const n=Array.isArray(s.rows)?s.rows.slice(0,6):[];if(n.length){const i=o("dl","dm-badge-pop-rows");for(const c of n)i.appendChild(o("dt",null,c.label)),i.appendChild(o("dd",c.tone==="danger"?"is-danger":null,c.value));e.appendChild(i)}const d=Array.isArray(s.items)?s.items.slice(0,6):[];if(d.length){const i=o("ul","dm-badge-pop-items");for(const c of d){const u=o("li",c.tone==="danger"?"is-danger":null);u.appendChild(o("span","dm-badge-pop-text",c.text)),c.meta&&u.appendChild(o("span","dm-badge-pop-meta",c.meta)),i.appendChild(u)}e.appendChild(i)}else s.empty&&e.appendChild(o("p","dm-badge-pop-empty",s.empty))}function Je(e){let t=null,s=null;const o=()=>e.classList.contains("is-collapsed"),n=()=>{clearTimeout(s),t?.remove(),t=null},d=(r,a)=>{n(),s=setTimeout(()=>{t=document.createElement("div"),t.className="dm-help-pop dm-badge-pop",t.setAttribute("role","tooltip"),a(t),document.body.appendChild(t);const m=r.getBoundingClientRect(),b=t.getBoundingClientRect(),v=Math.min(m.right+10,innerWidth-b.width-8);t.style.left=`${Math.max(8,v)}px`,t.style.top=`${Math.max(8,Math.min(m.top+m.height/2-b.height/2,innerHeight-b.height-8))}px`},150)},i=r=>{const a=r?.dataset.badgeLabel;if(!a)return n();d(r,m=>ue(m,a,R.get(r.dataset.countFor)))},c=r=>{const a=r.querySelector(":scope > .sidebar-text")?.textContent.trim()||"",m=r.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");d(r,b=>{const v=m&&R.get(m.dataset.countFor);if(v)return ue(b,m.dataset.badgeLabel,{...v,title:v.title||a});if(!m){b.textContent=a;return}const w=document.createElement("strong");w.className="dm-badge-pop-title",w.textContent=a;const k=document.createElement("p");k.className="dm-badge-pop-sub",k.textContent=m.dataset.badgeLabel,b.append(w,k)})},u=r=>{const a=r.closest?.("a.sidebar-link, summary");return a&&e.contains(a)?a:null};e.addEventListener("mouseover",r=>{if(o()){const m=u(r.target);m&&!m.contains(r.relatedTarget)&&c(m);return}const a=r.target.closest?.(".sidebar-badge[data-badge-label]");a&&i(a)}),e.addEventListener("mouseout",r=>{if(o()){const a=u(r.target);a&&!a.contains(r.relatedTarget)&&n();return}r.target.closest?.(".sidebar-badge[data-badge-label]")&&n()}),e.addEventListener("focusin",r=>{const a=r.target.closest?.("a, summary");if(o()&&a&&e.contains(a)&&a.querySelector(":scope > .sidebar-text"))return c(a);const m=a?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");m?i(m):n()}),e.addEventListener("focusout",n),e.addEventListener("click",n),window.addEventListener("scroll",n,!0),window.addEventListener("hashchange",n)}async function Qe(e=[],t=null){if(t?.title)return t;if(!z(e,"settings"))return{title:"Domma CMS"};try{const s=await g.settings.get();return{...s?.adminBrand,title:s?.adminBrand?.title||s?.title||"Domma CMS"}}catch{return{title:"Domma CMS"}}}export async function renderAdminSidebar({mount:e,permissions:t,adminScope:s=null,brand:o=null}){const n=$(e).get(0);if(!n)return;const d=Pe(g,T()).catch(()=>{});let i,c=null,u=null,r=null,a=null,m=null;try{const l=await g.get("/sidebar/menu");i=Array.isArray(l?.items)?l.items:null,c=l?.variant||null,u=l?.position||null,r=l?.style||null,a=l?.float||null,m=l?.highlight||null}catch{i=null}(!i||!i.some(l=>l&&(!l.hidden||l.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),i=Ue.slice());let b=[];try{b=await H.get("/api/sidebar/registered-items")||[]}catch{}i=we(i,ee),i=ve(i,b.filter(l=>(l?.item??l)?.url!==ee)),i=xe(i),i=Se(i,[$e()]);const v=await ze(t);v.length&&We(i,v),i=qe(i,t,s),i=ke(i),await d;const w=Be(i,G(T()),{hidden:He(T())});w&&(i=[w,...i]),Ie(i);const[k,A]=await Promise.all([Ke(b.filter(l=>z(t,l?.item?.permission)),t,s).catch(()=>({})),Qe(t,o)]),y=c?` dm-admin-sidebar--${f(c)}`:"";function C(l,q="px"){if(l==null)return l;const h=String(l).trim();return/^\d+(\.\d+)?$/.test(h)?`${h}${q}`:h}let B="";if(r){const l=[];r.fontFamily&&l.push(`font-family: ${r.fontFamily}, sans-serif`),r.fontSize&&l.push(`font-size: ${C(r.fontSize)}`),r.fontWeight&&l.push(`font-weight: ${r.fontWeight}`),r.letterSpacing&&l.push(`letter-spacing: ${C(r.letterSpacing,"em")}`);const q=[];if(l.length&&q.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 { ${l.join("; ")} }`),r.iconSize){const h=C(r.iconSize);q.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${h} !important; height: ${h} !important; }`)}q.length&&(B=`<style data-admin-sidebar-style>${q.join(" ")}</style>`)}const _=Ae(t)?Ce():"",L=String(A.logo||"").trim(),O=/^(?:\/(?!\/)|https?:\/\/)/i.test(L)?L:"",p=`<div class="dm-admin-sidebar-header">${O?`<img src="${f(O)}" alt="" style="width:28px;height:28px;object-fit:contain;flex-shrink:0;">`:`<span data-icon="${f(A.icon||"layout")}"></span>`}<span class="dm-admin-sidebar-title">${f(A.title)}</span>${_}${Le()}</div>`,x=i.some(l=>l&&l.type==="spacer"&&l.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",D=`${B}<nav class="dm-admin-sidebar${y}${x}">${p}${i.map(l=>le(l,k)).join("")}</nav>`,U=document.createRange();U.selectNodeContents(n);const j=U.createContextualFragment(D);n.replaceChildren(j),Domma.icons.scan(n),n.querySelector(".dm-admin-sidebar-arrange")?.addEventListener("click",()=>Fe(n));for(const l of F)V.set(l.url,k[l.url]??null);ae(n),Ye(n),n.removeAttribute("data-menu-hover"),n.removeAttribute("data-menu-active"),n.style.removeProperty("--dm-menu-highlight"),be(n,{highlight:m});const N=document.querySelector(".dashboard-wrapper");["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(l=>{n.style[l]=""}),n.classList.remove("dm-menu-floating"),N&&(N.style.paddingLeft="",N.style.paddingRight=""),n.__dmGutter=()=>{if(u!=="floating"||!N)return;const l=a&&a.anchor||"TL",q=Number.isFinite(Number(a?.offsetX))?Number(a.offsetX):16,h=n.classList.contains("is-collapsed")?Me:parseInt(n.style.width,10)||n.getBoundingClientRect().width||260,P=Math.round(h+q*2)+"px";l==="R"||l==="TR"||l==="BR"?N.style.paddingRight=P:N.style.paddingLeft=P},u==="floating"&&ge(n,{position:"floating",float:a||{}}),n.querySelectorAll("details").forEach(l=>{l.addEventListener("toggle",function(){const q=this.getAttribute("data-state-key");q&&S.set(q,this.open);const h=this.querySelector(":scope > .sidebar-children");if(h)if(this.open){const P=h.scrollHeight;h.style.maxHeight="0",requestAnimationFrame(()=>{h.style.maxHeight=P+"px",h.addEventListener("transitionend",function pe(){h.style.maxHeight="none",h.removeEventListener("transitionend",pe)})})}else{const P=h.scrollHeight;h.style.maxHeight=P+"px",requestAnimationFrame(()=>{h.style.maxHeight="0"})}})}),Ee(n),st(n),n.dataset.routeWired||(n.dataset.routeWired="1",M.subscribe("router:afterChange",()=>n.__dmSetActive?.()));function Y(){const l=/^#\/(dashboards|my-dashboard)\b/.test(location.hash)?"#/":location.hash||"#/";$(n).find(".sidebar-link").removeClass("active"),$(n).find(`.sidebar-link[data-url="${l}"]`).addClass("active")}Y(),n.__dmSetActive=Y}function me(){try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}function Z(e){return`${location.origin}${location.pathname}${e}`}function I(e,t){const s=T(),o=e(G(s));if(!Re(s,o)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}o.length&&se(s,!1),fe(s),t&&E.toast(t,{type:"success",duration:2500}),me()}function fe(e){Ne(g,e).catch(()=>E.toast("Frequent is saved in this browser only - the server could not keep it.",{type:"warning"}))}function et(e){if(!se(T(),e)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}fe(T()),E.toast(e?"Frequent hidden. Add a Tool to it from its right-click menu to bring it back.":"Frequent shown.",{type:"success",duration:3500}),me()}function tt(e){const t=e.dataset.url;if(!t)return[];const s=e.querySelector(".sidebar-text")?.textContent.trim()||t,o=G(T()),n=o.includes(t),d=!!e.closest("details[data-frequent]"),i=o.indexOf(t),c=!n&&o.length>=te;return[{header:s},{label:"Open",icon:"arrow-right",...oe(t)&&{shortcut:Oe(oe(t))},action:()=>{location.hash=t}},{label:"Open in a new tab",icon:"external-link",action:()=>window.open(Z(t),"_blank","noopener")},{type:"divider"},n?{label:"Remove from Frequent",icon:"star",action:()=>I(u=>je(u,t),`${s} removed from Frequent.`)}:{label:c?`Frequent is full (${te})`:"Add to Frequent",icon:"star",disabled:c,action:()=>I(u=>Te(u,t),`${s} added to Frequent.`)},...d?[{label:"Move up",icon:"arrow-up",disabled:i<=0,action:()=>I(u=>ne(u,t,-1))},{label:"Move down",icon:"arrow-down",disabled:i<0||i>=o.length-1,action:()=>I(u=>ne(u,t,1))}]:[],{type:"divider"},{label:"Copy link",icon:"link",action:async()=>{try{await navigator.clipboard.writeText(Z(t)),E.toast("Link copied.",{type:"success",duration:2e3})}catch{E.toast(Z(t),{type:"info",duration:8e3})}}}]}function nt(e,t){const s=e.closest("details"),o=e.querySelector(".sidebar-text")?.textContent.trim()||"Folder",n=d=>t.querySelectorAll("details").forEach(i=>{i.open!==d&&(i.open=d)});return[{header:o},{label:s?.open?"Close":"Open",icon:s?.open?"chevron-up":"chevron-down",action:()=>{s&&(s.open=!s.open)}},{label:"Open every folder",icon:"chevrons-down",action:()=>n(!0)},{label:"Close every folder",icon:"chevrons-up",action:()=>n(!1)},...s?.hasAttribute("data-frequent-empty")?[{type:"divider"},{label:"Hide Frequent until I add a Tool",icon:"eye-off",action:()=>et(!0)}]:s?.hasAttribute("data-frequent")?[{type:"divider"},{label:"Clear Frequent",icon:"x",action:()=>I(()=>[],"Frequent cleared.")}]:[]]}function st(e){e.dataset.ctxWired||typeof E>"u"||!E.contextMenu||(e.dataset.ctxWired="1",E.contextMenu(e,{match:"a.sidebar-link, details > summary",inherit:!1,density:"compact",items:t=>t.matches("summary")?nt(t,e):tt(t)}))}
|
|
7
|
+
</details>`}return`<a href="${l}" class="sidebar-link" data-url="${l}"${v}${m}${k}>${d} <span class="sidebar-text">${i}</span>${Ze(e,t)}${q}</a>`}async function Je(e=[],t=[],s=null){const o=g=>g.then(x=>Array.isArray(x)?x.length:Array.isArray(x?.entries)?x.entries.length:0).catch(()=>0);L=tt(e,s);const n=new Set(L.map(g=>g.url)),d={pages:"#/pages",media:"#/media",menus:"#/menus","context-menus":"#/context-menus",theme:"#/theme",collections:"#/collections",forms:"#/forms",views:"#/views",actions:"#/actions",blocks:"#/blocks",components:"#/components",users:"#/users",plugins:"#/plugins",notifications:"#/system/notifications"},i=(g,x)=>z(t,g)&&!n.has(d[g])?x():Promise.resolve(0),[l,u,a,r,m,y,v,w,k,q,b,A,B,j]=await Promise.all([i("pages",()=>o(h.pages.list())),i("media",()=>o(h.media.list())),i("menus",()=>o(h.menus.list())),i("context-menus",()=>o(h.contextMenus.list())),i("theme",()=>h.theme.get().then(g=>(g?.overrides||[]).length).catch(()=>0)),i("collections",()=>o(h.collections.list())),i("forms",()=>o(h.forms.list())),i("views",()=>o(h.views.list())),i("actions",()=>o(h.actions.list())),i("blocks",()=>o(h.blocks.list())),i("components",()=>o(h.components.list())),i("users",()=>o(h.users.list())),i("plugins",()=>o(h.plugins.list())),i("notifications",()=>h.system?.notifications?.unreadCount?.().then(g=>g?.count??0).catch(()=>0)??Promise.resolve(0))]),N={};await Promise.all(L.map(async g=>{const x=await ce(g);x&&(N[g.url]=x)}));const U={"#/pages":l,"#/media":u,"#/menus":a,"#/context-menus":r,"#/theme":m,"#/collections":y,"#/forms":v,"#/views":w,"#/actions":k,"#/blocks":q,"#/components":b,"#/users":A,"#/plugins":B,"#/system/notifications":j},R={};for(const[g,x]of Object.entries(U)){if(n.has(g))continue;const[W,D]=Ye[g]??["item","items"],T=K(x);T&&(R[g]={...T,label:`${T.count} ${T.count===1?W:D}`})}return{...R,...N}}let L=[];const Qe="dm:sidebar-count",et=6e4;function tt(e=[],t=null){const s=[],o=n=>{if(n&&!(t&&typeof n.url=="string"&&n.url.startsWith("#/")&&!xe(t,n.url.slice(1)))){n.url&&typeof n.countUrl=="string"&&n.countUrl&&s.push({url:n.url,countUrl:n.countUrl,text:n.text||"",countLabel:n.countLabel||"",inventory:n.inventory===!0});for(const d of[...n.children||[],...n.items||[]])o(d)}};for(const n of e??[])o(n?.item??n);return s}async function ce(e){try{const t=new Date,s=`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`,o=e.countUrl+(e.countUrl.includes("?")?"&":"?")+`today=${s}`;return K(await H.get(o),{fallbackLabel:e.countLabel||e.text})}catch{return null}}function de(e,t,s){ve(t,s);const o=[...e.querySelectorAll("a.sidebar-link")].filter(n=>n.dataset.url===t);if(o.length){for(const n of o){const d=n.querySelector(".sidebar-badge[data-count-for]");if(!s||!(s.count>0)&&!s.showZero)d?.remove();else{const i=document.createRange();i.selectNodeContents(n);const l=i.createContextualFragment(ie(t,s)).firstElementChild;d?d.replaceWith(l):n.querySelector(".sidebar-text")?.after(l)}}V.set(t,s),ae(e)}}const V=new Map;async function X(e,t=null){const s=t?L.filter(o=>o.url===t):L;await Promise.all(s.map(async o=>{const n=await ce(o),d=V.get(o.url);JSON.stringify(d??null)!==JSON.stringify(n)&&de(e,o.url,n)}))}function nt(e){e.dataset.liveCounts||(e.dataset.liveCounts="1",window.addEventListener(Qe,t=>{const s=t.detail||{};if(s.url)if(s.count!==void 0){const o=L.find(n=>n.url===s.url);de(e,s.url,K(s,{fallbackLabel:o?.countLabel||o?.text||""}))}else X(e,s.url)}),setInterval(()=>{!document.hidden&&document.body.contains(e)&&X(e)},et),document.addEventListener("visibilitychange",()=>{document.hidden||X(e)}),st(e))}function ue(e,t,s){const o=(i,l,u)=>{const a=document.createElement(i);return l&&(a.className=l),u!=null&&(a.textContent=String(u)),a};if(!s){e.textContent=t;return}e.appendChild(o("strong","dm-badge-pop-title",s.title||t)),(s.rows?.length||!s.items?.length)&&e.appendChild(o("p","dm-badge-pop-sub",t));const n=Array.isArray(s.rows)?s.rows.slice(0,6):[];if(n.length){const i=o("dl","dm-badge-pop-rows");for(const l of n)i.appendChild(o("dt",null,l.label)),i.appendChild(o("dd",l.tone==="danger"?"is-danger":null,l.value));e.appendChild(i)}const d=Array.isArray(s.items)?s.items.slice(0,6):[];if(d.length){const i=o("ul","dm-badge-pop-items");for(const l of d){const u=o("li",l.tone==="danger"?"is-danger":null);u.appendChild(o("span","dm-badge-pop-text",l.text)),l.meta&&u.appendChild(o("span","dm-badge-pop-meta",l.meta)),i.appendChild(u)}e.appendChild(i)}else s.empty&&e.appendChild(o("p","dm-badge-pop-empty",s.empty))}function st(e){let t=null,s=null;const o=()=>e.classList.contains("is-collapsed"),n=()=>{clearTimeout(s),t?.remove(),t=null},d=(a,r)=>{n(),s=setTimeout(()=>{t=document.createElement("div"),t.className="dm-help-pop dm-badge-pop",t.setAttribute("role","tooltip"),r(t),document.body.appendChild(t);const m=a.getBoundingClientRect(),y=t.getBoundingClientRect(),v=Math.min(m.right+10,innerWidth-y.width-8);t.style.left=`${Math.max(8,v)}px`,t.style.top=`${Math.max(8,Math.min(m.top+m.height/2-y.height/2,innerHeight-y.height-8))}px`},150)},i=a=>{const r=a?.dataset.badgeLabel;if(!r)return n();d(a,m=>ue(m,r,I.get(a.dataset.countFor)))},l=a=>{const r=a.querySelector(":scope > .sidebar-text")?.textContent.trim()||"",m=a.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");d(a,y=>{const v=m&&I.get(m.dataset.countFor);if(v)return ue(y,m.dataset.badgeLabel,{...v,title:v.title||r});if(!m){y.textContent=r;return}const w=document.createElement("strong");w.className="dm-badge-pop-title",w.textContent=r;const k=document.createElement("p");k.className="dm-badge-pop-sub",k.textContent=m.dataset.badgeLabel,y.append(w,k)})},u=a=>{const r=a.closest?.("a.sidebar-link, summary");return r&&e.contains(r)?r:null};e.addEventListener("mouseover",a=>{if(o()){const m=u(a.target);m&&!m.contains(a.relatedTarget)&&l(m);return}const r=a.target.closest?.(".sidebar-badge[data-badge-label]");r&&i(r)}),e.addEventListener("mouseout",a=>{if(o()){const r=u(a.target);r&&!r.contains(a.relatedTarget)&&n();return}a.target.closest?.(".sidebar-badge[data-badge-label]")&&n()}),e.addEventListener("focusin",a=>{const r=a.target.closest?.("a, summary");if(o()&&r&&e.contains(r)&&r.querySelector(":scope > .sidebar-text"))return l(r);const m=r?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");m?i(m):n()}),e.addEventListener("focusout",n),e.addEventListener("click",n),window.addEventListener("scroll",n,!0),window.addEventListener("hashchange",n)}async function ot(e=[],t=null){if(t?.title)return t;if(!z(e,"settings"))return{title:"Domma CMS"};try{const s=await h.settings.get();return{...s?.adminBrand,title:s?.adminBrand?.title||s?.title||"Domma CMS"}}catch{return{title:"Domma CMS"}}}export async function renderAdminSidebar({mount:e,permissions:t,adminScope:s=null,brand:o=null}){const n=$(e).get(0);if(!n)return;const d=Ue(h,F()).catch(()=>{});let i,l=null,u=null,a=null,r=null,m=null;try{const c=await h.get("/sidebar/menu");i=Array.isArray(c?.items)?c.items:null,l=c?.variant||null,u=c?.position||null,a=c?.style||null,r=c?.float||null,m=c?.highlight||null}catch{i=null}(!i||!i.some(c=>c&&(!c.hidden||c.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),i=Ke.slice());let y=[];try{y=await H.get("/api/sidebar/registered-items")||[]}catch{}i=Ae(i,ee),i=ke(i,y.filter(c=>(c?.item??c)?.url!==ee)),i=Ce(i),i=Fe(i,[qe()]);const v=await Ve(t);v.length&&Xe(i,v),i=Ee(i,t,s),i=Le(i),await d;const w=Pe(i,G(F()),{hidden:Ie(F())});w&&(i=[w,...i]),De(i);const k=y.filter(c=>z(t,c?.item?.permission)),[q,b]=await Promise.all([ye({user:F(),permissions:t,adminScope:s,registered:k,tree:i,actions:{linkItems:pe,folderItems:he},fetcher:()=>Je(k,t,s)}),ot(t,o)]),A=l?` dm-admin-sidebar--${f(l)}`:"";function B(c,C="px"){if(c==null)return c;const p=String(c).trim();return/^\d+(\.\d+)?$/.test(p)?`${p}${C}`:p}let j="";if(a){const c=[];a.fontFamily&&c.push(`font-family: ${a.fontFamily}, sans-serif`),a.fontSize&&c.push(`font-size: ${B(a.fontSize)}`),a.fontWeight&&c.push(`font-weight: ${a.fontWeight}`),a.letterSpacing&&c.push(`letter-spacing: ${B(a.letterSpacing,"em")}`);const C=[];if(c.length&&C.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 { ${c.join("; ")} }`),a.iconSize){const p=B(a.iconSize);C.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${p} !important; height: ${p} !important; }`)}C.length&&(j=`<style data-admin-sidebar-style>${C.join(" ")}</style>`)}const N=Me(t)?Be():"",U=String(b.logo||"").trim(),R=/^(?:\/(?!\/)|https?:\/\/)/i.test(U)?U:"",x=`<div class="dm-admin-sidebar-header">${R?`<img src="${f(R)}" alt="" style="width:28px;height:28px;object-fit:contain;flex-shrink:0;">`:`<span data-icon="${f(b.icon||"layout")}"></span>`}<span class="dm-admin-sidebar-title">${f(b.title)}</span>${N}${He()}</div>`,W=i.some(c=>c&&c.type==="spacer"&&c.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",D=`${j}<nav class="dm-admin-sidebar${A}${W}">${x}${i.map(c=>le(c,q)).join("")}</nav>`,T=document.createRange();T.selectNodeContents(n);const ge=T.createContextualFragment(D);n.replaceChildren(ge),Domma.icons.scan(n),n.querySelector(".dm-admin-sidebar-arrange")?.addEventListener("click",()=>Te(n));for(const c of L)V.set(c.url,q[c.url]??null);ae(n),nt(n),n.removeAttribute("data-menu-hover"),n.removeAttribute("data-menu-active"),n.style.removeProperty("--dm-menu-highlight"),we(n,{highlight:m});const O=document.querySelector(".dashboard-wrapper");["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(c=>{n.style[c]=""}),n.classList.remove("dm-menu-floating"),O&&(O.style.paddingLeft="",O.style.paddingRight=""),n.__dmGutter=()=>{if(u!=="floating"||!O)return;const c=r&&r.anchor||"TL",C=Number.isFinite(Number(r?.offsetX))?Number(r.offsetX):16,p=n.classList.contains("is-collapsed")?Ne:parseInt(n.style.width,10)||n.getBoundingClientRect().width||260,P=Math.round(p+C*2)+"px";c==="R"||c==="TR"||c==="BR"?O.style.paddingRight=P:O.style.paddingLeft=P},u==="floating"&&$e(n,{position:"floating",float:r||{}}),n.querySelectorAll("details").forEach(c=>{c.addEventListener("toggle",function(){const C=this.getAttribute("data-state-key");C&&S.set(C,this.open);const p=this.querySelector(":scope > .sidebar-children");if(p)if(this.open){const P=p.scrollHeight;p.style.maxHeight="0",requestAnimationFrame(()=>{p.style.maxHeight=P+"px",p.addEventListener("transitionend",function be(){p.style.maxHeight="none",p.removeEventListener("transitionend",be)})})}else{const P=p.scrollHeight;p.style.maxHeight=P+"px",requestAnimationFrame(()=>{p.style.maxHeight="0"})}})}),je(n),at(n),n.dataset.routeWired||(n.dataset.routeWired="1",M.subscribe("router:afterChange",()=>n.__dmSetActive?.()));function Y(){const c=/^#\/(dashboards|my-dashboard)\b/.test(location.hash)?"#/":location.hash||"#/";$(n).find(".sidebar-link").removeClass("active"),$(n).find(`.sidebar-link[data-url="${c}"]`).addClass("active")}Y(),n.__dmSetActive=Y}function me(){try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}function Z(e){return`${location.origin}${location.pathname}${e}`}function _(e,t){const s=F(),o=e(G(s));if(!ze(s,o)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}o.length&&se(s,!1),fe(s),t&&E.toast(t,{type:"success",duration:2500}),me()}function fe(e){_e(h,e).catch(()=>E.toast("Frequent is saved in this browser only - the server could not keep it.",{type:"warning"}))}function it(e){if(!se(F(),e)){E.toast("Frequent could not be saved - this browser is blocking storage.",{type:"error"});return}fe(F()),E.toast(e?"Frequent hidden. Add a Tool to it from its right-click menu to bring it back.":"Frequent shown.",{type:"success",duration:3500}),me()}function pe(e){const t=e.dataset.url;if(!t)return[];const s=e.querySelector(".sidebar-text")?.textContent.trim()||t,o=G(F()),n=o.includes(t),d=!!e.closest("[data-frequent]"),i=o.indexOf(t),l=!n&&o.length>=te;return[{header:s},{label:"Open",icon:"arrow-right",...oe(t)&&{shortcut:Ge(oe(t))},action:()=>{location.hash=t}},{label:"Open in a new tab",icon:"external-link",action:()=>window.open(Z(t),"_blank","noopener")},{type:"divider"},n?{label:"Remove from Frequent",icon:"star",action:()=>_(u=>Re(u,t),`${s} removed from Frequent.`)}:{label:l?`Frequent is full (${te})`:"Add to Frequent",icon:"star",disabled:l,action:()=>_(u=>Oe(u,t),`${s} added to Frequent.`)},...d?[{label:"Move up",icon:"arrow-up",disabled:i<=0,action:()=>_(u=>ne(u,t,-1))},{label:"Move down",icon:"arrow-down",disabled:i<0||i>=o.length-1,action:()=>_(u=>ne(u,t,1))}]:[],{type:"divider"},{label:"Copy link",icon:"link",action:async()=>{try{await navigator.clipboard.writeText(Z(t)),E.toast("Link copied.",{type:"success",duration:2e3})}catch{E.toast(Z(t),{type:"info",duration:8e3})}}}]}function he(e,t,s={}){const o=e.closest("details, [data-frequent]"),n=s.isOpen||(()=>!!o?.open),d=s.setOpen||(u=>{o&&(o.open=u)}),i=e.querySelector(".sidebar-text")?.textContent.trim()||"Folder",l=s.setAll||(u=>t.querySelectorAll("details").forEach(a=>{a.open!==u&&(a.open=u)}));return[{header:i},{label:n()?"Close":"Open",icon:n()?"chevron-up":"chevron-down",action:()=>d(!n())},...s.singleBranch?[]:[{label:"Open every folder",icon:"chevrons-down",action:()=>l(!0)}],{label:s.singleBranch?"Close all menus":"Close every folder",icon:"chevrons-up",action:()=>l(!1)},...o?.hasAttribute("data-frequent-empty")?[{type:"divider"},{label:"Hide Frequent until I add a Tool",icon:"eye-off",action:()=>it(!0)}]:o?.hasAttribute("data-frequent")?[{type:"divider"},{label:"Clear Frequent",icon:"x",action:()=>_(()=>[],"Frequent cleared.")}]:[]]}function at(e){e.dataset.ctxWired||typeof E>"u"||!E.contextMenu||(e.dataset.ctxWired="1",E.contextMenu(e,{match:"a.sidebar-link, details > summary",inherit:!1,density:"compact",items:t=>t.matches("summary")?he(t,e):pe(t)}))}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const TAB_FIELDS={general:["title","tagline","siteUrl","adminHome","spacerSize","bodyClass"],branding:["brandText","brandLogo","brandIcon","brandUrl","adminBrandTitle","adminBrandLogo","adminBrandIcon"],favicon:["favicon"],seo:["seoTitle","seoSeparator","seoDescription"],footer:["footerCopyright","footerLayout","footerBlurb","footerBlocks","footerMotionToggle","footerMotionDefault","footerMotionControl","footerClass","footerSocialClass","socialTwitter","socialFacebook","socialInstagram","socialLinkedin","socialGithub","socialYoutube"],email:["smtpHost","smtpPort","smtpUser","smtpPass","smtpSecure","smtpInsecureTLS","smtpFromAddress","smtpFromName"],
|
|
1
|
+
export const TAB_FIELDS={general:["title","tagline","siteUrl","adminHome","spacerSize","bodyClass"],branding:["brandText","brandLogo","brandIcon","brandUrl","adminBrandTitle","adminBrandLogo","adminBrandIcon"],favicon:["favicon"],seo:["seoTitle","seoSeparator","seoDescription"],footer:["footerCopyright","footerLayout","footerBlurb","footerBlocks","footerMotionToggle","footerMotionDefault","footerMotionControl","footerClass","footerSocialClass","socialTwitter","socialFacebook","socialInstagram","socialLinkedin","socialGithub","socialYoutube"],email:["smtpHost","smtpPort","smtpUser","smtpPass","smtpSecure","smtpInsecureTLS","smtpFromAddress","smtpFromName"],pageNavigation:["bttEnabled","bttSmooth","bttLabel","bttThreshold","bttPosition","bttOffset","bttBottomOffset","gtbEnabled","gtbSmooth","gtbLabel","gtbThreshold","gtbPosition","gtbOffset","gtbBottomOffset"],cookies:["ccEnabled","ccMessage","ccAcceptAll","ccRejectAll","ccCustomize","ccSavePrefs","ccPrivacyText","ccPrivacyUrl","ccCookieText","ccCookieUrl","ccPosition","ccLayout","ccTheme","ccShowFunctional","ccShowAnalytics","ccShowMarketing","ccVersion","ccSettingsLink","ccSettingsLinkText"],analytics:["gaId"],breadcrumbs:["bcEnabled","bcHomeLabel","bcPosition","bcOffsetX","bcOffsetY"]},SECRET_FIELDS=["smtpPass"],BREADCRUMB_POSITIONS=["TL","TR","BL","BR"];export function footerBlockNames(t){return[...new Set(String(t??"").split(/[\s,]+/).map(r=>r.trim().toLowerCase()).filter(Boolean))]}export function gaIdError(t){const r=o(t).trim();return!r||/^G-[A-Z0-9]{4,20}$/i.test(r)?"":"A measurement ID looks like G-XXXXXXXXXX (Google Analytics > Admin > Data streams)."}export const FOOTER_LAYOUTS=["auto","columns","row"];const o=(t,r="")=>t==null?r:String(t),n=(t,r)=>{const s=Number.parseInt(t,10);return Number.isFinite(s)?s:r};export function homeValue(t){return/^\/[A-Za-z0-9\-_/]*$/.test(t||"")&&String(t).replace(/\/+$/,"")||"/"}export function formFromSettings(t={}){const r=t.backToTop||{},s=t.goToBottom||{},e=t.cookieConsent||{},i=t.breadcrumbs||{};return{title:o(t.title),tagline:o(t.tagline),siteUrl:o(t.baseUrl),adminHome:homeValue(t.adminHome),spacerSize:o(t.layoutOptions?.spacerSize??40),bodyClass:o(t.bodyClass),brandText:o(t.brand?.text),brandLogo:o(t.brand?.logo),brandIcon:o(t.brand?.icon),brandUrl:o(t.brand?.url,"/"),favicon:o(t.favicon),adminBrandTitle:o(t.adminBrand?.title),adminBrandLogo:o(t.adminBrand?.logo),adminBrandIcon:o(t.adminBrand?.icon),seoTitle:o(t.seo?.defaultTitle),seoSeparator:o(t.seo?.titleSeparator," | "),seoDescription:o(t.seo?.defaultDescription),footerCopyright:o(t.footer?.copyright),footerLayout:FOOTER_LAYOUTS.includes(t.footer?.layout)?t.footer.layout:"auto",footerBlurb:o(t.footer?.blurb),footerBlocks:Array.isArray(t.footer?.blocks)?t.footer.blocks.filter(c=>typeof c=="string").join(", "):"",footerMotionToggle:t.footer?.showMotionToggle!==!1,footerMotionDefault:["off","on"].includes(t.footer?.motionDefault)?t.footer.motionDefault:"system",footerMotionControl:t.footer?.motionControl==="checkbox"?"checkbox":"switch",footerClass:o(t.footer?.class),footerSocialClass:o(t.footer?.socialClass),socialTwitter:o(t.social?.twitter),socialFacebook:o(t.social?.facebook),socialInstagram:o(t.social?.instagram),socialLinkedin:o(t.social?.linkedin),socialGithub:o(t.social?.github),socialYoutube:o(t.social?.youtube),smtpHost:o(t.smtp?.host),smtpPort:o(t.smtp?.port||587),smtpUser:o(t.smtp?.user),smtpPass:"",smtpSecure:t.smtp?.secure===!0,smtpInsecureTLS:t.smtp?.allowInsecureTLS===!0,smtpFromAddress:o(t.smtp?.fromAddress),smtpFromName:o(t.smtp?.fromName),bttEnabled:r.enabled!==!1,bttSmooth:r.smooth!==!1,bttLabel:o(r.label),bttThreshold:o(r.scrollThreshold??300),bttPosition:o(r.position,"bottom-right"),bttOffset:o(r.offset??32),bttBottomOffset:o(r.bottomOffset??r.offset??32),gtbEnabled:s.enabled===!0,gtbSmooth:s.smooth!==!1,gtbLabel:o(s.label),gtbThreshold:o(s.scrollThreshold??300),gtbPosition:o(s.position,"bottom-right"),gtbOffset:o(s.offset??32),gtbBottomOffset:o(s.bottomOffset??s.offset??32),ccEnabled:e.enabled!==!1,ccMessage:o(e.message),ccAcceptAll:o(e.acceptAllText,"Accept All"),ccRejectAll:o(e.rejectAllText,"Reject All"),ccCustomize:o(e.customizeText,"Customize"),ccSavePrefs:o(e.savePreferencesText,"Save Preferences"),ccPrivacyText:o(e.privacyPolicyText,"Privacy Policy"),ccPrivacyUrl:o(e.privacyPolicyUrl),ccCookieText:o(e.cookiePolicyText,"Cookie Policy"),ccCookieUrl:o(e.cookiePolicyUrl),ccPosition:o(e.position,"bottom"),ccLayout:o(e.layout,"bar"),ccTheme:o(e.theme,"dark"),ccShowFunctional:e.showFunctional!==!1,ccShowAnalytics:e.showAnalytics!==!1,ccShowMarketing:e.showMarketing!==!1,ccVersion:o(e.consentVersion,"1.0"),ccSettingsLink:e.showSettingsLink!==!1,ccSettingsLinkText:o(e.settingsLinkText,"Cookie settings"),gaId:o(t.googleAnalytics?.measurementId),bcEnabled:i.enabled===!0,bcHomeLabel:o(i.homeLabel,"Home"),bcPosition:BREADCRUMB_POSITIONS.includes(i.position)?i.position:"TL",bcOffsetX:o(i.offsetX??8),bcOffsetY:o(i.offsetY??8)}}export function payloadFromForm(t,r={},{adminHomeReady:s=!0}={}){const e=i=>o(i).trim();return{title:e(t.title),tagline:e(t.tagline),baseUrl:e(t.siteUrl).replace(/\/+$/,""),...s&&{adminHome:e(t.adminHome)||"/"},layoutOptions:{spacerSize:n(t.spacerSize,40)||40},bodyClass:e(t.bodyClass),brand:{...r.brand,text:e(t.brandText),logo:e(t.brandLogo),icon:e(t.brandIcon),url:e(t.brandUrl)||"/"},favicon:e(t.favicon),adminBrand:{...r.adminBrand,title:e(t.adminBrandTitle),logo:e(t.adminBrandLogo),icon:e(t.adminBrandIcon)},seo:{defaultTitle:e(t.seoTitle),titleSeparator:o(t.seoSeparator)||" | ",defaultDescription:e(t.seoDescription)},footer:{copyright:e(t.footerCopyright),layout:FOOTER_LAYOUTS.includes(t.footerLayout)?t.footerLayout:"auto",blurb:e(t.footerBlurb),blocks:footerBlockNames(t.footerBlocks),showMotionToggle:t.footerMotionToggle===!0,links:r.footer?.links||[],motionDefault:["off","on"].includes(t.footerMotionDefault)?t.footerMotionDefault:"system",motionControl:t.footerMotionControl==="checkbox"?"checkbox":"switch",class:e(t.footerClass),socialClass:e(t.footerSocialClass)},social:{twitter:e(t.socialTwitter),facebook:e(t.socialFacebook),instagram:e(t.socialInstagram),linkedin:e(t.socialLinkedin),github:e(t.socialGithub),youtube:e(t.socialYoutube)},smtp:{host:e(t.smtpHost),port:n(t.smtpPort,587)||587,user:e(t.smtpUser),pass:o(t.smtpPass),secure:t.smtpSecure===!0,allowInsecureTLS:t.smtpInsecureTLS===!0,fromAddress:e(t.smtpFromAddress),fromName:e(t.smtpFromName)},backToTop:{enabled:t.bttEnabled===!0,scrollThreshold:n(t.bttThreshold,300),position:o(t.bttPosition)||"bottom-right",offset:n(t.bttOffset,32),bottomOffset:n(t.bttBottomOffset,32),label:e(t.bttLabel),smooth:t.bttSmooth===!0},goToBottom:{enabled:t.gtbEnabled===!0,scrollThreshold:n(t.gtbThreshold,300),position:o(t.gtbPosition)||"bottom-right",offset:n(t.gtbOffset,32),bottomOffset:n(t.gtbBottomOffset,32),label:e(t.gtbLabel),smooth:t.gtbSmooth===!0},cookieConsent:{enabled:t.ccEnabled===!0,message:e(t.ccMessage),acceptAllText:e(t.ccAcceptAll),rejectAllText:e(t.ccRejectAll),customizeText:e(t.ccCustomize),savePreferencesText:e(t.ccSavePrefs),privacyPolicyText:e(t.ccPrivacyText),privacyPolicyUrl:e(t.ccPrivacyUrl),cookiePolicyText:e(t.ccCookieText),cookiePolicyUrl:e(t.ccCookieUrl),position:o(t.ccPosition)||"bottom",layout:o(t.ccLayout)||"bar",theme:o(t.ccTheme)||"dark",showFunctional:t.ccShowFunctional===!0,showAnalytics:t.ccShowAnalytics===!0,showMarketing:t.ccShowMarketing===!0,consentVersion:e(t.ccVersion)||"1.0",showSettingsLink:t.ccSettingsLink===!0,settingsLinkText:e(t.ccSettingsLinkText)||"Cookie settings"},googleAnalytics:{measurementId:e(t.gaId).toUpperCase()},breadcrumbs:{enabled:t.bcEnabled===!0,homeLabel:e(t.bcHomeLabel)||"Home",position:BREADCRUMB_POSITIONS.includes(t.bcPosition)?t.bcPosition:"TL",offsetX:n(t.bcOffsetX,8),offsetY:n(t.bcOffsetY,8)}}}export function siteUrlError(t){const r=o(t).trim().replace(/\/+$/,"");return r?/^https?:\/\//i.test(r)?/^https?:\/\/([a-z0-9.\-]+|\[[0-9a-f:.]+\])(:\d{1,5})?$/i.test(r)?"":"Just the address, like https://example.com - no page path after it.":"Start with https:// (or http://).":""}const a=t=>typeof t=="boolean"?t:o(t);export function snapshot(t){return JSON.stringify(Object.keys(t).sort().map(r=>[r,a(t[r])]))}export function changedTabs(t,r){const s=[];for(const[e,i]of Object.entries(TAB_FIELDS))i.some(c=>a(t[c])!==a(r[c]))&&s.push(e);return s}export function draftOf(t){return Object.fromEntries(Object.entries(t).filter(([r])=>!SECRET_FIELDS.includes(r)))}export function settingsProblems(t){const r=[];return o(t.smtpHost).trim()?o(t.smtpFromAddress).trim()||r.push({tone:"warn",tab:"email",text:"No From address - mail has no sender and many servers refuse it."}):r.push({tone:"danger",tab:"email",text:"No SMTP host - mail goes to a throwaway test inbox and reaches no one (password resets, form notifications)."}),(t.ccEnabled===!0||o(t.gaId).trim())&&!o(t.ccPrivacyUrl).trim()&&r.push({tone:"warn",tab:"cookies",text:"The cookie banner is on but links to no privacy policy."}),r}export function describeCacheKey(t){const r=/^page:(.*?):m\d+:role([^:]*):/.exec(String(t||""));return r?{path:r[1]||"/",role:r[2]||"anon",page:!0}:{path:String(t||""),role:"",page:!1}}export function expiresIn(t,r=Date.now()){if(t==null)return"no expiry";const s=t-r;return s<=0?"expired":s<6e4?`${Math.round(s/1e3)}s`:s<36e5?`${Math.round(s/6e4)}m`:`${Math.round(s/36e5)}h`}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let s={};export function renderFrameworkVersions(r){r&&(s=r);for(const[e,i,o]of[["topbar-reactive-version","Reactive",s.reactive],["topbar-js-version","JS",globalThis.Domma?.version||s.js]]){const n=document.getElementById(e);n&&(n.textContent=o||"",n.parentElement.hidden=!o,n.hidden=!o)}}export function sidebarPreferenceKey(r){return"sidebar.visible."+(r?.id||"anonymous")}export function wireAccountMenu(r){c("topbar-account"),c("topbar-versions-menu");const e=document.getElementById("topbar-show-sidebar");if(!e||e.dataset.wired)return;e.dataset.wired="1";const i=sidebarPreferenceKey(r);let o=!0;try{o=S.get(i)!==!1}catch{}const n=a=>{!a&&document.body.classList.contains("dm-sidebar-open")&&document.getElementById("topbar-sidebar-toggle")?.click(),document.body.classList.toggle("dm-sidebar-hidden",!a),e.checked=a};n(o),e.addEventListener("change",()=>{n(e.checked);try{S.set(i,e.checked)}catch{}})}const d=new Map;function c(r){const e=document.getElementById(r);if(!e||e.dataset.wired)return;e.dataset.wired="1";const i=e.querySelector("button"),o=e.querySelector(".topbar-account-menu"),n=t=>{t&&document.dispatchEvent(new CustomEvent("dm:topbar-menu-open",{detail:{owner:e}})),o.hidden=!t,i.setAttribute("aria-expanded",String(t))};i.addEventListener("click",()=>n(o.hidden)),i.addEventListener("keydown",t=>{t.key==="ArrowDown"&&(t.preventDefault(),n(!0),o.querySelector("a, input")?.focus())}),e.addEventListener("click",t=>{t.target.closest("a")&&n(!1)}),d.get(r)?.abort();const a=new AbortController;d.set(r,a),document.addEventListener("click",t=>{e.contains(t.target)||n(!1)},{signal:a.signal}),document.addEventListener("dm:topbar-menu-open",t=>{t.detail.owner!==e&&n(!1)},{signal:a.signal}),document.addEventListener("keydown",t=>{!t.defaultPrevented&&t.key==="Escape"&&!o.hidden&&(n(!1),i.focus(),t.preventDefault())},{signal:a.signal}),window.addEventListener("hashchange",()=>n(!1),{signal:a.signal})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function navigationItems(f){return(Array.isArray(f)?f:[]).flatMap(a=>{if(!a||a.hidden||a.restricted||["separator","spacer","theme-switcher"].includes(a.type))return[];const u=navigationItems(a.items),m=typeof a.url=="string"&&/^#\//.test(a.url)?a.url:null;return u.length||m||a.frequent?[{text:String(a.text||""),url:m,items:u,...a.key&&{key:a.key},...a.icon&&{icon:a.icon},...a.frequent&&{frequent:!0,empty:!u.length}}]:[]})}export function navigationBadge(f,a){const u=f.url&&a[f.url];if(u&&(u.count>0||u.showZero))return{count:u.count,show:!0,label:u.label||`${u.count} items`,tone:u.tone||"info"};let m=0,g=!1;const s=new Set,h=b=>{const l=b.url&&a[b.url];l?.aggregate&&l.count>0&&!s.has(b.url)&&(s.add(b.url),m+=l.count,g||(g=l.tone==="danger")),b.items.forEach(h)};return f.items.forEach(h),{count:m,show:m>0,label:`${m} across ${f.text}`,tone:g?"danger":"info"}}let y;export function updateTopbarCounts(f,{replace:a=!1}={}){y&&(y.value=a?f:{...y.peek(),...f})}let L,q,O,P,C,B,z;export function renderTopbarNavigation(f,{linkItems:a,folderItems:u,counts:m={}}={}){const g=document.getElementById("admin-topbar");if(!g)return;let s=document.getElementById("topbar-navigation");s||(s=document.createElement("nav"),s.id="topbar-navigation",s.className="topbar-navigation",s.setAttribute("aria-label","Admin sections"),g.insertBefore(s,g.querySelector(".topbar-user"))),L?.abort(),O?.dispose(),C?.dispose?.(),B?.dispose?.(),z?.(),P?.destroy?.(),L=new AbortController;const{signal:h}=L;s.replaceChildren();const b=new Map,l=M.observable([]);y=M.observable(m);const A=new Map;C=M.computed(()=>Object.fromEntries(l.value.map(e=>[e,!0])));const v=({focus:e=!1}={})=>{const t=b.get(l.peek()[0]);l.value=[],e&&t?.button.focus()},$=(e,t,o)=>{const n=document.createElement("span");n.setAttribute("data-icon",t.icon||(o?"folder":"file")),e.append(n);const d=document.createElement("span");d.className="sidebar-text",d.textContent=t.text,e.append(d);const i="b"+A.size;A.set(i,t);const r=document.createElement("span");if(r.className="topbar-nav-count",r.setAttribute("data-count-for",t.url||"folder:"+t.text),r.setAttribute("data-bind-text",`badges.value.${i}.count`),r.setAttribute("data-bind-hidden",`!badges.value.${i}.show`),r.setAttribute("data-bind-title",`badges.value.${i}.label`),r.setAttribute("data-bind-aria-label",`badges.value.${i}.label`),r.setAttribute("data-bind-class",`badges.value.${i}.tone === 'danger' ? 'is-danger' : ''`),e.append(r),o){const p=document.createElement("span");p.className="topbar-nav-chevron",p.setAttribute("data-icon",o),e.append(p)}},N=e=>{if(!l.peek().includes(e.id))return;const t=e.button.getBoundingClientRect(),o=e.panel.offsetWidth;let n=t.left,d=g.getBoundingClientRect().bottom;if(e.parents.length){const i=b.get(e.parents.at(-1)).panel.getBoundingClientRect();n=i.right-2,n+o>innerWidth-8&&(n=i.left-o+2),d=Math.min(t.top,innerHeight-Math.min(e.panel.scrollHeight,240)-12)}d=Math.max(g.getBoundingClientRect().bottom,d),e.panel.style.left=Math.max(8,Math.min(n,innerWidth-o-8))+"px",e.panel.style.top=d+"px",e.panel.style.maxHeight=Math.max(100,innerHeight-d-12)+"px"},w=(e,{focus:t=!1}={})=>{document.dispatchEvent(new CustomEvent("dm:topbar-menu-open",{detail:{owner:s}})),l.value=[...e.parents,e.id],requestAnimationFrame(()=>{N(e),t&&e.panel.querySelector("a, button")?.focus()})},R=(e,t,o)=>{const n=document.createElement("a");n.className="topbar-nav-link",n.href=t.url,n.dataset.url=t.url,$(n,t),n.addEventListener("pointerenter",()=>{l.peek().length&&(l.value=o)}),e.append(n)},D=(e,t,o=[])=>{for(const n of t){if(!n.items.length&&!n.frequent){R(e,n,o);continue}const d=document.createElement("div");d.className="topbar-nav-group",d.dataset.menuKey=n.key||n.text.trim().toLowerCase().replace(/\s+/g,"-"),n.frequent&&(d.setAttribute("data-frequent",""),n.empty&&d.setAttribute("data-frequent-empty",""));const i=document.createElement("button");i.type="button",i.className="topbar-nav-button",$(i,n,o.length?"chevron-right":"chevron-down");const r=document.createElement("div");r.className="topbar-nav-panel";const p="n"+b.size;r.id="topbar-nav-panel-"+p,r.setAttribute("aria-label",n.text),r.setAttribute("data-bind-hidden",`!open.value.${p}`),r.hidden=!0,i.setAttribute("aria-controls",r.id),i.setAttribute("data-bind-aria-expanded",`open.value.${p} ? 'true' : 'false'`),i.setAttribute("data-on-click",`toggle('${p}')`);const x={id:p,button:i,panel:r,parents:o};if(b.set(p,x),i.dataset.entry=p,n.url&&R(r,n,[...o,p]),D(r,n.items,[...o,p]),n.empty){const c=document.createElement("p");c.className="topbar-nav-empty",c.textContent="Right-click a tool to add it to Frequent.",r.append(c)}i.addEventListener("pointerenter",c=>{c.pointerType==="mouse"&&o.length&&w(x)}),i.addEventListener("keydown",c=>{(c.key==="ArrowDown"||o.length&&c.key==="ArrowRight")&&(c.preventDefault(),w(x,{focus:!0}))}),r.addEventListener("keydown",c=>{if(!c.defaultPrevented){if(c.key==="ArrowLeft"||c.key==="Escape")c.preventDefault(),c.stopPropagation(),l.value=o,i.focus();else if(c.key==="ArrowDown"||c.key==="ArrowUp"){const k=[...r.querySelectorAll(":scope > a, :scope > .topbar-nav-group > button")],S=k.indexOf(document.activeElement);S>=0&&(c.preventDefault(),c.stopPropagation(),k[(S+(c.key==="ArrowDown"?1:k.length-1))%k.length]?.focus())}}}),r.addEventListener("scroll",()=>{l.value=[...o,p]}),d.append(i,r),e.append(d)}};D(s,navigationItems(f)),s.hidden=!s.children.length,B=M.computed(()=>Object.fromEntries([...A].map(([e,t])=>[e,navigationBadge(t,y.value)]))),O=M.applyBindings({open:C,badges:B},s,{methods:{toggle:e=>{const t=b.get(e);!t.parents.length&&l.peek().includes(e)?l.value=t.parents:w(t)}}}),z=M.effect(()=>{y.value,requestAnimationFrame(()=>l.peek().forEach(e=>N(b.get(e))))}),Domma.icons.scan(s),E.contextMenu&&a&&u&&(P=E.contextMenu(s,{match:"a.topbar-nav-link, button.topbar-nav-button",inherit:!1,density:"compact",items:e=>{if(e.matches("a"))return a(e);const t=b.get(e.dataset.entry);return u(e,s,{singleBranch:!0,isOpen:()=>l.peek().includes(t.id),setOpen:o=>o?w(t):l.value=t.parents,setAll:o=>o?w(t):v()})}})),s.addEventListener("click",e=>{e.target.closest("a")&&v()},{signal:h}),document.addEventListener("click",e=>{s.contains(e.target)||v()},{signal:h}),document.addEventListener("dm:topbar-menu-open",e=>{e.detail.owner!==s&&v()},{signal:h}),document.addEventListener("keydown",e=>{!e.defaultPrevented&&e.key==="Escape"&&l.peek().length&&(v({focus:!0}),e.preventDefault())},{signal:h}),window.addEventListener("hashchange",()=>v(),{signal:h}),window.addEventListener("resize",()=>v(),{signal:h}),s.addEventListener("scroll",()=>v(),{signal:h}),q?.disconnect(),q=new ResizeObserver(()=>{const e=g.getBoundingClientRect().height;e&&document.documentElement.style.setProperty("--admin-topbar-height",e+"px")}),q.observe(g)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function topbarProjectSlug(n){const[o,t=""]=String(n||"").replace(/^#/,"").split("?"),e=new URLSearchParams(t).get("project");if(e)return e;const r=o.match(/^\/projects\/(?:edit\/)?([^/]+)(?:\/|$)/);if(!r||r[1]==="new")return null;try{return decodeURIComponent(r[1])}catch{return null}}let a=0;export async function refreshTopbarProject(n){const o=++a,t=document.getElementById("topbar-project");if(!t)return;t.hidden=!0;const e=topbarProjectSlug(location.hash);if(e)try{const r=await n.projects.get(e);if(o!==a||!r)return;const c=r.name||e;t.querySelector("#topbar-project-name").textContent=c,t.href="#/projects/"+encodeURIComponent(e),t.title=`Current project: ${c}`,t.setAttribute("aria-label",`Current project: ${c}`),t.hidden=!1}catch{}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const c="x-domma-cms-version";export function noticeFor(t,n){const e=typeof n=="string"?n.trim():"";return e?t.baseline?e===t.baseline||e===t.dismissed?{baseline:t.baseline,show:null}:{baseline:t.baseline,show:e}:{baseline:e,show:null}:{baseline:t.baseline,show:null}}const i={baseline:null,dismissed:null,showing:null};let a=!1,o=null;function d(t){if(!o){o=document.createElement("div"),o.className="dm-update-notice",o.setAttribute("role","status");const n=document.createElement("span");n.className="dm-update-notice__text";const e=document.createElement("button");e.type="button",e.className="btn btn-sm btn-primary",e.textContent="Reload",e.addEventListener("click",()=>location.reload());const s=document.createElement("button");s.type="button",s.className="btn btn-sm btn-ghost",s.textContent="Later",s.addEventListener("click",()=>{i.dismissed=i.showing,i.showing=null,o.hidden=!0}),o.append(n,e,s),document.body.appendChild(o)}o.querySelector(".dm-update-notice__text").textContent=`Domma CMS has been updated to ${t}. This tab is still running ${i.baseline} - save what you are working on, then reload so new settings are saved properly.`,o.hidden=!1}let l=null;export function renderCmsVersion(){const t=document.getElementById("topbar-cms-version");!t||!l||(t.textContent=l,t.parentElement.hidden=!1,t.hidden=!1)}function u(t){try{const n=t.headers.get(c);n&&n.trim()&&(l=n.trim(),renderCmsVersion());const e=noticeFor(i,n);i.baseline=e.baseline,e.show&&e.show!==i.showing&&(i.showing=e.show,d(e.show))}catch{}}export function installUpdateNotice(){if(a||typeof window>"u"||typeof window.fetch!="function")return;a=!0;const t=window.fetch;window.fetch=function(n,e){const s=t.call(this,n,e),r=typeof n=="string"?n:n&&n.url||"";return(r.startsWith("/api/")||r.startsWith(`${location.origin}/api/`))&&s.then(u,()=>{}),s}}
|
|
@@ -99,6 +99,8 @@
|
|
|
99
99
|
<tr><td><code>seo</code>, <code>footer</code>, <code>social</code>, <code>backToTop</code>,
|
|
100
100
|
<code>cookieConsent</code>, <code>breadcrumbs</code>, <code>layoutOptions</code></td><td>The Site Settings
|
|
101
101
|
tabs of the same names</td></tr>
|
|
102
|
+
<tr><td><code>googleAnalytics</code></td><td><code>{"measurementId": "G-XXXXXXXXXX"}</code> - the Analytics tab;
|
|
103
|
+
an empty ID switches it off, and anything that is not a GA4 ID is refused (400)</td></tr>
|
|
102
104
|
<tr><td><code>theme</code>, <code>adminTheme</code>, <code>autoTheme</code>, <code>fontFamily</code>,
|
|
103
105
|
<code>fontSize</code>, <code>adminBrand</code>, <code>locale</code>, <code>analytics</code>, <code>brand</code>,
|
|
104
106
|
<code>url</code>, <code>baseTheme</code></td><td>Also accepted; most are set from Theme or kept for older
|
|
@@ -54,6 +54,11 @@
|
|
|
54
54
|
<td>Back to top, Cookie consent, Breadcrumbs</td>
|
|
55
55
|
<td>Switch each on or off and set its wording and position.</td>
|
|
56
56
|
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<td>Analytics</td>
|
|
59
|
+
<td>Your Google Analytics 4 measurement ID - see <a href="#google-analytics">Google
|
|
60
|
+
Analytics</a> below. Empty means Google Analytics is off.</td>
|
|
61
|
+
</tr>
|
|
57
62
|
<tr>
|
|
58
63
|
<td>Custom CSS</td>
|
|
59
64
|
<td><code>content/custom.css</code>, applied to every public page after the theme.</td>
|
|
@@ -65,6 +70,32 @@
|
|
|
65
70
|
</tbody>
|
|
66
71
|
</table>
|
|
67
72
|
|
|
73
|
+
<h3 id="google-analytics">Google Analytics</h3>
|
|
74
|
+
<p>To use Google Analytics, copy the measurement ID of your website's data stream from Google
|
|
75
|
+
Analytics (<strong>Admin > Data streams</strong>, it looks like <code>G-XXXXXXXXXX</code>),
|
|
76
|
+
paste it into <strong>Site Settings > Analytics</strong> and save. It applies to every
|
|
77
|
+
public page at once - there is nothing to paste into pages or templates.</p>
|
|
78
|
+
<ul>
|
|
79
|
+
<li><strong>Visitors are asked first.</strong> Google Analytics sets cookies, so it loads only
|
|
80
|
+
for visitors who accept <strong>Analytics</strong> cookies in the cookie banner. Visitors
|
|
81
|
+
who reject them, or have not answered yet, are never sent to Google, and so do not
|
|
82
|
+
appear in your Google Analytics reports.</li>
|
|
83
|
+
<li><strong>The cookie banner is shown while an ID is set,</strong> with its Analytics
|
|
84
|
+
choice, even if it is switched off under Cookie consent. Adding an ID asks every visitor
|
|
85
|
+
again, because an answer given before was not consent to Google. Set a privacy policy
|
|
86
|
+
address on the Cookie consent tab, and say there that you use Google Analytics.</li>
|
|
87
|
+
<li><strong>Changing their mind:</strong> while the banner is on, the footer has a
|
|
88
|
+
<strong>Cookie settings</strong> link that opens it again. A visitor who withdraws consent
|
|
89
|
+
there stops being tracked and has Google Analytics' cookies removed. The link's wording,
|
|
90
|
+
and whether it is shown, are on the Cookie consent tab. To put it somewhere else, add a
|
|
91
|
+
menu item whose address is <code>#cookie-settings</code> - the footer then leaves its own
|
|
92
|
+
out.</li>
|
|
93
|
+
<li>Previews of unsaved pages are never sent to Google.</li>
|
|
94
|
+
<li>The built-in <strong>Analytics</strong> Tool is separate: it needs no cookies, counts
|
|
95
|
+
every visitor, and keeps the figures on your own site. You can use both; expect Google
|
|
96
|
+
Analytics to show fewer visitors, since it only counts those who said yes.</li>
|
|
97
|
+
</ul>
|
|
98
|
+
|
|
68
99
|
<h3>Theme</h3>
|
|
69
100
|
<p><strong>Content > Theme</strong> (stored in <code>config/theme.json</code>) sets the public
|
|
70
101
|
theme, the admin theme, fonts, the visitor theme switcher, automatic day and night themes (at
|