domma-cms 0.9.10 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +248 -159
- package/admin/css/admin.css +1 -1
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +7 -3
- package/admin/js/config/sidebar-config.js +1 -1
- package/admin/js/http-interceptor.js +1 -0
- package/admin/js/lib/card-builder.js +2 -2
- package/admin/js/lib/markdown-toolbar.js +5 -5
- package/admin/js/lib/safe-html.js +1 -0
- package/admin/js/lib/shortcode-modal.js +1 -0
- package/admin/js/templates/layouts.html +5 -4
- package/admin/js/templates/notifications.html +14 -0
- package/admin/js/templates/plugin-marketplace.html +16 -0
- package/admin/js/templates/plugins.html +17 -5
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/layouts.js +1 -16
- package/admin/js/views/notifications.js +1 -0
- package/admin/js/views/page-editor.js +37 -33
- package/admin/js/views/plugin-marketplace.js +1 -0
- package/admin/js/views/plugins.js +16 -16
- package/config/navigation.json +5 -72
- package/config/plugins.json +10 -14
- package/config/presets.json +50 -13
- package/config/site.json +11 -63
- package/package.json +2 -1
- package/plugins/_template/admin/templates/index.html +17 -0
- package/plugins/_template/admin/views/index.js +19 -0
- package/plugins/_template/config.js +8 -0
- package/plugins/_template/plugin.js +23 -0
- package/plugins/_template/plugin.json +34 -0
- package/plugins/analytics/plugin.json +41 -31
- package/plugins/blog/admin/templates/blog.html +22 -0
- package/plugins/blog/admin/templates/categories.html +7 -0
- package/plugins/blog/admin/templates/comments.html +11 -0
- package/plugins/blog/admin/templates/post-editor.html +97 -0
- package/plugins/blog/admin/templates/settings.html +11 -0
- package/plugins/blog/admin/views/blog.js +183 -0
- package/plugins/blog/admin/views/categories.js +235 -0
- package/plugins/blog/admin/views/comments.js +187 -0
- package/plugins/blog/admin/views/post-editor.js +291 -0
- package/plugins/blog/admin/views/settings.js +100 -0
- package/plugins/blog/collections/categories/schema.json +12 -0
- package/plugins/blog/collections/comments/schema.json +16 -0
- package/plugins/blog/collections/posts/schema.json +19 -0
- package/plugins/blog/config.js +8 -0
- package/plugins/blog/plugin.js +352 -0
- package/plugins/blog/plugin.json +96 -0
- package/plugins/blog/roles/blog-author.json +10 -0
- package/plugins/blog/roles/blog-editor.json +12 -0
- package/plugins/blog/templates/author.html +9 -0
- package/plugins/blog/templates/category.html +9 -0
- package/plugins/blog/templates/index.html +9 -0
- package/plugins/blog/templates/post.html +17 -0
- package/plugins/blog/templates/tag.html +9 -0
- package/plugins/contacts/collections/user-contact-groups/schema.json +1 -1
- package/plugins/contacts/collections/user-contacts/schema.json +1 -1
- package/plugins/contacts/plugin.js +4 -10
- package/plugins/contacts/plugin.json +13 -3
- package/plugins/notes/collections/user-notes/schema.json +1 -1
- package/plugins/notes/plugin.js +3 -9
- package/plugins/notes/plugin.json +13 -3
- package/plugins/site-search/plugin.json +5 -2
- package/plugins/theme-switcher/plugin.json +1 -1
- package/plugins/todo/collections/todos/schema.json +1 -1
- package/plugins/todo/plugin.js +3 -9
- package/plugins/todo/plugin.json +13 -3
- package/public/css/site.css +1 -1
- package/public/js/site.js +1 -1
- package/scripts/build.js +48 -0
- package/scripts/create-plugin.js +113 -0
- package/scripts/fresh.js +6 -7
- package/scripts/gen-instance-secret.js +46 -0
- package/scripts/reset.js +3 -3
- package/scripts/setup.js +31 -13
- package/server/middleware/auth.js +48 -0
- package/server/middleware/managerAuth.js +36 -0
- package/server/routes/api/actions.js +1 -1
- package/server/routes/api/auth.js +4 -3
- package/server/routes/api/layouts.js +173 -49
- package/server/routes/api/notifications.js +155 -0
- package/server/routes/api/plugin-marketplace.js +75 -0
- package/server/routes/api/users.js +1 -1
- package/server/routes/api/views.js +1 -1
- package/server/routes/public.js +4 -9
- package/server/server.js +32 -3
- package/server/services/actions.js +1 -1
- package/server/services/managerClient.js +182 -0
- package/server/services/markdown.js +76 -9
- package/server/services/permissionRegistry.js +245 -173
- package/server/services/pluginInstaller.js +301 -0
- package/server/services/plugins.js +117 -10
- package/server/services/presetCollections.js +66 -251
- package/server/services/renderer.js +99 -0
- package/server/services/roles.js +191 -39
- package/server/services/users.js +1 -1
- package/server/services/views.js +1 -1
- package/server/templates/page.html +2 -2
- package/plugins/docs/admin/templates/docs.html +0 -69
- package/plugins/docs/admin/views/docs.js +0 -276
- package/plugins/docs/config.js +0 -8
- package/plugins/docs/data/documents/57e003f0-68f2-47dc-9c36-ed4b10ed3deb.json +0 -11
- package/plugins/docs/data/folders.json +0 -9
- package/plugins/docs/data/templates.json +0 -1
- package/plugins/docs/data/versions/57e003f0-68f2-47dc-9c36-ed4b10ed3deb/1.json +0 -5
- package/plugins/docs/plugin.js +0 -375
- package/plugins/docs/plugin.json +0 -23
- package/plugins/form-builder/data/forms/contacts.json +0 -66
- package/plugins/form-builder/data/forms/enquiries.json +0 -103
- package/plugins/form-builder/data/forms/feedback.json +0 -131
- package/plugins/form-builder/data/forms/notes.json +0 -79
- package/plugins/form-builder/data/forms/to-do.json +0 -100
- package/plugins/form-builder/data/submissions/contacts.json +0 -1
- package/plugins/form-builder/data/submissions/enquiries.json +0 -1
- package/plugins/form-builder/data/submissions/feedback.json +0 -1
- package/plugins/form-builder/data/submissions/notes.json +0 -1
- package/plugins/form-builder/data/submissions/to-do.json +0 -1
- package/plugins/garage/admin/templates/garage.html +0 -111
- package/plugins/garage/admin/views/garage.js +0 -622
- package/plugins/garage/collections/garage-vehicles/schema.json +0 -101
- package/plugins/garage/config.js +0 -18
- package/plugins/garage/data/vehicles.json +0 -70
- package/plugins/garage/plugin.js +0 -398
- package/plugins/garage/plugin.json +0 -33
- package/scripts/seed.js +0 -1996
- package/server/services/userTypes.js +0 -227
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<div class="view-container">
|
|
2
|
+
<div class="view-header">
|
|
3
|
+
<h1><span data-icon="bell"></span> Notifications</h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div id="notif-list"></div>
|
|
7
|
+
|
|
8
|
+
<div id="notif-empty" hidden class="card">
|
|
9
|
+
<div class="card-body" style="text-align:center;padding:3rem;color:var(--dm-color-text-muted)">
|
|
10
|
+
<span data-icon="check-circle" style="font-size:2rem;display:block;margin-bottom:.5rem"></span>
|
|
11
|
+
<p>No notifications — you're all caught up.</p>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<div class="view-header">
|
|
2
|
+
<h2><span data-icon="store"></span> Plugin Marketplace</h2>
|
|
3
|
+
<p class="text-muted">Install premium plugins from the Domma manager.</p>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div id="marketplace-unavailable" style="display:none">
|
|
7
|
+
<div class="card">
|
|
8
|
+
<div class="card-body text-center">
|
|
9
|
+
<p>The Domma Manager is not configured. Set <code>MANAGER_URL</code> and <code>LICENCE_TOKEN</code> in your <code>.env</code> to enable the marketplace.</p>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div id="marketplace-available" style="display:none">
|
|
15
|
+
<div id="marketplace-grid" class="card-grid"></div>
|
|
16
|
+
</div>
|
|
@@ -3,10 +3,22 @@
|
|
|
3
3
|
<p class="text-muted" style="margin:0;font-size:.875rem">Plugins extend the CMS with new features. Changes take effect after a server restart.</p>
|
|
4
4
|
</div>
|
|
5
5
|
|
|
6
|
-
<div id="
|
|
7
|
-
<div class="
|
|
8
|
-
|
|
6
|
+
<div id="plugin-tabs" class="tabs">
|
|
7
|
+
<div class="tab-list">
|
|
8
|
+
<button class="tab-item active" data-tab="installed">Installed Plugins</button>
|
|
9
|
+
<button class="tab-item" data-tab="marketplace">Marketplace</button>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="tab-panel active" data-panel="installed">
|
|
13
|
+
<div id="plugins-empty" class="card" style="display:none">
|
|
14
|
+
<div class="card-body text-muted">
|
|
15
|
+
No plugins found. Drop a plugin folder into the <code>plugins/</code> directory to get started.
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<div id="plugins-grid" class="plugins-grid"></div>
|
|
9
19
|
</div>
|
|
10
|
-
</div>
|
|
11
20
|
|
|
12
|
-
<div
|
|
21
|
+
<div class="tab-panel" data-panel="marketplace">
|
|
22
|
+
<div id="marketplace-mount"></div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
package/admin/js/views/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dashboardView as o}from"./dashboard.js";import{pagesView as i}from"./pages.js";import{pageEditorView as r}from"./page-editor.js?v=4";import{settingsView as
|
|
1
|
+
import{dashboardView as o}from"./dashboard.js";import{pagesView as i}from"./pages.js";import{pageEditorView as r}from"./page-editor.js?v=4";import{settingsView as t}from"./settings.js";import{navigationView as e}from"./navigation.js";import{notificationsView as m}from"./notifications.js";import{layoutsView as s}from"./layouts.js";import{mediaView as f}from"./media.js";import{loginView as p}from"./login.js";import{usersView as w}from"./users.js";import{userEditorView as n}from"./user-editor.js";import{pluginsView as V}from"./plugins.js";import{documentationView as c}from"./documentation.js";import{tutorialsView as l}from"./tutorials.js";import{apiReferenceView as a}from"./api-reference.js";import{collectionsView as d}from"./collections.js";import{collectionEditorView as E}from"./collection-editor.js";import{collectionEntriesView as u}from"./collection-entries.js";import{formsView as g}from"./forms.js";import{formEditorView as v}from"./form-editor.js";import{formSubmissionsView as b}from"./form-submissions.js";import{viewsListView as k}from"./views-list.js";import{viewEditorView as y}from"./view-editor.js";import{viewPreviewView as L}from"./view-preview.js";import{actionsListView as P}from"./actions-list.js";import{actionEditorView as h}from"./action-editor.js";import{proDocsView as D}from"./pro-docs.js";import{blocksView as R}from"./blocks.js";import{blockEditorView as S}from"./block-editor.js";import{myProfileView as x}from"./my-profile.js";import{rolesView as j}from"./roles.js";import{roleEditorView as q}from"./role-editor.js";import{effectsView as z}from"./effects.js";export const views={dashboard:o,pages:i,pageEditor:r,settings:t,navigation:e,layouts:s,media:f,login:p,users:w,userEditor:n,plugins:V,documentation:c,tutorials:l,apiReference:a,collections:d,collectionEditor:E,collectionEntries:u,forms:g,formEditor:v,formSubmissions:b,viewsList:k,viewEditor:y,viewPreview:L,actionsList:P,actionEditor:h,proDocs:D,blocks:R,blockEditor:S,myProfile:x,roles:j,roleEditor:q,effects:z,notifications:m};
|
|
@@ -1,16 +1 @@
|
|
|
1
|
-
import{api as
|
|
2
|
-
<div class="preset-card card" data-key="${s}">
|
|
3
|
-
<div class="card-header">
|
|
4
|
-
<h3>${e.label||s}</h3>
|
|
5
|
-
<span class="badge">${s}</span>
|
|
6
|
-
</div>
|
|
7
|
-
<div class="card-body">
|
|
8
|
-
<p class="text-muted">${e.description||""}</p>
|
|
9
|
-
<div class="preset-toggles">
|
|
10
|
-
<label class="toggle-label"><input type="checkbox" class="form-check preset-navbar" ${e.navbar?"checked":""}> Navbar</label>
|
|
11
|
-
<label class="toggle-label"><input type="checkbox" class="form-check preset-footer" ${e.footer?"checked":""}> Footer</label>
|
|
12
|
-
<label class="toggle-label"><input type="checkbox" class="form-check preset-sidebar" ${e.sidebar?"checked":""}> Sidebar</label>
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
</div>
|
|
16
|
-
`)}),a.find("#save-layouts-btn").on("click",async()=>{a.find(".preset-card").each(function(){const s=$(this).data("key");t[s]&&(t[s].navbar=$(this).find(".preset-navbar").is(":checked"),t[s].footer=$(this).find(".preset-footer").is(":checked"),t[s].sidebar=$(this).find(".preset-sidebar").is(":checked"))});try{await c.layouts.save(t),E.toast("Layouts saved.",{type:"success"})}catch{E.toast("Failed to save layouts.",{type:"error"})}});const l=await c.layouts.getOptions().catch(()=>({spacerSize:8,spacerClass:""})),o=a.find("#spacer-size-input"),i=a.find("#spacer-class-input");o.val(l.spacerSize??8),i.val(l.spacerClass??""),a.find("#save-options-btn").on("click",async()=>{const s=parseInt(o.val(),10)||8,e=i.val().trim();try{await c.layouts.saveOptions({spacerSize:s,spacerClass:e}),E.toast("Layout options saved.",{type:"success"})}catch{E.toast("Failed to save layout options.",{type:"error"})}})}};
|
|
1
|
+
import{api as f}from"../api.js";const N={narrow:"Narrow",normal:"Normal",wide:"Wide",full:"Full"},B="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem;",S="width:100%;padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;box-sizing:border-box;";function x(n,e){const t=document.createElement("div");t.style.cssText="display:flex;flex-direction:column;gap:.25rem;";const a=document.createElement("label");return a.style.cssText=B,a.textContent=n,t.appendChild(a),t.appendChild(e),t}function T(n,e){const t=document.createElement("input");return t.type="text",t.placeholder=n||"",t.value=e||"",t.style.cssText=S,t}function L(n,e){const t=document.createElement("label");t.style.cssText="display:flex;align-items:center;gap:.5rem;cursor:pointer;";const a=document.createElement("input");a.type="checkbox",a.checked=!!e;const o=document.createElement("span");return o.style.cssText="font-size:.9em;color:var(--dm-text,#eee);",o.textContent=n,t.appendChild(a),t.appendChild(o),{wrap:t,cb:a}}function F(n){const e=document.createElement("select");return e.style.cssText=S,[["narrow","Narrow (768px)"],["normal","Normal (1100px)"],["wide","Wide (1280px)"],["full","Full width"]].forEach(([t,a])=>{const o=document.createElement("option");o.value=t,o.textContent=a,t===(n||"normal")&&(o.selected=!0),e.appendChild(o)}),e}function D(n){const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;";const t=document.createElement("input");t.type="color",t.value=n||"#ffffff",t.disabled=!n,t.style.cssText="width:38px;height:32px;padding:2px;border:1px solid var(--dm-border,#333);border-radius:4px;background:transparent;cursor:pointer;";const a=document.createElement("span");a.style.cssText="font-size:.85em;color:var(--dm-text-muted,#aaa);min-width:4rem;",a.textContent=n||"None";const o=document.createElement("button");o.type="button",o.textContent="Choose",o.style.cssText="padding:.25rem .6rem;font-size:.8em;background:transparent;border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text-muted,#aaa);cursor:pointer;";const s=document.createElement("button");return s.type="button",s.textContent="Clear",s.style.cssText=o.style.cssText,s.disabled=!n,o.addEventListener("click",()=>{t.disabled=!1,s.disabled=!1,t.click()}),t.addEventListener("input",()=>{a.textContent=t.value,s.disabled=!1}),s.addEventListener("click",()=>{t.value="#ffffff",t.disabled=!0,s.disabled=!0,a.textContent="None"}),e.appendChild(t),e.appendChild(a),e.appendChild(o),e.appendChild(s),{wrap:e,getValue(){return t.disabled?"":t.value}}}function O(n,e,t){const a=document.createElement("div");a.className="card preset-card",a.style.cssText="cursor:pointer;transition:box-shadow .15s;",a.addEventListener("mouseenter",()=>{a.style.boxShadow="0 0 0 2px var(--dm-primary,#4f7fff)"}),a.addEventListener("mouseleave",()=>{a.style.boxShadow=""}),a.addEventListener("click",()=>t(n,e));const o=document.createElement("div");o.className="card-header",o.style.cssText="display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;";const s=document.createElement("strong");if(s.textContent=e.label||n,o.appendChild(s),e.builtin){const r=document.createElement("span");r.className="badge",r.textContent="built-in",r.style.cssText="font-size:.65rem;",o.appendChild(r)}const d=document.createElement("span");d.className="badge badge-outline",d.textContent=N[e.width]||"Normal",d.style.cssText="margin-left:auto;font-size:.65rem;",o.appendChild(d),a.appendChild(o);const l=document.createElement("div");if(l.className="card-body",e.description){const r=document.createElement("p");r.className="text-muted",r.style.cssText="font-size:.85em;margin:0 0 .5rem;",r.textContent=e.description,l.appendChild(r)}const c=document.createElement("div");if(c.style.cssText="display:flex;gap:.75rem;flex-wrap:wrap;",[["Navbar",e.navbar],["Footer",e.footer],["Sidebar",e.sidebar]].forEach(([r,u])=>{const p=document.createElement("span");p.style.cssText=`font-size:.75em;color:${u?"var(--dm-success,#4caf50)":"var(--dm-text-muted,#666)"};display:flex;align-items:center;gap:.25rem;`,p.textContent=(u?"\u25CF ":"\u25CB ")+r,c.appendChild(p)}),l.appendChild(c),e.bgColor){const r=document.createElement("span");r.title=e.bgColor,r.style.cssText=`display:inline-block;width:14px;height:14px;border-radius:3px;background:${e.bgColor};border:1px solid var(--dm-border,#333);margin-top:.4rem;vertical-align:middle;`,l.appendChild(r)}return a.appendChild(l),a}function z(n,e,t,a,o){const s=E.slideover({title:t?"New Layout":"Edit Layout",size:"md"}),d=document.createElement("div");d.style.cssText="display:flex;flex-direction:column;gap:1rem;padding:1rem;";const l=T("e.g. Dark Landing",e.label||""),c=T("Optional description",e.description||""),r=F(e.width),u=L("Show Navbar",e.navbar!==!1),p=L("Show Footer",e.footer!==!1),g=L("Show Sidebar",e.sidebar===!0),b=D(e.bgColor||""),C=T("https://...",e.bgImage||""),k=T("e.g. no-hero wide-content",e.class||"");d.appendChild(x("Label",l)),d.appendChild(x("Description",c)),d.appendChild(x("Width",r));const h=document.createElement("div");h.style.cssText="display:flex;gap:1.5rem;flex-wrap:wrap;",h.appendChild(u.wrap),h.appendChild(p.wrap),h.appendChild(g.wrap),d.appendChild(h),d.appendChild(x("Background Colour",b.wrap)),d.appendChild(x("Background Image URL",C)),d.appendChild(x("Custom CSS Class",k));const v=document.createElement("div");v.style.cssText="display:flex;gap:.5rem;flex-wrap:wrap;padding-top:.5rem;border-top:1px solid var(--dm-border,#333);";const y=document.createElement("button");if(y.type="button",y.className="btn btn-primary",y.textContent="Save",v.appendChild(y),!t&&!e.builtin){const i=document.createElement("button");i.type="button",i.className="btn btn-danger",i.style.marginLeft="auto",i.textContent="Delete",i.addEventListener("click",async()=>{if(await E.confirm(`Delete the "${e.label||n}" layout?`))try{await f.layouts.remove(n),E.toast("Layout deleted.",{type:"success"}),s.close(),o(n)}catch(m){E.toast(m?.message||"Failed to delete layout.",{type:"error"})}}),v.appendChild(i)}d.appendChild(v),y.addEventListener("click",async()=>{const i=l.value.trim();if(!i){E.toast("Label is required.",{type:"warning"});return}const w={label:i,description:c.value.trim(),width:r.value,navbar:u.cb.checked,footer:p.cb.checked,sidebar:g.cb.checked,bgColor:b.getValue(),bgImage:C.value.trim(),class:k.value.trim()};try{let m;t?m=await f.layouts.create(w):m=await f.layouts.update(n,w),E.toast("Layout saved.",{type:"success"}),s.close(),a(t?m.key:n,m.preset||{...e,...w})}catch(m){E.toast(m?.message||"Failed to save layout.",{type:"error"})}}),s.element.appendChild(d),s.open()}export const layoutsView={templateUrl:"/admin/js/templates/layouts.html",async onMount(n){E.tabs(n.find("#layouts-tabs").get(0));let e=await f.layouts.get().catch(()=>({}));const t=n.find("#presets-grid");function a(){t.empty();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem;",Object.entries(e).forEach(([c,r])=>{const u=O(c,r,(p,g)=>{z(p,g,!1,(b,C)=>{e[b]={...e[b],...C},a()},b=>{delete e[b],a()})});l.appendChild(u)}),t.get(0).appendChild(l),I.scan(t.get(0))}a(),n.find("#create-layout-btn").on("click",()=>{z(null,{},!0,(l,c)=>{if(!l){E.toast("Layout saved but key missing \u2014 please refresh.",{type:"warning"});return}e[l]=c,a()},()=>{})});const o=await f.layouts.getOptions().catch(()=>({spacerSize:8,spacerClass:""})),s=n.find("#spacer-size-input"),d=n.find("#spacer-class-input");s.val(o.spacerSize??8),d.val(o.spacerClass??""),n.find("#save-options-btn").on("click",async()=>{const l=parseInt(s.val(),10)||8,c=d.val().trim();try{await f.layouts.saveOptions({spacerSize:l,spacerClass:c}),E.toast("Layout options saved.",{type:"success"})}catch{E.toast("Failed to save layout options.",{type:"error"})}})}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{api as p}from"../api.js";export const notificationsView={templateUrl:"/admin/js/templates/notifications.html",async onMount(r){const f=r.find("#notif-list"),C=r.find("#notif-empty");let o=[];try{o=await p.system.notifications.list()}catch{E.toast("Could not load notifications.",{type:"error"});return}if(!Array.isArray(o)||o.length===0){C.removeAttr("hidden"),Domma.icons.scan(r.get(0));return}o.forEach(e=>{e.unread&&p.system.notifications.markRead(e.id).catch(()=>{})}),o.forEach(e=>{const t=e.data||{},s=t.severity||"info",l=t.createdAt?new Date(t.createdAt).toLocaleString():"",c=s==="critical"?"danger":s==="warning"?"warning":s==="success"?"success":"info",n=document.createElement("div");n.className="card mb-3 notif-card",n.dataset.id=String(e.id);const i=document.createElement("div");i.className="card-header",i.style.cssText="display:flex;align-items:center;gap:.5rem;";const y=document.createElement("span");y.className=`badge badge-${c}`,y.textContent=s.toUpperCase();const g=document.createElement("strong");g.style.flex="1",g.textContent=t.title||"";const h=document.createElement("small");h.className="text-muted",h.textContent=l,i.appendChild(y),i.appendChild(g),i.appendChild(h);const d=document.createElement("div");d.className="card-body";const u=document.createElement("p");if(u.style.cssText="white-space:pre-wrap;margin:0 0 .75rem",u.textContent=t.body||"",d.appendChild(u),t.link){const a=document.createElement("a");a.href=t.link,a.target="_blank",a.rel="noopener",a.className="btn btn-sm btn-secondary",a.textContent="Open Link ";const x=document.createElement("span");x.dataset.icon="external-link",a.appendChild(x),d.appendChild(a)}const b=document.createElement("div");b.style.cssText="margin-top:.5rem;display:flex;gap:.5rem;";const m=document.createElement("button");m.className="btn btn-sm btn-secondary js-dismiss",m.dataset.id=String(e.id),m.textContent="Dismiss",b.appendChild(m),d.appendChild(b),n.appendChild(i),n.appendChild(d),f.get(0).appendChild(n)}),f.get(0).addEventListener("click",async e=>{const t=e.target.closest(".js-dismiss");if(!t)return;const s=t.dataset.id;try{await p.system.notifications.dismiss(s);const l=t.closest(".notif-card");l&&l.remove(),f.get(0).querySelectorAll(".notif-card").length===0&&C.removeAttr("hidden");const{count:c}=await p.system.notifications.unreadCount().catch(()=>({count:0})),n=$("#topbar-bell-badge");c>0?n.text(c>99?"99+":String(c)).removeAttr("hidden"):n.attr("hidden","").text("")}catch{E.toast("Could not dismiss notification.",{type:"error"})}}),Domma.icons.scan(r.get(0))}};
|