domma-cms 0.95.0 → 0.97.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/admin/css/admin.css +1 -1
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/js/lib/menu-drag.js +1 -0
- package/admin/js/lib/sidebar-arrange.js +7 -0
- package/admin/js/lib/sidebar-grouping.js +1 -1
- package/admin/js/lib/sidebar-renderer.js +4 -4
- package/admin/js/templates/docs/usage-navigation.html +33 -2
- package/admin/js/templates/docs/usage-tools.html +5 -4
- package/admin/js/templates/menu-editor.html +3 -3
- package/admin/js/views/menu-editor.js +18 -18
- package/package.json +2 -2
- package/server/server.js +3 -1
- package/server/services/hooks.js +9 -2
- package/server/services/plugins.js +3 -2
- package/server/services/siteGitignore.js +3 -0
package/admin/css/admin.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.dashboard-layout{display:flex;flex-direction:column;height:100vh;min-height:100vh;overflow:hidden}.dashboard-wrapper{display:flex;flex:1;min-height:0;overflow:hidden}.dashboard-main{flex:1;min-width:0;overflow-y:auto}#admin-sidebar.dashboard-sidebar{display:flex;flex-direction:column;flex-shrink:0;overflow:hidden}#admin-sidebar .dm-admin-sidebar{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar{width:8px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-track{background:transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.view-container{padding:1.5rem 2rem;max-width:1200px}.view-container:has(>.dm-plugin-shell){max-width:100%}.view-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem}.view-header h1{font-size:1.5rem;font-weight:700;margin:0;display:flex;align-items:center;gap:.5rem}.view-header-actions{display:flex;gap:.75rem;flex-wrap:wrap}.view-header-actions .btn-primary,.view-header-actions .btn-success,.view-header-actions .btn-danger{margin-left:.5rem}.stat-card .card-body{display:flex;align-items:center;gap:1rem}.stat-icon{width:44px;height:44px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0}.stat-icon--success{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.stat-icon--warning{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.stat-value{font-size:1.75rem;font-weight:700;line-height:1}.stat-label{font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.toolbar{display:flex;align-items:center;gap:.75rem}.form-check-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9rem}.form-hint{display:block;font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.dashboard-main:has(#editor-meta-tabs){overflow:hidden}.view-container:has(#editor-meta-tabs){display:flex;flex-direction:column;height:calc(100dvh - 60px);max-width:100%;padding-bottom:0}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-banner,.view-container:has(#editor-meta-tabs) .pex-bar{flex:none}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-body{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#block-editor-body){max-width:100%}.view-container:has(#ep-editor-tabs){max-width:100%}.ep-editor-grid{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) minmax(0,1.3fr);gap:1rem;align-items:start}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:sticky;top:1rem;display:flex;flex-direction:column;gap:1rem;min-width:0}@media(max-width:1500px){.ep-editor-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.ep-editor-grid>:first-child{grid-column:1 / -1}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:static}}@media(max-width:1024px){.ep-editor-grid{grid-template-columns:minmax(0,1fr)}}#editor-meta-tabs{flex:1;min-height:0;display:flex;flex-direction:column}#editor-meta-tabs .tab-content{flex:1;min-height:0;overflow:hidden}#editor-meta-tabs .tab-panel{height:100%;overflow-y:auto}#editor-meta-tabs .tab-panel:has(.editor-card),#live-preview-panel{overflow:hidden}.live-preview-bar{display:flex;align-items:center;gap:var(--dm-space-4);flex-wrap:wrap;padding:var(--dm-space-2) 0;border-bottom:1px solid var(--dm-border);margin-bottom:var(--dm-space-2)}.live-preview-widths{display:inline-flex;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);overflow:hidden}.live-preview-width{display:inline-flex;align-items:center;justify-content:center;padding:.3rem .55rem;border:none;background:transparent;color:inherit;cursor:pointer;line-height:1}.live-preview-width+.live-preview-width{border-left:1px solid var(--dm-border)}.live-preview-width:hover{background:var(--dm-hover-bg)}.live-preview-width.active{background:var(--dm-active-bg)}.live-preview-status{flex:1 1 auto;font-size:.8rem;opacity:.75}.live-preview-actions{display:flex;gap:var(--dm-space-1)}.live-preview-wrap{display:flex;flex-direction:column;height:100%;min-height:0}.live-preview-wrap>.live-preview-bar{flex:none}.live-preview-stage{display:flex;justify-content:center;flex:1;min-height:0;overflow:auto;background:var(--dm-background-alt);border-radius:var(--dm-radius-md)}.page-live-preview-frame{display:block;width:100%;max-width:100%;height:100%;border:none;border-radius:6px;background:var(--dm-background);transition:max-width .18s ease}.page-live-preview-frame[data-width="1024"]{max-width:1024px}.page-live-preview-frame[data-width="390"]{max-width:390px}.page-live-preview-frame[data-width="1024"],.page-live-preview-frame[data-width="390"]{border-left:1px solid var(--dm-border);border-right:1px solid var(--dm-border)}.editor-card{display:flex;flex-direction:column;height:100%}.editor-card .card-body{display:flex;flex-direction:column;flex:1;min-height:0;padding:0!important}.editor-toolbar{display:flex;align-items:center;gap:2px;padding:6px 10px;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .08));flex-wrap:wrap;flex-shrink:0}.editor-toolbar-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-toolbar-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-toolbar-sep{width:1px;height:20px;background:var(--dm-border, rgba(255, 255, 255, .08));margin:0 4px;flex-shrink:0}.editor-toolbar-right{margin-left:auto;display:flex;align-items:center;gap:2px}.editor-view-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-view-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-view-btn.active{color:var(--dm-primary, #5b8cff);background:color-mix(in srgb,var(--dm-primary) 14%,transparent)}.editor-body{display:flex;flex:1;min-height:0;--dm-editor-split: 50%}@media(min-width:769px){.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--write{flex:0 0 var(--dm-editor-split, 50%)}.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--preview{flex:1 1 0}}.editor-pane{flex:1;display:flex;flex-direction:column;min-width:0}.editor-pane--write,.editor-pane--preview{overflow:hidden}.editor-pane--write{flex-direction:row}.editor-line-numbers{padding:1rem .6rem 1rem .75rem;background:var(--dm-background-alt, rgba(0, 0, 0, .15));border-right:1px solid var(--dm-border, rgba(255, 255, 255, .08));color:var(--dm-text-muted, #666);font-family:Fira Code,Courier New,monospace;font-size:.9rem;line-height:1.6;text-align:right;user-select:none;white-space:pre;overflow:hidden;flex-shrink:0;min-width:2.5rem}.editor-line-numbers--foldable{padding:1rem 0;min-width:3rem;white-space:normal;text-align:left;display:flex;flex-direction:column}.editor-line-number-row{display:flex;align-items:center;justify-content:flex-end;padding-right:.6rem;gap:.15rem}.fold-toggle{display:inline-flex;align-items:center;justify-content:center;width:1em;font-size:.6rem;cursor:default;color:transparent}.fold-toggle--open,.fold-toggle--folded{cursor:pointer;color:var(--dm-text-muted, #666);transition:color .1s}.fold-toggle--open:hover,.fold-toggle--folded:hover{color:var(--dm-primary, #4a9eff)}.editor-line-num{min-width:1.5rem;text-align:right}.editor-mode-write .editor-pane--preview,.editor-mode-write .editor-divider,.editor-mode-preview .editor-pane--write,.editor-mode-preview .editor-divider{display:none}.editor-divider{width:7px;background:linear-gradient(to right,transparent 0,transparent 3px,var(--dm-border, rgba(255,255,255,.08)) 3px,var(--dm-border, rgba(255,255,255,.08)) 4px,transparent 4px,transparent 100%);cursor:col-resize;flex-shrink:0;touch-action:none;transition:background .12s ease}.editor-divider:hover,.editor-divider:focus-visible,.editor-divider.is-dragging{background:linear-gradient(to right,transparent 0,transparent 2px,var(--dm-primary, #5b8cff) 2px,var(--dm-primary, #5b8cff) 5px,transparent 5px,transparent 100%);outline:none}.editor-body.is-resizing .editor-pane{pointer-events:none}.editor-body.is-resizing{cursor:col-resize;user-select:none}.editor-textarea{flex:1;resize:none;border:none;border-radius:0;background:transparent;font-family:Fira Code,Courier New,monospace;font-size:.9rem;padding:1rem;outline:none;color:inherit;line-height:1.6}#editor-body .editor-textarea,#editor-body .editor-line-numbers{font-family:var(--pe-font, "Fira Code", "Courier New", monospace);font-size:var(--pe-size, .9rem);line-height:var(--pe-line, 1.6)}#editor-body.pe-nowrap .editor-textarea{white-space:pre;overflow-x:auto}.editor-preview{flex:1;display:block;width:100%;border:none;background:var(--dm-background)}.editor-fullscreen{position:fixed;inset:0;z-index:1000;border-radius:0;margin:0}.editor-fullscreen .card-body{height:100vh}.media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:.75rem;max-height:400px;overflow-y:auto;padding:.25rem}.media-picker-item{cursor:pointer;border:2px solid transparent;border-radius:6px;overflow:hidden;transition:border-color .15s}.media-picker-item:hover{border-color:var(--dm-primary, #5b8cff)}.media-picker-item img{width:100%;height:80px;object-fit:cover;display:block}.media-picker-item span{display:block;font-size:.75rem;padding:4px 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docs-body h3{margin-top:1.25rem;margin-bottom:.5rem}.docs-body p{margin-bottom:.5rem;line-height:1.6}.docs-body ol,.docs-body ul{margin-bottom:.75rem;padding-left:1.25rem}.docs-body li{margin-bottom:.25rem}.docs-body hr{margin:1.25rem 0;border-color:var(--dm-border, rgba(255, 255, 255, .08))}.docs-body .table{margin-bottom:.75rem}.docs-body h2{margin-top:1.75rem;margin-bottom:.6rem;padding-bottom:.3rem;border-bottom:1px solid var(--dm-border)}.docs-body h2:first-child{margin-top:0}.docs-body blockquote{margin:.75rem 0;padding:.5rem .9rem;border-left:3px solid var(--dm-primary);background:var(--dm-surface);border-radius:var(--dm-radius, 6px)}.docs-body pre{margin-bottom:.75rem;overflow-x:auto}.pg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem;margin-top:1.5rem}.pg-grid>.card.pg-card{display:block;margin:0;text-decoration:none}.pg-card h3{margin-top:0}.pg-card .text-muted,.pg-card-pages{margin-bottom:0}.pg-card-pages{margin-top:.5rem;font-size:.8rem;color:var(--dm-text-muted)}.pg-actions{display:flex;gap:.5rem;flex-wrap:wrap}.pg-meta{margin-bottom:.75rem}.pg-pages{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:1rem}.pg-body{max-width:80ch}.nav-items-header,.nav-item-row{display:flex;gap:.5rem;align-items:center;padding:.35rem .75rem}.nav-items-header{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));padding-bottom:.4rem;margin-bottom:.25rem}.nav-item-row{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.04))}.nav-item-row:last-child{border-bottom:none}.nav-col-indent{width:18px;flex-shrink:0;color:var(--dm-text-muted, #888);text-align:center;font-size:.85rem}.nav-col-main{flex:2;min-width:0}.nav-col-icon{flex:0 0 90px}.nav-col-parent{flex:2;min-width:0}.nav-col-action{flex-shrink:0}.nav-item-row--child{background:color-mix(in srgb,var(--dm-text) 3%,transparent)}.nav-col-action{display:flex;align-items:center;gap:.25rem}.nav-item-row--hidden{opacity:.45}.nav-item-row--hidden .item-text,.nav-item-row--hidden .footer-link-text{text-decoration:line-through}.btn-toggle-hidden{color:var(--dm-text-muted, #888)}.btn-toggle-hidden.active{color:var(--dm-warning, #f59e0b)}.fb-field-card.fb-drag-over{outline:2px dashed var(--dm-primary, #6366f1);outline-offset:-2px}.btn-ghost span[data-icon=trash]{color:var(--dm-danger, #dc2626)}.view-container:has(.fb-fields-layout){max-width:none}.fb-fields-layout{display:grid;grid-template-columns:minmax(0,6fr) minmax(320px,4fr);gap:1.25rem;align-items:start}.fb-preview-pane{position:sticky;top:1rem;min-width:0}@media(max-width:1100px){.fb-fields-layout{grid-template-columns:1fr}.fb-preview-pane{position:static}}.toggle-label{display:flex;align-items:center;gap:.4rem;font-size:.9rem;cursor:pointer;margin-right:1rem}.preset-toggles{display:flex;flex-wrap:wrap;margin-top:.75rem}.presets-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}@media(max-width:900px){.presets-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:600px){.presets-grid{grid-template-columns:1fr}}.card-header{padding:.5rem 1rem}.card-header h2{margin:0;font-size:.9rem;font-weight:600;letter-spacing:.02em}.preset-card .card-header{display:flex;align-items:center;justify-content:space-between}.preset-card .card-header h3{margin:0;font-size:1rem}.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:1rem}.media-card{background:var(--dm-card-bg, rgba(255,255,255,.04));border:1px solid var(--dm-border, rgba(255,255,255,.08));border-radius:8px;overflow:hidden}.media-preview{height:130px;display:flex;align-items:center;justify-content:center;background:#0003;overflow:hidden}.media-thumb{width:100%;height:100%;object-fit:cover}.media-thumb--file{font-size:2rem;color:var(--dm-text-muted, #888)}.media-info{padding:.5rem .75rem;display:flex;flex-direction:column;gap:.15rem}.media-name{font-size:.8rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default}.media-rename-input{width:100%;font-size:.8rem;font-weight:500;padding:.1rem .25rem;border:1px solid var(--dm-primary, #7c6af7);border-radius:3px;background:var(--dm-input-bg, transparent);color:inherit;outline:none}.media-size{font-size:.75rem;color:var(--dm-text-muted, #888)}.media-actions{padding:.5rem .75rem;display:flex;gap:.4rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}#admin-topbar{height:60px;display:flex;align-items:center;gap:1rem;padding:0 1.25rem;background:var(--dm-navbar-bg, rgba(0,0,0,.3));border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));position:sticky;top:0;z-index:200;flex-shrink:0}.topbar-brand{display:flex;align-items:center;gap:.5rem;font-weight:700;font-size:.95rem;color:inherit;flex-shrink:0;margin-right:.5rem}.topbar-brand span[data-icon],.topbar-brand svg{color:var(--dm-primary, #5b8cff);width:22px;height:22px}.topbar-brand-text{opacity:.85}.topbar-brand-logo{height:28px;width:auto;display:inline-block;vertical-align:middle;margin-right:.4em;object-fit:contain}.topbar-user{display:flex;align-items:center;gap:.6rem;flex:1}.topbar-user-name{font-size:.875rem;font-weight:500}.topbar-avatar{width:1.75rem;height:1.75rem;border-radius:50%;object-fit:cover;flex-shrink:0}.topbar-role-badge{font-size:.7rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:.15rem .45rem;border-radius:4px}.topbar-role-badge--admin{background:color-mix(in srgb,var(--dm-primary) 15%,transparent);color:var(--dm-primary)}.topbar-role-badge--manager{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.topbar-role-badge--editor{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.topbar-role-badge--subscriber{background:color-mix(in srgb,var(--dm-text-muted) 15%,transparent);color:var(--dm-text-muted)}.topbar-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.topbar-action-link{display:flex;align-items:center;gap:.35rem;font-size:.875rem;color:var(--dm-text-muted, #888);text-decoration:none;padding:.4rem .65rem;border-radius:6px;transition:color .15s,background .15s}.topbar-action-link:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.topbar-action-link span[data-icon],.topbar-action-link svg{width:16px;height:16px}.topbar-signout{display:flex;align-items:center;gap:.35rem;font-size:.875rem}.topbar-signout span[data-icon],.topbar-signout svg{width:16px;height:16px}.login-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:1rem;background:var(--dm-background, #0f1117);z-index:100;overflow-y:auto}.login-card{width:100%;max-width:460px}.ob-done-icon{font-size:3rem;color:var(--dm-success);margin-bottom:1rem;text-align:center}.btn-skip{display:block;text-align:center;margin-top:.75rem;font-size:.85rem;color:var(--dm-text-muted, #888);text-decoration:none}.btn-skip:hover{text-decoration:underline}.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}.theme-swatch{border:2px solid var(--dm-border, rgba(255,255,255,.1));border-radius:8px;overflow:hidden;cursor:pointer;transition:border-color .15s,transform .1s}.theme-swatch:hover{border-color:var(--dm-primary, #5b8cff);transform:translateY(-1px)}.theme-swatch.selected{border-color:var(--dm-primary, #5b8cff);box-shadow:0 0 0 2px var(--dm-primary, #5b8cff)}.theme-swatch-preview{height:52px;position:relative;display:flex;align-items:flex-end;padding:.35rem}.theme-swatch-accent{width:28px;height:6px;border-radius:3px}.theme-swatch-label{display:flex;justify-content:space-between;align-items:center;padding:.3rem .45rem;font-size:.7rem;background:var(--dm-card-bg, rgba(255,255,255,.04))}.theme-swatch-mode{color:var(--dm-text-muted, #888);font-size:.65rem}.login-logo{display:flex;align-items:center;gap:.75rem;margin-bottom:1.75rem;font-size:1.5rem}.login-logo span[data-icon]{font-size:2rem;color:var(--dm-primary, #5b8cff)}.login-logo h1{margin:0;font-size:1.5rem;font-weight:700}.login-card [hidden]{display:none!important}.login-heading{font-size:1.1rem;font-weight:600;margin-bottom:1.25rem}.login-rules{margin:.25rem 0 .75rem;padding-left:1.1rem;color:var(--dm-danger);font-size:.85rem}.login-rules li+li{margin-top:.2rem}.login-small{font-size:.8rem;margin-top:.75rem}.login-icon-warn{color:var(--dm-warning)}.pwf{position:relative;display:block}.pwf>input{width:100%;padding-right:2.5rem}.pwf-toggle{position:absolute;top:50%;right:.35rem;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:0;border-radius:var(--dm-radius-sm);background:transparent;color:var(--dm-text-muted);cursor:pointer}.pwf-toggle:hover,.pwf-toggle:focus-visible{color:var(--dm-text);background:var(--dm-hover-bg)}.pwf-toggle svg{width:16px;height:16px}.pwf-toggle [data-icon=eye-off],.pwf.is-shown .pwf-toggle [data-icon=eye]{display:none}.pwf.is-shown .pwf-toggle [data-icon=eye-off]{display:inline-block}.pwf-caps{display:block;margin-top:.25rem;color:var(--dm-warning);font-size:.8rem}.pwf-caps[hidden]{display:none}.btn-block{width:100%}.plugins-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem}.plugin-card{display:flex;flex-direction:column;--plugin-accent: var(--dm-primary, #5b8cff);position:relative;overflow:hidden;background-image:radial-gradient(120% 90% at 100% 0%,color-mix(in srgb,var(--plugin-accent) 13%,transparent) 0%,color-mix(in srgb,var(--plugin-accent) 4%,transparent) 42%,transparent 72%)}.plugin-card .plugin-icon{background:color-mix(in srgb,var(--plugin-accent) 16%,transparent);color:var(--plugin-accent)}.plugin-watermark{position:absolute;top:-34px;right:-30px;width:148px;height:148px;display:block;color:var(--plugin-accent);opacity:.09;pointer-events:none;z-index:0}.plugin-card>.card-body,.plugin-card>.plugin-footer{position:relative;z-index:1}.plugin-card:has(.badge-secondary) .plugin-watermark{opacity:.05}@media(prefers-reduced-motion:no-preference){.plugin-card{transition:background-image .2s ease}}.plugin-card .card-body{flex:1}.plugin-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.75rem;flex-wrap:wrap}.plugin-icon{width:40px;height:40px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;flex-shrink:0}.plugin-meta{flex:1 1 140px;min-width:0}.plugin-name{font-weight:600;margin-bottom:.15rem}.plugin-version{font-size:.75rem;color:var(--dm-text-muted, #888)}.plugin-desc{font-size:.875rem;color:var(--dm-text-muted, #888);margin-bottom:1rem}.plugin-footer{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}.plugin-footer-actions{display:flex;align-items:center;gap:.5rem}#admin-sidebar .sidebar-link{position:relative!important}#admin-sidebar .sidebar-badge{position:absolute!important;right:.75rem!important;top:50%!important;transform:translateY(-50%)!important;margin-left:0!important;padding-left:.45rem!important;padding-right:.45rem!important}#admin-sidebar .sidebar-text{padding-right:2rem!important}#admin-sidebar.sidebar-dark{background:var(--dm-surface);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header{background:var(--dm-surface-raised);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header-title{color:var(--dm-text)}#admin-sidebar.sidebar-dark .sidebar-link{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-link:hover{color:var(--dm-text);background:var(--dm-surface-overlay)}#admin-sidebar.sidebar-dark .sidebar-link.active{color:var(--dm-primary);background:color-mix(in srgb,var(--dm-primary) 14%,transparent);border-left-color:var(--dm-primary)}#admin-sidebar.sidebar-dark .sidebar-heading{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-divider{background:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-footer{background:var(--dm-surface-raised);border-color:var(--dm-border)}.sidebar-heading--collapsible{display:flex!important;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}.sidebar-heading-toggle{display:flex;align-items:center;opacity:.5;flex-shrink:0;transition:transform .2s ease}.sidebar-heading--collapsible.is-collapsed .sidebar-heading-toggle{transform:rotate(-90deg)}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.p-0{padding:0!important}.text-muted{color:var(--dm-text-muted, #888)}@media(max-width:768px){.view-container{padding:1rem}.editor-body{flex-direction:column}.editor-divider{width:auto;height:1px;cursor:default;background:var(--dm-border, rgba(255,255,255,.08))}}.image-editor{display:flex;flex-direction:column;gap:0}.image-editor-toolbar{display:flex;flex-direction:row;align-items:center;gap:.25rem;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-sep{display:inline-block;width:1px;height:1.5rem;background:var(--dm-border, rgba(255, 255, 255, .15));margin:0 .25rem;flex-shrink:0}.editor-toolbar-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent)}.editor-toolbar-caret{font-size:.6rem;line-height:1;margin-left:2px;opacity:.6}.editor-toolbar-dropdown{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:4px;min-width:160px;max-height:70vh;overflow-y:auto}.editor-toolbar-dropdown-heading{padding:6px 10px 3px;color:var(--dm-text-muted, #8a8a9a);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.editor-toolbar-dropdown-item{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:7px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-toolbar-dropdown-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-toolbar-dropdown-item span[data-icon],.editor-toolbar-dropdown-item svg{width:15px;height:15px;flex-shrink:0;opacity:.75}.editor-toolbar{position:relative}.editor-effects-dropdown-menu{position:absolute;top:100%;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:6px;min-width:180px;max-height:340px;overflow-y:auto}.editor-effects-category{padding:6px 8px 3px;font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dm-text-muted, #888)}.editor-effects-item{display:block;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:6px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-effects-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:8px;width:320px}.editor-icon-picker-search{width:100%;margin-bottom:8px;font-size:.8rem}.editor-spacer-picker{position:absolute;z-index:9999;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, #333);border-radius:8px;padding:12px;width:240px;box-shadow:0 8px 24px #00000073}.editor-spacer-picker-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888);margin-bottom:10px}.editor-spacer-picker-row{display:flex;align-items:center;gap:10px;margin-bottom:12px}.editor-spacer-slider{flex:1;accent-color:var(--dm-primary, #6366f1);cursor:pointer}.editor-spacer-slider-value{font-size:13px;font-weight:600;min-width:38px;text-align:right;color:var(--dm-text, #cdd6f4)}.editor-spacer-insert-btn{width:100%}.editor-icon-picker-size-row{display:flex;align-items:center;gap:8px;padding:0 8px 8px}.editor-icon-picker-size-row label{font-size:11px;color:var(--dm-text-muted, #888);white-space:nowrap}.editor-icon-picker-size{width:70px;font-size:12px;padding:3px 6px}.editor-icon-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(52px,1fr));gap:2px;max-height:280px;overflow-y:auto}.editor-icon-picker-item{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px 2px;border-radius:5px;cursor:pointer;background:none;border:none;color:var(--dm-text, #ddd);font-size:.58rem;text-align:center;gap:4px;overflow:hidden;transition:background .12s,color .12s}.editor-icon-picker-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker-item span[data-icon],.editor-icon-picker-item svg{width:16px;height:16px;flex-shrink:0}.editor-icon-picker-item>span:last-child{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.2}.editor-icon-picker-empty{grid-column:1 / -1;text-align:center;color:var(--dm-text-muted, #888);font-size:.8rem;padding:1.5rem}.image-editor-canvas{min-height:320px;max-height:520px;background:#111;overflow:hidden;display:flex;align-items:center;justify-content:center}.image-editor-canvas img{display:block;max-width:100%;max-height:520px}.image-editor-resize{display:flex;flex-direction:row;align-items:center;gap:.5rem;padding:.6rem .75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));font-size:.85rem}.image-editor-resize label{font-weight:600;color:var(--dm-text-muted, #888);font-size:.8rem}.image-editor-resize .form-input{width:5rem;padding:.25rem .5rem;font-size:.85rem}.image-editor-footer{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:.75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));gap:.5rem}.image-editor-effects{border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-tab-bar{display:flex;flex-direction:row;overflow-x:auto;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1));scrollbar-width:none}.image-editor-tab-bar::-webkit-scrollbar{display:none}.image-editor-tab-btn{display:inline-flex;align-items:center;gap:.35rem;padding:.5rem .85rem;font-size:.8rem;font-weight:500;border:none;border-bottom:2px solid transparent;background:transparent;cursor:pointer;color:var(--dm-text-muted, #888);white-space:nowrap;transition:color .15s,border-color .15s;flex-shrink:0}.image-editor-tab-btn:hover{color:var(--dm-text, #eee)}.image-editor-tab-btn.active{color:var(--dm-primary, #7c6af7);border-bottom-color:var(--dm-primary, #7c6af7)}.image-editor-tab-panel{padding:.75rem;max-height:200px;overflow-y:auto}.ie-presets-grid{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:.5rem}.ie-preset-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent);border-color:var(--dm-primary, #7c6af7)}.ie-server-note{font-size:.73rem;color:var(--dm-text-muted, #888);font-style:italic;margin:.25rem 0 0;line-height:1.4}.ie-slider-row{display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem}.ie-slider-label{width:6rem;font-size:.8rem;color:var(--dm-text-muted, #888);font-weight:600;flex-shrink:0}.ie-slider{flex:1;accent-color:var(--dm-primary, #7c6af7);cursor:pointer}.ie-slider-val{width:3rem;font-size:.8rem;text-align:right;color:var(--dm-text, #eee);flex-shrink:0}.ie-select{flex:1;font-size:.85rem;padding:.25rem .5rem}.ie-colour-input{width:40px;height:28px;padding:0;border:1px solid var(--dm-border, rgba(255, 255, 255, .15));border-radius:4px;cursor:pointer;background:transparent;flex-shrink:0}.ie-wm-preview-row{display:flex;align-items:center;gap:.5rem;margin:.4rem 0}.ie-wm-preview-img{width:48px;height:48px;object-fit:contain;border-radius:4px;background:var(--dm-surface-raised, rgba(255, 255, 255, .06));flex-shrink:0}.ie-wm-preview-name{font-size:.8rem;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text, #eee)}.ie-media-picker{padding:.25rem 0}.ie-media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:.5rem;max-height:300px;overflow-y:auto}.ie-media-thumb{display:flex;flex-direction:column;align-items:center;gap:.25rem;padding:.4rem;border-radius:6px;cursor:pointer;border:2px solid transparent;transition:border-color .15s,background .15s}.ie-media-thumb:hover{background:var(--dm-surface-raised, rgba(255, 255, 255, .08));border-color:var(--dm-primary, #7c6af7)}.ie-media-thumb img{width:72px;height:72px;object-fit:cover;border-radius:4px}.ie-media-thumb-name{font-size:.7rem;color:var(--dm-text-muted, #888);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:72px}.dm-slideover-left,.dm-slideover-right{width:min(40rem,95vw)!important;min-width:min(36rem,100vw)!important;max-width:100vw!important}.dm-slideover-resizer{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;z-index:2;background:transparent}.dm-slideover-right>.dm-slideover-resizer{left:0}.dm-slideover-left>.dm-slideover-resizer{right:0}.dm-slideover-resizer:hover,.is-resizing>.dm-slideover-resizer{background:var(--dm-primary);opacity:.7}.dm-slideover.is-resizing{user-select:none;transition:none!important}.dm-slideover-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border, #333);flex-shrink:0}.dm-slideover-title{margin:0;font-size:1rem;font-weight:600}.dm-slideover-close{padding:.2rem .35rem!important;line-height:1;font-size:.75rem}.dm-slideover-body{flex:1;overflow:auto;overscroll-behavior:contain;min-height:0;padding:1.5rem!important;box-sizing:border-box}.dm-slideover-body:empty{flex:0 0 auto;padding:0!important}.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-body):not(.dm-slideover-close){padding:1.5rem!important;box-sizing:border-box;flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.dm-slideover-body,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close){scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}.dm-slideover-body::-webkit-scrollbar,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar{width:8px;height:8px}.dm-slideover-body::-webkit-scrollbar-track,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-track{background:transparent}.dm-slideover-body::-webkit-scrollbar-thumb,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}.dm-slideover-body::-webkit-scrollbar-thumb:hover,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.dm-slideover-body>div{padding-left:0!important;padding-right:0!important}.dm-slideover-body>button.btn:last-child{margin-top:.5rem}.dconfig-textarea{font-family:monospace;min-height:100px;resize:vertical}.dm-editor-line-numbers{white-space:pre}.dm-code-inline{font-family:Fira Code,Courier New,monospace;font-size:.82em;padding:.15em .35em;border-radius:3px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08))}.dm-code-block{font-family:Fira Code,Courier New,monospace;font-size:.82rem;line-height:1.6;padding:.65rem .9rem;border-radius:6px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08));white-space:pre;overflow-x:auto;display:block;margin:.4rem 0}.tabs-centered{text-align:center}.tabs-centered .tab-list{display:inline-flex}.tabs-centered .tab-content{text-align:left}@media(max-width:768px){.view-header{flex-direction:column;align-items:flex-start}.theme-grid{grid-template-columns:repeat(2,1fr)}.nav-item-row{flex-wrap:wrap}.nav-col-icon,.nav-col-parent{display:none}#admin-topbar{padding:0 .75rem}.topbar-brand-text{display:none}.image-editor-toolbar{flex-wrap:wrap}}#topbar-bell{position:relative}.topbar-action-link[hidden],.topbar-bell-badge[hidden]{display:none}.topbar-bell-badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 4px;background:var(--dm-danger, #dc2626);color:var(--dm-danger-text, #fff);font-size:10px;font-weight:700;line-height:16px;border-radius:9999px;text-align:center;pointer-events:none}.cb-scaffolder{padding:1rem 1.1rem;background:var(--dm-background-alt);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-scaffolder-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-scaffolder-head .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-scaffolder-head h2{margin:0;font-size:1.05rem;font-weight:700;color:var(--dm-text)}.cb-scaffolder-blurb{margin:0 0 .75rem;font-size:.88rem;line-height:1.5;color:var(--dm-text-muted)}.cb-recipe-list{display:flex;flex-direction:column;gap:.5rem}.cb-recipe-card{display:flex;align-items:flex-start;gap:.75rem;text-align:left;padding:.75rem 1rem;background:var(--dm-surface);border:1px solid var(--dm-border);border-radius:6px;cursor:pointer;transition:border-color .12s;width:100%;color:var(--dm-text)}.cb-recipe-card:hover{border-color:var(--dm-primary)}.cb-recipe-card .cb-icon{flex-shrink:0;font-size:1.5rem;color:var(--dm-primary);margin-top:.1rem}.cb-recipe-meta{flex:1}.cb-recipe-name{font-weight:600;margin-bottom:.15rem;font-size:.95rem;color:var(--dm-text)}.cb-recipe-desc{font-size:.83rem;line-height:1.45;color:var(--dm-text-muted)}.cb-apply-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-apply-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-apply-head .cb-icon{color:var(--dm-primary);font-size:1.4rem}.cb-apply-head h3{margin:0;font-size:1rem;font-weight:600;color:var(--dm-text)}.cb-apply-desc,.cb-apply-hint{margin:.25rem 0 .75rem;font-size:.85rem;line-height:1.5;color:var(--dm-text-muted)}.cb-apply-hint{font-size:.75rem;margin-top:.2rem}.cb-apply-field{margin-bottom:.6rem}.cb-apply-field label{display:block;font-size:.82rem;font-weight:600;margin-bottom:.2rem;color:var(--dm-text)}.cb-apply-field input{width:100%;padding:.4rem .55rem;border:1px solid var(--dm-border);border-radius:4px;font-size:.88rem;background:var(--dm-surface);color:var(--dm-text)}.cb-apply-status{margin:.5rem 0;font-size:.85rem;min-height:1.2rem;color:var(--dm-text)}.cb-apply-status.cb-error{color:var(--dm-danger, #dc2626)}.cb-apply-buttons{display:flex;gap:.5rem;justify-content:flex-end;margin-top:.5rem}.cb-success-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-success, #16a34a);border-radius:8px;color:var(--dm-text)}.cb-success-panel .cb-icon{color:var(--dm-success, #16a34a);font-size:1.4rem}.cb-success-summary{margin:.25rem 0 .5rem;padding-left:1.2rem;font-size:.86rem;line-height:1.6;color:var(--dm-text)}.cb-success-warning{margin:.5rem 0;padding:.5rem .75rem;background:var(--dm-background-alt);border-left:3px solid var(--dm-warning, #eab308);border-radius:0 4px 4px 0;font-size:.82rem;color:var(--dm-text-muted)}.cb-success-snippet-label{margin:0 0 .25rem;font-size:.82rem;font-weight:600;color:var(--dm-text)}.cb-success-actions{display:flex;gap:.5rem;margin-top:.5rem;flex-wrap:wrap}.cb-code{position:relative}.cb-code pre{background:var(--dm-background-alt);color:var(--dm-text);display:block;padding:.6rem 2.4rem .6rem .75rem;white-space:pre;overflow-x:auto;margin:0;border-radius:6px;font-size:.82em;font-family:monospace;line-height:1.45}.cb-code .cb-copy{position:absolute;top:.35rem;right:.35rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.2rem;line-height:1;color:var(--dm-text)}.cb-code .cb-copy:hover{opacity:1}.cb-intro{padding:.75rem 1rem;border-left:3px solid var(--dm-primary);background:var(--dm-background-alt);border-radius:0 6px 6px 0}.cb-intro p{margin:0;font-size:.92rem;line-height:1.5;color:var(--dm-text)}.cb-tutorial-link{display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;border:1px solid var(--dm-border);border-radius:6px;text-decoration:none;color:var(--dm-text);font-size:.88rem;transition:border-color .12s}.cb-tutorial-link:hover{border-color:var(--dm-primary)}.cb-tutorial-link .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-tutorial-link .cb-arrow{color:var(--dm-text-muted);font-size:1.1rem;margin-left:auto}.menu-tree-row{display:grid;grid-template-columns:16px 1.4fr 1.4fr .9fr .7fr .9fr repeat(6,auto);gap:6px;align-items:center;padding:4px 0;transition:opacity .15s ease}.menu-tree-row--hidden{opacity:.5}.menu-tree-row--tool .me-tool-badge{margin-left:.4rem;font-size:.7rem;vertical-align:middle}.menu-tree-row--default .me-row-label{font-style:italic;opacity:.8}.menu-tree-grip{cursor:grab;color:var(--dm-text-muted)}.menu-tree{padding:8px 0}.menu-tree-row--separator{display:grid;grid-template-columns:16px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--separator:hover{opacity:1}.menu-tree-row--separator .me-sep-line{display:flex;align-items:center;gap:10px;width:100%}.menu-tree-row--separator .me-sep-line:before,.menu-tree-row--separator .me-sep-line:after{content:"";flex:1;border-top:1px dashed var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--separator .me-sep-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.dm-admin-sidebar .sidebar-divider{border:0;border-top:1px solid var(--dm-border, rgba(128, 128, 128, .5));margin:.5rem .75rem;opacity:.8}.dm-admin-sidebar .sidebar-spacer--xs{height:var(--dm-space-1, .25rem)}.dm-admin-sidebar .sidebar-spacer--sm{height:var(--dm-space-2, .5rem)}.dm-admin-sidebar .sidebar-spacer--md{height:var(--dm-space-4, 1rem)}.dm-admin-sidebar .sidebar-spacer--lg{height:var(--dm-space-6, 1.5rem)}.dm-admin-sidebar .sidebar-spacer--xl{height:var(--dm-space-10, 2.5rem)}.dm-admin-sidebar .sidebar-spacer--flex{flex:1 1 auto;min-height:var(--dm-space-4, 1rem)}.dm-admin-sidebar--has-flex-spacer{display:flex;flex-direction:column;min-height:100%}.menu-tree-row--spacer{display:grid;grid-template-columns:16px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--spacer:hover{opacity:1}.menu-tree-row--spacer .me-spacer-line{display:flex;align-items:center;gap:8px;width:100%}.menu-tree-row--spacer .me-spacer-line:before,.menu-tree-row--spacer .me-spacer-line:after{content:"";flex:1;border-top:1px dotted var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--spacer .me-spacer-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.menu-tree-row--spacer .me-spacer-size{width:auto;min-width:5.5rem;height:26px;padding:0 .35rem;font-size:.75rem}.menu-tree-row .me-icon-wrap{display:flex;gap:2px}.menu-tree-row .me-icon-wrap .me-icon{flex:1;min-width:0}.menu-tree-row .me-icon-wrap .me-icon-pick{flex-shrink:0;padding:.2rem .45rem;font-size:.85em}.dm-admin-sidebar{display:flex;flex-direction:column;gap:2px;padding:8px 0;font-size:.875rem}.dm-admin-sidebar details{margin:0}.dm-admin-sidebar details>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.4rem .75rem;border-radius:4px;user-select:none;font-size:.78rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888)}.dm-admin-sidebar details details>summary{font-size:.875rem;font-weight:500;text-transform:none;letter-spacing:0;color:inherit}.dm-admin-sidebar .dm-menu-badge{font-size:.7rem;font-weight:600}.dm-admin-sidebar details>summary::-webkit-details-marker{display:none}.dm-admin-sidebar details>summary:after{content:"\25b8";margin-left:auto;transition:transform .15s ease;color:var(--dm-text-muted, #999);font-size:.85em}.dm-admin-sidebar details[open]>summary:after{transform:rotate(90deg)}.dm-admin-sidebar details>div{padding-left:1rem;border-left:1px solid var(--dm-border-light, rgba(0, 0, 0, .08));margin-left:.95rem}.dm-admin-sidebar .sidebar-link{display:flex;align-items:center;gap:.5rem;padding:.35rem .75rem;text-decoration:none;color:var(--dm-text, inherit);border-radius:4px}.dm-admin-sidebar .sidebar-link:hover,.dm-admin-sidebar details>summary:hover{background:var(--dm-hover-bg, rgba(0, 0, 0, .05))}.dm-admin-sidebar .sidebar-link.active{background:var(--dm-active-bg, rgba(0, 0, 0, .08));font-weight:600}.dm-admin-sidebar .sidebar-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-admin-sidebar [data-icon]{flex-shrink:0}.dm-admin-sidebar-header{position:sticky;top:0;z-index:2;background:var(--dm-surface);display:flex;align-items:center;gap:.5rem;padding:.65rem .85rem;margin:0 0 .5rem;font-weight:600;font-size:.95rem;letter-spacing:.01em;color:var(--dm-text, inherit);border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.dm-admin-sidebar--dark .dm-admin-sidebar-header{background:#1a1d24}.dm-admin-sidebar--light .dm-admin-sidebar-header{background:#fff}.dm-admin-sidebar-header [data-icon]{color:var(--dm-text-muted, #999)}.dm-admin-sidebar .sidebar-badge{margin-left:auto;padding:0 .4rem;min-width:1.25rem;height:1.1rem;line-height:1.1rem;text-align:center;font-size:.7rem;font-weight:600;border-radius:999px;background:var(--dm-active-bg, rgba(0, 0, 0, .12));color:var(--dm-text-muted, #888)}.dm-admin-sidebar .sidebar-link.active .sidebar-badge{background:var(--dm-primary, #4a86e8);color:var(--dm-primary-text, #fff)}.dm-admin-sidebar .sidebar-children{overflow:hidden;transition:max-height .22s ease,opacity .18s ease}.dm-admin-sidebar details:not([open])>.sidebar-children{opacity:0}.dm-admin-sidebar{position:relative}.dm-admin-sidebar-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;background:transparent;z-index:10;transition:background .15s}.dm-admin-sidebar-handle:hover,.dm-admin-sidebar-handle:active{background:var(--dm-primary, #4a86e8);opacity:.35}.dm-admin-sidebar--dark{background:#1a1d24;color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link,.dm-admin-sidebar--dark summary{color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link:hover,.dm-admin-sidebar--dark details>summary:hover{background:#ffffff0f}.dm-admin-sidebar--dark .sidebar-link.active{background:#4a86e840}.dm-admin-sidebar--dark .sidebar-badge{background:#ffffff1f;color:#cbd0d8}.dm-admin-sidebar--light{background:#fff;color:#1a1d24;border-right:1px solid rgba(0,0,0,.08)}.dm-admin-sidebar--light .sidebar-link,.dm-admin-sidebar--light summary{color:#1a1d24}.dm-admin-sidebar--light .sidebar-link:hover,.dm-admin-sidebar--light details>summary:hover{background:#0000000a}.dm-admin-sidebar--light .sidebar-link.active{background:#4a86e826}.dm-admin-sidebar--transparent{background:transparent}.page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin:0 0 1.25rem;padding-bottom:.75rem;border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.page-header h2{margin:0;display:flex;align-items:center;gap:.5rem;font-size:1.4rem;line-height:1.2}.page-header h2 [data-icon]{color:var(--dm-text-muted, #888)}.header-actions{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.card+.card,.card+p,p+.card,.card+.toolbar,.toolbar+.card,.card+.grid{margin-top:1rem}.toolbar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin:0 0 1rem}.btn+.btn,.btn+a.btn,a.btn+.btn,a.btn+a.btn{margin-left:.35rem}[style*=inline-flex] .btn+.btn,[style*=inline-flex] .btn+a.btn,[style*=inline-flex] a.btn+.btn{margin-left:0}.card-body>[id$=-form],.card-body>form{margin:.25rem 0}.card-header{display:flex;align-items:center;gap:.5rem}.card-header h3{margin:0;font-size:1.05rem}.card-header [data-icon]{color:var(--dm-text-muted, #888)}.page-header+p.text-muted{margin:-.5rem 0 1rem}.dm-pe-grid{gap:.75rem 1rem}.dm-pe-grid .form-group{display:flex;flex-direction:column;gap:.25rem;margin:0}.dm-pe-grid .form-group.col-span-2{grid-column:1 / -1}.dm-pe-grid label{font-size:.85rem;font-weight:600;color:var(--dm-text, inherit)}.dm-pe-grid label .required{color:var(--dm-danger, #c33);margin-left:2px}.dm-pe-grid .form-hint{font-size:.75rem;color:var(--dm-text-muted, #888);margin-top:.1rem}.dm-pe-grid .form-input{width:100%;padding:.4rem .6rem}.dm-pe-grid textarea.form-input{resize:vertical;min-height:2.5rem}.dm-menu-badge{display:inline-block;margin-left:6px;padding:1px 7px;font-size:.7em;font-weight:700;line-height:1.4;border-radius:999px;background:var(--dm-text-muted);color:var(--dm-text-inverse, #fff);vertical-align:middle}.menu-tree-row--slim{display:grid;grid-template-columns:16px 1fr auto repeat(9,auto);gap:6px;align-items:center}.menu-tree-row--slim .me-row-label{font-weight:600}.menu-tree-row--slim .me-row-url{color:var(--dm-text-muted);font-size:.85em}.menu-tree-row.me-drop-above{box-shadow:inset 0 2px 0 0 var(--dm-primary)}.menu-tree-row.me-drop-below{box-shadow:inset 0 -2px 0 0 var(--dm-primary)}.menu-tree-row.me-drop-into{background:color-mix(in srgb,var(--dm-primary) 12%,transparent);box-shadow:inset 0 0 0 1px var(--dm-primary);border-radius:var(--dm-radius-sm, 4px)}.menu-tree-row[draggable=true] .menu-tree-grip{cursor:grabbing}.me-pages-picker{display:flex;gap:6px;align-items:center;margin-bottom:6px}.me-pages-picker .form-input{flex:1;min-width:0}.me-colour-control{display:flex;gap:6px;align-items:center}.me-colour-control .me-colour-hex{width:48px;height:32px;padding:2px;flex:none}.me-bind-summary{padding:.6rem .8rem;border:1px solid var(--dm-border, rgba(128, 128, 128, .35));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-text) 4%,transparent);font-size:.9em}.me-bind-summary code{font-size:.9em}.me-item-form{display:flex;flex-direction:column;gap:10px;padding:4px 2px}.me-item-form .form-field{display:flex;flex-direction:column;gap:4px}.me-item-form .form-label{font-size:.85em;color:var(--dm-text-muted)}.me-form-section{margin:12px 0 2px;padding-top:10px;border-top:1px solid var(--dm-border-light, rgba(0,0,0,.15));font-size:.78em;text-transform:uppercase;letter-spacing:.06em;color:var(--dm-text-muted)}.me-item-form .me-form-section:first-child{margin-top:0;padding-top:0;border-top:0}.me-item-form .me-colour-hex{width:48px;height:32px;padding:2px}.me-item-form .me-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.me-item-form .me-field-grid .form-field{margin:0}.me-item-form .me-icon-field{display:flex;align-items:center;gap:8px}.me-item-form .me-icon-field .form-input{flex:1}.me-item-form .me-icon-preview{width:24px;height:24px;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;color:var(--dm-text-muted)}#admin-sidebar.dm-menu-floating{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 8px);box-shadow:var(--dm-shadow-lg);overflow:hidden}@media(max-width:768px){#admin-sidebar.dm-menu-floating{position:static!important;inset:auto!important;max-height:none!important;transform:none!important}.dashboard-wrapper{padding-left:0!important;padding-right:0!important}}[data-logic-section]{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 6px);padding:.9rem 1rem 1rem;margin-bottom:1rem;background:color-mix(in srgb,var(--dm-text) 3%,transparent)}[data-logic-section] .fb-logic-cond-row,[data-logic-section] .fb-logic-val-rule{padding:.55rem .65rem;border-radius:var(--dm-radius-sm, 4px);border:1px solid var(--dm-border);background:var(--dm-surface, transparent)}[data-logic-section] .fb-logic-cond-row:last-of-type,[data-logic-section] .fb-logic-val-rule:last-of-type{margin-bottom:.75rem}[data-logic-section]>.btn{margin-top:.15rem}[data-logic-section] textarea{min-height:5rem}.project-filter-notice{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;margin:0 0 1rem;padding:.6rem .85rem;border:1px solid var(--dm-border);border-left:3px solid var(--dm-info, var(--dm-primary));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-info, var(--dm-primary)) 6%,transparent);font-size:.85rem;color:var(--dm-text-muted)}.project-filter-notice a{color:var(--dm-primary);font-weight:600}.ctx-help{display:inline-flex;align-items:center;justify-content:center;width:1.05rem;height:1.05rem;margin-left:.35rem;padding:0;border:1px solid var(--dm-border-dark, var(--dm-border));border-radius:var(--dm-radius-full, 9999px);background:transparent;color:var(--dm-text-muted);font-size:.68rem;font-weight:700;line-height:1;cursor:pointer;vertical-align:middle;flex-shrink:0}.ctx-help:hover,.ctx-help:focus-visible{border-color:var(--dm-primary);color:var(--dm-primary);outline:none}.card-header h3 .ctx-help{align-self:center}.ctx-preview-card{position:sticky;top:1rem}@media(max-width:1100px){.ctx-workspace>.col-8,.ctx-workspace>.col-4{flex:0 0 auto;width:100%}.ctx-preview-card{position:static}}.dm-plugin-shell{border:1px solid var(--dm-border);border-radius:var(--dm-radius-lg, 12px);background:var(--dm-surface);overflow:hidden}.dm-plugin-banner{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.7rem 1rem;background:var(--dm-background-alt);border-bottom:1px solid var(--dm-border)}.dm-plugin-banner-identity{display:flex;align-items:center;gap:.55rem;min-width:0;margin-right:auto}.dm-plugin-banner-actions{display:flex;align-items:center;gap:.25rem;flex:0 0 auto;margin-right:.15rem;padding-right:.4rem;border-right:1px solid var(--dm-border)}.dm-plugin-banner-action{padding:.25rem .4rem;line-height:1;color:var(--dm-text-muted)}.dm-plugin-banner-action:hover{color:var(--dm-primary)}.dm-plugin-banner-icon{display:inline-flex;align-items:center;color:var(--dm-primary);flex:0 0 auto}.dm-plugin-banner-name{margin:0;font-size:1.05rem;font-weight:600;letter-spacing:.01em;color:var(--dm-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dm-activity{display:inline-flex;align-items:center;flex:0 0 auto;margin-left:.35rem}.dm-activity domma-loader{display:inline-block;line-height:0}.dm-activity[hidden]{display:none!important}#admin-topbar>.dm-activity{margin:0 .75rem 0 0}.dm-plugin-banner-parent{font-weight:500;color:var(--dm-text-muted)}.dm-plugin-banner-sep{margin:0 .4rem;color:var(--dm-text-muted)}.dm-plugin-banner-facts{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}.dm-plugin-fact{font-size:.72rem;line-height:1.6;padding:1px 8px;border-radius:999px;border:1px solid var(--dm-border);color:var(--dm-text-muted);background:var(--dm-surface);white-space:nowrap}.dm-plugin-fact--version{font-variant-numeric:tabular-nums;color:var(--dm-text)}.dm-plugin-fact--licence.is-included{color:var(--dm-info);border-color:var(--dm-info)}.dm-plugin-fact--licence.is-licensed{color:var(--dm-success);border-color:var(--dm-success)}.dm-plugin-fact--expiry{font-variant-numeric:tabular-nums}.dm-plugin-fact--expiry.is-warning{color:var(--dm-warning);border-color:var(--dm-warning)}.dm-plugin-fact--expiry.is-danger{color:var(--dm-danger);border-color:var(--dm-danger)}.dm-plugin-body{padding:1rem}.dm-plugin-body .card.dm-plugin-unwrap{border:0;background:none;box-shadow:none;margin:0}.dm-plugin-body .card.dm-plugin-unwrap>.card-body{padding:0}.dm-plugin-body>.p-4{padding:0}@media(max-width:640px){.dm-plugin-banner{align-items:flex-start;flex-direction:column;gap:.5rem}.dm-plugin-body{padding:.75rem}}.analytics-filter{max-width:240px}.dm-help-btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;margin-left:.3rem;padding:0;border:0;background:none;line-height:1;color:var(--dm-text-muted);opacity:.75;cursor:pointer}.dm-help-btn:hover,.dm-help-btn:focus-visible{color:var(--dm-primary);opacity:1}.dm-help-pop{position:fixed;z-index:10050;max-width:300px;padding:.6rem .75rem;background:var(--dm-surface, var(--dm-background));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:var(--dm-radius-md);box-shadow:0 8px 24px #00000040;font-size:.85rem;line-height:1.45;text-align:left;font-weight:400}.dm-help-pop strong{display:block;margin-bottom:.2rem;font-weight:600}.dm-help-pop p{margin:0}.dm-admin-sidebar .sidebar-badge[data-badge-label]{cursor:help}.dm-admin-sidebar .sidebar-badge--danger,.dm-admin-sidebar .sidebar-link.active .sidebar-badge--danger{background:var(--dm-danger, #dc2626);color:#fff}.dm-admin-sidebar .sidebar-badge--live{background:color-mix(in srgb,var(--dm-success, #16a34a) 20%,transparent);color:var(--dm-success, #16a34a)}#admin-sidebar .sidebar-badge--live{padding-left:1.05rem!important}#admin-sidebar summary>.sidebar-badge--sum{position:static!important;transform:none!important;margin-left:auto!important;margin-right:.45rem;text-transform:none;letter-spacing:0}#admin-sidebar summary:has(>.sidebar-badge--sum):after{margin-left:0}#admin-sidebar details[open]>summary>.sidebar-badge--sum{display:none}.dm-admin-sidebar .sidebar-badge--live:before{content:"";position:absolute;left:.4rem;top:50%;width:.4rem;height:.4rem;margin-top:-.2rem;border-radius:50%;background:currentColor;animation:dm-badge-pulse 2s ease-in-out infinite}@keyframes dm-badge-pulse{50%{opacity:.35}}@media(prefers-reduced-motion:reduce){.dm-admin-sidebar .sidebar-badge--live:before{animation:none}}.dm-badge-pop{width:290px;max-width:calc(100vw - 16px);font-size:.8rem;pointer-events:none}.dm-badge-pop-title{display:block;font-size:.85rem}.dm-badge-pop-sub{margin:.1rem 0 .5rem;color:var(--dm-text-muted)}.dm-badge-pop-rows{display:grid;grid-template-columns:1fr auto;gap:.2rem .75rem;margin:0 0 .5rem;padding:.45rem 0;border-top:1px solid var(--dm-border);border-bottom:1px solid var(--dm-border)}.dm-badge-pop-rows dt{color:var(--dm-text-muted)}.dm-badge-pop-rows dd{margin:0;text-align:right;font-weight:600;font-variant-numeric:tabular-nums}.dm-badge-pop-items{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.dm-badge-pop-items li{display:flex;flex-direction:column;min-width:0}.dm-badge-pop-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-badge-pop-meta{font-size:.72rem;color:var(--dm-text-muted)}.dm-badge-pop .is-danger,.dm-badge-pop li.is-danger .dm-badge-pop-meta{color:var(--dm-danger, #dc2626)}.dm-badge-pop-empty{margin:0;color:var(--dm-text-muted)}.dm-plugin-body,.dm-slideover{font-family:var(--dm-font-sans, inherit)}.dm-plugin-body :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea),.dm-slideover :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea){font-family:inherit}.dm-plugin-body :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg),.dm-slideover :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg){font-size:var(--dm-text-sm)}.dm-plugin-body .form-input-lg{font-size:var(--dm-text-base)}.dm-plugin-body :is(.font-mono,code,pre,kbd),.dm-slideover :is(.font-mono,code,pre,kbd){font-family:var(--dm-font-mono, monospace)}.dm-plugin-body .form-label,.dm-slideover .form-label{font-size:var(--dm-text-sm)}.related-box{display:flex;flex-direction:column;gap:.6rem;border-top:1px solid var(--dm-border);padding-top:.75rem}.related-box[hidden]{display:none}.related-head{display:flex;align-items:center;gap:.4rem}.related-head strong{flex:1}.related-list{list-style:none;margin:.3rem 0 0;padding:0;display:flex;flex-direction:column;gap:.25rem}.related-list li{display:flex;flex-direction:column}.related-list li.is-past{opacity:.7}.related-meta,.related-note,.related-loading{color:var(--dm-text-muted);font-size:var(--dm-text-xs);margin:0}.login-challenge{display:flex;flex-direction:column;gap:.6rem;margin-bottom:.75rem}.login-challenge #challenge-code{font-size:1.25rem;letter-spacing:.2em;text-align:center}.login-trust{display:flex;align-items:center;gap:.45rem;font-size:.875rem}.login-enrol{display:flex;flex-direction:column;align-items:center;gap:.6rem;margin-bottom:1rem}.login-enrol img{background:#fff;padding:.5rem;border-radius:.5rem}.login-secret{display:flex;flex-direction:column;align-items:center;gap:.25rem;text-align:center}.login-secret code{font-size:.95rem;letter-spacing:.08em;word-break:break-all}.usx-secret{display:flex;flex-direction:column;gap:.75rem;padding:1rem}.usx-secret-link{display:block;padding:.6rem .75rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);background:var(--dm-background-alt);word-break:break-all;font-size:.8rem;user-select:all}.usx-secret-actions{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.usx-secret-actions .btn{display:inline-flex;align-items:center;gap:.35rem}.usx-secret-note{margin-right:auto;color:var(--dm-success)}.usx-secret-foot{color:var(--dm-text-muted);font-size:.8rem;margin:0}.uex-reset{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem .5rem;margin-top:.5rem}.uex-reset>small:first-child{flex-basis:100%;color:var(--dm-text-muted)}.uex-reset .btn{display:inline-flex;align-items:center;gap:.35rem}.uex-reset-open{flex-basis:100%;color:var(--dm-info)}
|
|
1
|
+
.dashboard-layout{display:flex;flex-direction:column;height:100vh;min-height:100vh;overflow:hidden}.dashboard-wrapper{display:flex;flex:1;min-height:0;overflow:hidden}.dashboard-main{flex:1;min-width:0;overflow-y:auto}#admin-sidebar.dashboard-sidebar{display:flex;flex-direction:column;flex-shrink:0;overflow:hidden}#admin-sidebar .dm-admin-sidebar{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar{width:8px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-track{background:transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.view-container{padding:1.5rem 2rem;max-width:1200px}.view-container:has(>.dm-plugin-shell){max-width:100%}.view-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem}.view-header h1{font-size:1.5rem;font-weight:700;margin:0;display:flex;align-items:center;gap:.5rem}.view-header-actions{display:flex;gap:.75rem;flex-wrap:wrap}.view-header-actions .btn-primary,.view-header-actions .btn-success,.view-header-actions .btn-danger{margin-left:.5rem}.stat-card .card-body{display:flex;align-items:center;gap:1rem}.stat-icon{width:44px;height:44px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0}.stat-icon--success{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.stat-icon--warning{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.stat-value{font-size:1.75rem;font-weight:700;line-height:1}.stat-label{font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.toolbar{display:flex;align-items:center;gap:.75rem}.form-check-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9rem}.form-hint{display:block;font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.dashboard-main:has(#editor-meta-tabs){overflow:hidden}.view-container:has(#editor-meta-tabs){display:flex;flex-direction:column;height:calc(100dvh - 60px);max-width:100%;padding-bottom:0}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-banner,.view-container:has(#editor-meta-tabs) .pex-bar{flex:none}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-body{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#block-editor-body){max-width:100%}.view-container:has(#ep-editor-tabs){max-width:100%}.ep-editor-grid{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) minmax(0,1.3fr);gap:1rem;align-items:start}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:sticky;top:1rem;display:flex;flex-direction:column;gap:1rem;min-width:0}@media(max-width:1500px){.ep-editor-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.ep-editor-grid>:first-child{grid-column:1 / -1}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:static}}@media(max-width:1024px){.ep-editor-grid{grid-template-columns:minmax(0,1fr)}}#editor-meta-tabs{flex:1;min-height:0;display:flex;flex-direction:column}#editor-meta-tabs .tab-content{flex:1;min-height:0;overflow:hidden}#editor-meta-tabs .tab-panel{height:100%;overflow-y:auto}#editor-meta-tabs .tab-panel:has(.editor-card),#live-preview-panel{overflow:hidden}.live-preview-bar{display:flex;align-items:center;gap:var(--dm-space-4);flex-wrap:wrap;padding:var(--dm-space-2) 0;border-bottom:1px solid var(--dm-border);margin-bottom:var(--dm-space-2)}.live-preview-widths{display:inline-flex;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);overflow:hidden}.live-preview-width{display:inline-flex;align-items:center;justify-content:center;padding:.3rem .55rem;border:none;background:transparent;color:inherit;cursor:pointer;line-height:1}.live-preview-width+.live-preview-width{border-left:1px solid var(--dm-border)}.live-preview-width:hover{background:var(--dm-hover-bg)}.live-preview-width.active{background:var(--dm-active-bg)}.live-preview-status{flex:1 1 auto;font-size:.8rem;opacity:.75}.live-preview-actions{display:flex;gap:var(--dm-space-1)}.live-preview-wrap{display:flex;flex-direction:column;height:100%;min-height:0}.live-preview-wrap>.live-preview-bar{flex:none}.live-preview-stage{display:flex;justify-content:center;flex:1;min-height:0;overflow:auto;background:var(--dm-background-alt);border-radius:var(--dm-radius-md)}.page-live-preview-frame{display:block;width:100%;max-width:100%;height:100%;border:none;border-radius:6px;background:var(--dm-background);transition:max-width .18s ease}.page-live-preview-frame[data-width="1024"]{max-width:1024px}.page-live-preview-frame[data-width="390"]{max-width:390px}.page-live-preview-frame[data-width="1024"],.page-live-preview-frame[data-width="390"]{border-left:1px solid var(--dm-border);border-right:1px solid var(--dm-border)}.editor-card{display:flex;flex-direction:column;height:100%}.editor-card .card-body{display:flex;flex-direction:column;flex:1;min-height:0;padding:0!important}.editor-toolbar{display:flex;align-items:center;gap:2px;padding:6px 10px;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .08));flex-wrap:wrap;flex-shrink:0}.editor-toolbar-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-toolbar-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-toolbar-sep{width:1px;height:20px;background:var(--dm-border, rgba(255, 255, 255, .08));margin:0 4px;flex-shrink:0}.editor-toolbar-right{margin-left:auto;display:flex;align-items:center;gap:2px}.editor-view-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-view-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-view-btn.active{color:var(--dm-primary, #5b8cff);background:color-mix(in srgb,var(--dm-primary) 14%,transparent)}.editor-body{display:flex;flex:1;min-height:0;--dm-editor-split: 50%}@media(min-width:769px){.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--write{flex:0 0 var(--dm-editor-split, 50%)}.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--preview{flex:1 1 0}}.editor-pane{flex:1;display:flex;flex-direction:column;min-width:0}.editor-pane--write,.editor-pane--preview{overflow:hidden}.editor-pane--write{flex-direction:row}.editor-line-numbers{padding:1rem .6rem 1rem .75rem;background:var(--dm-background-alt, rgba(0, 0, 0, .15));border-right:1px solid var(--dm-border, rgba(255, 255, 255, .08));color:var(--dm-text-muted, #666);font-family:Fira Code,Courier New,monospace;font-size:.9rem;line-height:1.6;text-align:right;user-select:none;white-space:pre;overflow:hidden;flex-shrink:0;min-width:2.5rem}.editor-line-numbers--foldable{padding:1rem 0;min-width:3rem;white-space:normal;text-align:left;display:flex;flex-direction:column}.editor-line-number-row{display:flex;align-items:center;justify-content:flex-end;padding-right:.6rem;gap:.15rem}.fold-toggle{display:inline-flex;align-items:center;justify-content:center;width:1em;font-size:.6rem;cursor:default;color:transparent}.fold-toggle--open,.fold-toggle--folded{cursor:pointer;color:var(--dm-text-muted, #666);transition:color .1s}.fold-toggle--open:hover,.fold-toggle--folded:hover{color:var(--dm-primary, #4a9eff)}.editor-line-num{min-width:1.5rem;text-align:right}.editor-mode-write .editor-pane--preview,.editor-mode-write .editor-divider,.editor-mode-preview .editor-pane--write,.editor-mode-preview .editor-divider{display:none}.editor-divider{width:7px;background:linear-gradient(to right,transparent 0,transparent 3px,var(--dm-border, rgba(255,255,255,.08)) 3px,var(--dm-border, rgba(255,255,255,.08)) 4px,transparent 4px,transparent 100%);cursor:col-resize;flex-shrink:0;touch-action:none;transition:background .12s ease}.editor-divider:hover,.editor-divider:focus-visible,.editor-divider.is-dragging{background:linear-gradient(to right,transparent 0,transparent 2px,var(--dm-primary, #5b8cff) 2px,var(--dm-primary, #5b8cff) 5px,transparent 5px,transparent 100%);outline:none}.editor-body.is-resizing .editor-pane{pointer-events:none}.editor-body.is-resizing{cursor:col-resize;user-select:none}.editor-textarea{flex:1;resize:none;border:none;border-radius:0;background:transparent;font-family:Fira Code,Courier New,monospace;font-size:.9rem;padding:1rem;outline:none;color:inherit;line-height:1.6}#editor-body .editor-textarea,#editor-body .editor-line-numbers{font-family:var(--pe-font, "Fira Code", "Courier New", monospace);font-size:var(--pe-size, .9rem);line-height:var(--pe-line, 1.6)}#editor-body.pe-nowrap .editor-textarea{white-space:pre;overflow-x:auto}.editor-preview{flex:1;display:block;width:100%;border:none;background:var(--dm-background)}.editor-fullscreen{position:fixed;inset:0;z-index:1000;border-radius:0;margin:0}.editor-fullscreen .card-body{height:100vh}.media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:.75rem;max-height:400px;overflow-y:auto;padding:.25rem}.media-picker-item{cursor:pointer;border:2px solid transparent;border-radius:6px;overflow:hidden;transition:border-color .15s}.media-picker-item:hover{border-color:var(--dm-primary, #5b8cff)}.media-picker-item img{width:100%;height:80px;object-fit:cover;display:block}.media-picker-item span{display:block;font-size:.75rem;padding:4px 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docs-body h3{margin-top:1.25rem;margin-bottom:.5rem}.docs-body p{margin-bottom:.5rem;line-height:1.6}.docs-body ol,.docs-body ul{margin-bottom:.75rem;padding-left:1.25rem}.docs-body li{margin-bottom:.25rem}.docs-body hr{margin:1.25rem 0;border-color:var(--dm-border, rgba(255, 255, 255, .08))}.docs-body .table{margin-bottom:.75rem}.docs-body h2{margin-top:1.75rem;margin-bottom:.6rem;padding-bottom:.3rem;border-bottom:1px solid var(--dm-border)}.docs-body h2:first-child{margin-top:0}.docs-body blockquote{margin:.75rem 0;padding:.5rem .9rem;border-left:3px solid var(--dm-primary);background:var(--dm-surface);border-radius:var(--dm-radius, 6px)}.docs-body pre{margin-bottom:.75rem;overflow-x:auto}.pg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem;margin-top:1.5rem}.pg-grid>.card.pg-card{display:block;margin:0;text-decoration:none}.pg-card h3{margin-top:0}.pg-card .text-muted,.pg-card-pages{margin-bottom:0}.pg-card-pages{margin-top:.5rem;font-size:.8rem;color:var(--dm-text-muted)}.pg-actions{display:flex;gap:.5rem;flex-wrap:wrap}.pg-meta{margin-bottom:.75rem}.pg-pages{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:1rem}.pg-body{max-width:80ch}.nav-items-header,.nav-item-row{display:flex;gap:.5rem;align-items:center;padding:.35rem .75rem}.nav-items-header{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));padding-bottom:.4rem;margin-bottom:.25rem}.nav-item-row{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.04))}.nav-item-row:last-child{border-bottom:none}.nav-col-indent{width:18px;flex-shrink:0;color:var(--dm-text-muted, #888);text-align:center;font-size:.85rem}.nav-col-main{flex:2;min-width:0}.nav-col-icon{flex:0 0 90px}.nav-col-parent{flex:2;min-width:0}.nav-col-action{flex-shrink:0}.nav-item-row--child{background:color-mix(in srgb,var(--dm-text) 3%,transparent)}.nav-col-action{display:flex;align-items:center;gap:.25rem}.nav-item-row--hidden{opacity:.45}.nav-item-row--hidden .item-text,.nav-item-row--hidden .footer-link-text{text-decoration:line-through}.btn-toggle-hidden{color:var(--dm-text-muted, #888)}.btn-toggle-hidden.active{color:var(--dm-warning, #f59e0b)}.fb-field-card.fb-drag-over{outline:2px dashed var(--dm-primary, #6366f1);outline-offset:-2px}.btn-ghost span[data-icon=trash]{color:var(--dm-danger, #dc2626)}.view-container:has(.fb-fields-layout){max-width:none}.fb-fields-layout{display:grid;grid-template-columns:minmax(0,6fr) minmax(320px,4fr);gap:1.25rem;align-items:start}.fb-preview-pane{position:sticky;top:1rem;min-width:0}@media(max-width:1100px){.fb-fields-layout{grid-template-columns:1fr}.fb-preview-pane{position:static}}.toggle-label{display:flex;align-items:center;gap:.4rem;font-size:.9rem;cursor:pointer;margin-right:1rem}.preset-toggles{display:flex;flex-wrap:wrap;margin-top:.75rem}.presets-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}@media(max-width:900px){.presets-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:600px){.presets-grid{grid-template-columns:1fr}}.card-header{padding:.5rem 1rem}.card-header h2{margin:0;font-size:.9rem;font-weight:600;letter-spacing:.02em}.preset-card .card-header{display:flex;align-items:center;justify-content:space-between}.preset-card .card-header h3{margin:0;font-size:1rem}.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:1rem}.media-card{background:var(--dm-card-bg, rgba(255,255,255,.04));border:1px solid var(--dm-border, rgba(255,255,255,.08));border-radius:8px;overflow:hidden}.media-preview{height:130px;display:flex;align-items:center;justify-content:center;background:#0003;overflow:hidden}.media-thumb{width:100%;height:100%;object-fit:cover}.media-thumb--file{font-size:2rem;color:var(--dm-text-muted, #888)}.media-info{padding:.5rem .75rem;display:flex;flex-direction:column;gap:.15rem}.media-name{font-size:.8rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default}.media-rename-input{width:100%;font-size:.8rem;font-weight:500;padding:.1rem .25rem;border:1px solid var(--dm-primary, #7c6af7);border-radius:3px;background:var(--dm-input-bg, transparent);color:inherit;outline:none}.media-size{font-size:.75rem;color:var(--dm-text-muted, #888)}.media-actions{padding:.5rem .75rem;display:flex;gap:.4rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}#admin-topbar{height:60px;display:flex;align-items:center;gap:1rem;padding:0 1.25rem;background:var(--dm-navbar-bg, rgba(0,0,0,.3));border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));position:sticky;top:0;z-index:200;flex-shrink:0}.topbar-brand{display:flex;align-items:center;gap:.5rem;font-weight:700;font-size:.95rem;color:inherit;flex-shrink:0;margin-right:.5rem}.topbar-brand span[data-icon],.topbar-brand svg{color:var(--dm-primary, #5b8cff);width:22px;height:22px}.topbar-brand-text{opacity:.85}.topbar-brand-logo{height:28px;width:auto;display:inline-block;vertical-align:middle;margin-right:.4em;object-fit:contain}.topbar-user{display:flex;align-items:center;gap:.6rem;flex:1}.topbar-user-name{font-size:.875rem;font-weight:500}.topbar-avatar{width:1.75rem;height:1.75rem;border-radius:50%;object-fit:cover;flex-shrink:0}.topbar-role-badge{font-size:.7rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:.15rem .45rem;border-radius:4px}.topbar-role-badge--admin{background:color-mix(in srgb,var(--dm-primary) 15%,transparent);color:var(--dm-primary)}.topbar-role-badge--manager{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.topbar-role-badge--editor{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.topbar-role-badge--subscriber{background:color-mix(in srgb,var(--dm-text-muted) 15%,transparent);color:var(--dm-text-muted)}.topbar-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.topbar-action-link{display:flex;align-items:center;gap:.35rem;font-size:.875rem;color:var(--dm-text-muted, #888);text-decoration:none;padding:.4rem .65rem;border-radius:6px;transition:color .15s,background .15s}.topbar-action-link:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.topbar-action-link span[data-icon],.topbar-action-link svg{width:16px;height:16px}.topbar-signout{display:flex;align-items:center;gap:.35rem;font-size:.875rem}.topbar-signout span[data-icon],.topbar-signout svg{width:16px;height:16px}.login-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:1rem;background:var(--dm-background, #0f1117);z-index:100;overflow-y:auto}.login-card{width:100%;max-width:460px}.ob-done-icon{font-size:3rem;color:var(--dm-success);margin-bottom:1rem;text-align:center}.btn-skip{display:block;text-align:center;margin-top:.75rem;font-size:.85rem;color:var(--dm-text-muted, #888);text-decoration:none}.btn-skip:hover{text-decoration:underline}.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}.theme-swatch{border:2px solid var(--dm-border, rgba(255,255,255,.1));border-radius:8px;overflow:hidden;cursor:pointer;transition:border-color .15s,transform .1s}.theme-swatch:hover{border-color:var(--dm-primary, #5b8cff);transform:translateY(-1px)}.theme-swatch.selected{border-color:var(--dm-primary, #5b8cff);box-shadow:0 0 0 2px var(--dm-primary, #5b8cff)}.theme-swatch-preview{height:52px;position:relative;display:flex;align-items:flex-end;padding:.35rem}.theme-swatch-accent{width:28px;height:6px;border-radius:3px}.theme-swatch-label{display:flex;justify-content:space-between;align-items:center;padding:.3rem .45rem;font-size:.7rem;background:var(--dm-card-bg, rgba(255,255,255,.04))}.theme-swatch-mode{color:var(--dm-text-muted, #888);font-size:.65rem}.login-logo{display:flex;align-items:center;gap:.75rem;margin-bottom:1.75rem;font-size:1.5rem}.login-logo span[data-icon]{font-size:2rem;color:var(--dm-primary, #5b8cff)}.login-logo h1{margin:0;font-size:1.5rem;font-weight:700}.login-card [hidden]{display:none!important}.login-heading{font-size:1.1rem;font-weight:600;margin-bottom:1.25rem}.login-rules{margin:.25rem 0 .75rem;padding-left:1.1rem;color:var(--dm-danger);font-size:.85rem}.login-rules li+li{margin-top:.2rem}.login-small{font-size:.8rem;margin-top:.75rem}.login-icon-warn{color:var(--dm-warning)}.pwf{position:relative;display:block}.pwf>input{width:100%;padding-right:2.5rem}.pwf-toggle{position:absolute;top:50%;right:.35rem;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:0;border-radius:var(--dm-radius-sm);background:transparent;color:var(--dm-text-muted);cursor:pointer}.pwf-toggle:hover,.pwf-toggle:focus-visible{color:var(--dm-text);background:var(--dm-hover-bg)}.pwf-toggle svg{width:16px;height:16px}.pwf-toggle [data-icon=eye-off],.pwf.is-shown .pwf-toggle [data-icon=eye]{display:none}.pwf.is-shown .pwf-toggle [data-icon=eye-off]{display:inline-block}.pwf-caps{display:block;margin-top:.25rem;color:var(--dm-warning);font-size:.8rem}.pwf-caps[hidden]{display:none}.btn-block{width:100%}.plugins-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem}.plugin-card{display:flex;flex-direction:column;--plugin-accent: var(--dm-primary, #5b8cff);position:relative;overflow:hidden;background-image:radial-gradient(120% 90% at 100% 0%,color-mix(in srgb,var(--plugin-accent) 13%,transparent) 0%,color-mix(in srgb,var(--plugin-accent) 4%,transparent) 42%,transparent 72%)}.plugin-card .plugin-icon{background:color-mix(in srgb,var(--plugin-accent) 16%,transparent);color:var(--plugin-accent)}.plugin-watermark{position:absolute;top:-34px;right:-30px;width:148px;height:148px;display:block;color:var(--plugin-accent);opacity:.09;pointer-events:none;z-index:0}.plugin-card>.card-body,.plugin-card>.plugin-footer{position:relative;z-index:1}.plugin-card:has(.badge-secondary) .plugin-watermark{opacity:.05}@media(prefers-reduced-motion:no-preference){.plugin-card{transition:background-image .2s ease}}.plugin-card .card-body{flex:1}.plugin-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.75rem;flex-wrap:wrap}.plugin-icon{width:40px;height:40px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;flex-shrink:0}.plugin-meta{flex:1 1 140px;min-width:0}.plugin-name{font-weight:600;margin-bottom:.15rem}.plugin-version{font-size:.75rem;color:var(--dm-text-muted, #888)}.plugin-desc{font-size:.875rem;color:var(--dm-text-muted, #888);margin-bottom:1rem}.plugin-footer{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}.plugin-footer-actions{display:flex;align-items:center;gap:.5rem}#admin-sidebar .sidebar-link{position:relative!important}#admin-sidebar .sidebar-badge{position:absolute!important;right:.75rem!important;top:50%!important;transform:translateY(-50%)!important;margin-left:0!important;padding-left:.45rem!important;padding-right:.45rem!important}#admin-sidebar .sidebar-text{padding-right:2rem!important}#admin-sidebar.sidebar-dark{background:var(--dm-surface);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header{background:var(--dm-surface-raised);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header-title{color:var(--dm-text)}#admin-sidebar.sidebar-dark .sidebar-link{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-link:hover{color:var(--dm-text);background:var(--dm-surface-overlay)}#admin-sidebar.sidebar-dark .sidebar-link.active{color:var(--dm-primary);background:color-mix(in srgb,var(--dm-primary) 14%,transparent);border-left-color:var(--dm-primary)}#admin-sidebar.sidebar-dark .sidebar-heading{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-divider{background:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-footer{background:var(--dm-surface-raised);border-color:var(--dm-border)}.sidebar-heading--collapsible{display:flex!important;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}.sidebar-heading-toggle{display:flex;align-items:center;opacity:.5;flex-shrink:0;transition:transform .2s ease}.sidebar-heading--collapsible.is-collapsed .sidebar-heading-toggle{transform:rotate(-90deg)}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.p-0{padding:0!important}.text-muted{color:var(--dm-text-muted, #888)}@media(max-width:768px){.view-container{padding:1rem}.editor-body{flex-direction:column}.editor-divider{width:auto;height:1px;cursor:default;background:var(--dm-border, rgba(255,255,255,.08))}}.image-editor{display:flex;flex-direction:column;gap:0}.image-editor-toolbar{display:flex;flex-direction:row;align-items:center;gap:.25rem;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-sep{display:inline-block;width:1px;height:1.5rem;background:var(--dm-border, rgba(255, 255, 255, .15));margin:0 .25rem;flex-shrink:0}.editor-toolbar-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent)}.editor-toolbar-caret{font-size:.6rem;line-height:1;margin-left:2px;opacity:.6}.editor-toolbar-dropdown{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:4px;min-width:160px;max-height:70vh;overflow-y:auto}.editor-toolbar-dropdown-heading{padding:6px 10px 3px;color:var(--dm-text-muted, #8a8a9a);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.editor-toolbar-dropdown-item{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:7px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-toolbar-dropdown-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-toolbar-dropdown-item span[data-icon],.editor-toolbar-dropdown-item svg{width:15px;height:15px;flex-shrink:0;opacity:.75}.editor-toolbar{position:relative}.editor-effects-dropdown-menu{position:absolute;top:100%;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:6px;min-width:180px;max-height:340px;overflow-y:auto}.editor-effects-category{padding:6px 8px 3px;font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dm-text-muted, #888)}.editor-effects-item{display:block;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:6px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-effects-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:8px;width:320px}.editor-icon-picker-search{width:100%;margin-bottom:8px;font-size:.8rem}.editor-spacer-picker{position:absolute;z-index:9999;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, #333);border-radius:8px;padding:12px;width:240px;box-shadow:0 8px 24px #00000073}.editor-spacer-picker-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888);margin-bottom:10px}.editor-spacer-picker-row{display:flex;align-items:center;gap:10px;margin-bottom:12px}.editor-spacer-slider{flex:1;accent-color:var(--dm-primary, #6366f1);cursor:pointer}.editor-spacer-slider-value{font-size:13px;font-weight:600;min-width:38px;text-align:right;color:var(--dm-text, #cdd6f4)}.editor-spacer-insert-btn{width:100%}.editor-icon-picker-size-row{display:flex;align-items:center;gap:8px;padding:0 8px 8px}.editor-icon-picker-size-row label{font-size:11px;color:var(--dm-text-muted, #888);white-space:nowrap}.editor-icon-picker-size{width:70px;font-size:12px;padding:3px 6px}.editor-icon-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(52px,1fr));gap:2px;max-height:280px;overflow-y:auto}.editor-icon-picker-item{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px 2px;border-radius:5px;cursor:pointer;background:none;border:none;color:var(--dm-text, #ddd);font-size:.58rem;text-align:center;gap:4px;overflow:hidden;transition:background .12s,color .12s}.editor-icon-picker-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker-item span[data-icon],.editor-icon-picker-item svg{width:16px;height:16px;flex-shrink:0}.editor-icon-picker-item>span:last-child{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.2}.editor-icon-picker-empty{grid-column:1 / -1;text-align:center;color:var(--dm-text-muted, #888);font-size:.8rem;padding:1.5rem}.image-editor-canvas{min-height:320px;max-height:520px;background:#111;overflow:hidden;display:flex;align-items:center;justify-content:center}.image-editor-canvas img{display:block;max-width:100%;max-height:520px}.image-editor-resize{display:flex;flex-direction:row;align-items:center;gap:.5rem;padding:.6rem .75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));font-size:.85rem}.image-editor-resize label{font-weight:600;color:var(--dm-text-muted, #888);font-size:.8rem}.image-editor-resize .form-input{width:5rem;padding:.25rem .5rem;font-size:.85rem}.image-editor-footer{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:.75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));gap:.5rem}.image-editor-effects{border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-tab-bar{display:flex;flex-direction:row;overflow-x:auto;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1));scrollbar-width:none}.image-editor-tab-bar::-webkit-scrollbar{display:none}.image-editor-tab-btn{display:inline-flex;align-items:center;gap:.35rem;padding:.5rem .85rem;font-size:.8rem;font-weight:500;border:none;border-bottom:2px solid transparent;background:transparent;cursor:pointer;color:var(--dm-text-muted, #888);white-space:nowrap;transition:color .15s,border-color .15s;flex-shrink:0}.image-editor-tab-btn:hover{color:var(--dm-text, #eee)}.image-editor-tab-btn.active{color:var(--dm-primary, #7c6af7);border-bottom-color:var(--dm-primary, #7c6af7)}.image-editor-tab-panel{padding:.75rem;max-height:200px;overflow-y:auto}.ie-presets-grid{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:.5rem}.ie-preset-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent);border-color:var(--dm-primary, #7c6af7)}.ie-server-note{font-size:.73rem;color:var(--dm-text-muted, #888);font-style:italic;margin:.25rem 0 0;line-height:1.4}.ie-slider-row{display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem}.ie-slider-label{width:6rem;font-size:.8rem;color:var(--dm-text-muted, #888);font-weight:600;flex-shrink:0}.ie-slider{flex:1;accent-color:var(--dm-primary, #7c6af7);cursor:pointer}.ie-slider-val{width:3rem;font-size:.8rem;text-align:right;color:var(--dm-text, #eee);flex-shrink:0}.ie-select{flex:1;font-size:.85rem;padding:.25rem .5rem}.ie-colour-input{width:40px;height:28px;padding:0;border:1px solid var(--dm-border, rgba(255, 255, 255, .15));border-radius:4px;cursor:pointer;background:transparent;flex-shrink:0}.ie-wm-preview-row{display:flex;align-items:center;gap:.5rem;margin:.4rem 0}.ie-wm-preview-img{width:48px;height:48px;object-fit:contain;border-radius:4px;background:var(--dm-surface-raised, rgba(255, 255, 255, .06));flex-shrink:0}.ie-wm-preview-name{font-size:.8rem;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text, #eee)}.ie-media-picker{padding:.25rem 0}.ie-media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:.5rem;max-height:300px;overflow-y:auto}.ie-media-thumb{display:flex;flex-direction:column;align-items:center;gap:.25rem;padding:.4rem;border-radius:6px;cursor:pointer;border:2px solid transparent;transition:border-color .15s,background .15s}.ie-media-thumb:hover{background:var(--dm-surface-raised, rgba(255, 255, 255, .08));border-color:var(--dm-primary, #7c6af7)}.ie-media-thumb img{width:72px;height:72px;object-fit:cover;border-radius:4px}.ie-media-thumb-name{font-size:.7rem;color:var(--dm-text-muted, #888);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:72px}.dm-slideover-left,.dm-slideover-right{width:min(40rem,95vw)!important;min-width:min(36rem,100vw)!important;max-width:100vw!important}.dm-slideover-resizer{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;z-index:2;background:transparent}.dm-slideover-right>.dm-slideover-resizer{left:0}.dm-slideover-left>.dm-slideover-resizer{right:0}.dm-slideover-resizer:hover,.is-resizing>.dm-slideover-resizer{background:var(--dm-primary);opacity:.7}.dm-slideover.is-resizing{user-select:none;transition:none!important}.dm-slideover-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border, #333);flex-shrink:0}.dm-slideover-title{margin:0;font-size:1rem;font-weight:600}.dm-slideover-close{padding:.2rem .35rem!important;line-height:1;font-size:.75rem}.dm-slideover-body{flex:1;overflow:auto;overscroll-behavior:contain;min-height:0;padding:1.5rem!important;box-sizing:border-box}.dm-slideover-body:empty{flex:0 0 auto;padding:0!important}.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-body):not(.dm-slideover-close){padding:1.5rem!important;box-sizing:border-box;flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.dm-slideover-body,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close){scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}.dm-slideover-body::-webkit-scrollbar,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar{width:8px;height:8px}.dm-slideover-body::-webkit-scrollbar-track,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-track{background:transparent}.dm-slideover-body::-webkit-scrollbar-thumb,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}.dm-slideover-body::-webkit-scrollbar-thumb:hover,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.dm-slideover-body>div{padding-left:0!important;padding-right:0!important}.dm-slideover-body>button.btn:last-child{margin-top:.5rem}.dconfig-textarea{font-family:monospace;min-height:100px;resize:vertical}.dm-editor-line-numbers{white-space:pre}.dm-code-inline{font-family:Fira Code,Courier New,monospace;font-size:.82em;padding:.15em .35em;border-radius:3px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08))}.dm-code-block{font-family:Fira Code,Courier New,monospace;font-size:.82rem;line-height:1.6;padding:.65rem .9rem;border-radius:6px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08));white-space:pre;overflow-x:auto;display:block;margin:.4rem 0}.tabs-centered{text-align:center}.tabs-centered .tab-list{display:inline-flex}.tabs-centered .tab-content{text-align:left}@media(max-width:768px){.view-header{flex-direction:column;align-items:flex-start}.theme-grid{grid-template-columns:repeat(2,1fr)}.nav-item-row{flex-wrap:wrap}.nav-col-icon,.nav-col-parent{display:none}#admin-topbar{padding:0 .75rem}.topbar-brand-text{display:none}.image-editor-toolbar{flex-wrap:wrap}}#topbar-bell{position:relative}.topbar-action-link[hidden],.topbar-bell-badge[hidden]{display:none}.topbar-bell-badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 4px;background:var(--dm-danger, #dc2626);color:var(--dm-danger-text, #fff);font-size:10px;font-weight:700;line-height:16px;border-radius:9999px;text-align:center;pointer-events:none}.cb-scaffolder{padding:1rem 1.1rem;background:var(--dm-background-alt);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-scaffolder-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-scaffolder-head .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-scaffolder-head h2{margin:0;font-size:1.05rem;font-weight:700;color:var(--dm-text)}.cb-scaffolder-blurb{margin:0 0 .75rem;font-size:.88rem;line-height:1.5;color:var(--dm-text-muted)}.cb-recipe-list{display:flex;flex-direction:column;gap:.5rem}.cb-recipe-card{display:flex;align-items:flex-start;gap:.75rem;text-align:left;padding:.75rem 1rem;background:var(--dm-surface);border:1px solid var(--dm-border);border-radius:6px;cursor:pointer;transition:border-color .12s;width:100%;color:var(--dm-text)}.cb-recipe-card:hover{border-color:var(--dm-primary)}.cb-recipe-card .cb-icon{flex-shrink:0;font-size:1.5rem;color:var(--dm-primary);margin-top:.1rem}.cb-recipe-meta{flex:1}.cb-recipe-name{font-weight:600;margin-bottom:.15rem;font-size:.95rem;color:var(--dm-text)}.cb-recipe-desc{font-size:.83rem;line-height:1.45;color:var(--dm-text-muted)}.cb-apply-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-apply-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-apply-head .cb-icon{color:var(--dm-primary);font-size:1.4rem}.cb-apply-head h3{margin:0;font-size:1rem;font-weight:600;color:var(--dm-text)}.cb-apply-desc,.cb-apply-hint{margin:.25rem 0 .75rem;font-size:.85rem;line-height:1.5;color:var(--dm-text-muted)}.cb-apply-hint{font-size:.75rem;margin-top:.2rem}.cb-apply-field{margin-bottom:.6rem}.cb-apply-field label{display:block;font-size:.82rem;font-weight:600;margin-bottom:.2rem;color:var(--dm-text)}.cb-apply-field input{width:100%;padding:.4rem .55rem;border:1px solid var(--dm-border);border-radius:4px;font-size:.88rem;background:var(--dm-surface);color:var(--dm-text)}.cb-apply-status{margin:.5rem 0;font-size:.85rem;min-height:1.2rem;color:var(--dm-text)}.cb-apply-status.cb-error{color:var(--dm-danger, #dc2626)}.cb-apply-buttons{display:flex;gap:.5rem;justify-content:flex-end;margin-top:.5rem}.cb-success-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-success, #16a34a);border-radius:8px;color:var(--dm-text)}.cb-success-panel .cb-icon{color:var(--dm-success, #16a34a);font-size:1.4rem}.cb-success-summary{margin:.25rem 0 .5rem;padding-left:1.2rem;font-size:.86rem;line-height:1.6;color:var(--dm-text)}.cb-success-warning{margin:.5rem 0;padding:.5rem .75rem;background:var(--dm-background-alt);border-left:3px solid var(--dm-warning, #eab308);border-radius:0 4px 4px 0;font-size:.82rem;color:var(--dm-text-muted)}.cb-success-snippet-label{margin:0 0 .25rem;font-size:.82rem;font-weight:600;color:var(--dm-text)}.cb-success-actions{display:flex;gap:.5rem;margin-top:.5rem;flex-wrap:wrap}.cb-code{position:relative}.cb-code pre{background:var(--dm-background-alt);color:var(--dm-text);display:block;padding:.6rem 2.4rem .6rem .75rem;white-space:pre;overflow-x:auto;margin:0;border-radius:6px;font-size:.82em;font-family:monospace;line-height:1.45}.cb-code .cb-copy{position:absolute;top:.35rem;right:.35rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.2rem;line-height:1;color:var(--dm-text)}.cb-code .cb-copy:hover{opacity:1}.cb-intro{padding:.75rem 1rem;border-left:3px solid var(--dm-primary);background:var(--dm-background-alt);border-radius:0 6px 6px 0}.cb-intro p{margin:0;font-size:.92rem;line-height:1.5;color:var(--dm-text)}.cb-tutorial-link{display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;border:1px solid var(--dm-border);border-radius:6px;text-decoration:none;color:var(--dm-text);font-size:.88rem;transition:border-color .12s}.cb-tutorial-link:hover{border-color:var(--dm-primary)}.cb-tutorial-link .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-tutorial-link .cb-arrow{color:var(--dm-text-muted);font-size:1.1rem;margin-left:auto}.menu-tree-row{display:grid;grid-template-columns:26px 1.4fr 1.4fr .9fr .7fr .9fr repeat(6,auto);gap:6px;align-items:center;padding:4px 0;transition:opacity .15s ease}.menu-tree-row--hidden{opacity:.5}.menu-tree-row--tool .me-tool-badge{margin-left:.4rem;font-size:.7rem;vertical-align:middle}.menu-tree-row--default .me-row-label{font-style:italic;opacity:.8}.menu-tree-grip{cursor:grab;color:var(--dm-text-muted)}.menu-tree-grip:hover{color:var(--dm-text)}.menu-tree{padding:8px 0}.menu-tree-row--separator{display:grid;grid-template-columns:26px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--separator:hover{opacity:1}.menu-tree-row--separator .me-sep-line{display:flex;align-items:center;gap:10px;width:100%}.menu-tree-row--separator .me-sep-line:before,.menu-tree-row--separator .me-sep-line:after{content:"";flex:1;border-top:1px dashed var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--separator .me-sep-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.dm-admin-sidebar .sidebar-divider{border:0;border-top:1px solid var(--dm-border, rgba(128, 128, 128, .5));margin:.5rem .75rem;opacity:.8}.dm-admin-sidebar .sidebar-spacer--xs{height:var(--dm-space-1, .25rem)}.dm-admin-sidebar .sidebar-spacer--sm{height:var(--dm-space-2, .5rem)}.dm-admin-sidebar .sidebar-spacer--md{height:var(--dm-space-4, 1rem)}.dm-admin-sidebar .sidebar-spacer--lg{height:var(--dm-space-6, 1.5rem)}.dm-admin-sidebar .sidebar-spacer--xl{height:var(--dm-space-10, 2.5rem)}.dm-admin-sidebar .sidebar-spacer--flex{flex:1 1 auto;min-height:var(--dm-space-4, 1rem)}.dm-admin-sidebar--has-flex-spacer{display:flex;flex-direction:column;min-height:100%}.menu-tree-row--spacer{display:grid;grid-template-columns:26px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--spacer:hover{opacity:1}.menu-tree-row--spacer .me-spacer-line{display:flex;align-items:center;gap:8px;width:100%}.menu-tree-row--spacer .me-spacer-line:before,.menu-tree-row--spacer .me-spacer-line:after{content:"";flex:1;border-top:1px dotted var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--spacer .me-spacer-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.menu-tree-row--spacer .me-spacer-size{width:auto;min-width:5.5rem;height:26px;padding:0 .35rem;font-size:.75rem}.menu-tree-row .me-icon-wrap{display:flex;gap:2px}.menu-tree-row .me-icon-wrap .me-icon{flex:1;min-width:0}.menu-tree-row .me-icon-wrap .me-icon-pick{flex-shrink:0;padding:.2rem .45rem;font-size:.85em}.dm-admin-sidebar{display:flex;flex-direction:column;gap:2px;padding:8px 0;font-size:.875rem}.dm-admin-sidebar details{margin:0}.dm-admin-sidebar details>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.4rem .75rem;border-radius:4px;user-select:none;font-size:.78rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888)}.dm-admin-sidebar details details>summary{font-size:.875rem;font-weight:500;text-transform:none;letter-spacing:0;color:inherit}.dm-admin-sidebar .dm-menu-badge{font-size:.7rem;font-weight:600}.dm-admin-sidebar details>summary::-webkit-details-marker{display:none}.dm-admin-sidebar details>summary:after{content:"\25b8";margin-left:auto;transition:transform .15s ease;color:var(--dm-text-muted, #999);font-size:.85em}.dm-admin-sidebar details[open]>summary:after{transform:rotate(90deg)}.dm-admin-sidebar details>div{padding-left:1rem;border-left:1px solid var(--dm-border-light, rgba(0, 0, 0, .08));margin-left:.95rem}.dm-admin-sidebar .sidebar-link{display:flex;align-items:center;gap:.5rem;padding:.35rem .75rem;text-decoration:none;color:var(--dm-text, inherit);border-radius:4px}.dm-admin-sidebar .sidebar-link:hover,.dm-admin-sidebar details>summary:hover{background:var(--dm-hover-bg, rgba(0, 0, 0, .05))}.dm-admin-sidebar .sidebar-link.active{background:var(--dm-active-bg, rgba(0, 0, 0, .08));font-weight:600}.dm-admin-sidebar .sidebar-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-admin-sidebar [data-icon]{flex-shrink:0}.dm-admin-sidebar-header{position:sticky;top:0;z-index:2;background:var(--dm-surface);display:flex;align-items:center;gap:.5rem;padding:.65rem .85rem;margin:0 0 .5rem;font-weight:600;font-size:.95rem;letter-spacing:.01em;color:var(--dm-text, inherit);border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.dm-admin-sidebar--dark .dm-admin-sidebar-header{background:#1a1d24}.dm-admin-sidebar--light .dm-admin-sidebar-header{background:#fff}.dm-admin-sidebar-header [data-icon]{color:var(--dm-text-muted, #999)}.dm-admin-sidebar-header .dm-admin-sidebar-arrange{margin-left:auto;padding:.2rem .35rem;color:var(--dm-text-muted, #999);line-height:1}.dm-admin-sidebar-header .dm-admin-sidebar-arrange:hover,.dm-admin-sidebar-header .dm-admin-sidebar-arrange:focus-visible{color:var(--dm-text)}.dm-admin-sidebar.is-arranging>:not(.dm-admin-sidebar-header):not(.sb-arrange):not(style){display:none!important}.dm-admin-sidebar.is-arranging .dm-admin-sidebar-arrange{display:none}.sb-arrange{box-sizing:border-box;max-width:100vw;padding:0 .5rem 1rem;animation:sb-arrange-in .18s cubic-bezier(.2,.8,.2,1)}@keyframes sb-arrange-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}.sb-arrange-bar{position:sticky;top:2.6rem;z-index:2;display:flex;align-items:center;gap:.4rem;padding:.4rem .25rem;background:inherit}.sb-arrange-title{font-weight:600;margin-right:auto}.sb-arrange-hint{margin:0 .25rem .5rem;font-size:.78rem;line-height:1.35;color:var(--dm-text-muted)}.sb-arr-row{display:flex;align-items:center;gap:.45rem;padding:.35rem .4rem .35rem calc(.4rem + var(--sb-arr-depth, 0) * 1rem);border-radius:var(--dm-radius-sm, 4px);cursor:grab;user-select:none;font-size:.9rem}.sb-arr-row:hover{background:color-mix(in srgb,var(--dm-text) 6%,transparent)}.sb-arr-row:focus-visible{outline:2px solid var(--dm-primary);outline-offset:-2px}.sb-arr-row--folder .sb-arr-text{font-weight:600}.sb-arr-row--hidden .sb-arr-text,.sb-arr-row--hidden .sb-arr-icon{opacity:.45;text-decoration:line-through}.sb-arr-row--structural .sb-arr-text{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted)}.sb-arr-grip{color:var(--dm-text-muted);flex:none}.sb-arr-icon{width:16px;flex:none}.sb-arr-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-arr-hide{flex:none;display:inline-flex;padding:.15rem;border:0;border-radius:var(--dm-radius-sm, 4px);background:transparent;color:var(--dm-text-muted);cursor:pointer}.sb-arr-hide:hover,.sb-arr-hide:focus-visible{color:var(--dm-text);background:color-mix(in srgb,var(--dm-text) 8%,transparent)}.sb-arr-lock{flex:none;color:var(--dm-text-muted);opacity:.6}.dm-admin-sidebar .sidebar-badge{margin-left:auto;padding:0 .4rem;min-width:1.25rem;height:1.1rem;line-height:1.1rem;text-align:center;font-size:.7rem;font-weight:600;border-radius:999px;background:var(--dm-active-bg, rgba(0, 0, 0, .12));color:var(--dm-text-muted, #888)}.dm-admin-sidebar .sidebar-link.active .sidebar-badge{background:var(--dm-primary, #4a86e8);color:var(--dm-primary-text, #fff)}.dm-admin-sidebar .sidebar-children{overflow:hidden;transition:max-height .22s ease,opacity .18s ease}.dm-admin-sidebar details:not([open])>.sidebar-children{opacity:0}.dm-admin-sidebar{position:relative}.dm-admin-sidebar-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;background:transparent;z-index:10;transition:background .15s}.dm-admin-sidebar-handle:hover,.dm-admin-sidebar-handle:active{background:var(--dm-primary, #4a86e8);opacity:.35}.dm-admin-sidebar--dark{background:#1a1d24;color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link,.dm-admin-sidebar--dark summary{color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link:hover,.dm-admin-sidebar--dark details>summary:hover{background:#ffffff0f}.dm-admin-sidebar--dark .sidebar-link.active{background:#4a86e840}.dm-admin-sidebar--dark .sidebar-badge{background:#ffffff1f;color:#cbd0d8}.dm-admin-sidebar--light{background:#fff;color:#1a1d24;border-right:1px solid rgba(0,0,0,.08)}.dm-admin-sidebar--light .sidebar-link,.dm-admin-sidebar--light summary{color:#1a1d24}.dm-admin-sidebar--light .sidebar-link:hover,.dm-admin-sidebar--light details>summary:hover{background:#0000000a}.dm-admin-sidebar--light .sidebar-link.active{background:#4a86e826}.dm-admin-sidebar--transparent{background:transparent}.page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin:0 0 1.25rem;padding-bottom:.75rem;border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.page-header h2{margin:0;display:flex;align-items:center;gap:.5rem;font-size:1.4rem;line-height:1.2}.page-header h2 [data-icon]{color:var(--dm-text-muted, #888)}.header-actions{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.card+.card,.card+p,p+.card,.card+.toolbar,.toolbar+.card,.card+.grid{margin-top:1rem}.toolbar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin:0 0 1rem}.btn+.btn,.btn+a.btn,a.btn+.btn,a.btn+a.btn{margin-left:.35rem}[style*=inline-flex] .btn+.btn,[style*=inline-flex] .btn+a.btn,[style*=inline-flex] a.btn+.btn{margin-left:0}.card-body>[id$=-form],.card-body>form{margin:.25rem 0}.card-header{display:flex;align-items:center;gap:.5rem}.card-header h3{margin:0;font-size:1.05rem}.card-header [data-icon]{color:var(--dm-text-muted, #888)}.page-header+p.text-muted{margin:-.5rem 0 1rem}.dm-pe-grid{gap:.75rem 1rem}.dm-pe-grid .form-group{display:flex;flex-direction:column;gap:.25rem;margin:0}.dm-pe-grid .form-group.col-span-2{grid-column:1 / -1}.dm-pe-grid label{font-size:.85rem;font-weight:600;color:var(--dm-text, inherit)}.dm-pe-grid label .required{color:var(--dm-danger, #c33);margin-left:2px}.dm-pe-grid .form-hint{font-size:.75rem;color:var(--dm-text-muted, #888);margin-top:.1rem}.dm-pe-grid .form-input{width:100%;padding:.4rem .6rem}.dm-pe-grid textarea.form-input{resize:vertical;min-height:2.5rem}.dm-menu-badge{display:inline-block;margin-left:6px;padding:1px 7px;font-size:.7em;font-weight:700;line-height:1.4;border-radius:999px;background:var(--dm-text-muted);color:var(--dm-text-inverse, #fff);vertical-align:middle}.menu-tree-row--slim{display:grid;grid-template-columns:26px 1fr auto repeat(9,auto);gap:6px;align-items:center}.menu-tree-row--slim .me-row-label{font-weight:600}.menu-tree-row--slim .me-row-url{color:var(--dm-text-muted);font-size:.85em}.me-pages-picker{display:flex;gap:6px;align-items:center;margin-bottom:6px}.me-pages-picker .form-input{flex:1;min-width:0}.me-colour-control{display:flex;gap:6px;align-items:center}.me-colour-control .me-colour-hex{width:48px;height:32px;padding:2px;flex:none}.me-bind-summary{padding:.6rem .8rem;border:1px solid var(--dm-border, rgba(128, 128, 128, .35));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-text) 4%,transparent);font-size:.9em}.me-bind-summary code{font-size:.9em}.me-item-form{display:flex;flex-direction:column;gap:10px;padding:4px 2px}.me-item-form .form-field{display:flex;flex-direction:column;gap:4px}.me-item-form .form-label{font-size:.85em;color:var(--dm-text-muted)}.me-form-section{margin:12px 0 2px;padding-top:10px;border-top:1px solid var(--dm-border-light, rgba(0,0,0,.15));font-size:.78em;text-transform:uppercase;letter-spacing:.06em;color:var(--dm-text-muted)}.me-item-form .me-form-section:first-child{margin-top:0;padding-top:0;border-top:0}.me-item-form .me-colour-hex{width:48px;height:32px;padding:2px}.me-item-form .me-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.me-item-form .me-field-grid .form-field{margin:0}.me-item-form .me-icon-field{display:flex;align-items:center;gap:8px}.me-item-form .me-icon-field .form-input{flex:1}.me-item-form .me-icon-preview{width:24px;height:24px;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;color:var(--dm-text-muted)}#admin-sidebar.dm-menu-floating{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 8px);box-shadow:var(--dm-shadow-lg);overflow:hidden}@media(max-width:768px){#admin-sidebar.dm-menu-floating{position:static!important;inset:auto!important;max-height:none!important;transform:none!important}.dashboard-wrapper{padding-left:0!important;padding-right:0!important}}[data-logic-section]{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 6px);padding:.9rem 1rem 1rem;margin-bottom:1rem;background:color-mix(in srgb,var(--dm-text) 3%,transparent)}[data-logic-section] .fb-logic-cond-row,[data-logic-section] .fb-logic-val-rule{padding:.55rem .65rem;border-radius:var(--dm-radius-sm, 4px);border:1px solid var(--dm-border);background:var(--dm-surface, transparent)}[data-logic-section] .fb-logic-cond-row:last-of-type,[data-logic-section] .fb-logic-val-rule:last-of-type{margin-bottom:.75rem}[data-logic-section]>.btn{margin-top:.15rem}[data-logic-section] textarea{min-height:5rem}.project-filter-notice{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;margin:0 0 1rem;padding:.6rem .85rem;border:1px solid var(--dm-border);border-left:3px solid var(--dm-info, var(--dm-primary));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-info, var(--dm-primary)) 6%,transparent);font-size:.85rem;color:var(--dm-text-muted)}.project-filter-notice a{color:var(--dm-primary);font-weight:600}.ctx-help{display:inline-flex;align-items:center;justify-content:center;width:1.05rem;height:1.05rem;margin-left:.35rem;padding:0;border:1px solid var(--dm-border-dark, var(--dm-border));border-radius:var(--dm-radius-full, 9999px);background:transparent;color:var(--dm-text-muted);font-size:.68rem;font-weight:700;line-height:1;cursor:pointer;vertical-align:middle;flex-shrink:0}.ctx-help:hover,.ctx-help:focus-visible{border-color:var(--dm-primary);color:var(--dm-primary);outline:none}.card-header h3 .ctx-help{align-self:center}.ctx-preview-card{position:sticky;top:1rem}@media(max-width:1100px){.ctx-workspace>.col-8,.ctx-workspace>.col-4{flex:0 0 auto;width:100%}.ctx-preview-card{position:static}}.dm-plugin-shell{border:1px solid var(--dm-border);border-radius:var(--dm-radius-lg, 12px);background:var(--dm-surface);overflow:hidden}.dm-plugin-banner{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.7rem 1rem;background:var(--dm-background-alt);border-bottom:1px solid var(--dm-border)}.dm-plugin-banner-identity{display:flex;align-items:center;gap:.55rem;min-width:0;margin-right:auto}.dm-plugin-banner-actions{display:flex;align-items:center;gap:.25rem;flex:0 0 auto;margin-right:.15rem;padding-right:.4rem;border-right:1px solid var(--dm-border)}.dm-plugin-banner-action{padding:.25rem .4rem;line-height:1;color:var(--dm-text-muted)}.dm-plugin-banner-action:hover{color:var(--dm-primary)}.dm-plugin-banner-icon{display:inline-flex;align-items:center;color:var(--dm-primary);flex:0 0 auto}.dm-plugin-banner-name{margin:0;font-size:1.05rem;font-weight:600;letter-spacing:.01em;color:var(--dm-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dm-activity{display:inline-flex;align-items:center;flex:0 0 auto;margin-left:.35rem}.dm-activity domma-loader{display:inline-block;line-height:0}.dm-activity[hidden]{display:none!important}#admin-topbar>.dm-activity{margin:0 .75rem 0 0}.dm-plugin-banner-parent{font-weight:500;color:var(--dm-text-muted)}.dm-plugin-banner-sep{margin:0 .4rem;color:var(--dm-text-muted)}.dm-plugin-banner-facts{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}.dm-plugin-fact{font-size:.72rem;line-height:1.6;padding:1px 8px;border-radius:999px;border:1px solid var(--dm-border);color:var(--dm-text-muted);background:var(--dm-surface);white-space:nowrap}.dm-plugin-fact--version{font-variant-numeric:tabular-nums;color:var(--dm-text)}.dm-plugin-fact--licence.is-included{color:var(--dm-info);border-color:var(--dm-info)}.dm-plugin-fact--licence.is-licensed{color:var(--dm-success);border-color:var(--dm-success)}.dm-plugin-fact--expiry{font-variant-numeric:tabular-nums}.dm-plugin-fact--expiry.is-warning{color:var(--dm-warning);border-color:var(--dm-warning)}.dm-plugin-fact--expiry.is-danger{color:var(--dm-danger);border-color:var(--dm-danger)}.dm-plugin-body{padding:1rem}.dm-plugin-body .card.dm-plugin-unwrap{border:0;background:none;box-shadow:none;margin:0}.dm-plugin-body .card.dm-plugin-unwrap>.card-body{padding:0}.dm-plugin-body>.p-4{padding:0}@media(max-width:640px){.dm-plugin-banner{align-items:flex-start;flex-direction:column;gap:.5rem}.dm-plugin-body{padding:.75rem}}.analytics-filter{max-width:240px}.dm-help-btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;margin-left:.3rem;padding:0;border:0;background:none;line-height:1;color:var(--dm-text-muted);opacity:.75;cursor:pointer}.dm-help-btn:hover,.dm-help-btn:focus-visible{color:var(--dm-primary);opacity:1}.dm-help-pop{position:fixed;z-index:10050;max-width:300px;padding:.6rem .75rem;background:var(--dm-surface, var(--dm-background));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:var(--dm-radius-md);box-shadow:0 8px 24px #00000040;font-size:.85rem;line-height:1.45;text-align:left;font-weight:400}.dm-help-pop strong{display:block;margin-bottom:.2rem;font-weight:600}.dm-help-pop p{margin:0}.dm-admin-sidebar .sidebar-badge[data-badge-label]{cursor:help}.dm-admin-sidebar .sidebar-badge--danger,.dm-admin-sidebar .sidebar-link.active .sidebar-badge--danger{background:var(--dm-danger, #dc2626);color:#fff}.dm-admin-sidebar .sidebar-badge--live{background:color-mix(in srgb,var(--dm-success, #16a34a) 20%,transparent);color:var(--dm-success, #16a34a)}#admin-sidebar .sidebar-badge--live{padding-left:1.05rem!important}#admin-sidebar summary>.sidebar-badge--sum{position:static!important;transform:none!important;margin-left:auto!important;margin-right:.45rem;text-transform:none;letter-spacing:0}#admin-sidebar summary:has(>.sidebar-badge--sum):after{margin-left:0}#admin-sidebar details[open]>summary>.sidebar-badge--sum{display:none}.dm-admin-sidebar .sidebar-badge--live:before{content:"";position:absolute;left:.4rem;top:50%;width:.4rem;height:.4rem;margin-top:-.2rem;border-radius:50%;background:currentColor;animation:dm-badge-pulse 2s ease-in-out infinite}@keyframes dm-badge-pulse{50%{opacity:.35}}@media(prefers-reduced-motion:reduce){.dm-admin-sidebar .sidebar-badge--live:before{animation:none}}.dm-badge-pop{width:290px;max-width:calc(100vw - 16px);font-size:.8rem;pointer-events:none}.dm-badge-pop-title{display:block;font-size:.85rem}.dm-badge-pop-sub{margin:.1rem 0 .5rem;color:var(--dm-text-muted)}.dm-badge-pop-rows{display:grid;grid-template-columns:1fr auto;gap:.2rem .75rem;margin:0 0 .5rem;padding:.45rem 0;border-top:1px solid var(--dm-border);border-bottom:1px solid var(--dm-border)}.dm-badge-pop-rows dt{color:var(--dm-text-muted)}.dm-badge-pop-rows dd{margin:0;text-align:right;font-weight:600;font-variant-numeric:tabular-nums}.dm-badge-pop-items{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.dm-badge-pop-items li{display:flex;flex-direction:column;min-width:0}.dm-badge-pop-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-badge-pop-meta{font-size:.72rem;color:var(--dm-text-muted)}.dm-badge-pop .is-danger,.dm-badge-pop li.is-danger .dm-badge-pop-meta{color:var(--dm-danger, #dc2626)}.dm-badge-pop-empty{margin:0;color:var(--dm-text-muted)}.dm-plugin-body,.dm-slideover{font-family:var(--dm-font-sans, inherit)}.dm-plugin-body :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea),.dm-slideover :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea){font-family:inherit}.dm-plugin-body :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg),.dm-slideover :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg){font-size:var(--dm-text-sm)}.dm-plugin-body .form-input-lg{font-size:var(--dm-text-base)}.dm-plugin-body :is(.font-mono,code,pre,kbd),.dm-slideover :is(.font-mono,code,pre,kbd){font-family:var(--dm-font-mono, monospace)}.dm-plugin-body .form-label,.dm-slideover .form-label{font-size:var(--dm-text-sm)}.related-box{display:flex;flex-direction:column;gap:.6rem;border-top:1px solid var(--dm-border);padding-top:.75rem}.related-box[hidden]{display:none}.related-head{display:flex;align-items:center;gap:.4rem}.related-head strong{flex:1}.related-list{list-style:none;margin:.3rem 0 0;padding:0;display:flex;flex-direction:column;gap:.25rem}.related-list li{display:flex;flex-direction:column}.related-list li.is-past{opacity:.7}.related-meta,.related-note,.related-loading{color:var(--dm-text-muted);font-size:var(--dm-text-xs);margin:0}.login-challenge{display:flex;flex-direction:column;gap:.6rem;margin-bottom:.75rem}.login-challenge #challenge-code{font-size:1.25rem;letter-spacing:.2em;text-align:center}.login-trust{display:flex;align-items:center;gap:.45rem;font-size:.875rem}.login-enrol{display:flex;flex-direction:column;align-items:center;gap:.6rem;margin-bottom:1rem}.login-enrol img{background:#fff;padding:.5rem;border-radius:.5rem}.login-secret{display:flex;flex-direction:column;align-items:center;gap:.25rem;text-align:center}.login-secret code{font-size:.95rem;letter-spacing:.08em;word-break:break-all}.usx-secret{display:flex;flex-direction:column;gap:.75rem;padding:1rem}.usx-secret-link{display:block;padding:.6rem .75rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);background:var(--dm-background-alt);word-break:break-all;font-size:.8rem;user-select:all}.usx-secret-actions{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.usx-secret-actions .btn{display:inline-flex;align-items:center;gap:.35rem}.usx-secret-note{margin-right:auto;color:var(--dm-success)}.usx-secret-foot{color:var(--dm-text-muted);font-size:.8rem;margin:0}.uex-reset{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem .5rem;margin-top:.5rem}.uex-reset>small:first-child{flex-basis:100%;color:var(--dm-text-muted)}.uex-reset .btn{display:inline-flex;align-items:center;gap:.35rem}.uex-reset-open{flex-basis:100%;color:var(--dm-info)}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Domma Tools CSS v0.
|
|
2
|
+
* Domma Tools CSS v0.45.0
|
|
3
3
|
* Dynamic Object Manipulation & Modeling API
|
|
4
4
|
* (c) 2026 Darryl Waterhouse & DCBW-IT
|
|
5
|
-
* Built: 2026-09-
|
|
6
|
-
* Commit:
|
|
5
|
+
* Built: 2026-09-27T18:03:07.363Z
|
|
6
|
+
* Commit: 224c5a0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/*!
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Domma Tools v0.
|
|
2
|
+
* Domma Tools v0.45.0
|
|
3
3
|
* Developer tools: Theme Roller & Page Roller
|
|
4
4
|
* (c) 2026 Darryl Waterhouse & DCBW-IT
|
|
5
|
-
* Built: 2026-09-
|
|
6
|
-
* Commit:
|
|
5
|
+
* Built: 2026-09-27T18:02:54.057Z
|
|
6
|
+
* Commit: 224c5a0
|
|
7
7
|
*
|
|
8
8
|
* Requires: domma.min.js
|
|
9
9
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{applyDrop as d,isWithin as l}from"./menu-tree.js";import{isStructural as c}from"./menu-editor-arrange.js";const p={before:"above",after:"below",into:"into"};export function dropRow(o,r,u,f){const i=f==="after"?o.find(t=>t.parentId===u):null,n=i?i.id!==r&&d(o,r,i.id,"above"):d(o,r,u,p[f]);if(n){const t=o.find(e=>e.id===r);t&&(t.touched=!0)}return n}export function sortableMenuRows(o,r,u,{items:f,handle:i=null}){return typeof E.sortable!="function"?null:E.sortable(o,{items:f,handle:i,nest:!0,accepts(n,t,e){const s=r();return!(l(s,t.dataset.id,n.dataset.id)||e==="into"&&c(s.find(a=>a.id===t.dataset.id)))},onDrop({key:n,targetKey:t,zone:e}){return dropRow(r(),n,t,e)?(u(),!0):!1}})}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{api as S}from"../api.js";import{flatten as D,nest as k}from"./menu-rows.js";import{ensureLockedTools as N,isLockedUrl as R,placeTools as T}from"./sidebar-grouping.js";import{indentRow as z,moveRow as L,outdentRow as M}from"./menu-editor-arrange.js";import{sortableMenuRows as O}from"./menu-drag.js";const $="admin-sidebar",g=n=>String(n??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");export function canArrange(n=[]){return n.includes("menus")||n.includes("menus.update")}export function arrangeButtonMarkup(){return'<button type="button" class="btn btn-sm btn-ghost dm-admin-sidebar-arrange" title="Arrange the sidebar - drag items to move them or put them in folders" aria-label="Arrange the sidebar"><span data-icon="grip-vertical" data-icon-size="16"></span></button>'}function j(n){const s=new Set,l=new Set,d=r=>{for(const o of n.filter(m=>m.parentId===r))!o.type&&R(o.url)&&!l.has(o.url)&&(l.add(o.url),s.add(o.id)),d(o.id)};return d(null),s}function I(n){const s=j(n),l=new Set(n.map(o=>o.parentId).filter(Boolean)),d=[],r=(o,m)=>{for(const e of n.filter(i=>i.parentId===o)){const i=` style="--sb-arr-depth:${m}"`;if(e.type==="separator"||e.type==="spacer"){d.push(`<div class="sb-arr-row sb-arr-row--structural" data-id="${g(e.id)}" tabindex="0"${i}>
|
|
2
|
+
<span class="sb-arr-grip" data-icon="grip-vertical" data-icon-size="14"></span>
|
|
3
|
+
<span class="sb-arr-text">${e.type==="separator"?"Separator":"Spacer"}</span></div>`);continue}const w=l.has(e.id),a=e.text||e.tool?.label||"(no label)",b=s.has(e.id)?'<span class="sb-arr-lock" data-icon="lock" data-icon-size="14" title="Always shown - it can be moved, not hidden"></span>':`<button type="button" class="sb-arr-hide" aria-pressed="${e.hidden?"true":"false"}" title="${e.hidden?"Hidden - click to show":"Hide"}" aria-label="${e.hidden?"Show":"Hide"} ${g(a)}"><span data-icon="${e.hidden?"eye-off":"eye"}" data-icon-size="14"></span></button>`;d.push(`<div class="sb-arr-row${w?" sb-arr-row--folder":""}${e.hidden?" sb-arr-row--hidden":""}" data-id="${g(e.id)}" tabindex="0" aria-label="${g(a)}"${i}>
|
|
4
|
+
<span class="sb-arr-grip" data-icon="grip-vertical" data-icon-size="14"></span>
|
|
5
|
+
${e.icon?`<span class="sb-arr-icon" data-icon="${g(e.icon)}" data-icon-size="16"></span>`:'<span class="sb-arr-icon"></span>'}
|
|
6
|
+
<span class="sb-arr-text">${g(a)}</span>
|
|
7
|
+
${b}</div>`),r(e.id,m+1)}};return r(null,0),d.join("")}export async function startArrange(n){const s=n.querySelector(".dm-admin-sidebar");if(!s||s.classList.contains("is-arranging"))return;let l,d;try{[l,d]=await Promise.all([S.menus.get($),H.get("/api/sidebar/registered-items").catch(()=>[])])}catch{E.toast("Could not load the sidebar menu to arrange.",{type:"error"});return}if(!l){E.toast("There is no admin sidebar menu to arrange yet - create one in Content > Menus.",{type:"warning"});return}let r=D(N(T(l.items||[],d||[],{forEditor:!0}),{leaveInHiddenFolders:!0}));const o=JSON.stringify(k(r)),m=()=>JSON.stringify(k(r))!==o,e=document.createElement("div");e.className="sb-arrange",e.setAttribute("role","region"),e.setAttribute("aria-label","Arrange the sidebar");const i=document.createElement("div");i.className="sb-arrange-bar",i.append(Object.assign(document.createElement("span"),{className:"sb-arrange-title",textContent:"Arrange"}),Object.assign(document.createElement("button"),{type:"button",className:"btn btn-sm btn-ghost sb-arrange-cancel",textContent:"Cancel"}),Object.assign(document.createElement("button"),{type:"button",className:"btn btn-sm btn-primary sb-arrange-done",textContent:"Done"}));const w=Object.assign(document.createElement("p"),{className:"sb-arrange-hint",textContent:"Drag an item to move it. Drop it on the middle of another to put it inside. The eye hides or shows it. Alt+arrow keys move the focused item."}),a=document.createElement("div");a.className="sb-arrange-list",e.append(i,w,a);const b=()=>{const p=document.createRange();p.selectNodeContents(a),a.replaceChildren(p.createContextualFragment(I(r))),Domma.icons.scan(a)},A=p=>requestAnimationFrame(()=>a.querySelector(`.sb-arr-row[data-id="${CSS.escape(p)}"]`)?.focus());e.style.width=`${Math.max(Math.round(s.getBoundingClientRect().width),240)}px`,s.classList.add("is-arranging"),s.querySelector(".dm-admin-sidebar-header")?.after(e),b();const f=O(a,()=>r,b,{items:".sb-arr-row",handle:null});return new Promise(p=>{let h=!1;const v=t=>{f?.destroy(),document.removeEventListener("keydown",C,!0),e.remove(),s.classList.remove("is-arranging"),t?document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild")):s.querySelector(".dm-admin-sidebar-arrange")?.focus(),p(t)},x=async()=>{h||m()&&!await E.confirm("Leave Arrange without saving? Your moves will be lost.",{title:"Discard changes?",confirmText:"Discard",cancelText:"Keep arranging"})||v(!1)},q=async()=>{if(!h){if(!m()){v(!1);return}h=!0,i.querySelectorAll("button").forEach(t=>{t.disabled=!0});try{const t=await S.menus.get($);await S.menus.update($,{...t,items:k(r)}),E.toast("Sidebar arranged.",{type:"success"}),v(!0)}catch(t){h=!1,i.querySelectorAll("button").forEach(u=>{u.disabled=!1}),E.toast(`Could not save the sidebar: ${t?.message||t}`,{type:"error"})}}};i.querySelector(".sb-arrange-cancel").addEventListener("click",x),i.querySelector(".sb-arrange-done").addEventListener("click",q),a.addEventListener("click",t=>{const u=t.target.closest(".sb-arr-hide");if(!u)return;const c=r.find(y=>y.id===u.closest(".sb-arr-row")?.dataset.id);c&&(c.hidden=!c.hidden,c.touched=!0,b(),A(c.id))}),a.addEventListener("keydown",t=>{const u=t.target.closest(".sb-arr-row");if(!u||t.target!==u||!t.altKey)return;const c=u.dataset.id,y={ArrowUp:()=>L(r,c,-1),ArrowDown:()=>L(r,c,1),ArrowRight:()=>z(r,c),ArrowLeft:()=>M(r,c)};y[t.key]&&(t.preventDefault(),y[t.key]()&&(f?f.animate(b):b(),A(c)))});function C(t){t.key!=="Escape"||f?.dragging||!e.contains(document.activeElement)&&document.activeElement!==document.body||(t.preventDefault(),t.stopPropagation(),setTimeout(x,0))}document.addEventListener("keydown",C,!0),a.querySelector(".sb-arr-row")?.focus()})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const TOOLS_FOLDER_TEXT="Tools",MANAGE_PLUGINS_URL="#/plugins",MANAGE_PLUGINS_ITEM={text:"Marketplace",url:MANAGE_PLUGINS_URL,icon:"store",permission:"plugins"};export function stripItemByUrl(t
|
|
1
|
+
import{isPathAllowed as F}from"./admin-scope.js";export const TOOLS_FOLDER_TEXT="Tools",MANAGE_PLUGINS_URL="#/plugins",MANAGE_PLUGINS_ITEM={text:"Marketplace",url:MANAGE_PLUGINS_URL,icon:"store",permission:"plugins"};export function stripItemByUrl(e,t){const n=[];for(const r of e||[]){if(!r||r.url===t)continue;const s={...r};Array.isArray(r.items)&&r.items.length&&(s.items=stripItemByUrl(r.items,t)),n.push(s)}return n}export function managePluginsItem(){return{...MANAGE_PLUGINS_ITEM}}export const TOOLS_FOLDER_KEY="tools";const M=["countUrl","core","permission"],c=e=>String(e??"").toLowerCase();export function slugify(e){return c(e).trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}export function groupKeyFor(e,t){return`${c(e)}.${slugify(t)}`}export const GROUP_ICON="folder";const P=e=>e&&(e.type==="separator"||e.type==="spacer"),A=e=>e&&!P(e)&&!e.url;function O(e){return(e||[]).filter(Boolean).map(t=>Array.isArray(t.items)?{...t,items:O(t.items)}:{...t})}function E(e,t,n=[]){for(const r of e||[]){if(!r)continue;if(t(r))return[...n,r];const s=E(r.items,t,[...n,r]);if(s)return s}return null}function I(e,t,n=[],r=[]){for(const s of e||[])s&&(t(s)&&r.push([...n,s]),I(s.items,t,[...n,s],r));return r}const U=e=>!e.some(t=>t.hidden||t.restricted);function $(e,t){for(const n of e||[]){if(t(n))return n;const r=$(n?.items,t);if(r)return r}return null}export function findFolder(e,t){if(!t)return null;const n=c(t);return $(e,r=>A(r)&&c(r.key)===n)||$(e,r=>A(r)&&!r.key&&c(r.text)===n)}function b(e,t){const n={...t,...e};for(const r of M)t[r]!==void 0&&(n[r]=t[r]);return!(Array.isArray(e.items)&&e.items.length)&&Array.isArray(t.items)&&(n.items=t.items),e.text||(n.text=t.text),!e.icon&&t.icon&&(n.icon=t.icon),delete n.ref,delete n.folder,delete n.group,n}function _(e,{persisted:t,orphan:n=!1,node:r=null}){const s=e?.item||{};return{persisted:t,orphan:n,source:s.source||(s.core?"Built in":""),folder:e?.folder||TOOLS_FOLDER_KEY,defaults:n?{text:null,icon:null}:{text:s.text||"",icon:s.icon||""},...n&&r&&{label:r.text||r.url},...(e?.group||e?.item?.group)&&{group:e.group||e.item.group}}}export function placeTools(e,t,{forEditor:n=!1}={}){const r=O(e),s=(t||[]).filter(o=>o&&o.item&&typeof o.item.text=="string"),d=new Map;for(const o of s)o.item.url&&!d.has(o.item.url)&&d.set(o.item.url,o);const y=new Set,m=o=>{const i=[];for(const u of o){const h=u.url?d.get(u.url):null;if(h&&!y.has(u.url)){y.add(u.url);const g=b(u,h.item);Array.isArray(u.items)&&u.items.length?g.items=m(u.items):n&&(g.items=[]),n&&(g.$tool=_(h,{persisted:!0})),i.push(g);continue}if(u.ref){if(!n)continue;const{ref:g,...f}=u;i.push({...f,items:m(u.items||[]),$tool:_(null,{persisted:!0,orphan:!0,node:u})});continue}Array.isArray(u.items)&&(u.items=m(u.items)),i.push(u)}return i},a=m(r),T=new Set,L=o=>{for(const i of o||[])i.hidden&&i.text&&!i.url&&!(Array.isArray(i.items)&&i.items.length)&&T.add(c(i.text)),L(i.items)};L(a);let x=null;const S=()=>{const o=findFolder(a,TOOLS_FOLDER_KEY);if(o)return o;if(!x){x={text:TOOLS_FOLDER_TEXT,key:TOOLS_FOLDER_KEY,icon:"tool",items:[],synthesised:!0};const i=a.findIndex(u=>["system","documentation"].includes(c(u?.key||u?.text)));a.splice(i===-1?a.length:i,0,x)}return x},l=new Set,k=(o,i)=>{const u=groupKeyFor(o.key||slugify(o.text),i),h=$(a,p=>A(p)&&c(p.key)===u)||(o.items||[]).find(p=>A(p)&&(!p.key||c(p.key)===u)&&c(p.text)===c(i));if(h)return h;const g={text:String(i),key:u,icon:GROUP_ICON,items:[],synthesised:!0},f=o.items.findIndex(p=>l.has(p));return o.items.splice(f===-1?o.items.length:f,0,g),g};for(const o of s){const{item:i}=o;if(i.url&&y.has(i.url))continue;i.url&&y.add(i.url);const u=T.has(c(i.text));if(u&&!n)continue;const h=b({},i);n&&(h.items=[],h.$tool=_(o,{persisted:!1}),u&&(h.hidden=!0));let f=(o.parent?findFolder(a,o.parent)||$(a,w=>!P(w)&&c(w.text)===c(o.parent)):null)||findFolder(a,o.folder||i.folder)||S();f.items=Array.isArray(f.items)?f.items:[];const p=typeof(o.group||i.group)=="string"?(o.group||i.group).trim():"";p&&slugify(p)&&(f=k(f,p),f.items=Array.isArray(f.items)?f.items:[]),f.items.push(h),l.add(h)}return a}export const LOCKED_TOOLS=[{folder:"overview",item:{text:"Dashboard",url:"#/",icon:"home"}},{folder:"content",item:{text:"Menus",url:"#/menus",icon:"menu",permission:"menus"}},{folder:"system",item:{text:"Users",url:"#/users",icon:"users",permission:"users"}},{folder:"system",item:{text:"My Profile",url:"#/my-profile",icon:"user"}}];export function isLockedUrl(e){return LOCKED_TOOLS.some(t=>t.item.url===e)}export function ensureLockedTools(e,{leaveInHiddenFolders:t=!1}={}){const n=O(e);for(const{folder:r,item:s}of LOCKED_TOOLS){const d=I(n,l=>l?.url===s.url),y=d.find(l=>!l.some(k=>k.restricted));if(!y&&d.length)continue;const m=y?.at(-1);if(m){if(m.hidden&&delete m.hidden,!y.slice(0,-1).some(o=>o.hidden)||t)continue;const k=y.at(-2);k.items=k.items.filter(o=>o!==m)}const a=c(r),T=I(n,l=>A(l)&&c(l.key)===a).filter(U),L=I(n,l=>A(l)&&!l.key&&c(l.text)===a).filter(U),x=(T[0]||L[0])?.at(-1)||null,S=m||{...s};x?(x.items=Array.isArray(x.items)?x.items:[],x.items.push(S)):n.push(S)}return n}export function insertFoldersBeforeSystem(e,t){const n=(t||[]).filter(Boolean);if(!n.length)return e;const r=["system","documentation"],s=e.findIndex(d=>r.includes(c(d?.key||d?.text)));return s===-1?[...e,...n]:[...e.slice(0,s),...n,...e.slice(s)]}export function canAny(e,t){return t?!e||!e.length?!1:e.includes(t)?!0:["read","create","update","delete"].some(n=>e.includes(`${t}.${n}`)):!0}export function filterByPermission(e,t,n=null){const r=[];for(const s of e){if(s.hidden||s.permission&&!canAny(t,s.permission))continue;const d=typeof s.url=="string"?s.url:"";if(n&&d.startsWith("#/")&&!F(n,d.slice(1)))continue;const y=Array.isArray(s.items)&&s.items.length>0,m=y?filterByPermission(s.items,t,n):[];y&&!m.length&&!d||r.push({...s,items:m})}return r}export function sidebarStateKey(e,t=null){const n=String(e?.text||"").replace(/\s*\(\d+\)\s*$/,"").toLowerCase().replace(/\s+/g,"-"),r=String(e?.url||"").match(/^#\/projects\/([^/]+)/);let s="";if(r)try{s=`project-${decodeURIComponent(r[1])}.`}catch{s=`project-${r[1]}.`}return t?e?.key?`sidebar.expanded.key.${c(e.key)}`:`${t}/${s}${n}`:`sidebar.expanded.${s}${n}`}export function pruneEmptyToolsFolder(e){return(e||[]).filter(t=>A(t)?!(c(t.key)===TOOLS_FOLDER_KEY||!t.key&&t.text===TOOLS_FOLDER_TEXT)||Array.isArray(t.items)&&t.items.length>0:!0)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{api as
|
|
2
|
-
<summary${
|
|
3
|
-
<div class="sidebar-children">${
|
|
4
|
-
</details>`}return`<a href="${s}" class="sidebar-link" data-url="${s}"${m}${c}>${i} <span class="sidebar-text">${e}</span>${pe(t,n)}${v}</a>`}async function be(t=[],n=[],i=null){const e=d=>d.then(g=>Array.isArray(g)?g.length:Array.isArray(g?.entries)?g.entries.length:0).catch(()=>0);C=xe(t,i);const s=new Set(C.map(d=>d.url)),l={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"},a=(d,g)=>F(n,d)&&!s.has(l[d])?g():Promise.resolve(0),[o,c,u,m,v,y,L,E,w,P,T,I,U,R]=await Promise.all([a("pages",()=>e(p.pages.list())),a("media",()=>e(p.media.list())),a("menus",()=>e(p.menus.list())),a("context-menus",()=>e(p.contextMenus.list())),a("theme",()=>p.theme.get().then(d=>(d?.overrides||[]).length).catch(()=>0)),a("collections",()=>e(p.collections.list())),a("forms",()=>e(p.forms.list())),a("views",()=>e(p.views.list())),a("actions",()=>e(p.actions.list())),a("blocks",()=>e(p.blocks.list())),a("components",()=>e(p.components.list())),a("users",()=>e(p.users.list())),a("plugins",()=>e(p.plugins.list())),a("notifications",()=>p.system?.notifications?.unreadCount?.().then(d=>d?.count??0).catch(()=>0)??Promise.resolve(0))]),_={};await Promise.all(C.map(async d=>{const g=await ee(d);g&&(_[d.url]=g)}));const A={"#/pages":o,"#/media":c,"#/menus":u,"#/context-menus":m,"#/theme":v,"#/collections":y,"#/forms":L,"#/views":E,"#/actions":w,"#/blocks":P,"#/components":T,"#/users":I,"#/plugins":U,"#/system/notifications":R},x={};for(const[d,g]of Object.entries(A)){if(s.has(d))continue;const[z,B]=he[d]??["item","items"],k=W(g);k&&(x[d]={...k,label:`${k.count} ${k.count===1?z:B}`})}return{...x,..._}}let C=[];const ye="dm:sidebar-count",ve=6e4;function xe(t=[],n=null){const i=[],e=s=>{if(s&&!(n&&typeof s.url=="string"&&s.url.startsWith("#/")&&!X(n,s.url.slice(1)))){s.url&&typeof s.countUrl=="string"&&s.countUrl&&i.push({url:s.url,countUrl:s.countUrl,text:s.text||"",countLabel:s.countLabel||"",inventory:s.inventory===!0});for(const l of[...s.children||[],...s.items||[]])e(l)}};for(const s of t??[])e(s?.item??s);return i}async function ee(t){try{const n=new Date,i=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`,e=t.countUrl+(t.countUrl.includes("?")?"&":"?")+`today=${i}`;return W(await H.get(e),{fallbackLabel:t.countLabel||t.text})}catch{return null}}function te(t,n,i){const e=[...t.querySelectorAll("a.sidebar-link")].find(l=>l.dataset.url===n);if(!e)return;const s=e.querySelector(".sidebar-badge[data-count-for]");if(!i||!(i.count>0))s?.remove();else{const l=document.createRange();l.selectNodeContents(e);const a=l.createContextualFragment(J(n,i)).firstElementChild;s?s.replaceWith(a):e.querySelector(".sidebar-text")?.after(a)}O.set(n,i),Y(t)}const O=new Map;async function D(t,n=null){const i=n?C.filter(e=>e.url===n):C;await Promise.all(i.map(async e=>{const s=await ee(e),l=O.get(e.url);JSON.stringify(l??null)!==JSON.stringify(s)&&te(t,e.url,s)}))}function $e(t){t.dataset.liveCounts||(t.dataset.liveCounts="1",window.addEventListener(ye,n=>{const i=n.detail||{};if(i.url)if(i.count!==void 0){const e=C.find(s=>s.url===i.url);te(t,i.url,W(i,{fallbackLabel:e?.countLabel||e?.text||""}))}else D(t,i.url)}),setInterval(()=>{!document.hidden&&document.body.contains(t)&&D(t)},ve),document.addEventListener("visibilitychange",()=>{document.hidden||D(t)}),Se(t))}function Ce(t,n,i){const e=(a,o,c)=>{const u=document.createElement(a);return o&&(u.className=o),c!=null&&(u.textContent=String(c)),u};if(!i){t.textContent=n;return}t.appendChild(e("strong","dm-badge-pop-title",i.title||n)),(i.rows?.length||!i.items?.length)&&t.appendChild(e("p","dm-badge-pop-sub",n));const s=Array.isArray(i.rows)?i.rows.slice(0,6):[];if(s.length){const a=e("dl","dm-badge-pop-rows");for(const o of s)a.appendChild(e("dt",null,o.label)),a.appendChild(e("dd",o.tone==="danger"?"is-danger":null,o.value));t.appendChild(a)}const l=Array.isArray(i.items)?i.items.slice(0,6):[];if(l.length){const a=e("ul","dm-badge-pop-items");for(const o of l){const c=e("li",o.tone==="danger"?"is-danger":null);c.appendChild(e("span","dm-badge-pop-text",o.text)),o.meta&&c.appendChild(e("span","dm-badge-pop-meta",o.meta)),a.appendChild(c)}t.appendChild(a)}else i.empty&&t.appendChild(e("p","dm-badge-pop-empty",i.empty))}function Se(t){let n=null,i=null;const e=()=>{clearTimeout(i),n?.remove(),n=null},s=l=>{e();const a=l?.dataset.badgeLabel;a&&(i=setTimeout(()=>{n=document.createElement("div"),n.className="dm-help-pop dm-badge-pop",n.setAttribute("role","tooltip"),Ce(n,a,N.get(l.dataset.countFor)),document.body.appendChild(n);const o=l.getBoundingClientRect(),c=n.getBoundingClientRect(),u=Math.min(o.right+10,innerWidth-c.width-8);n.style.left=`${Math.max(8,u)}px`,n.style.top=`${Math.max(8,Math.min(o.top+o.height/2-c.height/2,innerHeight-c.height-8))}px`},150))};t.addEventListener("mouseover",l=>{const a=l.target.closest?.(".sidebar-badge[data-badge-label]");a&&s(a)}),t.addEventListener("mouseout",l=>{l.target.closest?.(".sidebar-badge[data-badge-label]")&&e()}),t.addEventListener("focusin",l=>{const a=l.target.closest?.("a, summary")?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");a?s(a):e()}),t.addEventListener("focusout",e),window.addEventListener("scroll",e,!0),window.addEventListener("hashchange",e)}async function we(t=[]){if(!F(t,"settings"))return"Admin";try{const n=await p.settings.get();return n?.adminBrand?.title||n?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:t,permissions:n,adminScope:i=null}){const e=$(t).get(0);if(!e)return;let s,l=null,a=null,o=null,c=null,u=null;try{const r=await p.get("/sidebar/menu");s=Array.isArray(r?.items)?r.items:null,l=r?.variant||null,a=r?.position||null,o=r?.style||null,c=r?.float||null,u=r?.highlight||null}catch{s=null}(!s||!s.some(r=>r&&(!r.hidden||r.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),s=ue.slice());let m=[];try{m=await H.get("/api/sidebar/registered-items")||[]}catch{}s=le(s,V),s=oe(s,m.filter(r=>(r?.item??r)?.url!==V)),s=ae(s),s=ce(s,[re()]);const v=await me(n);v.length&&fe(s,v),s=G(s,n,i),s=de(s);const[y,L]=await Promise.all([be(m.filter(r=>F(n,r?.item?.permission)),n,i).catch(()=>({})),we(n)]),E=l?` dm-admin-sidebar--${h(l)}`:"";function w(r,b="px"){if(r==null)return r;const f=String(r).trim();return/^\d+(\.\d+)?$/.test(f)?`${f}${b}`:f}let P="";if(o){const r=[];o.fontFamily&&r.push(`font-family: ${o.fontFamily}, sans-serif`),o.fontSize&&r.push(`font-size: ${w(o.fontSize)}`),o.fontWeight&&r.push(`font-weight: ${o.fontWeight}`),o.letterSpacing&&r.push(`letter-spacing: ${w(o.letterSpacing,"em")}`);const b=[];if(r.length&&b.push(`#admin-sidebar .dm-admin-sidebar, #admin-sidebar .dm-admin-sidebar .sidebar-link, #admin-sidebar .dm-admin-sidebar summary, #admin-sidebar .dm-admin-sidebar .sidebar-text { ${r.join("; ")} }`),o.iconSize){const f=w(o.iconSize);b.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${f} !important; height: ${f} !important; }`)}b.length&&(P=`<style data-admin-sidebar-style>${b.join(" ")}</style>`)}const T=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span> ${h(L)}</div>`,I=s.some(r=>r&&r.type==="spacer"&&r.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",U=`${P}<nav class="dm-admin-sidebar${E}${I}">${T}${s.map(r=>Z(r,y)).join("")}</nav>`,R=document.createRange();R.selectNodeContents(e);const _=R.createContextualFragment(U);e.replaceChildren(_),Domma.icons.scan(e);for(const r of C)O.set(r.url,y[r.url]??null);Y(e),$e(e);const A=Number.parseInt(S.get("sidebar.width"),10);Number.isFinite(A)&&A>=180&&A<=480&&(e.style.width=A+"px"),e.removeAttribute("data-menu-hover"),e.removeAttribute("data-menu-active"),e.style.removeProperty("--dm-menu-highlight"),se(e,{highlight:u});const x=document.querySelector(".dashboard-wrapper");if(["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(r=>{e.style[r]=""}),e.classList.remove("dm-menu-floating"),x&&(x.style.paddingLeft="",x.style.paddingRight=""),a==="floating"){ne(e,{position:"floating",float:c||{}});const b=c&&c.anchor||"TL",f=Number.isFinite(Number(c?.offsetX))?Number(c.offsetX):16,j=e.getBoundingClientRect().width||A||260;if(x){const q=Math.round(j+f*2)+"px";b==="R"||b==="TR"||b==="BR"?x.style.paddingRight=q:x.style.paddingLeft=q}}const d=document.createElement("div");d.className="dm-admin-sidebar-handle",d.setAttribute("aria-label","Resize sidebar"),e.appendChild(d),e.querySelectorAll("details").forEach(r=>{r.addEventListener("toggle",function(){const b=this.getAttribute("data-state-key");b&&S.set(b,this.open);const f=this.querySelector(":scope > .sidebar-children");if(f)if(this.open){const j=f.scrollHeight;f.style.maxHeight="0",requestAnimationFrame(()=>{f.style.maxHeight=j+"px",f.addEventListener("transitionend",function q(){f.style.maxHeight="none",f.removeEventListener("transitionend",q)})})}else{const j=f.scrollHeight;f.style.maxHeight=j+"px",requestAnimationFrame(()=>{f.style.maxHeight="0"})}})});let g=!1,z=0,B=0;d.addEventListener("mousedown",r=>{g=!0,z=r.clientX,B=e.getBoundingClientRect().width,document.body.style.cursor="col-resize",document.body.style.userSelect="none",r.preventDefault()}),e.dataset.resizeWired||(e.dataset.resizeWired="1",document.addEventListener("mousemove",r=>e.__dmResize?.move(r)),document.addEventListener("mouseup",()=>e.__dmResize?.up()),M.subscribe("router:afterChange",()=>e.__dmSetActive?.())),e.__dmResize={move(r){if(!g)return;const b=Math.max(180,Math.min(480,B+(r.clientX-z)));e.style.width=b+"px"},up(){g&&(g=!1,document.body.style.cursor="",document.body.style.userSelect="",S.set("sidebar.width",parseInt(e.style.width,10)))}};function k(){const r=location.hash||"#/";$(e).find(".sidebar-link").removeClass("active"),$(e).find(`.sidebar-link[data-url="${r}"]`).addClass("active")}k(),e.__dmSetActive=k}
|
|
1
|
+
import{api as g}from"../api.js";import{isPathAllowed as te}from"./admin-scope.js";import{colourToCss as K,applyFloat as ne,applyHighlight as se,itemHighlightAttrs as ie}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{placeTools as oe,ensureLockedTools as ae,managePluginsItem as re,stripItemByUrl as le,insertFoldersBeforeSystem as ce,pruneEmptyToolsFolder as de,sidebarStateKey as ue,canAny as _,filterByPermission as me,MANAGE_PLUGINS_URL as V}from"./sidebar-grouping.js";import{arrangeButtonMarkup as fe,canArrange as ge,startArrange as pe}from"./sidebar-arrange.js";function p(t){return String(t??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const he=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Menus",url:"#/menus",icon:"menu",permission:"menus"}];async function be(t){if(!_(t,"projects"))return[];let n=[];try{n=await g.projects.listWithCounts()}catch{return[]}if(!Array.isArray(n))return[];const i=[{key:"pages",text:"Pages",icon:"file-text",path:"/pages"},{key:"collections",text:"Collections",icon:"database",path:"/collections"},{key:"forms",text:"Forms",icon:"layout",path:"/forms"},{key:"actions",text:"Actions",icon:"zap",path:"/actions"},{key:"menus",text:"Menus",icon:"menu",path:"/menus"},{key:"blocks",text:"Blocks",icon:"box",path:"/blocks"},{key:"components",text:"Components",icon:"component",path:"/components"},{key:"views",text:"Views",icon:"eye",path:"/views"},{key:"roles",text:"Roles",icon:"shield",path:"/roles"},{key:"users",text:"Users",icon:"users",path:"/users"},{key:"apis",text:"APIs",icon:"code",path:"/apis"}];return n.map(e=>{const l="#/projects/"+encodeURIComponent(e.slug),r=e.counts||{},a=[{text:"Overview",url:l,icon:e.icon||"folder"}];for(const u of i){const m=Number(r[u.key])||0;m<=0||a.push({text:`${u.text} (${m})`,url:l+u.path,icon:u.icon})}a.push({text:"Settings",url:l+"/settings",icon:"settings"});const c=e.enabled===!1;return{text:e.name||e.slug,key:`project.${e.slug}`,icon:e.icon||"folder",items:a,...c&&{colour:"neutral",badge:{text:"off"}}}})}function ye(t,n){for(const i of t)if(!i.hidden&&(i.key==="projects"||!i.key&&(i.text||"").toLowerCase()==="projects")){i.items=Array.isArray(i.items)?i.items.slice():[],i.items.push(...n);return}}function G(t,n){const i=Y.includes(n.tone)?n.tone:"info",e=n.label||String(n.count);n.details?R.set(t,n.details):R.delete(t);const s=!n.inventory&&w.some(l=>l.url===t&&!l.inventory)?" data-live":"";return`<span class="sidebar-badge sidebar-badge--${i}" data-count-for="${p(t)}"${s} data-badge-label="${p(e)}" aria-label="${p(e)}">${p(String(n.count))}</span>`}function J(t){for(const n of t.querySelectorAll("details")){const i=n.querySelector(":scope > summary");if(!i)continue;let e=0,s=!1;const l=[];for(const m of n.querySelectorAll(":scope > .sidebar-children .sidebar-badge[data-live]")){const v=Number(m.textContent)||0;v&&(e+=v,s||(s=m.classList.contains("sidebar-badge--danger")),l.push({text:m.closest("a")?.querySelector(".sidebar-text")?.textContent.trim()??"",meta:m.dataset.badgeLabel,tone:m.classList.contains("sidebar-badge--danger")?"danger":void 0}))}const r=`folder:${n.dataset.stateKey||i.textContent.trim()}`;let a=i.querySelector(":scope > .sidebar-badge--sum");if(!e){a?.remove(),R.delete(r);continue}a||(a=document.createElement("span"),i.querySelector(".sidebar-text")?.after(a));const c=i.querySelector(".sidebar-text")?.textContent.trim()||"This folder",u=l.map(m=>`${m.text}: ${m.meta}`).join(" \xB7 ");a.className=`sidebar-badge sidebar-badge--sum sidebar-badge--${s?"danger":"info"}`,a.dataset.countFor=r,a.dataset.badgeLabel=u,a.setAttribute("aria-label",u),a.textContent=String(e),R.set(r,{title:c,items:l})}}const R=new Map;function ve(t,n){if(!t.url||!n)return"";const i=n[t.url];return!i||!(i.count>0)?"":G(t.url,i)}const Y=["info","attention","danger","live"],xe={"#/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 O(t,{fallbackLabel:n="",tone:i="info"}={}){const e=Number(typeof t=="object"&&t!==null?t.count:t);if(!Number.isFinite(e)||e<0)return null;const s=typeof t?.label=="string"&&t.label||(n?`${e} - ${n}`:String(e)),l={count:Math.round(e),label:s,tone:Y.includes(t?.tone)?t.tone:i};return t?.details&&typeof t.details=="object"&&(l.details=t.details),t?.inventory===!0&&(l.inventory=!0),l}function Q(t,n,i=null){if(t&&t.type==="separator")return'<hr class="sidebar-divider">';if(t&&t.type==="spacer"){const y=["xs","sm","md","lg","xl","flex"].includes(t.size)?t.size:"md";return`<div class="sidebar-spacer sidebar-spacer--${p(y)}" aria-hidden="true"></div>`}const e=t.icon?`<span data-icon="${p(t.icon)}"></span>`:"",s=p(t.text||""),l=t.url?p(t.url):"",r=Array.isArray(t.items)&&t.items.length>0,a=t.colour?K(t.colour):"",c=ie(t),u=[c.hover&&` data-menu-item-hover="${p(c.hover)}"`,c.active&&` data-menu-item-active="${p(c.active)}"`].filter(Boolean).join(""),m=[a&&`color:${p(a)}`,c.accent&&`--dm-menu-highlight:${p(c.accent)}`].filter(Boolean).join(";"),v=m?` style="${m}"`:"";let x="";if(t.badge&&t.badge.text!=null&&t.badge.text!==""){const y=t.badge.variant?K(t.badge.variant):"";x=`<span class="dm-menu-badge"${y?` style="background:${p(y)};color:var(--dm-text-inverse,#fff)"`:""}>${p(String(t.badge.text))}</span>`}if(r){const y=ue(t,i),L=S.get(y)!==!1,A=t.items.map(E=>Q(E,n,y)).join("");return`<details data-state-key="${p(y)}"${L?" open":""}>
|
|
2
|
+
<summary${v}>${e} <span class="sidebar-text">${s}</span>${x}</summary>
|
|
3
|
+
<div class="sidebar-children">${A}</div>
|
|
4
|
+
</details>`}return`<a href="${l}" class="sidebar-link" data-url="${l}"${v}${u}>${e} <span class="sidebar-text">${s}</span>${ve(t,n)}${x}</a>`}async function $e(t=[],n=[],i=null){const e=d=>d.then(h=>Array.isArray(h)?h.length:Array.isArray(h?.entries)?h.entries.length:0).catch(()=>0);w=we(t,i);const s=new Set(w.map(d=>d.url)),l={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"},r=(d,h)=>_(n,d)&&!s.has(l[d])?h():Promise.resolve(0),[a,c,u,m,v,x,y,L,A,E,z,q,T,I]=await Promise.all([r("pages",()=>e(g.pages.list())),r("media",()=>e(g.media.list())),r("menus",()=>e(g.menus.list())),r("context-menus",()=>e(g.contextMenus.list())),r("theme",()=>g.theme.get().then(d=>(d?.overrides||[]).length).catch(()=>0)),r("collections",()=>e(g.collections.list())),r("forms",()=>e(g.forms.list())),r("views",()=>e(g.views.list())),r("actions",()=>e(g.actions.list())),r("blocks",()=>e(g.blocks.list())),r("components",()=>e(g.components.list())),r("users",()=>e(g.users.list())),r("plugins",()=>e(g.plugins.list())),r("notifications",()=>g.system?.notifications?.unreadCount?.().then(d=>d?.count??0).catch(()=>0)??Promise.resolve(0))]),j={};await Promise.all(w.map(async d=>{const h=await Z(d);h&&(j[d.url]=h)}));const U={"#/pages":a,"#/media":c,"#/menus":u,"#/context-menus":m,"#/theme":v,"#/collections":x,"#/forms":y,"#/views":L,"#/actions":A,"#/blocks":E,"#/components":z,"#/users":q,"#/plugins":T,"#/system/notifications":I},C={};for(const[d,h]of Object.entries(U)){if(s.has(d))continue;const[N,B]=xe[d]??["item","items"],k=O(h);k&&(C[d]={...k,label:`${k.count} ${k.count===1?N:B}`})}return{...C,...j}}let w=[];const Se="dm:sidebar-count",Ce=6e4;function we(t=[],n=null){const i=[],e=s=>{if(s&&!(n&&typeof s.url=="string"&&s.url.startsWith("#/")&&!te(n,s.url.slice(1)))){s.url&&typeof s.countUrl=="string"&&s.countUrl&&i.push({url:s.url,countUrl:s.countUrl,text:s.text||"",countLabel:s.countLabel||"",inventory:s.inventory===!0});for(const l of[...s.children||[],...s.items||[]])e(l)}};for(const s of t??[])e(s?.item??s);return i}async function Z(t){try{const n=new Date,i=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`,e=t.countUrl+(t.countUrl.includes("?")?"&":"?")+`today=${i}`;return O(await H.get(e),{fallbackLabel:t.countLabel||t.text})}catch{return null}}function ee(t,n,i){const e=[...t.querySelectorAll("a.sidebar-link")].find(l=>l.dataset.url===n);if(!e)return;const s=e.querySelector(".sidebar-badge[data-count-for]");if(!i||!(i.count>0))s?.remove();else{const l=document.createRange();l.selectNodeContents(e);const r=l.createContextualFragment(G(n,i)).firstElementChild;s?s.replaceWith(r):e.querySelector(".sidebar-text")?.after(r)}W.set(n,i),J(t)}const W=new Map;async function D(t,n=null){const i=n?w.filter(e=>e.url===n):w;await Promise.all(i.map(async e=>{const s=await Z(e),l=W.get(e.url);JSON.stringify(l??null)!==JSON.stringify(s)&&ee(t,e.url,s)}))}function Ae(t){t.dataset.liveCounts||(t.dataset.liveCounts="1",window.addEventListener(Se,n=>{const i=n.detail||{};if(i.url)if(i.count!==void 0){const e=w.find(s=>s.url===i.url);ee(t,i.url,O(i,{fallbackLabel:e?.countLabel||e?.text||""}))}else D(t,i.url)}),setInterval(()=>{!document.hidden&&document.body.contains(t)&&D(t)},Ce),document.addEventListener("visibilitychange",()=>{document.hidden||D(t)}),Le(t))}function ke(t,n,i){const e=(r,a,c)=>{const u=document.createElement(r);return a&&(u.className=a),c!=null&&(u.textContent=String(c)),u};if(!i){t.textContent=n;return}t.appendChild(e("strong","dm-badge-pop-title",i.title||n)),(i.rows?.length||!i.items?.length)&&t.appendChild(e("p","dm-badge-pop-sub",n));const s=Array.isArray(i.rows)?i.rows.slice(0,6):[];if(s.length){const r=e("dl","dm-badge-pop-rows");for(const a of s)r.appendChild(e("dt",null,a.label)),r.appendChild(e("dd",a.tone==="danger"?"is-danger":null,a.value));t.appendChild(r)}const l=Array.isArray(i.items)?i.items.slice(0,6):[];if(l.length){const r=e("ul","dm-badge-pop-items");for(const a of l){const c=e("li",a.tone==="danger"?"is-danger":null);c.appendChild(e("span","dm-badge-pop-text",a.text)),a.meta&&c.appendChild(e("span","dm-badge-pop-meta",a.meta)),r.appendChild(c)}t.appendChild(r)}else i.empty&&t.appendChild(e("p","dm-badge-pop-empty",i.empty))}function Le(t){let n=null,i=null;const e=()=>{clearTimeout(i),n?.remove(),n=null},s=l=>{e();const r=l?.dataset.badgeLabel;r&&(i=setTimeout(()=>{n=document.createElement("div"),n.className="dm-help-pop dm-badge-pop",n.setAttribute("role","tooltip"),ke(n,r,R.get(l.dataset.countFor)),document.body.appendChild(n);const a=l.getBoundingClientRect(),c=n.getBoundingClientRect(),u=Math.min(a.right+10,innerWidth-c.width-8);n.style.left=`${Math.max(8,u)}px`,n.style.top=`${Math.max(8,Math.min(a.top+a.height/2-c.height/2,innerHeight-c.height-8))}px`},150))};t.addEventListener("mouseover",l=>{const r=l.target.closest?.(".sidebar-badge[data-badge-label]");r&&s(r)}),t.addEventListener("mouseout",l=>{l.target.closest?.(".sidebar-badge[data-badge-label]")&&e()}),t.addEventListener("focusin",l=>{const r=l.target.closest?.("a, summary")?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");r?s(r):e()}),t.addEventListener("focusout",e),window.addEventListener("scroll",e,!0),window.addEventListener("hashchange",e)}async function Ee(t=[]){if(!_(t,"settings"))return"Admin";try{const n=await g.settings.get();return n?.adminBrand?.title||n?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:t,permissions:n,adminScope:i=null}){const e=$(t).get(0);if(!e)return;let s,l=null,r=null,a=null,c=null,u=null;try{const o=await g.get("/sidebar/menu");s=Array.isArray(o?.items)?o.items:null,l=o?.variant||null,r=o?.position||null,a=o?.style||null,c=o?.float||null,u=o?.highlight||null}catch{s=null}(!s||!s.some(o=>o&&(!o.hidden||o.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),s=he.slice());let m=[];try{m=await H.get("/api/sidebar/registered-items")||[]}catch{}s=le(s,V),s=oe(s,m.filter(o=>(o?.item??o)?.url!==V)),s=ae(s),s=ce(s,[re()]);const v=await be(n);v.length&&ye(s,v),s=me(s,n,i),s=de(s);const[x,y]=await Promise.all([$e(m.filter(o=>_(n,o?.item?.permission)),n,i).catch(()=>({})),Ee(n)]),L=l?` dm-admin-sidebar--${p(l)}`:"";function A(o,b="px"){if(o==null)return o;const f=String(o).trim();return/^\d+(\.\d+)?$/.test(f)?`${f}${b}`:f}let E="";if(a){const o=[];a.fontFamily&&o.push(`font-family: ${a.fontFamily}, sans-serif`),a.fontSize&&o.push(`font-size: ${A(a.fontSize)}`),a.fontWeight&&o.push(`font-weight: ${a.fontWeight}`),a.letterSpacing&&o.push(`letter-spacing: ${A(a.letterSpacing,"em")}`);const b=[];if(o.length&&b.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 { ${o.join("; ")} }`),a.iconSize){const f=A(a.iconSize);b.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${f} !important; height: ${f} !important; }`)}b.length&&(E=`<style data-admin-sidebar-style>${b.join(" ")}</style>`)}const z=ge(n)?fe():"",q=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span> ${p(y)}${z}</div>`,T=s.some(o=>o&&o.type==="spacer"&&o.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",I=`${E}<nav class="dm-admin-sidebar${L}${T}">${q}${s.map(o=>Q(o,x)).join("")}</nav>`,j=document.createRange();j.selectNodeContents(e);const U=j.createContextualFragment(I);e.replaceChildren(U),Domma.icons.scan(e),e.querySelector(".dm-admin-sidebar-arrange")?.addEventListener("click",()=>pe(e));for(const o of w)W.set(o.url,x[o.url]??null);J(e),Ae(e);const C=Number.parseInt(S.get("sidebar.width"),10);Number.isFinite(C)&&C>=180&&C<=480&&(e.style.width=C+"px"),e.removeAttribute("data-menu-hover"),e.removeAttribute("data-menu-active"),e.style.removeProperty("--dm-menu-highlight"),se(e,{highlight:u});const d=document.querySelector(".dashboard-wrapper");if(["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(o=>{e.style[o]=""}),e.classList.remove("dm-menu-floating"),d&&(d.style.paddingLeft="",d.style.paddingRight=""),r==="floating"){ne(e,{position:"floating",float:c||{}});const b=c&&c.anchor||"TL",f=Number.isFinite(Number(c?.offsetX))?Number(c.offsetX):16,F=e.getBoundingClientRect().width||C||260;if(d){const P=Math.round(F+f*2)+"px";b==="R"||b==="TR"||b==="BR"?d.style.paddingRight=P:d.style.paddingLeft=P}}const h=document.createElement("div");h.className="dm-admin-sidebar-handle",h.setAttribute("aria-label","Resize sidebar"),e.appendChild(h),e.querySelectorAll("details").forEach(o=>{o.addEventListener("toggle",function(){const b=this.getAttribute("data-state-key");b&&S.set(b,this.open);const f=this.querySelector(":scope > .sidebar-children");if(f)if(this.open){const F=f.scrollHeight;f.style.maxHeight="0",requestAnimationFrame(()=>{f.style.maxHeight=F+"px",f.addEventListener("transitionend",function P(){f.style.maxHeight="none",f.removeEventListener("transitionend",P)})})}else{const F=f.scrollHeight;f.style.maxHeight=F+"px",requestAnimationFrame(()=>{f.style.maxHeight="0"})}})});let N=!1,B=0,k=0;h.addEventListener("mousedown",o=>{N=!0,B=o.clientX,k=e.getBoundingClientRect().width,document.body.style.cursor="col-resize",document.body.style.userSelect="none",o.preventDefault()}),e.dataset.resizeWired||(e.dataset.resizeWired="1",document.addEventListener("mousemove",o=>e.__dmResize?.move(o)),document.addEventListener("mouseup",()=>e.__dmResize?.up()),M.subscribe("router:afterChange",()=>e.__dmSetActive?.())),e.__dmResize={move(o){if(!N)return;const b=Math.max(180,Math.min(480,k+(o.clientX-B)));e.style.width=b+"px"},up(){N&&(N=!1,document.body.style.cursor="",document.body.style.userSelect="",S.set("sidebar.width",parseInt(e.style.width,10)))}};function X(){const o=location.hash||"#/";$(e).find(".sidebar-link").removeClass("active"),$(e).find(`.sidebar-link[data-url="${o}"]`).addClass("active")}X(),e.__dmSetActive=X}
|
|
@@ -46,8 +46,10 @@
|
|
|
46
46
|
<h3>Editing a menu</h3>
|
|
47
47
|
<ul>
|
|
48
48
|
<li><strong>Items</strong> - click an item to edit its label, link, icon, badge, look and who
|
|
49
|
-
sees it. Drag the grip to move an item
|
|
50
|
-
|
|
49
|
+
sees it. Drag the grip to move an item: a line shows where it will land, and an outline
|
|
50
|
+
round a row means it will go inside that row (the navbar shows nested items as a dropdown,
|
|
51
|
+
the admin sidebar as a folder inside a folder). Press Esc while dragging to cancel. On a
|
|
52
|
+
touch screen, drag by the grip too. Right-click an item for add, move, indent, duplicate,
|
|
51
53
|
hide and remove. Separators and spacers are items too.</li>
|
|
52
54
|
<li><strong>Behaviour</strong> - colour scheme, sticky, fixed, static or floating, horizontal
|
|
53
55
|
or vertical, alignment, and the hover and current-page highlight. A single item can
|
|
@@ -78,6 +80,35 @@
|
|
|
78
80
|
<p>The <code>admin-sidebar</code> menu is this sidebar. In the Menus editor you can move Tools
|
|
79
81
|
between folders, rename them, hide them or add links of your own. Dashboard, Menus, Users and
|
|
80
82
|
My Profile can be moved but never hidden, so you can always get back from a bad edit.</p>
|
|
83
|
+
<p>Folders can hold folders. The built-in Tools come in a <strong>Core</strong> group inside Tools;
|
|
84
|
+
move a Tool out of it, or move the whole group, and your arrangement is kept. A group that
|
|
85
|
+
nothing of yours has been saved into is not stored - it is made again when the sidebar draws,
|
|
86
|
+
and a user who may use none of its Tools does not see it. <strong>Back to its default
|
|
87
|
+
place</strong> on a Tool puts it back in its group. Each folder remembers whether you left it
|
|
88
|
+
open or closed on its own, so closing Tools > Core does not close a project that is also
|
|
89
|
+
called Core.</p>
|
|
90
|
+
|
|
91
|
+
<h3>Arrange the sidebar in place</h3>
|
|
92
|
+
<p>You can also rearrange the sidebar without leaving the page you are on. Click the six-dot
|
|
93
|
+
button at the top of the sidebar, beside the site name, to turn on <strong>Arrange</strong>.
|
|
94
|
+
The sidebar then lists every item as a row, including hidden ones (dimmed and struck through),
|
|
95
|
+
and clicking a row no longer opens it.</p>
|
|
96
|
+
<ul>
|
|
97
|
+
<li><strong>Move</strong> - drag a row. A line shows where it will land.</li>
|
|
98
|
+
<li><strong>Put inside a folder</strong> - drop it on the middle of another row; an outline
|
|
99
|
+
shows it going in. Dropping on the line just under a folder puts it at the top of that
|
|
100
|
+
folder.</li>
|
|
101
|
+
<li><strong>Hide or show</strong> - the eye at the end of a row. A padlock means the item
|
|
102
|
+
can be moved but not hidden.</li>
|
|
103
|
+
<li><strong>Keyboard</strong> - with a row focused, Alt+Up and Alt+Down move it,
|
|
104
|
+
Alt+Right puts it inside the row above, Alt+Left takes it out of its folder.</li>
|
|
105
|
+
<li><strong>Done</strong> saves and redraws the sidebar. <strong>Cancel</strong> or Esc leaves
|
|
106
|
+
it as it was, asking first if you moved anything.</li>
|
|
107
|
+
</ul>
|
|
108
|
+
<p>Arrange changes the same <code>admin-sidebar</code> menu as the Menus editor, so it changes
|
|
109
|
+
the sidebar for everyone; each person still sees only what their role allows. Renaming items,
|
|
110
|
+
changing icons, badges or who can see an item, and adding links is done in the Menus editor.
|
|
111
|
+
The button is shown to users who may edit menus.</p>
|
|
81
112
|
|
|
82
113
|
<p>Right-click menus on public pages are a separate feature: <strong>Content > Context
|
|
83
114
|
Menus</strong>.</p>
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<div class="col-12">
|
|
8
8
|
<div class="docs-body">
|
|
9
9
|
|
|
10
|
-
<p>Contacts, Notes, Todo, Analytics and SEO are part of the CMS. They sit in
|
|
11
|
-
and are on unless you switch them off at the top of the Marketplace (<strong>System >
|
|
10
|
+
<p>Contacts, Notes, Todo, Analytics and SEO are part of the CMS. They sit together in a <strong>Core</strong>
|
|
11
|
+
group inside the sidebar's Tools folder (<strong>Tools > Core > Notes</strong>) and are on unless you switch them off at the top of the Marketplace (<strong>System >
|
|
12
12
|
Plugins</strong>). Switching a Tool off hides it and stops its screens and API; nothing is
|
|
13
13
|
deleted. Who may use each is a permission under <strong>System > Roles</strong> (Tools
|
|
14
14
|
group): the level-0 role and Admin have them all to begin with (Admin is given them once -
|
|
@@ -65,8 +65,9 @@
|
|
|
65
65
|
project.</p>
|
|
66
66
|
|
|
67
67
|
<h3>Plugins</h3>
|
|
68
|
-
<p>Tools from the Marketplace (Calendar, Blog, Feedback, Mail Reader and others)
|
|
69
|
-
folder when switched on
|
|
68
|
+
<p>Tools from the Marketplace (Calendar, Blog, Feedback, Mail Reader and others) sit directly in
|
|
69
|
+
the Tools folder when switched on, beside the Core group, unless the plugin names a group of
|
|
70
|
+
its own. See <a href="#/docs/plugins">Plugin guides</a> for each one you have
|
|
70
71
|
installed, and <a href="#/docs/usage/plugins">Plugins</a> for installing and switching.</p>
|
|
71
72
|
|
|
72
73
|
</div>
|
|
@@ -313,8 +313,8 @@
|
|
|
313
313
|
.mex-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
|
|
314
314
|
.mex-toolbar .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
315
315
|
/* Rows: grip, label, url, hide, edit, ⋮ - everything else is in the row's context menu. */
|
|
316
|
-
.mex .menu-tree-row--slim { grid-template-columns:
|
|
317
|
-
.mex .menu-tree-row--separator, .mex .menu-tree-row--spacer { grid-template-columns:
|
|
316
|
+
.mex .menu-tree-row--slim { grid-template-columns: 26px minmax(0, 1fr) auto repeat(3, auto); padding: 3px 4px; border-radius: var(--dm-radius-sm); cursor: pointer; }
|
|
317
|
+
.mex .menu-tree-row--separator, .mex .menu-tree-row--spacer { grid-template-columns: 26px minmax(80px, 1fr) auto; padding: 2px 4px; }
|
|
318
318
|
.mex .menu-tree-row:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 5%, transparent)); }
|
|
319
319
|
.mex .menu-tree-row:focus-visible { outline: 2px solid var(--dm-primary); outline-offset: 1px; }
|
|
320
320
|
.mex .menu-tree-row .me-row-label, .mex .menu-tree-row .me-row-url { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
|
|
@@ -322,5 +322,5 @@
|
|
|
322
322
|
.mex .mex-untitled { color: var(--dm-danger); font-style: italic; font-weight: 500; }
|
|
323
323
|
.mex-kebab { font-size: var(--dm-text-lg); line-height: 1; color: var(--dm-text-muted); padding: 0 .4rem; }
|
|
324
324
|
.mex-kebab:hover { color: var(--dm-primary); }
|
|
325
|
-
@media (max-width: 640px) { .mex .menu-tree-row--slim .me-row-url { display: none; } .mex .menu-tree-row--slim { grid-template-columns:
|
|
325
|
+
@media (max-width: 640px) { .mex .menu-tree-row--slim .me-row-url { display: none; } .mex .menu-tree-row--slim { grid-template-columns: 26px minmax(0, 1fr) repeat(3, auto); } }
|
|
326
326
|
</style>
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import{api as
|
|
2
|
-
<div class="menu-tree-row menu-tree-row--separator" data-id="${
|
|
3
|
-
<span class="menu-tree-grip" data-icon="
|
|
1
|
+
import{api as C}from"../api.js";import{colourToCss as wt,HIGHLIGHT_HOVER as tt,HIGHLIGHT_ACTIVE as nt,HIGHLIGHT_HOVER_LABELS as ot,HIGHLIGHT_ACTIVE_LABELS as at}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{openIconPicker as kt}from"../lib/card-builder.js";import{sortableMenuRows as St}from"../lib/menu-drag.js";import{placeTools as $t,ensureLockedTools as xt,isLockedUrl as Et,groupKeyFor as At,slugify as Lt,GROUP_ICON as _t,TOOLS_FOLDER_KEY as Ct}from"../lib/sidebar-grouping.js";import{flatten as it,nest as Ht,uid as Ee}from"../lib/menu-rows.js";import{addBannerAction as Be}from"../lib/plugin-chrome.js";import{helpPopovers as It}from"../lib/help-popover.js";import{onceClosed as Rt,openMenuAt as ze,sidebarCount as Tt}from"../lib/tool-kit.js";import{addChild as jt,bindingFrom as Dt,duplicateRow as Nt,indentRow as Ot,insertBelow as Pt,isStructural as oe,menuFromForm as Ft,menuProblems as st,moveRow as lt,outdentRow as Bt,siblingsOf as zt,snapshot as Ae}from"../lib/menu-editor-arrange.js";import{fmtDateTime as Mt}from"../lib/dates.js";const Kt=760,Wt="admin-sidebar",qt=/^\/menus\/(new|edit\/[^?#]+)(\?.*)?$/;function y(t){return String(t||"").replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<")}const Le=t=>String(t??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Ut(t,d){let s=0,l=d.find(i=>i.id===t);for(;l&&l.parentId;)s++,l=d.find(i=>i.id===l.parentId);return s}function rt(t){const d=new Set,s=new Set,l=i=>{for(const g of t.filter(k=>k.parentId===i))!g.type&&Et(g.url)&&!s.has(g.url)&&(s.add(g.url),d.add(g.id)),l(g.id)};return l(null),d}const Me='<button type="button" class="btn btn-sm btn-ghost mex-kebab" aria-label="Actions" title="Actions (right-click, or Shift+F10)">\u22EE</button>';function Gt(t,d,s=!1){const l=s?rt(d):new Set,i=[];function g(k){for(const f of d.filter(N=>N.parentId===k)){const _=`style="margin-left:${Ut(f.id,d)*28}px"`;if(f.type==="separator"){i.push(`
|
|
2
|
+
<div class="menu-tree-row menu-tree-row--separator" data-id="${f.id}" tabindex="0" ${_}>
|
|
3
|
+
<span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
|
|
4
4
|
<span class="me-sep-line"><span class="me-sep-label">Separator</span></span>
|
|
5
|
-
${
|
|
6
|
-
</div>`);continue}if(
|
|
7
|
-
<div class="menu-tree-row menu-tree-row--spacer" data-id="${
|
|
8
|
-
<span class="menu-tree-grip" data-icon="
|
|
5
|
+
${Me}
|
|
6
|
+
</div>`);continue}if(f.type==="spacer"){const ee=["xs","sm","md","lg","xl","flex"].map(O=>`<option value="${O}"${(f.size||"md")===O?" selected":""}>${O==="flex"?"flexible":O}</option>`).join("");i.push(`
|
|
7
|
+
<div class="menu-tree-row menu-tree-row--spacer" data-id="${f.id}" tabindex="0" ${_}>
|
|
8
|
+
<span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
|
|
9
9
|
<span class="me-spacer-line">
|
|
10
10
|
<span class="me-spacer-label">Spacer</span>
|
|
11
11
|
<select class="form-input me-spacer-size" title="Spacer size - flexible fills the leftover room" aria-label="Spacer size">${ee}</select>
|
|
12
12
|
</span>
|
|
13
|
-
${
|
|
14
|
-
</div>`);continue}const
|
|
15
|
-
<div class="menu-tree-row menu-tree-row--slim${
|
|
16
|
-
<span class="menu-tree-grip" data-icon="
|
|
17
|
-
<span class="me-row-label${!
|
|
18
|
-
<span class="me-row-url">${
|
|
13
|
+
${Me}
|
|
14
|
+
</div>`);continue}const V=f.badge&&(f.badge.text||f.badge.countFrom)?`<span class="dm-menu-badge">${y(String(f.badge.text||"#"))}</span>`:"",A=f.tool,h=A&&(A.persisted||f.touched),B=A?A.orphan?' <span class="badge badge-secondary me-tool-badge" title="A placeholder for a Tool that is not enabled - it returns here when it is">Not enabled</span>':` <span class="badge badge-secondary me-tool-badge" title="${h?"A Tool, placed here by this menu":"A Tool in its default place - move or edit it to place it here"}">${y(A.source||"Tool")}${h?"":" \xB7 default"}</span>`:"",ae=l.has(f.id),Z=wt(f.colour),z=Z?` style="color:${y(Z)}"`:"",ie=ae?'<button type="button" class="btn btn-sm btn-ghost" disabled title="Always shown - it can be moved, not hidden" aria-label="Always shown"><span data-icon="lock"></span></button>':`<button type="button" class="btn btn-sm btn-ghost me-hidden ${f.hidden?"active":""}" title="${f.hidden?"Hidden - click to show":"Hide"}" aria-label="${f.hidden?"Show":"Hide"}" aria-pressed="${f.hidden?"true":"false"}"><span data-icon="${f.hidden?"eye-off":"eye"}"></span></button>`;i.push(`
|
|
15
|
+
<div class="menu-tree-row menu-tree-row--slim${f.hidden?" menu-tree-row--hidden":""}${A?" menu-tree-row--tool":""}${A&&!h?" menu-tree-row--default":""}" data-id="${f.id}" tabindex="0" ${_}>
|
|
16
|
+
<span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
|
|
17
|
+
<span class="me-row-label${!f.text&&!A?" mex-untitled":""}"${z}>${y(f.text||A?.label||"(no label - click to add one)")}${V}${B}</span>
|
|
18
|
+
<span class="me-row-url">${y(f.url||"")}</span>
|
|
19
19
|
${ie}
|
|
20
20
|
<button type="button" class="btn btn-sm btn-ghost me-edit" title="Edit" aria-label="Edit"><span data-icon="edit"></span></button>
|
|
21
|
-
${
|
|
22
|
-
</div>`),f(d.id)}}f(null),t.innerHTML=o.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(t)}function k(t,r={},...l){const i=document.createElement(t);Object.assign(i,r);for(const o of l)o!=null&&i.append(o);return i}function D(t,r,l){const i=k("label",{className:"form-field"},k("span",{className:"form-label",textContent:t}),r);return l&&i.append(k("small",{className:"form-hint",textContent:l,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),i}function Vt(t,r){const l=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(r||[]).map(o=>[o.name,`${o.label||o.name} and above`]),...(r||[]).filter(o=>o.level!==0).map(o=>[`=${o.name}`,`${o.label||o.name} only`]),["private","Private - super-admin only"]];t&&!l.some(([o])=>o===t)&&l.push([t,`${t} (custom)`]);const i=Z(l,t||"");return i.name="visibility",i}function Z(t,r){const l=k("select",{className:"form-select"});return t.forEach(([i,o])=>l.add(new Option(o,i))),l.value=r??"",l}function _e(t,r){const l=typeof r=="string"&&r.startsWith("#"),i=Z([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],l?"__custom__":r||""),o=k("input",{type:"color",className:"form-input me-colour-hex",value:l?r:"#000000"});o.style.display=l?"":"none",i.addEventListener("change",()=>{o.style.display=i.value==="__custom__"?"":"none"});const f=D(t,i);return f.append(o),f._read=()=>i.value==="__custom__"?o.value:i.value,f}function Yt(t,r){const l=k("input",{className:"form-input me-icon",name:"icon",value:r||""}),i=k("span",{className:"me-icon-preview"});r&&i.setAttribute("data-icon",r);const o=k("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),f=h=>{h?i.setAttribute("data-icon",h):i.removeAttribute("data-icon"),Domma.icons.scan(i.parentNode||i)};return o.addEventListener("click",()=>St(h=>{l.value=h,f(h)})),l.addEventListener("input",()=>f(l.value.trim())),D(t,k("div",{className:"me-icon-field"},l,o,i))}function He(...t){return k("div",{className:"me-field-grid"},...t)}async function Xt(t,r,l,i,o){const f=t.text||t.tool?.label||"",h=c=>k("h4",{className:"me-form-section",textContent:c}),d=D("Label",k("input",{className:"form-input",name:"text",value:t.text||""}),"The text shown for this item."),C=k("input",{className:"form-input",name:"url",value:t.url||""}),$=D("URL",C,t.tool||t.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(t.tool||t.locked)&&(C.readOnly=!0);const j=Yt("Icon",t.icon||""),A=Vt(t.visibility||"",i),g=D("Visibility",A,t.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');t.locked&&(A.disabled=!0);const W=Z([["","- no permission gate -"],...(r||[]).map(c=>[c.key,c.label||c.key])],t.permission||"");W.name="permission";const ae=D("Permission",W,t.tool||t.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(t.tool||t.locked)&&(W.disabled=!0);const Q=D("Badge text",k("input",{className:"form-input",name:"badgeText",value:t.badge?.text||""})),K=Z([["","- none -"],...(l||[]).map(c=>[c.slug,c.title||c.slug])],t.badge?.countFrom||"");K.name="badgeCount";const ie=D("Badge count from",K,"Show a live count of this collection\u2019s entries as the badge."),ee=_e("Badge colour",t.badge?.variant||""),P=Z([["link","Link"],["pill","Pill"]],t.pill?"pill":"link");P.name="renderAs";const Ce=D("Render as",P,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),U=D("Pill style",Z([["filled","Filled"],["outline","Outline"]],t.pill?.style||"filled"));U.querySelector("select").name="pillStyle";const me=_e("Pill colour",t.pill?.variant||""),se=k("div",{className:"me-pill-wrap"},He(U,me));se.style.display=t.pill?"":"none",P.addEventListener("change",()=>{se.style.display=P.value==="pill"?"":"none"});const p=_e("Text colour",t.colour||""),N=Z([["","- use the menu default -"],...nt.map(c=>[c,at[c]||c])],t.highlight?.hover||"");N.name="hlHover";const le=D("Hover effect",N,"Overrides the menu-wide hover effect for this item only."),pe=Z([["","- use the menu default -"],...ot.map(c=>[c,it[c]||c])],t.highlight?.active||"");pe.name="hlActive";const be=D("When selected",pe,"How this item is marked when it points at the page being viewed."),B=_e("Highlight colour",t.highlight?.accent||""),x=k("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),F=k("div",{className:"me-item-form"},h("Link"),d,$,j,h("Access"),He(g,ae),h("Badge"),He(Q,ee),ie,h("Appearance"),Ce,se,p,h("Highlighting"),He(le,be),B,x),y=E.slideover({title:f?`Edit ${Le(f)}`:"Edit menu item",size:"lg",position:"right"});y.element.appendChild(F);const Y=()=>JSON.stringify([...F.querySelectorAll("input, select, textarea")].map(c=>c.type==="checkbox"?c.checked:c.value)),te=Y();let G=!1,re=!1;It(y);const ye=y.close.bind(y);y.close=async c=>{if(!G&&c!==!0&&Y()!==te){if(re)return;re=!0;const V=await E.confirm("Discard the changes to this item?");if(re=!1,!V)return}return G=!0,ye()},F.addEventListener("keydown",c=>{(c.ctrlKey||c.metaKey)&&c.key==="Enter"&&(c.preventDefault(),x.click())}),y.open();const fe=y.element.closest(".dm-slideover")||y.element.querySelector(".dm-slideover")||y.element;fe.style.setProperty("width",Mt+"px","important"),fe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(F);const L=c=>F.querySelector(`[name="${c}"]`)?.value||"";x.addEventListener("click",()=>{t.text=L("text"),t.icon=L("icon"),t.locked||(t.visibility=L("visibility")),!t.tool&&!t.locked?(t.url=L("url"),t.permission=L("permission")):t.touched=!0;const c=L("badgeText"),V=L("badgeCount"),ne=ee._read();if(t.badge=c||V?{...c&&{text:c},...V&&{countFrom:V},...ne&&{variant:ne}}:null,L("renderAs")==="pill"){const he=me._read();t.pill={style:L("pillStyle")||"filled",...he&&{variant:he}}}else t.pill=null;t.colour=p._read();const ce=L("hlHover"),de=L("hlActive"),ue=B._read();t.highlight=ce||de||ue?{...ce&&{hover:ce},...de&&{active:de},...ue&&{accent:ue}}:null,G=!0,y.close(!0),o()})}let q=null,ut=!1;function Jt(){ut||!window.R?.use||(ut=!0,R.use((t,r,l)=>{const i=r?.path||"";return!(Wt.test(i)&&(t?.path||"")!==i)||!q?.dirty()?l():E.confirm(`You have unsaved changes to the menu "${Le(q.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(f=>{f?l():history.replaceState(null,"",`#${i}`)})}),M.subscribe("router:afterChange",({to:t}={})=>{if(q&&(t?.path||"")!==q.path){const r=q;q=null,r.dispose()}}))}function mt(t,r){const l=t.querySelector(".dm-plugin-banner-name"),i=l?.querySelector(".dm-plugin-banner-sep");if(!(!l||!i)){for(;i.nextSibling;)i.nextSibling.remove();l.appendChild(document.createTextNode(r))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(t){if(Jt(),q){const e=q;q=null,e.dispose()}const r=[],l=e=>(r.push(e),e);let i=!1;const o=t.get(0).querySelector(".mex")||t.get(0),f=()=>!i&&o.isConnected,h=location.hash.replace(/^#/,""),d=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),C=d?decodeURIComponent(d[1]):null,$=!C,j=`menu-editor.draft.${C||"new"}`,A=E.loader(t.get(0),{type:"dots"});let g,W,ae,Q,K,ie,ee;try{if($)g={slug:"",name:"",description:"",items:[]};else try{g=await T.menus.get(C)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[W,ae,Q,K,ie,ee]=await Promise.all([T.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),T.collections.list().catch(()=>[]),T.get("/collections/roles/entries?limit=100").catch(()=>null),T.menuLocations.registry().catch(()=>[]),T.pages.list().catch(()=>[])])}finally{A.destroy()}if(!o.isConnected)return;const Ce=(Array.isArray(K)?K:K?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,n)=>n.level-e.level),U=!$&&C===qt;let me=[];if(U&&(me=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!o.isConnected))return;const se=e=>_t(U?xt(At(e||[],me,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let p=se(g.items);const N=M.observable(!1),le=M.observable(!1),pe=M.observable(""),be=M.observable(0);let B="";const x=o.querySelector("#me-items-list");function F(){Gt(x,p,U),Ut(x,()=>p,()=>{F(),z()}),be.value=p.filter(e=>!oe(e)).length}const y=()=>{F(),z()},Y=()=>U?dt(p):new Set,te=e=>p.find(n=>n.id===e);function G(e){requestAnimationFrame(()=>x.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function re(e){const n=u=>p.find(m=>!m.type&&!m.url&&!m.tool&&(m.key||"").toLowerCase()===u)||p.find(m=>!m.type&&!m.url&&!m.tool&&!m.key&&(m.text||"").toLowerCase()===u),s=n(String(e.tool.folder||"").toLowerCase())||n(Lt);e.parentId=s?s.id:null,p.splice(p.indexOf(e),1),p.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const ye=e=>!Y().has(e.id)&&!(e.tool&&!e.tool.orphan);async function fe(e){const n=te(e);if(!n||!ye(n))return;const s=b=>{let J=b;for(;J;){if(J.id===e)return!0;J=p.find(O=>O.id===J.parentId)}return!1},u=p.filter(b=>b.id!==e&&s(b));if(u.length&&!await E.confirm(`Remove "${Le(n.text||n.type||"this item")}" and the ${u.length} item${u.length===1?"":"s"} beneath it?`))return;const m=Y(),v=u.filter(b=>b.tool),_=u.filter(b=>!b.tool&&m.has(b.id));p=p.filter(b=>!s(b)||v.includes(b)||_.includes(b));for(const b of _)b.parentId=n.parentId??null;for(const b of v)b.tool.orphan?b.parentId=n.parentId??null:re(b);y()}function L(e){const n=te(e);!n||oe(n)||Y().has(e)||(n.hidden=!n.hidden,n.touched=!0,y())}function c(e){const n=te(e);!n||oe(n)||(n.locked=U&&Y().has(n.id),Xt(n,ae.resources||[],Q,Ce,()=>{y(),G(e)}))}function V(e){const n={id:xe(),parentId:null,...e==="separator"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};p.push(n),y(),oe(n)?G(n.id):c(n.id)}const ne=e=>n=>{e(n)&&(y(),G(n))},ce=ne(e=>lt(p,e,-1)),de=ne(e=>lt(p,e,1)),ue=ne(e=>Nt(p,e)),he=ne(e=>Bt(p,e));function pt(e){const n=te(e);if(!n)return[];const s=oe(n),u=Y().has(e),m=Ft(p,e),v=m.findIndex(O=>O.id===e),_=n.tool,b=_&&(_.persisted||n.touched),J=O=>()=>{const ge=Ot(p,e,O,xe());y(),ge&&!oe(ge)?c(ge.id):ge&&G(ge.id)};return[{header:s?n.type==="separator"?"Separator":"Spacer":n.text||_?.label||"(untitled)"},...s?[]:[{label:"Edit\u2026",icon:"edit",action:()=>c(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:J("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:s,action:()=>{const O=Dt(p,e,xe());y(),O&&c(O.id)}},{label:"Add separator below",icon:"minus",action:J("separator")},{label:"Add spacer below",icon:"move",action:J("spacer")},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:v<=0,action:()=>ce(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:v<0||v>=m.length-1,action:()=>de(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:v<=0||oe(m[v-1]),action:()=>ue(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:n.parentId==null,action:()=>he(e)},{type:"divider"},...s?[]:[{label:n.hidden?"Show":"Hide",icon:n.hidden?"eye":"eye-off",disabled:u,action:()=>L(e)}],{label:"Duplicate",icon:"copy",disabled:!!_,action:()=>{const O=jt(p,e,xe);y(),O&&G(O.id)}},..._&&!_.orphan&&b?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{re(n),y()}}]:[],{label:u?"Remove - always in the sidebar":_&&!_.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!ye(n),action:()=>fe(e)}]}const ft=E.contextMenu(x,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>pt(e.dataset.id)});l(()=>ft?.destroy?.());const We=e=>{const n=e.target.closest(".menu-tree-row");if(!n)return;const s=n.dataset.id;if(e.target.closest(".mex-kebab")){ze(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){L(s);return}if(e.target.closest(".me-edit")){c(s);return}e.target.closest("select, .menu-tree-grip, button")||c(s)},Ke=e=>{const n=e.target.closest(".menu-tree-row");if(!n||e.target!==n){n&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),ze(n));return}const s=n.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ze(n);else if(e.key==="Enter")e.preventDefault(),c(s);else if(e.key==="Delete")e.preventDefault(),fe(s);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),ce(s);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),de(s);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),ue(s);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),he(s);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const u=[...x.querySelectorAll(".menu-tree-row")],m=u.indexOf(n)+(e.key==="ArrowDown"?1:-1);u[m]&&(e.preventDefault(),u[m].focus())}},Ue=e=>{if(!e.target.matches(".me-spacer-size"))return;const n=te(e.target.closest(".menu-tree-row")?.dataset.id);n&&(n.size=e.target.value,z())};x.addEventListener("click",We),x.addEventListener("keydown",Ke),x.addEventListener("change",Ue),l(()=>{x.removeEventListener("click",We),x.removeEventListener("keydown",Ke),x.removeEventListener("change",Ue)});const a=e=>t.find(e),we=a("#me-float-accent"),Ie=a("#me-float-accent-hex"),Te=()=>{Ie.get(0).style.display=we.val()==="__custom__"?"":"none"},ht=()=>we.val()==="__custom__"?Ie.val():we.val(),ke=a("#me-highlight-accent"),De=a("#me-highlight-accent-hex"),Ge=()=>{De.get(0).style.display=ke.val()==="__custom__"?"":"none"},vt=()=>ke.val()==="__custom__"?De.val():ke.val(),Ve=()=>{const e=a("#me-position").val()==="floating";a(".dm-float-field").each(function(){this.style.display=e?"":"none"}),e&&Te();const n=a("#me-orientation").val()==="vertical";a(".dm-vertical-field").each(function(){this.style.display=n?"":"none"});const s=!!(a("#me-float-collapsible").get(0)||{}).checked;a(".dm-float-collapsed-field").each(function(){this.style.display=e&&s?"":"none"})},Ye=(e,n,s,u)=>{const m=a(e).get(0);m&&(m.innerHTML="",m.add(new Option(u,"")),n.forEach(v=>m.add(new Option(s[v]||v,v))))};Ye("#me-highlight-hover",nt,at,"- theme default -"),Ye("#me-highlight-active",ot,it,"- theme default -");const Re=a("#me-bind-slot"),je=a("#me-bind-projects"),Se=a("#me-bind-pages");Re.html('<option value="">- not bound -</option>'+(ie||[]).map(e=>`<option value="${w(e.slot)}">${w(e.label||e.slot)} (${w(e.slot)})</option>`).join("")),je.html(W.map(e=>`<option value="${w(e.slug)}">${w(e.name||e.slug)}</option>`).join("")),a("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ee.map(e=>{const n=e.urlPath||e.url||"";return n?`<option value="${w(n)}">${w(e.title||n)} - ${w(n)}</option>`:""}).join(""));const Xe=()=>Rt({slot:Re.val(),projects:Array.from(je.get(0).selectedOptions).map(e=>e.value),pagesText:Se.val()});function Ne(){const e=Xe(),n=a("#me-bind-summary");if(!e){n.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const s=[];e.projects.length&&s.push(`pages in ${e.projects.map(v=>`<code>${w(v)}</code>`).join(", ")}`),e.pages.length&&s.push(`pages matching ${e.pages.map(v=>`<code>${w(v)}</code>`).join(", ")}`);const u=e.pages.filter(v=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(v)),m=u.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${u.map(v=>`<code>${w(v)}</code>`).join(", ")}</div>`:"";n.html(s.length?`Takes over the <code>${w(e.slot)}</code> slot on ${s.join(" and ")}.${m}`:`<span class="text-warning">Slot <code>${w(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:gt}=await import("../lib/project-context.js");if(!f())return;const bt=$?gt():null;a("#me-project").html('<option value="">- none -</option>'+W.map(e=>`<option value="${w(e.slug)}">${w(e.name||e.slug)}</option>`).join(""));function Oe(e){p=se(e.items),a("#me-variant").val(e.variant||""),a("#me-position").val(e.position||"");const n=a("#me-appearOnHover").get(0);n&&(n.checked=e.appearOnHover===!0),a("#me-float-anchor").val(e.float?.anchor||"TL"),a("#me-float-offsetX").val(e.float?.offsetX??""),a("#me-float-offsetY").val(e.float?.offsetY??""),a("#me-float-width").val(e.float?.width??""),a("#me-float-radius").val(e.float?.radius??""),a("#me-float-shadow").val(e.float?.shadow||""),a("#me-float-opacity").val(e.float?.opacity??""),a("#me-float-title").val(e.float?.title||"");for(const[v,_]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const b=a(v).get(0);b&&(b.checked=_===!0)}const s=e.float?.accent||"";we.val(s.startsWith("#")?"__custom__":s),s.startsWith("#")&&Ie.val(s),Te(),a("#me-orientation").val(e.orientation||""),a("#me-align").val(e.align||""),a("#me-side").val(e.side||"left"),a("#me-highlight-hover").val(e.highlight?.hover||""),a("#me-highlight-active").val(e.highlight?.active||"");const u=e.highlight?.accent||"";ke.val(u.startsWith("#")?"__custom__":u),u.startsWith("#")&&De.val(u),Ge(),a("#me-fontFamily").val(e.style?.fontFamily||""),a("#me-fontSize").val(e.style?.fontSize||""),a("#me-fontWeight").val(e.style?.fontWeight||""),a("#me-letterSpacing").val(e.style?.letterSpacing||""),a("#me-iconSize").val(e.style?.iconSize||""),Re.val(e.binding?.slot||"");const m=new Set(e.binding?.projects||[]);Array.from(je.get(0).options).forEach(v=>{v.selected=m.has(v.value)}),Se.val((e.binding?.pages||[]).join(`
|
|
23
|
-
`)),
|
|
24
|
-
`).map(
|
|
25
|
-
`)),Ne(),
|
|
21
|
+
${Me}
|
|
22
|
+
</div>`),g(f.id)}}g(null),t.innerHTML=i.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(t)}function $(t,d={},...s){const l=document.createElement(t);Object.assign(l,d);for(const i of s)i!=null&&l.append(i);return l}function T(t,d,s){const l=$("label",{className:"form-field"},$("span",{className:"form-label",textContent:t}),d);return s&&l.append($("small",{className:"form-hint",textContent:s,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),l}function Vt(t,d){const s=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(d||[]).map(i=>[i.name,`${i.label||i.name} and above`]),...(d||[]).filter(i=>i.level!==0).map(i=>[`=${i.name}`,`${i.label||i.name} only`]),["private","Private - super-admin only"]];t&&!s.some(([i])=>i===t)&&s.push([t,`${t} (custom)`]);const l=Q(s,t||"");return l.name="visibility",l}function Q(t,d){const s=$("select",{className:"form-select"});return t.forEach(([l,i])=>s.add(new Option(i,l))),s.value=d??"",s}function _e(t,d){const s=typeof d=="string"&&d.startsWith("#"),l=Q([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],s?"__custom__":d||""),i=$("input",{type:"color",className:"form-input me-colour-hex",value:s?d:"#000000"});i.style.display=s?"":"none",l.addEventListener("change",()=>{i.style.display=l.value==="__custom__"?"":"none"});const g=T(t,l);return g.append(i),g._read=()=>l.value==="__custom__"?i.value:l.value,g}function Yt(t,d){const s=$("input",{className:"form-input me-icon",name:"icon",value:d||""}),l=$("span",{className:"me-icon-preview"});d&&l.setAttribute("data-icon",d);const i=$("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),g=k=>{k?l.setAttribute("data-icon",k):l.removeAttribute("data-icon"),Domma.icons.scan(l.parentNode||l)};return i.addEventListener("click",()=>kt(k=>{s.value=k,g(k)})),s.addEventListener("input",()=>g(s.value.trim())),T(t,$("div",{className:"me-icon-field"},s,i,l))}function Ce(...t){return $("div",{className:"me-field-grid"},...t)}async function Xt(t,d,s,l,i){const g=t.text||t.tool?.label||"",k=r=>$("h4",{className:"me-form-section",textContent:r}),f=T("Label",$("input",{className:"form-input",name:"text",value:t.text||""}),"The text shown for this item."),N=$("input",{className:"form-input",name:"url",value:t.url||""}),_=T("URL",N,t.tool||t.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(t.tool||t.locked)&&(N.readOnly=!0);const V=Yt("Icon",t.icon||""),A=Vt(t.visibility||"",l),h=T("Visibility",A,t.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');t.locked&&(A.disabled=!0);const B=Q([["","- no permission gate -"],...(d||[]).map(r=>[r.key,r.label||r.key])],t.permission||"");B.name="permission";const ae=T("Permission",B,t.tool||t.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(t.tool||t.locked)&&(B.disabled=!0);const Z=T("Badge text",$("input",{className:"form-input",name:"badgeText",value:t.badge?.text||""})),z=Q([["","- none -"],...(s||[]).map(r=>[r.slug,r.title||r.slug])],t.badge?.countFrom||"");z.name="badgeCount";const ie=T("Badge count from",z,"Show a live count of this collection\u2019s entries as the badge."),ee=_e("Badge colour",t.badge?.variant||""),O=Q([["link","Link"],["pill","Pill"]],t.pill?"pill":"link");O.name="renderAs";const He=T("Render as",O,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),K=T("Pill style",Q([["filled","Filled"],["outline","Outline"]],t.pill?.style||"filled"));K.querySelector("select").name="pillStyle";const me=_e("Pill colour",t.pill?.variant||""),se=$("div",{className:"me-pill-wrap"},Ce(K,me));se.style.display=t.pill?"":"none",O.addEventListener("change",()=>{se.style.display=O.value==="pill"?"":"none"});const m=_e("Text colour",t.colour||""),j=Q([["","- use the menu default -"],...tt.map(r=>[r,ot[r]||r])],t.highlight?.hover||"");j.name="hlHover";const le=T("Hover effect",j,"Overrides the menu-wide hover effect for this item only."),pe=Q([["","- use the menu default -"],...nt.map(r=>[r,at[r]||r])],t.highlight?.active||"");pe.name="hlActive";const be=T("When selected",pe,"How this item is marked when it points at the page being viewed."),P=_e("Highlight colour",t.highlight?.accent||""),x=$("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),W=$("div",{className:"me-item-form"},k("Link"),f,_,V,k("Access"),Ce(h,ae),k("Badge"),Ce(Z,ee),ie,k("Appearance"),He,se,m,k("Highlighting"),Ce(le,be),P,x),b=E.slideover({title:g?`Edit ${Le(g)}`:"Edit menu item",size:"lg",position:"right"});b.element.appendChild(W);const Y=()=>JSON.stringify([...W.querySelectorAll("input, select, textarea")].map(r=>r.type==="checkbox"?r.checked:r.value)),te=Y();let q=!1,re=!1;Rt(b);const ye=b.close.bind(b);b.close=async r=>{if(!q&&r!==!0&&Y()!==te){if(re)return;re=!0;const U=await E.confirm("Discard the changes to this item?");if(re=!1,!U)return}return q=!0,ye()},W.addEventListener("keydown",r=>{(r.ctrlKey||r.metaKey)&&r.key==="Enter"&&(r.preventDefault(),x.click())}),b.open();const fe=b.element.closest(".dm-slideover")||b.element.querySelector(".dm-slideover")||b.element;fe.style.setProperty("width",Kt+"px","important"),fe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(W);const L=r=>W.querySelector(`[name="${r}"]`)?.value||"";x.addEventListener("click",()=>{t.text=L("text"),t.icon=L("icon"),t.locked||(t.visibility=L("visibility")),!t.tool&&!t.locked?(t.url=L("url"),t.permission=L("permission")):t.touched=!0;const r=L("badgeText"),U=L("badgeCount"),ne=ee._read();if(t.badge=r||U?{...r&&{text:r},...U&&{countFrom:U},...ne&&{variant:ne}}:null,L("renderAs")==="pill"){const he=me._read();t.pill={style:L("pillStyle")||"filled",...he&&{variant:he}}}else t.pill=null;t.colour=m._read();const ce=L("hlHover"),de=L("hlActive"),ue=P._read();t.highlight=ce||de||ue?{...ce&&{hover:ce},...de&&{active:de},...ue&&{accent:ue}}:null,q=!0,b.close(!0),i()})}let F=null,ct=!1;function Jt(){ct||!window.R?.use||(ct=!0,R.use((t,d,s)=>{const l=d?.path||"";return!(qt.test(l)&&(t?.path||"")!==l)||!F?.dirty()?s():E.confirm(`You have unsaved changes to the menu "${Le(F.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(g=>{g?s():history.replaceState(null,"",`#${l}`)})}),M.subscribe("router:afterChange",({to:t}={})=>{if(F&&(t?.path||"")!==F.path){const d=F;F=null,d.dispose()}}))}function dt(t,d){const s=t.querySelector(".dm-plugin-banner-name"),l=s?.querySelector(".dm-plugin-banner-sep");if(!(!s||!l)){for(;l.nextSibling;)l.nextSibling.remove();s.appendChild(document.createTextNode(d))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(t){if(Jt(),F){const e=F;F=null,e.dispose()}const d=[],s=e=>(d.push(e),e);let l=!1;const i=t.get(0).querySelector(".mex")||t.get(0),g=()=>!l&&i.isConnected,k=location.hash.replace(/^#/,""),f=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),N=f?decodeURIComponent(f[1]):null,_=!N,V=`menu-editor.draft.${N||"new"}`,A=E.loader(t.get(0),{type:"dots"});let h,B,ae,Z,z,ie,ee;try{if(_)h={slug:"",name:"",description:"",items:[]};else try{h=await C.menus.get(N)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[B,ae,Z,z,ie,ee]=await Promise.all([C.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),C.collections.list().catch(()=>[]),C.get("/collections/roles/entries?limit=100").catch(()=>null),C.menuLocations.registry().catch(()=>[]),C.pages.list().catch(()=>[])])}finally{A.destroy()}if(!i.isConnected)return;const He=(Array.isArray(z)?z:z?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,n)=>n.level-e.level),K=!_&&N===Wt;let me=[];if(K&&(me=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!i.isConnected))return;const se=e=>it(K?xt($t(e||[],me,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let m=se(h.items);const j=M.observable(!1),le=M.observable(!1),pe=M.observable(""),be=M.observable(0);let P="";const x=i.querySelector("#me-items-list");function W(){Gt(x,m,K),be.value=m.filter(e=>!oe(e)).length}const b=()=>{W(),G()},Y=()=>K?rt(m):new Set,te=e=>m.find(n=>n.id===e);function q(e){requestAnimationFrame(()=>x.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function re(e){const n=v=>m.find(c=>!c.type&&!c.url&&!c.tool&&(c.key||"").toLowerCase()===v)||m.find(c=>!c.type&&!c.url&&!c.tool&&!c.key&&(c.text||"").toLowerCase()===v);let a=n(String(e.tool.folder||"").toLowerCase())||n(Ct);const p=String(e.tool.group||"").trim();if(a&&p){const v=At(a.key||Lt(a.text),p),c=u=>u!==e&&!u.type&&!u.url&&!u.tool;let w=m.find(u=>c(u)&&(u.key||"").toLowerCase()===v)||m.find(u=>c(u)&&u.parentId===a.id&&(!u.key||u.key.toLowerCase()===v)&&(u.text||"").toLowerCase()===p.toLowerCase());w||([w]=it([{text:p,key:v,icon:_t,synthesised:!0}],a.id),m.push(w)),a=w}e.parentId=a?a.id:null,m.splice(m.indexOf(e),1),m.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const ye=e=>!Y().has(e.id)&&!(e.tool&&!e.tool.orphan);async function fe(e){const n=te(e);if(!n||!ye(n))return;const a=u=>{let J=u;for(;J;){if(J.id===e)return!0;J=m.find(D=>D.id===J.parentId)}return!1},p=m.filter(u=>u.id!==e&&a(u));if(p.length&&!await E.confirm(`Remove "${Le(n.text||n.type||"this item")}" and the ${p.length} item${p.length===1?"":"s"} beneath it?`))return;const v=Y(),c=p.filter(u=>u.tool),w=p.filter(u=>!u.tool&&v.has(u.id));m=m.filter(u=>!a(u)||c.includes(u)||w.includes(u));for(const u of w)u.parentId=n.parentId??null;for(const u of c)u.tool.orphan?u.parentId=n.parentId??null:re(u);b()}function L(e){const n=te(e);!n||oe(n)||Y().has(e)||(n.hidden=!n.hidden,n.touched=!0,b())}function r(e){const n=te(e);!n||oe(n)||(n.locked=K&&Y().has(n.id),Xt(n,ae.resources||[],Z,He,()=>{b(),q(e)}))}function U(e){const n={id:Ee(),parentId:null,...e==="separator"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};m.push(n),b(),oe(n)?q(n.id):r(n.id)}const ne=e=>n=>{e(n)&&(b(),q(n))},ce=ne(e=>lt(m,e,-1)),de=ne(e=>lt(m,e,1)),ue=ne(e=>Ot(m,e)),he=ne(e=>Bt(m,e));function ut(e){const n=te(e);if(!n)return[];const a=oe(n),p=Y().has(e),v=zt(m,e),c=v.findIndex(D=>D.id===e),w=n.tool,u=w&&(w.persisted||n.touched),J=D=>()=>{const ge=Pt(m,e,D,Ee());b(),ge&&!oe(ge)?r(ge.id):ge&&q(ge.id)};return[{header:a?n.type==="separator"?"Separator":"Spacer":n.text||w?.label||"(untitled)"},...a?[]:[{label:"Edit\u2026",icon:"edit",action:()=>r(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:J("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:a,action:()=>{const D=jt(m,e,Ee());b(),D&&r(D.id)}},{label:"Add separator below",icon:"minus",action:J("separator")},{label:"Add spacer below",icon:"move",action:J("spacer")},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:c<=0,action:()=>ce(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:c<0||c>=v.length-1,action:()=>de(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:c<=0||oe(v[c-1]),action:()=>ue(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:n.parentId==null,action:()=>he(e)},{type:"divider"},...a?[]:[{label:n.hidden?"Show":"Hide",icon:n.hidden?"eye":"eye-off",disabled:p,action:()=>L(e)}],{label:"Duplicate",icon:"copy",disabled:!!w,action:()=>{const D=Nt(m,e,Ee);b(),D&&q(D.id)}},...w&&!w.orphan&&u?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{re(n),b()}}]:[],{label:p?"Remove - always in the sidebar":w&&!w.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!ye(n),action:()=>fe(e)}]}const mt=E.contextMenu(x,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>ut(e.dataset.id)});s(()=>mt?.destroy?.());const pt=St(x,()=>m,b,{items:".menu-tree-row",handle:".menu-tree-grip"});s(()=>pt?.destroy());const Ke=e=>{const n=e.target.closest(".menu-tree-row");if(!n)return;const a=n.dataset.id;if(e.target.closest(".mex-kebab")){ze(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){L(a);return}if(e.target.closest(".me-edit")){r(a);return}e.target.closest("select, .menu-tree-grip, button")||r(a)},We=e=>{const n=e.target.closest(".menu-tree-row");if(!n||e.target!==n){n&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),ze(n));return}const a=n.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ze(n);else if(e.key==="Enter")e.preventDefault(),r(a);else if(e.key==="Delete")e.preventDefault(),fe(a);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),ce(a);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),de(a);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),ue(a);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),he(a);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const p=[...x.querySelectorAll(".menu-tree-row")],v=p.indexOf(n)+(e.key==="ArrowDown"?1:-1);p[v]&&(e.preventDefault(),p[v].focus())}},qe=e=>{if(!e.target.matches(".me-spacer-size"))return;const n=te(e.target.closest(".menu-tree-row")?.dataset.id);n&&(n.size=e.target.value,G())};x.addEventListener("click",Ke),x.addEventListener("keydown",We),x.addEventListener("change",qe),s(()=>{x.removeEventListener("click",Ke),x.removeEventListener("keydown",We),x.removeEventListener("change",qe)});const o=e=>t.find(e),we=o("#me-float-accent"),Ie=o("#me-float-accent-hex"),Re=()=>{Ie.get(0).style.display=we.val()==="__custom__"?"":"none"},ft=()=>we.val()==="__custom__"?Ie.val():we.val(),ke=o("#me-highlight-accent"),Te=o("#me-highlight-accent-hex"),Ue=()=>{Te.get(0).style.display=ke.val()==="__custom__"?"":"none"},ht=()=>ke.val()==="__custom__"?Te.val():ke.val(),Ge=()=>{const e=o("#me-position").val()==="floating";o(".dm-float-field").each(function(){this.style.display=e?"":"none"}),e&&Re();const n=o("#me-orientation").val()==="vertical";o(".dm-vertical-field").each(function(){this.style.display=n?"":"none"});const a=!!(o("#me-float-collapsible").get(0)||{}).checked;o(".dm-float-collapsed-field").each(function(){this.style.display=e&&a?"":"none"})},Ve=(e,n,a,p)=>{const v=o(e).get(0);v&&(v.innerHTML="",v.add(new Option(p,"")),n.forEach(c=>v.add(new Option(a[c]||c,c))))};Ve("#me-highlight-hover",tt,ot,"- theme default -"),Ve("#me-highlight-active",nt,at,"- theme default -");const je=o("#me-bind-slot"),De=o("#me-bind-projects"),Se=o("#me-bind-pages");je.html('<option value="">- not bound -</option>'+(ie||[]).map(e=>`<option value="${y(e.slot)}">${y(e.label||e.slot)} (${y(e.slot)})</option>`).join("")),De.html(B.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join("")),o("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ee.map(e=>{const n=e.urlPath||e.url||"";return n?`<option value="${y(n)}">${y(e.title||n)} - ${y(n)}</option>`:""}).join(""));const Ye=()=>Dt({slot:je.val(),projects:Array.from(De.get(0).selectedOptions).map(e=>e.value),pagesText:Se.val()});function Ne(){const e=Ye(),n=o("#me-bind-summary");if(!e){n.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const a=[];e.projects.length&&a.push(`pages in ${e.projects.map(c=>`<code>${y(c)}</code>`).join(", ")}`),e.pages.length&&a.push(`pages matching ${e.pages.map(c=>`<code>${y(c)}</code>`).join(", ")}`);const p=e.pages.filter(c=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(c)),v=p.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${p.map(c=>`<code>${y(c)}</code>`).join(", ")}</div>`:"";n.html(a.length?`Takes over the <code>${y(e.slot)}</code> slot on ${a.join(" and ")}.${v}`:`<span class="text-warning">Slot <code>${y(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:vt}=await import("../lib/project-context.js");if(!g())return;const gt=_?vt():null;o("#me-project").html('<option value="">- none -</option>'+B.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join(""));function Oe(e){m=se(e.items),o("#me-variant").val(e.variant||""),o("#me-position").val(e.position||"");const n=o("#me-appearOnHover").get(0);n&&(n.checked=e.appearOnHover===!0),o("#me-float-anchor").val(e.float?.anchor||"TL"),o("#me-float-offsetX").val(e.float?.offsetX??""),o("#me-float-offsetY").val(e.float?.offsetY??""),o("#me-float-width").val(e.float?.width??""),o("#me-float-radius").val(e.float?.radius??""),o("#me-float-shadow").val(e.float?.shadow||""),o("#me-float-opacity").val(e.float?.opacity??""),o("#me-float-title").val(e.float?.title||"");for(const[c,w]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const u=o(c).get(0);u&&(u.checked=w===!0)}const a=e.float?.accent||"";we.val(a.startsWith("#")?"__custom__":a),a.startsWith("#")&&Ie.val(a),Re(),o("#me-orientation").val(e.orientation||""),o("#me-align").val(e.align||""),o("#me-side").val(e.side||"left"),o("#me-highlight-hover").val(e.highlight?.hover||""),o("#me-highlight-active").val(e.highlight?.active||"");const p=e.highlight?.accent||"";ke.val(p.startsWith("#")?"__custom__":p),p.startsWith("#")&&Te.val(p),Ue(),o("#me-fontFamily").val(e.style?.fontFamily||""),o("#me-fontSize").val(e.style?.fontSize||""),o("#me-fontWeight").val(e.style?.fontWeight||""),o("#me-letterSpacing").val(e.style?.letterSpacing||""),o("#me-iconSize").val(e.style?.iconSize||""),je.val(e.binding?.slot||"");const v=new Set(e.binding?.projects||[]);Array.from(De.get(0).options).forEach(c=>{c.selected=v.has(c.value)}),Se.val((e.binding?.pages||[]).join(`
|
|
23
|
+
`)),o("#me-slug").val(e.slug||""),o("#me-name").val(e.name||""),o("#me-description").val(e.description||""),o("#me-project").val(e.meta?.project||gt||""),Ge(),Ne(),W()}const ve=e=>!!(o(e).get(0)||{}).checked;function $e(){const e={variant:o("#me-variant").val(),position:o("#me-position").val(),appearOnHover:ve("#me-appearOnHover"),floatAnchor:o("#me-float-anchor").val(),floatOffsetX:o("#me-float-offsetX").val(),floatOffsetY:o("#me-float-offsetY").val(),floatWidth:o("#me-float-width").val(),floatRadius:o("#me-float-radius").val(),floatShadow:o("#me-float-shadow").val(),floatAccent:ft(),floatOpacity:o("#me-float-opacity").val(),floatTitle:o("#me-float-title").val(),floatCollapsible:ve("#me-float-collapsible"),floatCollapsed:ve("#me-float-collapsed"),floatMovable:ve("#me-float-movable"),floatResizable:ve("#me-float-resizable"),highlightHover:o("#me-highlight-hover").val(),highlightActive:o("#me-highlight-active").val(),highlightAccent:ht(),orientation:o("#me-orientation").val(),align:o("#me-align").val(),side:o("#me-side").val(),fontFamily:o("#me-fontFamily").val(),fontSize:o("#me-fontSize").val(),fontWeight:o("#me-fontWeight").val(),letterSpacing:o("#me-letterSpacing").val(),iconSize:o("#me-iconSize").val()},n={slug:o("#me-slug").val(),name:o("#me-name").val(),description:o("#me-description").val(),project:o("#me-project").val()};return Ft(e,n,Ye(),Ht(m),h.meta||{})}let Xe=!1,Pe=null;function G(){if(!P)return;const e=$e();Pe=e,j.value=Ae(e)!==P,pe.value=j.peek()||Xe?st(e).join(" "):""}const xe=e=>{e.target.closest("#me-items-list")||(e.target.matches("#me-position, #me-orientation, #me-float-collapsible")&&Ge(),e.target.matches("#me-float-accent")&&Re(),e.target.matches("#me-highlight-accent")&&Ue(),e.target.closest("#me-binding")&&Ne(),G())};i.addEventListener("input",xe),i.addEventListener("change",xe),s(()=>{i.removeEventListener("input",xe),i.removeEventListener("change",xe)}),o("#me-bind-page-add").on("click",()=>{const e=o("#me-bind-page-pick").val();if(!e)return;const n=Se.val().split(`
|
|
24
|
+
`).map(a=>a.trim()).filter(Boolean);n.includes(e)||n.push(e),Se.val(n.join(`
|
|
25
|
+
`)),Ne(),G()}),Oe(h),P=Ae($e()),G();const Je=()=>{try{S.remove?S.remove(V):S.set(V,null)}catch{}};async function Fe(){if(le.peek())return;const e=$e(),n=st(e);if(n.length){Xe=!0,G(),E.toast(n.join(" "),{type:"warning",duration:7e3});return}le.value=!0;try{if(_)await C.menus.create(e);else if(e.slug!==h.slug){await C.menus.create(e);const a=await C.menuLocations.get();let p=!1;for(const[v,c]of Object.entries(a))c===h.slug&&(a[v]=e.slug,p=!0);p&&await C.menuLocations.save(a),await C.menus.remove(h.slug)}else await C.menus.update(h.slug,e);if(P=Ae(e),j.value=!1,Je(),Tt("#/menus"),E.toast("Saved.",{type:"success"}),_||e.slug!==h.slug)location.hash="#/menus/edit/"+encodeURIComponent(e.slug);else{h={...h,...e};for(const a of m)a.tool&&a.touched&&(a.tool={...a.tool,persisted:!0});W(),P=Ae($e()),G(),dt(t.get(0),e.name||e.slug)}if(K)try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}catch(a){E.toast(`Save failed: ${a.message||a}`,{type:"error"})}finally{le.value=!1}}async function bt(){!j.peek()||!await E.confirm("Throw away the changes you have not saved?")||(Oe(h),G())}E.tabs(o("#me-tabs").get(0));const yt=M.applyBindings({dirty:j,saving:le,problems:pe,itemCount:be},i,{methods:{save:()=>Fe(),discard:()=>bt(),addItem:()=>U("item"),addSeparator:()=>U("separator"),addSpacer:()=>U("spacer")}});s(()=>yt.dispose()),s(It(i,{position:"bottom"})),dt(t.get(0),_?"New menu":h.name||h.slug),Be(t,{id:"menu-editor-back",icon:"arrow-left",title:"All menus",onClick:()=>{location.hash="#/menus"}}),Be(t,{id:"menu-editor-locations",icon:"map-pin",title:"Menu locations",onClick:()=>{location.hash="#/menu-locations"}}),Be(t,{id:"menu-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>Fe()});const Qe=e=>{if(!(!(e.ctrlKey||e.metaKey)||e.key!=="s")){if(e.preventDefault(),e.stopImmediatePropagation(),document.querySelector(".me-item-form")?.offsetParent){E.toast("Apply the item first (Ctrl+Enter), then Save.",{type:"info"});return}Fe()}};document.addEventListener("keydown",Qe,!0),s(()=>document.removeEventListener("keydown",Qe,!0));const Ze=()=>{if(!(!j.peek()||!Pe))try{S.set(V,{menu:Pe,base:P,at:new Date().toISOString()})}catch{}},et=e=>{j.peek()&&(Ze(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",et),s(()=>window.removeEventListener("beforeunload",et)),F={path:k,dirty:()=>j.peek(),name:()=>o("#me-name").val()||h.name||h.slug||"new menu",dispose(){l=!0,Ze(),d.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(i);let X=null;try{X=S.get(V)}catch{}if(X?.menu){Je();const e=X.base&&X.base!==P,n=X.at?` (${Mt(X.at)})`:"",a=_?"the new menu you started":`the menu "${Le(h.name||h.slug)}"`,p=e?`You left unsaved changes to ${a}${n}, but the saved menu has changed since. Restore your version anyway?`:`You left unsaved changes to ${a}${n}. Restore them?`;await E.confirm(p)&&g()&&(Oe({...X.menu,meta:{...h.meta||{},...X.menu.meta||{}}}),G())}}};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domma-cms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.97.0",
|
|
4
4
|
"description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/server.js",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"@fastify/rate-limit": "^10.3.0",
|
|
84
84
|
"@fastify/static": "9.1.1",
|
|
85
85
|
"bcryptjs": "^3.0.3",
|
|
86
|
-
"domma-js": "0.
|
|
86
|
+
"domma-js": "0.45.0",
|
|
87
87
|
"dotenv": "^17.2.3",
|
|
88
88
|
"fastify": "5.8.5",
|
|
89
89
|
"gray-matter": "^4.0.3",
|
package/server/server.js
CHANGED
|
@@ -583,6 +583,8 @@ await app.register(relatedRoutes, {prefix: '/api/related'});
|
|
|
583
583
|
// site would simply never see Notes or Todo. Registered items are placed at
|
|
584
584
|
// render time on every site (placeTools() in admin/js/lib/sidebar-grouping.js):
|
|
585
585
|
// in the Tools folder by default, or wherever an admin has moved them.
|
|
586
|
+
// `group: 'Core'` gathers them in a Core sub-folder (Tools -> Core -> Notes),
|
|
587
|
+
// apart from the marketplace plugins' Tools, which sit directly in Tools.
|
|
586
588
|
//
|
|
587
589
|
// `permission` is what hides each one from a role that cannot use it; the
|
|
588
590
|
// renderer filters on it.
|
|
@@ -598,7 +600,7 @@ const coreToolItems = [
|
|
|
598
600
|
{text: 'SEO', url: '#/seo', icon: 'search', permission: 'seo', countUrl: '/api/seo/count'}
|
|
599
601
|
];
|
|
600
602
|
for (const item of coreToolItems) {
|
|
601
|
-
if (isToolEnabled(item.permission)) registerSidebarItem({item: {source: 'Built in', ...item}});
|
|
603
|
+
if (isToolEnabled(item.permission)) registerSidebarItem({group: 'Core', item: {source: 'Built in', ...item}});
|
|
602
604
|
}
|
|
603
605
|
// Todo's to-dos on the calendar (registered when routes/api/todo.js loads).
|
|
604
606
|
if (!isToolEnabled('todo')) {
|
package/server/services/hooks.js
CHANGED
|
@@ -81,16 +81,23 @@ const _registeredSidebarItems = [];
|
|
|
81
81
|
* places by `url` first (see placeTools in admin/js/lib/sidebar-grouping.js).
|
|
82
82
|
* `parent` is the older form: any node matched by its text.
|
|
83
83
|
*
|
|
84
|
-
*
|
|
84
|
+
* `group` puts the Tool one level further down, in a sub-folder of that folder
|
|
85
|
+
* (`group: 'Core'` -> Tools -> Core -> the Tool). The sub-folder is keyed
|
|
86
|
+
* `<folder>.<slug of group>` and made at render time if the menu has none; an
|
|
87
|
+
* admin's own arrangement still wins.
|
|
88
|
+
*
|
|
89
|
+
* @param {{folder?: string, parent?: string, group?: string, item: {text: string, url: string, icon?: string, permission?: string, folder?: string, group?: string, items?: object[]}}} opts
|
|
85
90
|
*/
|
|
86
91
|
export function registerSidebarItem(opts) {
|
|
87
92
|
if (!opts || !opts.item || typeof opts.item.text !== 'string') {
|
|
88
93
|
throw new Error('registerSidebarItem: opts.item.text is required');
|
|
89
94
|
}
|
|
90
|
-
const {folder: itemFolder, ...item} = opts.item;
|
|
95
|
+
const {folder: itemFolder, group: itemGroup, ...item} = opts.item;
|
|
96
|
+
const group = [opts.group, itemGroup].find(g => typeof g === 'string' && g.trim());
|
|
91
97
|
_registeredSidebarItems.push({
|
|
92
98
|
parent: opts.parent || null,
|
|
93
99
|
folder: opts.folder || itemFolder || DEFAULT_TOOL_FOLDER,
|
|
100
|
+
...(group && {group: group.trim()}),
|
|
94
101
|
item
|
|
95
102
|
});
|
|
96
103
|
}
|
|
@@ -569,8 +569,9 @@ export async function registerPlugins(fastify) {
|
|
|
569
569
|
// reads plugin nav from /api/sidebar/registered-items; plugins
|
|
570
570
|
// declare their nav in the manifest rather than calling
|
|
571
571
|
// registerSidebarItem, so register it here on their behalf. An
|
|
572
|
-
// entry's `folder` is its default place (Tools when it names none)
|
|
573
|
-
// an
|
|
572
|
+
// entry's `folder` is its default place (Tools when it names none),
|
|
573
|
+
// and an optional `group` a sub-folder inside it; an admin can move
|
|
574
|
+
// it anywhere in the menu.
|
|
574
575
|
const isCore = CORE_PLUGINS.has(manifest.name);
|
|
575
576
|
for (const item of manifest.admin?.sidebar || []) {
|
|
576
577
|
try {
|
|
@@ -312,6 +312,9 @@ export function buildGitignore({sitePlugins = [], pluginContent = {}, sitePublic
|
|
|
312
312
|
// SEO's runtime state; its redirects and overrides beside them are authored, and tracked.
|
|
313
313
|
'/content/seo/audit.json',
|
|
314
314
|
'/content/seo/hits.json',
|
|
315
|
+
// When each notification source last ran, and which one-off migrations have run - rewritten by the CMS itself.
|
|
316
|
+
'/content/.notification-sources.json',
|
|
317
|
+
'/content/.migrations.json',
|
|
315
318
|
'/content/instances_log.json',
|
|
316
319
|
'/content/preview-links.json',
|
|
317
320
|
'/config/connections.json*',
|