domma-cms 0.51.0 → 0.53.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/js/templates/page-editor.html +9 -2
- package/admin/js/views/page-editor.js +26 -26
- package/package.json +1 -1
- package/plugins/analytics/public/inject-body.html +5 -0
- package/server/routes/api/pages.js +2 -1
- package/server/server.js +24 -1
- package/server/services/renderer.js +10 -0
- package/server/templates/page.html +7 -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-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(#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-stage{display:flex;justify-content:center;height:calc(100vh - 230px);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}.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:1px;background:var(--dm-border, rgba(255,255,255,.08));flex-shrink:0}.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-preview{flex:1;padding:1rem;overflow-y:auto;line-height:1.7}.editor-preview h1,.editor-preview h2,.editor-preview h3{margin-top:1.5rem}.editor-preview p{margin-bottom:.75rem}.editor-preview code{background:var(--dm-code-bg);padding:.1em .3em;border-radius:3px;font-size:.9em}.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}.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-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-heading{font-size:1.1rem;font-weight:600;margin-bottom:1.25rem}.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-card .card-body{flex:1}.plugin-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.75rem}.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;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}}.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-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-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-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}
|
|
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-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(#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-stage{display:flex;justify-content:center;height:calc(100vh - 230px);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-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}.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-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-heading{font-size:1.1rem;font-weight:600;margin-bottom:1.25rem}.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-card .card-body{flex:1}.plugin-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.75rem}.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;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-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-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-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}
|
|
@@ -35,9 +35,16 @@
|
|
|
35
35
|
<textarea id="css-editor" class="editor-textarea" style="display:none;font-family:monospace;"
|
|
36
36
|
placeholder="/* Custom CSS… */"></textarea>
|
|
37
37
|
</div>
|
|
38
|
-
<div class="editor-divider"
|
|
38
|
+
<div class="editor-divider" id="editor-divider" role="separator" aria-orientation="vertical"
|
|
39
|
+
tabindex="0" aria-label="Resize editor panes" aria-valuemin="15" aria-valuemax="85"
|
|
40
|
+
aria-valuenow="50" title="Drag to resize - double-click to reset"></div>
|
|
39
41
|
<div class="editor-pane editor-pane--preview">
|
|
40
|
-
|
|
42
|
+
<!-- An iframe, not a div: the page background comes from `body {
|
|
43
|
+
background-color: var(--dm-background) }`, which cannot apply
|
|
44
|
+
to a fragment, and the site stylesheet cannot be loaded into
|
|
45
|
+
the admin document without restyling the admin itself. -->
|
|
46
|
+
<iframe id="markdown-preview" class="editor-preview" title="Page preview"
|
|
47
|
+
sandbox="allow-same-origin allow-scripts allow-forms allow-popups"></iframe>
|
|
41
48
|
</div>
|
|
42
49
|
</div>
|
|
43
50
|
</div>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import{api as
|
|
1
|
+
import{api as L}from"../api.js";import{CardBuilder as Re}from"../lib/card-builder.js";import{TimelineBuilder as Be}from"../lib/timeline-builder.js";import{attachEditorKeybindings as Ie,createToolbar as He,insertAtCursor as $e}from"../lib/markdown-toolbar.js";import{EffectsBuilder as Ue}from"../lib/effects-builder.js";import{attachContextMenu as qe}from"../lib/shortcode-context-menu.js";import{registerCustomInserters as Oe}from"../lib/shortcode-insert.js";import{populateThemeSelect as Ve}from"../lib/themes.js";import{createFoldingManager as We}from"../lib/editor-folding.js";import{openScribeComposer as Ye}from"../lib/scribe-composer.js";import{openCrudTutorial as Ge}from"../lib/crud-tutorial.js";function _e(){const e=E.slideover({title:"Editor Reference",size:"md",position:"right"}),z="background:var(--dm-background-alt,#1a1a2e);padding:.2rem .4rem;border-radius:3px;font-size:.85em;font-family:monospace;",v="margin:1rem 0 .5rem;font-size:1rem;";function s(r){const d=document.createElement("code");return d.style.cssText=z,d.textContent=r,d}function C(r){const d=document.createElement("h3");return d.style.cssText=v,d.textContent=r,d}const Z=document.createElement("div");Z.style.cssText="padding:1rem;";const ne=document.createElement("div");ne.className="tabs";const ae=document.createElement("div");ae.className="tab-list",["Basics","Layout","Components","Data","Advanced"].forEach((r,d)=>{const n=document.createElement("button");n.className="tab-item"+(d===0?" active":""),n.textContent=r,ae.appendChild(n)});const m=document.createElement("div");m.className="tab-content";const O="display:flex;flex-direction:column;gap:1rem;",M=document.createElement("div");M.className="tab-panel active",M.style.cssText=O;const B=document.createElement("div");B.className="tab-panel",B.style.cssText=O;const N=document.createElement("div");N.className="tab-panel",N.style.cssText=O;const P=document.createElement("div");P.className="tab-panel",P.style.cssText=O;const J=document.createElement("div");J.className="tab-panel",J.style.cssText=O,m.appendChild(M),m.appendChild(B),m.appendChild(N),m.appendChild(P),m.appendChild(J),ne.appendChild(ae),ne.appendChild(m),Z.appendChild(ne);const _=document.createElement("div");_.appendChild(C("Markdown Basics"));const F=document.createElement("table");F.style.cssText="width:100%;border-collapse:collapse;font-size:.9em;";const g=document.createElement("thead"),y=document.createElement("tr");["Syntax","Result"].forEach(r=>{const d=document.createElement("th");d.style.cssText="text-align:left;padding:.4rem .5rem;border-bottom:1px solid var(--dm-border,#333);",d.textContent=r,y.appendChild(d)}),g.appendChild(y),F.appendChild(g);const U=document.createElement("tbody");[["**bold**","bold (rendered bold)"],["_italic_","italic (rendered italic)"],["## Heading","Heading (h2)"],["[text](url)","Link"],["","Image"],["- item","Bullet list"],["`code`","Inline code"],["---","Divider"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.35rem .5rem;vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.35rem .5rem;vertical-align:top;color:var(--dm-text-muted,#aaa);font-size:.85em;",o.textContent=d,n.appendChild(a),n.appendChild(o),U.appendChild(n)}),F.appendChild(U),_.appendChild(F),M.appendChild(_);const x=document.createElement("div");x.appendChild(C("Grid & Columns"));function f(r){const d=document.createElement("p");return d.style.cssText="margin:.3rem 0 .6rem;font-size:.82em;color:var(--dm-text-muted,#aaa);",d.textContent=r,d}function i(r,d,n){const a=document.createElement("p");a.style.cssText="margin:.75rem 0 .25rem;font-size:.85em;font-weight:600;",a.textContent=r;const o=document.createElement("div");o.style.cssText="position:relative;";const xe=document.createElement("pre");xe.style.cssText=z+"display:block;padding:.5rem 2rem .5rem .75rem;white-space:pre;overflow-x:auto;margin:0;",xe.textContent=d;const X=document.createElement("button");X.type="button",X.title="Copy code",X.style.cssText="position:absolute;top:.3rem;right:.3rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.15rem;line-height:1;color:inherit;",X.addEventListener("mouseenter",()=>{X.style.opacity="1"}),X.addEventListener("mouseleave",()=>{X.style.opacity=".45"});const Pe=document.createElement("span");Pe.setAttribute("data-icon","copy"),X.appendChild(Pe),X.addEventListener("click",()=>{const ke=document.createElement("textarea");ke.value=d,ke.style.cssText="position:fixed;opacity:0;",document.body.appendChild(ke),ke.select(),document.execCommand("copy"),ke.remove(),E.toast("Copied!",{type:"success",duration:1200})}),o.appendChild(xe),o.appendChild(X);const Se=document.createDocumentFragment();return Se.appendChild(a),Se.appendChild(o),n&&Se.appendChild(f(n)),Se}const w=document.createElement("table");w.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['cols="N"',"[grid] only","Number of columns (1-12)"],['gap="N"',"[grid], [row]","Gap between columns/rows (1-6)"],['span="N"',"[col] only","How many columns this cell spans"],['fullwidth="true"',"[grid] only","Break out of page container to span full viewport"],['class="x"',"all","Add extra CSS classes"]].forEach(([r,d,n])=>{const a=document.createElement("tr");[r,d,n].forEach((o,xe)=>{const X=document.createElement("td");X.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",xe===0?X.appendChild(s(r)):(X.style.color="var(--dm-text-muted,#aaa)",X.textContent=o),a.appendChild(X)}),w.appendChild(a)}),x.appendChild(w),x.appendChild(i("Equal columns",`[grid cols="3" gap="4"]
|
|
2
2
|
[col]One[/col]
|
|
3
3
|
[col]Two[/col]
|
|
4
4
|
[col]Three[/col]
|
|
5
|
-
[/grid]`,"cols sets the track count; each [col] fills one track.")),
|
|
5
|
+
[/grid]`,"cols sets the track count; each [col] fills one track.")),x.appendChild(i("Column spanning (12-col base)",`[grid cols="12" gap="3"]
|
|
6
6
|
[col span="8"]Main content[/col]
|
|
7
7
|
[col span="4"]Sidebar[/col]
|
|
8
|
-
[/grid]`,"span values must add up to cols. Common splits: 8/4, 6/6, 9/3.")),
|
|
8
|
+
[/grid]`,"span values must add up to cols. Common splits: 8/4, 6/6, 9/3.")),x.appendChild(i("Row (flexbox, equal-width)",`[row gap="4"]
|
|
9
9
|
[col]Left[/col]
|
|
10
10
|
[col]Right[/col]
|
|
11
|
-
[/row]`,"Use [row] when you want equal-width columns without specifying a count.")),
|
|
11
|
+
[/row]`,"Use [row] when you want equal-width columns without specifying a count.")),x.appendChild(i("Row with staggered reveal",`[row reveal reveal-mode="stagger" reveal-animation="slide-up" reveal-duration="400" reveal-stagger="60" reveal-delay="0" reveal-direction="ltr"]
|
|
12
12
|
[col]First[/col]
|
|
13
13
|
[col]Second[/col]
|
|
14
14
|
[col]Third[/col]
|
|
15
|
-
[/row]`,'Columns reveal one by one as the row scrolls into view. reveal-direction="rtl" reverses the order. Animations: slide-up, slide-down, slide-left, slide-right, fade, zoom, flip.')),
|
|
15
|
+
[/row]`,'Columns reveal one by one as the row scrolls into view. reveal-direction="rtl" reverses the order. Animations: slide-up, slide-down, slide-left, slide-right, fade, zoom, flip.')),x.appendChild(i("Card in a grid",`[grid cols="3" gap="4"]
|
|
16
16
|
[col]
|
|
17
17
|
[card title="One"]Content[/card]
|
|
18
18
|
[/col]
|
|
@@ -22,21 +22,21 @@ import{api as k}from"../api.js";import{CardBuilder as Me}from"../lib/card-builde
|
|
|
22
22
|
[col]
|
|
23
23
|
[card title="Three"]Content[/card]
|
|
24
24
|
[/col]
|
|
25
|
-
[/grid]`,null)),
|
|
25
|
+
[/grid]`,null)),B.appendChild(x);const q=document.createElement("div");q.appendChild(C("Cards")),q.appendChild(i("Basic card",`[card title="Optional Title"]
|
|
26
26
|
Markdown **works** here.
|
|
27
|
-
[/card]`,"Omit title for a card with no header.")),
|
|
27
|
+
[/card]`,"Omit title for a card with no header.")),q.appendChild(i("Icon - inline (default)",`[card title="Feature" icon="star"]
|
|
28
28
|
Icon sits left of the title in a flex row.
|
|
29
|
-
[/card]`,"icon accepts any Domma icon name. Default layout when icon is set.")),
|
|
29
|
+
[/card]`,"icon accepts any Domma icon name. Default layout when icon is set.")),q.appendChild(i("Icon - stacked (centred)",`[card title="Feature" icon="star" icon-layout="stacked" hover]
|
|
30
30
|
Icon is centred above the title. Great for feature tiles.
|
|
31
|
-
[/card]`,'icon-layout="stacked" centres the icon above the title. Combine with hover for a lift effect.')),
|
|
31
|
+
[/card]`,'icon-layout="stacked" centres the icon above the title. Combine with hover for a lift effect.')),q.appendChild(i("Icon with subtitle",`[card title="Feature" subtitle="Tagline here" icon="star" icon-layout="stacked"]
|
|
32
32
|
Body content.
|
|
33
|
-
[/card]`,"subtitle adds a secondary line beneath the title in both layouts.")),
|
|
33
|
+
[/card]`,"subtitle adds a secondary line beneath the title in both layouts.")),q.appendChild(i("Collapsible card",`[card title="Click to expand" collapsible="true"]
|
|
34
34
|
Hidden by default.
|
|
35
|
-
[/card]`,null)),
|
|
35
|
+
[/card]`,null)),q.appendChild(i("Full attribute reference",`[card title="Title" subtitle="Sub" icon="star" icon-layout="stacked"
|
|
36
36
|
variant="primary" hover footer="Footer text"
|
|
37
37
|
collapsible="true" class="extra" id="my-card"]
|
|
38
38
|
Body content.
|
|
39
|
-
[/card]`,'All attributes are optional. variant accepts "primary". icon-layout accepts "inline" (default) or "stacked".')),
|
|
39
|
+
[/card]`,'All attributes are optional. variant accepts "primary". icon-layout accepts "inline" (default) or "stacked".')),q.appendChild(i("Rich header / footer sub-tags",`[card]
|
|
40
40
|
[header]
|
|
41
41
|
### Custom Title with **bold** and [a link](/about)
|
|
42
42
|
[/header]
|
|
@@ -46,47 +46,47 @@ Body content here.
|
|
|
46
46
|
[footer]
|
|
47
47
|
[Read more](/about) | [icon name="arrow-right" /]
|
|
48
48
|
[/footer]
|
|
49
|
-
[/card]`,"Use [header] and [footer] sub-tags for Markdown-rendered header/footer regions. Sub-tags override the title/subtitle/icon and footer attributes when both are present.")),N.appendChild(
|
|
49
|
+
[/card]`,"Use [header] and [footer] sub-tags for Markdown-rendered header/footer regions. Sub-tags override the title/subtitle/icon and footer attributes when both are present.")),N.appendChild(q);const oe=document.createElement("div");oe.appendChild(C("Badge")),oe.appendChild(f("Inline badge/label elements. Self-closing renders an empty coloured dot."));const fe=document.createElement("table");fe.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['variant="..."',"primary (default), secondary, success, danger, warning, info, light, dark"],["pill","Flag: rounded pill shape (.badge-pill)"],["outline","Flag: outlined style (.badge-outline)"],['size="small|large"',"Reduced or enlarged badge"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),fe.appendChild(n)}),oe.appendChild(fe),oe.appendChild(i("Basic badge",'[badge variant="success"]New[/badge]',null)),oe.appendChild(i("Pill outline badge",'[badge variant="danger" outline pill]Deprecated[/badge]',null)),N.appendChild(oe);const b=document.createElement("div");b.appendChild(C("Button")),b.appendChild(f("Renders a styled anchor as a Domma button. Use the Insert \u2192 Button toolbar item for a guided dialog."));const A=document.createElement("table");A.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['href="..."',"Link destination (required)"],['label="..."',"Button text (self-closing form)"],['variant="..."',"primary (default), secondary, success, danger, warning, info, outline, ghost, link, outline-*"],['size="sm|lg"',"Button size modifier"],['icon="..."',"Domma icon name before the label"],['icon-after="..."',"Domma icon name after the label"],['target="..."','Link target, e.g. "_blank"'],['class="..."',"Extra CSS classes"],['id="..."',"Element id"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),A.appendChild(n)}),b.appendChild(A),b.appendChild(i("Primary button",'[button href="/contact" variant="primary"]Get in touch[/button]',null)),b.appendChild(i("Self-closing with icon",'[button href="/download" variant="success" icon="download" size="sm" label="Download" /]',null)),b.appendChild(i("Opens in new tab",'[button href="https://example.com" variant="outline" target="_blank"]Visit site[/button]',null)),N.appendChild(b);const j=document.createElement("div");j.appendChild(C("Link (shortcode)")),j.appendChild(f("Renders a plain anchor with optional icon, target, and class. Use Insert \u2192 Link for a guided dialog. For simple inline links, standard Markdown [text](url) is fine."));const ie=document.createElement("table");ie.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['href="..."',"Link destination (required)"],['label="..."',"Link text (self-closing form)"],['target="..."','Link target, e.g. "_blank"'],['class="..."',"CSS classes on the <a>"],['icon="..."',"Domma icon name before the text"],['icon-after="..."',"Domma icon name after the text"],['id="..."',"Element id"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),ie.appendChild(n)}),j.appendChild(ie),j.appendChild(i("External link in new tab",'[link href="https://example.com" target="_blank" icon-after="external-link"]Visit site[/link]',null)),j.appendChild(i("Self-closing with icon",'[link href="/about" icon="arrow-right" label="About us" /]',null)),N.appendChild(j);const le=document.createElement("div");le.appendChild(C("Spacer")),le.appendChild(f("Self-closing shortcode that inserts a fixed-height blank gap."));const ce=document.createElement("table");ce.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['size="N"',"Height in px (default: 8)"],['class="..."',"Extra CSS class on the spacer div"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),ce.appendChild(n)}),le.appendChild(ce),le.appendChild(i("32px gap",'[spacer size="32" /]',null)),B.appendChild(le);const de=document.createElement("div");de.appendChild(C("Icon")),de.appendChild(f("Self-closing shortcode that renders any Domma icon inline."));const pe=document.createElement("table");pe.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['name="..."',"Domma icon name (required). Also accepted as src=."],['size="N"',"Width and height in px"],['color="..."',"CSS colour applied via style"],['class="..."',"Extra CSS classes"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),pe.appendChild(n)}),de.appendChild(pe),de.appendChild(i("Coloured icon",'[icon name="star" size="24" color="#f5a623" /]',null)),N.appendChild(de);const V=document.createElement("div");V.appendChild(C("Center")),V.appendChild(f("Wraps content in a centred div. Works with any content including cards, grids, and text.")),V.appendChild(i("Example","[center]Centred content here[/center]",'Accepts an optional class="..." attribute for extra styling.')),B.appendChild(V);const Q=document.createElement("div");Q.appendChild(C("Hero")),Q.appendChild(f("Full-width hero sections - no plugin required. Uses Domma's built-in Hero CSS component."));const W=document.createElement("table");W.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['title="..."',"Heading text"],['tagline="..."',"Subtitle text"],['size="sm|lg|full"',"Height variant (default: normal)"],['variant="dark|primary|gradient-blue|gradient-purple|gradient-sunset|gradient-ocean"',"Colour / gradient preset"],['image="url"',"Background image URL (adds cover mode)"],['overlay="light|dark|darker|gradient|gradient-reverse"',"Image overlay style"],['align="center|left"',"Content alignment (default: center)"],['fullwidth="true"',"Break out of the page container to span full viewport width"],['bg="..."',"Background colour CSS value"],["twinkle","Flag: adds particle overlay (requires Effects plugin)"],['twinkle-count="N"',"Number of particles"],['twinkle-colour="..."',"Particle colour CSS value"],["blobs","Flag: adds ambient blob background"],['blobs-type="..."',"Blob animation type (default: float-blobs)"],['class="..."',"Extra CSS classes"],['id="..."',"Element id"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),W.appendChild(n)}),Q.appendChild(W),Q.appendChild(i("Basic hero",'[hero title="Welcome" tagline="Build something great"][/hero]',null)),Q.appendChild(i("Gradient with body content",`[hero title="Get Started" tagline="Everything you need." size="lg" variant="gradient-blue" align="center"]
|
|
50
50
|
Some introductory **Markdown** content here.
|
|
51
|
-
[/hero]`,null)),
|
|
51
|
+
[/hero]`,null)),Q.appendChild(i("Background image with overlay",'[hero title="Our Story" image="/media/hero.jpg" overlay="dark" size="full"][/hero]',"Combine image + overlay for text legibility over photos.")),B.appendChild(Q);const H=document.createElement("div");H.appendChild(C("Interactive Components")),H.appendChild(f("Tabs, accordion, carousel, and countdown - no plugin required.")),H.appendChild(i("Tabs",`[tabs]
|
|
52
52
|
[tab title="First"]Content **A**[/tab]
|
|
53
53
|
[tab title="Second"]Content **B**[/tab]
|
|
54
|
-
[/tabs]`,'Add style="pills" for pill-style navigation.')),
|
|
54
|
+
[/tabs]`,'Add style="pills" for pill-style navigation.')),H.appendChild(i("Accordion",`[accordion]
|
|
55
55
|
[item title="Question 1"]Answer here.[/item]
|
|
56
56
|
[item title="Question 2"]Answer here.[/item]
|
|
57
|
-
[/accordion]`,'Add multiple="true" to allow several panels open at once.')),
|
|
57
|
+
[/accordion]`,'Add multiple="true" to allow several panels open at once.')),H.appendChild(i("Accordion - collection-bound",'[collection slug="faq" display="accordion" title-field="title" body-field="description" /]',"Renders collection entries as accordion items. Use Insert \u2192 Accordion for a guided dialog.")),H.appendChild(i("Carousel",`[carousel autoplay="true" interval="5000"]
|
|
58
58
|
[slide title="Slide 1"]Description[/slide]
|
|
59
59
|
[slide image="/media/photo.jpg" title="Slide 2"]Caption[/slide]
|
|
60
|
-
[/carousel]`,'animation="slide|fade|crossfade" (default slide). Use Insert \u2192 Carousel for a guided dialog.')),
|
|
60
|
+
[/carousel]`,'animation="slide|fade|crossfade" (default slide). Use Insert \u2192 Carousel for a guided dialog.')),H.appendChild(i("Carousel - fade / crossfade",`[carousel animation="crossfade" animation-duration="800" animation-easing="ease-in-out" autoplay="true"]
|
|
61
61
|
[slide image="/media/one.jpg" title="One"][/slide]
|
|
62
62
|
[slide image="/media/two.jpg" title="Two"][/slide]
|
|
63
|
-
[/carousel]`,"fade swaps opacity per slide; crossfade overlaps the two. animation-easing accepts any CSS timing function (ease, linear, cubic-bezier(...)).")),
|
|
63
|
+
[/carousel]`,"fade swaps opacity per slide; crossfade overlaps the two. animation-easing accepts any CSS timing function (ease, linear, cubic-bezier(...)).")),H.appendChild(i("Countdown (to date)",'[countdown to="2026-12-31" format="DD:HH:mm:ss" /]',null)),H.appendChild(i("Countdown (duration)",'[countdown duration="300" format="mm:ss" /]',"duration is in seconds. format options: mm:ss \xB7 HH:mm:ss \xB7 DD:HH:mm:ss")),N.appendChild(H);const ee=document.createElement("div");ee.appendChild(C("Timeline")),ee.appendChild(f("Renders a Domma Progression component with event items."));const Y=document.createElement("table");Y.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['layout="vertical|centred|horizontal"',"[timeline] - layout orientation (default: vertical)"],['theme="minimal|corporate|modern"',"[timeline] - visual theme (default: minimal)"],['mode="timeline|roadmap"',"[timeline] - display mode (default: timeline)"],['class="..."',"[timeline] - extra CSS classes"],['id="..."',"[timeline] - element id"],['title="..."',"[event] - event heading"],['date="..."',"[event] - display date string"],['status="planned|in-progress|completed|blocked"',"[event] - progress status"],['icon="..."',"[event] - Domma icon name"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),Y.appendChild(n)}),ee.appendChild(Y),ee.appendChild(i("Vertical timeline",`[timeline layout="vertical" theme="modern"]
|
|
64
64
|
[event title="Kickoff" date="Jan 2025" status="completed" icon="flag"]
|
|
65
65
|
Project launched.
|
|
66
66
|
[/event]
|
|
67
67
|
[event title="Beta" date="Jun 2025" status="in-progress" icon="rocket"]
|
|
68
68
|
In active development.
|
|
69
69
|
[/event]
|
|
70
|
-
[/timeline]`,null)),N.appendChild(
|
|
70
|
+
[/timeline]`,null)),N.appendChild(ee);const me=document.createElement("div");me.appendChild(C("Embedding a Form"));const ve=document.createElement("table");ve.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['name="..."',"Form slug (required). Also accepted as slug=."],['class="..."',"Extra CSS classes on the wrapper div"],['id="..."',"id attribute on the wrapper div"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),ve.appendChild(n)}),me.appendChild(ve),me.appendChild(i("Basic",'[form name="contact" /]',"Forms are managed under Forms in the sidebar.")),me.appendChild(i("With wrapper styling",'[form name="newsletter" class="mt-4" id="newsletter-form" /]',null)),P.appendChild(me);const ue=document.createElement("div");ue.appendChild(C("Displaying a Collection"));const be=document.createElement("pre");be.style.cssText=z+"display:block;padding:.5rem .75rem;white-space:pre;overflow-x:auto;",be.textContent='[collection slug="enquiries" display="table" /]',ue.appendChild(be);const ye=[["slug","Required. The collection slug."],["display","table (default), cards, or list."],["fields","Comma-separated field keys to show. Defaults to all."],["limit","Maximum number of entries to display."],["sort","Field key to sort by."],["order","asc or desc (default asc)."],["title-field","Field used as the card/list title (cards + list)."],["columns","Grid columns for cards display (2-4, default 3)."],["search","true/false - enable search in table mode (default true)."],["sortable","true/false - enable column sorting in table mode (default true)."],["exportable","true/false - show CSV export button in table mode (default false)."],["page-size","Rows per page in table mode (default 25)."],["empty","Text shown when there are no entries."],["cta","Action slug: enables per-entry CTA buttons."],["cta-label",'CTA button label (default: "Run").'],["cta-icon","CTA button icon name."],["cta-style","CTA button variant (default: primary)."],["cta-confirm","CTA confirmation prompt text."],["class","Extra CSS classes on the wrapper div."],["id","id attribute on the wrapper div."]],t=document.createElement("table");t.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",ye.forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;width:35%;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),t.appendChild(n)}),ue.appendChild(t),ue.appendChild(f("Table display uses Domma Table - search, sort, pagination, column selector, and CSV export are all built in. Cards and lists are static.")),P.appendChild(ue);const l=document.createElement("div");l.appendChild(C("View - Pro")),l.appendChild(f("Renders a Collection with full filtering, pagination, and display options. Requires a Pro MongoDB collection."));const u=document.createElement("table");u.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["slug","Required. The collection slug."],["display","table (default), cards, or list."],["limit","Maximum number of entries to display."],["fields","Comma-separated field keys to show."],["title-field","Field used as the card/list title."],["columns","Grid columns for cards display (2-4, default 3)."],["empty","Text shown when there are no entries."],["class","Extra CSS classes on the wrapper div."],["id","id attribute on the wrapper div."]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;width:35%;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),u.appendChild(n)}),l.appendChild(u),l.appendChild(i("Table display",'[view slug="products" display="table" limit="50" /]',null)),l.appendChild(i("Cards display",'[view slug="team" display="cards" columns="3" title-field="name" /]',null)),P.appendChild(l);const c=document.createElement("div");c.appendChild(C("CTA - Pro")),c.appendChild(f("Renders an action button that triggers a Pro Action against an entry. Requires the Pro Actions feature."));const h=document.createElement("table");h.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["action","Required. The action slug."],["entry","Required. The entry id to act on."],["style","Button variant (default: primary)."],["icon","Domma icon name for the button."],["size","Button size (sm, lg)."],["confirm","Confirmation prompt text before running."],["label","Self-closing only: button label text."]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;width:35%;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),h.appendChild(n)}),c.appendChild(h),c.appendChild(i("Wrapping form",'[cta action="approve" entry="abc123" style="success" confirm="Approve this entry?"]Approve[/cta]',null)),c.appendChild(i("Self-closing",'[cta action="archive" entry="abc123" icon="archive" label="Archive" /]',null)),P.appendChild(c);const p=document.createElement("div");p.appendChild(C("Effects")),p.appendChild(f("Shortcodes for scroll-triggered animations, counters, typewriter text, and more. Requires the Domma Effects plugin."));const k=[['[reveal animation="fade"]...[/reveal]',"Fade/slide/zoom on scroll"],["[breathe]...[/breathe]","Continuous gentle scale loop"],["[pulse]...[/pulse]","Repeating scale pulse"],["[shake]...[/shake]","One-shot shake"],['[scribe speed="50"]...[/scribe]',"Typewriter - simple mode (text typed letter by letter)"],['[scribe loop="true"][render]Text[/render][wait]1500[/wait][undo /][/scribe]',"Typewriter - script mode (sequenced render/wait/undo actions)"],["[scramble]...[/scramble]","Character-scramble reveal"],['[counter to="100" /]',"Animated number counter (self-closing)"],["[ripple]...[/ripple]","Click-triggered ripple"],['[twinkle count="50"]...[/twinkle]',"Particle/star overlay"],['[animate type="fade-in-up"]...[/animate]',"CSS-only animation (no plugin needed)"],['[ambient type="aurora"]...[/ambient]',"CSS-only animated background"],['[firework type="burst" colour="rainbow" /]',"CSS firework (self-closing)"],["[fireworks]...[/fireworks]","Fireworks display container"],['[celebrate theme="auto" /]',"Seasonal canvas celebration (auto-detects date)"],["[christmas /]","Christmas - snowflakes, trees, snowmen, sleigh"],["[halloween /]","Halloween - pumpkins, ghosts, bats, spiders"],["[st-patricks /]","St Patrick's Day - shamrocks, coins, rainbows, leprechaun"],["[valentines /]","Valentine's Day - hearts, roses"],["[guy-fawkes /]","Guy Fawkes - fireworks, sparkles"],["[st-andrews /]","St Andrew's Day - heather, thistles"],["[st-davids /]","St David's Day - daffodils, dragons"],["[st-georges /]","St George's Day - roses, flags"]],te=document.createElement("table");te.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",k.forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),te.appendChild(n)}),p.appendChild(te),p.appendChild(i("Scribe script - looping multi-phrase typewriter",`[scribe loop="true" loop-delay="2000" delete-speed="20"]
|
|
71
71
|
[render]We build things that matter.[/render]
|
|
72
72
|
[wait]1200[/wait]
|
|
73
73
|
[undo all="true" /]
|
|
74
74
|
[render]We design for humans.[/render]
|
|
75
75
|
[wait]1200[/wait]
|
|
76
76
|
[undo all="true" /]
|
|
77
|
-
[/scribe]`,'Use [render]...[/render] to type text, [wait]Ms[/wait] to pause, and [undo /] to delete. loop="true" replays the sequence. Only [render], [wait], and [undo] shortcodes are parsed - plain text between actions is ignored.')),
|
|
77
|
+
[/scribe]`,'Use [render]...[/render] to type text, [wait]Ms[/wait] to pause, and [undo /] to delete. loop="true" replays the sequence. Only [render], [wait], and [undo] shortcodes are parsed - plain text between actions is ignored.')),p.appendChild(i("Christmas",'[christmas intensity="medium" snowmen="off" trees="off" wreaths="off" northStars="off" sleigh="off" train="off" elf="off" robin="off" firework="off" /]',"intensity: light | medium | heavy. Count-based (off disables entirely): snowmen, trees, wreaths, northStars. Probability-based specials (off prevents spawning): sleigh, train, elf, robin, firework. Snowflakes always fall.")),p.appendChild(i("Halloween",'[halloween intensity="medium" gravestones="off" jackOLanterns="off" spiders="off" scarecrows="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): gravestones, jackOLanterns, spiders, scarecrows, twinklingStars. Particles: bats, ghosts, pumpkins (always on). Fixed decorations: haunted-house, cauldron (always present).")),p.appendChild(i("St Patrick's Day",'[st-patricks intensity="medium" pots="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): pots (pots of gold), twinklingStars. Particles: shamrocks, clover petals, gold coins, sparkles (always on). Fixed decorations: rainbow, harp, moon. Leprechaun appears randomly - more likely at higher intensity.")),p.appendChild(i("Valentine's Day",'[valentines intensity="medium" garlands="off" butterflies="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): garlands (heart garlands), butterflies. Particles: hearts, rose petals, sparkles, lips (always on). Fixed decorations: envelopes (always present). Cupid appears randomly - more likely at higher intensity.")),p.appendChild(i("Guy Fawkes Night",'[guy-fawkes intensity="medium" bonfires="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): bonfires. Particles: embers, fireworks, sparks, rockets, bursts, trails (always on). Fixed decorations: guy-effigy, catherine-wheel, roman-candle, sparkler-bundle, moon. Starts at 25% particle density and builds up gradually.")),p.appendChild(i("St Andrew's Day",'[st-andrews intensity="medium" thistles="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): thistles, twinklingStars. Particles: heather petals, saltire sparkles (always on). Fixed decorations: bagpiper, saltire-flag, tartan-pattern, highland-scene (always present). Bagpiper probability increases with intensity.")),p.appendChild(i("St David's Day",'[st-davids intensity="medium" daffodilFields="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): daffodilFields, twinklingStars. Particles: daffodil petals, spring sparkles (always on). Fixed decorations: welsh-dragon, harp, leek-bundle, flag (always present). Flying dragon appears randomly - more likely at higher intensity.")),p.appendChild(i("St George's Day",'[st-georges intensity="medium" roses="off" twinklingStars="off" /]',"intensity: light | medium | heavy. Decoration toggles (off disables): roses (English roses), twinklingStars. Particles: rose petals, Tudor roses, oak leaves, sparkles (always on). Fixed decorations: st-georges-cross, dragon, shield, castle (always present). Knight appears randomly - more likely at higher intensity.")),p.appendChild(f("Enable the Domma Effects plugin to activate these shortcodes on your site.")),J.appendChild(p);const se=document.createElement("div");se.appendChild(C("Tables")),se.appendChild(f("Wrap a standard Markdown (GFM) table with Domma CSS classes and responsive horizontal scrolling."));const he=document.createElement("table");he.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['striped="true"',"Alternate row background (.table-striped)"],['bordered="true"',"Borders on all cells (.table-bordered)"],['compact="true"',"Reduced cell padding (.table-compact)"],['caption="..."',"Caption text above the table"],['class="..."',"Extra CSS classes appended to .table"],['id="..."',"id attribute on the <table> element"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),he.appendChild(n)}),se.appendChild(he),se.appendChild(i("Striped + bordered table",`[table striped="true" bordered="true" caption="Product Pricing"]
|
|
78
78
|
| Product | Price |
|
|
79
79
|
| ------- | ----: |
|
|
80
80
|
| Widget | $9.99 |
|
|
81
81
|
| Gadget | $14.99 |
|
|
82
|
-
[/table]`,"The inner content must be a valid GFM Markdown table. The shortcode adds Domma CSS classes and wraps in a responsive scroll container.")),N.appendChild(
|
|
82
|
+
[/table]`,"The inner content must be a valid GFM Markdown table. The shortcode adds Domma CSS classes and wraps in a responsive scroll container.")),N.appendChild(se);const T=document.createElement("div");T.appendChild(C("Slideover")),T.appendChild(f("A trigger button that opens a slide-in panel with Markdown content. No plugin required."));const re=document.createElement("table");re.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['title="..."',"Panel header text"],['trigger="..."','Button label (default: "Open")'],['size="sm|md|lg"',"Panel width (default: md)"],['position="right|left"',"Slide direction (default: right)"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),re.appendChild(n)}),T.appendChild(re),T.appendChild(i("Example",`[slideover title="More Info" trigger="Read more" size="md"]
|
|
83
83
|
## Details
|
|
84
84
|
Markdown content here.
|
|
85
|
-
[/slideover]`,"Nested [card] and [grid] shortcodes work inside the slideover body.")),N.appendChild(
|
|
85
|
+
[/slideover]`,"Nested [card] and [grid] shortcodes work inside the slideover body.")),N.appendChild(T);const K=document.createElement("div");K.appendChild(C("DConfig - Declarative Behaviour")),K.appendChild(f("Define click handlers and class toggles without writing JavaScript. Use the DConfig section above or embed inline with [dconfig]...[/dconfig] in the content body. Inline shortcodes win on selector conflict.")),K.appendChild(i("Toggle a class on click",'{ "#my-btn": { "events": { "click": { "target": "#panel", "toggleClass": "hidden" } } } }','Selector keys use standard CSS selectors. "target" is optional - defaults to the element itself.')),K.appendChild(i("Inline shortcode syntax",`[dconfig]
|
|
86
86
|
{ "#my-btn": { "events": { "click": { "target": "#panel", "toggleClass": "hidden" } } } }
|
|
87
|
-
[/dconfig]`,null)),_.appendChild(ue);const be=document.createElement("div");be.appendChild(g("CSS Editor")),be.appendChild(m("The toolbar's </> button (left of the Split View icon) swaps the left pane between Markdown and Custom CSS. Edits are saved together with the page - one Save, one toast."));const Te=document.createElement("table");Te.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["</> button","Toggle between Markdown editor and Custom CSS editor"],["Split / Write / Preview","Standard view mode buttons to the right of </>"],["Save","Saves both page content and CSS in a single operation"]].forEach(([d,l])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(r(d));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=l,n.appendChild(a),n.appendChild(o),Te.appendChild(n)}),be.appendChild(Te),_.appendChild(be);const Se=document.createElement("div");Se.appendChild(g("Colour Picker")),Se.appendChild(m("Insert \u2192 Colour Picker opens a centred colour picker. Pick a colour, then use Copy to copy the hex code to the clipboard or Insert to drop it at the cursor. Click outside the panel to dismiss.")),_.appendChild(Se);const De=document.createElement("div");De.appendChild(g("Keyboard Shortcuts"));const Le=document.createElement("table");Le.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["Ctrl + B","Bold selected text"],["Ctrl + I","Italic selected text"],["Ctrl + K","Insert link dialog"],["Tab","Indent 2 spaces at cursor"],["Shift + Tab","Dedent 2 spaces on current line"],["Ctrl + X","Cut current line (no selection) or cut selection"],["Ctrl + C","Copy current line (no selection) or copy selection"],["Ctrl + V","Paste from clipboard"],["Ctrl + Z","Undo"],["Ctrl + Y","Redo"]].forEach(([d,l])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;white-space:nowrap;",a.appendChild(r(d));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=l,n.appendChild(a),n.appendChild(o),Le.appendChild(n)}),De.appendChild(Le),H.appendChild(De);const Ee=document.createElement("div");Ee.appendChild(g("Tips"));const Ae=document.createElement("table");Ae.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['class="text-center"',"Centre text and inline elements on any shortcode"],['class="mx-auto"',"Centre a block element horizontally"],["[center]...[/center]","Shorthand wrapper for centred content"]].forEach(([d,l])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(r(d));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=l,n.appendChild(a),n.appendChild(o),Ae.appendChild(n)}),Ee.appendChild(Ae),Ee.appendChild(m("Most shortcodes accept a class attribute for custom styling.")),H.appendChild(Ee),e.setContent(X),e.open(),E.tabs(Q),I.scan(X)}function je(e,P){const f=e.find("#history-tab").get(0),r=e.find("#version-list").get(0),g=e.find("#version-compare").get(0),X=e.find("#version-compare-old").get(0),Q=e.find("#version-compare-new").get(0),ee=e.find("#version-compare-label").get(0),c=e.find("#version-compare-back-btn").get(0),V=e.find("#version-restore-btn").get(0),H=e.find("#history-save-named-btn").get(0),q=e.find("#history-delete-selected-btn").get(0);let N=!1,F=null;function _(){r.style.display="",g.style.display="none",F=null}function G(){r.style.display="none",g.style.display=""}async function B(){r.textContent="";const s=document.createElement("p");s.style.color="var(--dm-text-muted)",s.textContent="Loading\u2026",r.appendChild(s);let v;try{v=(await k.versions.list(P)).versions||[]}catch(h){r.textContent="";const x=document.createElement("p");x.style.color="var(--dm-danger,#e55)",x.textContent="Failed to load versions: "+h.message,r.appendChild(x);return}if(r.textContent="",q.style.display="none",!v.length){const h=document.createElement("p");h.style.color="var(--dm-text-muted)",h.textContent="No versions saved yet. Versions are created automatically on each save.",r.appendChild(h);return}const M=document.createElement("table");M.style.cssText="width:100%;border-collapse:collapse;font-size:.875rem;";const w=document.createElement("thead"),m=document.createElement("tr"),i=document.createElement("th");i.style.cssText="padding:.5rem .75rem;width:2rem;border-bottom:1px solid var(--dm-border);";const C=document.createElement("input");C.type="checkbox",C.setAttribute("aria-label","Select all versions"),i.appendChild(C),m.appendChild(i),["Date","Author","Type","Label","Actions"].forEach(h=>{const x=document.createElement("th");x.style.cssText="text-align:left;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border);font-size:.8rem;color:var(--dm-text-muted);",x.textContent=h,m.appendChild(x)}),w.appendChild(m),M.appendChild(w);const U=[];function ne(){const h=U.some(W=>W.checked),x=U.length>0&&U.every(W=>W.checked);q.style.display=h?"":"none",C.checked=x,C.indeterminate=h&&!x}C.addEventListener("change",()=>{U.forEach(h=>{h.checked=C.checked}),ne()});const re=document.createElement("tbody");v.forEach(h=>{const x=document.createElement("tr");x.style.borderBottom="1px solid var(--dm-border)";const W=document.createElement("td");W.style.padding=".5rem .75rem";const ae=document.createElement("input");ae.type="checkbox",ae.value=h.filename,ae.addEventListener("change",ne),W.appendChild(ae),U.push(ae);const oe=document.createElement("td");oe.style.padding=".5rem .75rem",oe.textContent=D(h.createdAt).format("D MMM YYYY, HH:mm");const Y=document.createElement("td");Y.style.padding=".5rem .75rem",Y.textContent=h.author||"-";const ie=document.createElement("td");ie.style.padding=".5rem .75rem";const j=document.createElement("span");j.className="badge badge-"+(h.type==="manual"?"primary":"secondary"),j.style.cssText="font-size:.75rem;padding:.2rem .5rem;border-radius:4px;",j.textContent=h.type,ie.appendChild(j);const le=document.createElement("td");le.style.cssText="padding:.5rem .75rem;color:var(--dm-text-muted);",le.textContent=h.label||"-";const J=document.createElement("td");J.style.padding=".5rem .75rem";const T=document.createElement("button");T.className="btn btn-ghost btn-xs",T.style.marginRight=".4rem",T.title="Compare",T.innerHTML='<span data-icon="columns"></span>',T.addEventListener("click",async()=>{try{const te=await k.versions.get(P,h.filename);X.textContent=te.content,Q.textContent=e.find("#markdown-editor").get(0).value,ee.textContent=D(h.createdAt).format("D MMM YYYY, HH:mm")+(h.label?` - ${h.label}`:""),F=h.filename,G()}catch(te){E.toast("Failed to load version: "+te.message,{type:"error"})}});const z=document.createElement("button");z.className="btn btn-ghost btn-xs",z.style.color="var(--dm-danger,#e55)",z.title="Delete",z.innerHTML='<span data-icon="trash"></span>',z.addEventListener("click",async()=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await k.versions.delete(P,h.filename),E.toast("Version deleted.",{type:"success"}),await B()}catch(te){E.toast("Failed to delete: "+te.message,{type:"error"})}}),J.appendChild(T),J.appendChild(z),x.appendChild(W),x.appendChild(oe),x.appendChild(Y),x.appendChild(ie),x.appendChild(le),x.appendChild(J),re.appendChild(x)}),M.appendChild(re),r.appendChild(M),I.scan(r)}f.addEventListener("click",async()=>{N||(N=!0,await B())}),c.addEventListener("click",()=>{_()}),V.addEventListener("click",async()=>{if(!(!F||!await E.confirm("Restore this version? The current page content will be overwritten (a pre-restore snapshot will be saved automatically).")))try{await k.versions.restore(P,F),E.toast("Page restored. Reloading editor\u2026",{type:"success"}),R.navigate("/pages"),setTimeout(()=>R.navigate(`/pages/edit${P}`),300)}catch(s){E.toast("Restore failed: "+s.message,{type:"error"})}}),q.addEventListener("click",async()=>{const s=[...r.querySelectorAll("tbody input[type=checkbox]:checked")].map(v=>v.value);if(!(!s.length||!await E.confirm(`Delete ${s.length} version${s.length>1?"s":""}? This cannot be undone.`)))try{await k.versions.bulkDelete(P,s),E.toast(`${s.length} version${s.length>1?"s":""} deleted.`,{type:"success"}),await B()}catch(v){E.toast("Delete failed: "+v.message,{type:"error"})}}),H.addEventListener("click",()=>{const s=E.slideover({title:"Save Named Version",size:"sm",position:"right"}),v=document.createElement("div");v.style.padding="1rem";const M=document.createElement("label");M.className="form-label",M.textContent="Version Label";const w=document.createElement("input");w.type="text",w.className="form-input",w.placeholder="e.g. Initial design, Before restructure",w.style.marginBottom=".75rem";const m=document.createElement("button");m.className="btn btn-primary",m.textContent="Save Version",m.addEventListener("click",async()=>{const i=w.value.trim();try{await k.versions.create(P,i||null),E.toast("Named version saved.",{type:"success"}),s.close(),N=!1,f.classList.contains("active")&&(N=!0,await B())}catch(C){E.toast("Failed to save version: "+C.message,{type:"error"})}}),v.appendChild(M),v.appendChild(w),v.appendChild(m),s.element.appendChild(v),s.open(),setTimeout(()=>w.focus(),100)})}function Je(e){try{return D(e).format("D MMM YYYY, HH:mm")}catch{return new Date(e).toLocaleString()}}async function Ke(e){const P=E.slideover({title:"Share preview link",size:"md",position:"right"}),f=document.createElement("div");f.style.padding="1rem";const r=document.createElement("p");r.className="form-hint",r.style.marginTop="0",r.textContent="Anyone with the link can view this page even while it is unpublished, without signing in. The link works for this page only, expires on its own, and can be revoked at any time.",f.appendChild(r);const g=document.createElement("label");g.className="form-label",g.textContent="Expires after";const X=document.createElement("select");X.className="form-select",[["1h","1 hour"],["24h","24 hours"],["7d","7 days"],["30d","30 days"]].forEach(([G,B])=>{const s=document.createElement("option");s.value=G,s.textContent=B,G==="7d"&&(s.selected=!0),X.appendChild(s)});const Q=document.createElement("label");Q.className="form-label",Q.style.marginTop=".75rem",Q.textContent="Note (optional)";const ee=document.createElement("input");ee.type="text",ee.className="form-input",ee.placeholder="e.g. For the client sign-off";const c=document.createElement("button");c.className="btn btn-primary",c.style.marginTop=".75rem",c.textContent="Create link";const V=document.createElement("div");V.style.marginTop=".75rem",V.style.display="none";const H=document.createElement("input");H.type="text",H.className="form-input",H.readOnly=!0,H.style.marginBottom=".4rem";const q=document.createElement("button");q.className="btn btn-secondary btn-sm",q.textContent="Copy link",q.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(H.value),E.toast("Link copied to clipboard.",{type:"success"})}catch{H.select(),E.toast("Press Ctrl+C to copy the selected link.",{type:"info"})}}),V.appendChild(H),V.appendChild(q),f.appendChild(g),f.appendChild(X),f.appendChild(Q),f.appendChild(ee),f.appendChild(c),f.appendChild(V);const N=document.createElement("h4");N.style.cssText="margin:1.5rem 0 .5rem;font-size:.9rem;",N.textContent="Active links",f.appendChild(N);const F=document.createElement("div");f.appendChild(F);const _=async()=>{F.textContent="";let G=[];try{G=await k.pages.previewLinks.list(e)}catch(s){const v=document.createElement("p");v.className="form-hint",v.textContent="Could not load existing links: "+(s.message||"unknown error"),F.appendChild(v);return}const B=G.filter(s=>!s.revokedAt&&!s.expired);if(!B.length){const s=document.createElement("p");s.className="form-hint",s.textContent="No active links for this page.",F.appendChild(s);return}B.forEach(s=>{const v=document.createElement("div");v.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.5rem 0;border-bottom:1px solid var(--dm-border-light);";const M=document.createElement("div");M.style.cssText="flex:1 1 auto;min-width:0;font-size:.82rem;";const w=document.createElement("div");w.style.fontWeight="600",w.textContent=s.label||"Untitled link";const m=document.createElement("div");m.style.opacity=".7";const i=s.useCount===1?"1 view":`${s.useCount||0} views`;m.textContent=`Expires ${Je(s.expiresAt)} - ${i}`,M.appendChild(w),M.appendChild(m);const C=document.createElement("button");C.className="btn btn-ghost btn-sm",C.textContent="Revoke",C.addEventListener("click",async()=>{if(await E.confirm("Revoke this link? Anyone holding it loses access immediately."))try{await k.pages.previewLinks.revoke(s.id),E.toast("Link revoked.",{type:"success"}),await _()}catch(ne){E.toast("Could not revoke: "+(ne.message||"unknown error"),{type:"error"})}}),v.appendChild(M),v.appendChild(C),F.appendChild(v)})};c.addEventListener("click",async()=>{c.disabled=!0,c.textContent="Creating\u2026";try{const G=await k.pages.previewLinks.create(e,X.value,ee.value.trim());H.value=G.url,V.style.display="",ee.value="",E.toast("Share link created.",{type:"success"}),await _(),H.select()}catch(G){E.toast("Could not create link: "+(G.message||"unknown error"),{type:"error"})}finally{c.disabled=!1,c.textContent="Create link"}}),P.element.appendChild(f),P.open(),await _()}let pe=!1,ke=null,ze=!1;function Ze(e){return e.split(`
|
|
88
|
-
`).map(
|
|
87
|
+
[/dconfig]`,null)),J.appendChild(K);const G=document.createElement("div");G.appendChild(C("CSS Editor")),G.appendChild(f("The toolbar's </> button (left of the Split View icon) swaps the left pane between Markdown and Custom CSS. Edits are saved together with the page - one Save, one toast."));const we=document.createElement("table");we.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["</> button","Toggle between Markdown editor and Custom CSS editor"],["Split / Write / Preview","Standard view mode buttons to the right of </>"],["Save","Saves both page content and CSS in a single operation"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),we.appendChild(n)}),G.appendChild(we),J.appendChild(G);const Ce=document.createElement("div");Ce.appendChild(C("Colour Picker")),Ce.appendChild(f("Insert \u2192 Colour Picker opens a centred colour picker. Pick a colour, then use Copy to copy the hex code to the clipboard or Insert to drop it at the cursor. Click outside the panel to dismiss.")),J.appendChild(Ce);const Ee=document.createElement("div");Ee.appendChild(C("Keyboard Shortcuts"));const De=document.createElement("table");De.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[["Ctrl + B","Bold selected text"],["Ctrl + I","Italic selected text"],["Ctrl + K","Insert link dialog"],["Tab","Indent 2 spaces at cursor"],["Shift + Tab","Dedent 2 spaces on current line"],["Ctrl + X","Cut current line (no selection) or cut selection"],["Ctrl + C","Copy current line (no selection) or copy selection"],["Ctrl + V","Paste from clipboard"],["Ctrl + Z","Undo"],["Ctrl + Y","Redo"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;white-space:nowrap;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),De.appendChild(n)}),Ee.appendChild(De),M.appendChild(Ee);const Te=document.createElement("div");Te.appendChild(C("Tips"));const Ae=document.createElement("table");Ae.style.cssText="width:100%;border-collapse:collapse;font-size:.85em;margin-bottom:.5rem;",[['class="text-center"',"Centre text and inline elements on any shortcode"],['class="mx-auto"',"Centre a block element horizontally"],["[center]...[/center]","Shorthand wrapper for centred content"]].forEach(([r,d])=>{const n=document.createElement("tr"),a=document.createElement("td");a.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;",a.appendChild(s(r));const o=document.createElement("td");o.style.cssText="padding:.3rem .4rem;border-bottom:1px solid var(--dm-border,#333);vertical-align:top;color:var(--dm-text-muted,#aaa);",o.textContent=d,n.appendChild(a),n.appendChild(o),Ae.appendChild(n)}),Te.appendChild(Ae),Te.appendChild(f("Most shortcodes accept a class attribute for custom styling.")),M.appendChild(Te),e.setContent(Z),e.open(),E.tabs(ne),I.scan(Z)}function je(e,z){const v=e.find("#history-tab").get(0),s=e.find("#version-list").get(0),C=e.find("#version-compare").get(0),Z=e.find("#version-compare-old").get(0),ne=e.find("#version-compare-new").get(0),ae=e.find("#version-compare-label").get(0),m=e.find("#version-compare-back-btn").get(0),O=e.find("#version-restore-btn").get(0),M=e.find("#history-save-named-btn").get(0),B=e.find("#history-delete-selected-btn").get(0);let N=!1,P=null;function J(){s.style.display="",C.style.display="none",P=null}function _(){s.style.display="none",C.style.display=""}async function F(){s.textContent="";const g=document.createElement("p");g.style.color="var(--dm-text-muted)",g.textContent="Loading\u2026",s.appendChild(g);let y;try{y=(await L.versions.list(z)).versions||[]}catch(b){s.textContent="";const A=document.createElement("p");A.style.color="var(--dm-danger,#e55)",A.textContent="Failed to load versions: "+b.message,s.appendChild(A);return}if(s.textContent="",B.style.display="none",!y.length){const b=document.createElement("p");b.style.color="var(--dm-text-muted)",b.textContent="No versions saved yet. Versions are created automatically on each save.",s.appendChild(b);return}const U=document.createElement("table");U.style.cssText="width:100%;border-collapse:collapse;font-size:.875rem;";const x=document.createElement("thead"),f=document.createElement("tr"),i=document.createElement("th");i.style.cssText="padding:.5rem .75rem;width:2rem;border-bottom:1px solid var(--dm-border);";const w=document.createElement("input");w.type="checkbox",w.setAttribute("aria-label","Select all versions"),i.appendChild(w),f.appendChild(i),["Date","Author","Type","Label","Actions"].forEach(b=>{const A=document.createElement("th");A.style.cssText="text-align:left;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border);font-size:.8rem;color:var(--dm-text-muted);",A.textContent=b,f.appendChild(A)}),x.appendChild(f),U.appendChild(x);const q=[];function oe(){const b=q.some(j=>j.checked),A=q.length>0&&q.every(j=>j.checked);B.style.display=b?"":"none",w.checked=A,w.indeterminate=b&&!A}w.addEventListener("change",()=>{q.forEach(b=>{b.checked=w.checked}),oe()});const fe=document.createElement("tbody");y.forEach(b=>{const A=document.createElement("tr");A.style.borderBottom="1px solid var(--dm-border)";const j=document.createElement("td");j.style.padding=".5rem .75rem";const ie=document.createElement("input");ie.type="checkbox",ie.value=b.filename,ie.addEventListener("change",oe),j.appendChild(ie),q.push(ie);const le=document.createElement("td");le.style.padding=".5rem .75rem",le.textContent=D(b.createdAt).format("D MMM YYYY, HH:mm");const ce=document.createElement("td");ce.style.padding=".5rem .75rem",ce.textContent=b.author||"-";const de=document.createElement("td");de.style.padding=".5rem .75rem";const pe=document.createElement("span");pe.className="badge badge-"+(b.type==="manual"?"primary":"secondary"),pe.style.cssText="font-size:.75rem;padding:.2rem .5rem;border-radius:4px;",pe.textContent=b.type,de.appendChild(pe);const V=document.createElement("td");V.style.cssText="padding:.5rem .75rem;color:var(--dm-text-muted);",V.textContent=b.label||"-";const Q=document.createElement("td");Q.style.padding=".5rem .75rem";const W=document.createElement("button");W.className="btn btn-ghost btn-xs",W.style.marginRight=".4rem",W.title="Compare",W.innerHTML='<span data-icon="columns"></span>',W.addEventListener("click",async()=>{try{const ee=await L.versions.get(z,b.filename);Z.textContent=ee.content,ne.textContent=e.find("#markdown-editor").get(0).value,ae.textContent=D(b.createdAt).format("D MMM YYYY, HH:mm")+(b.label?` - ${b.label}`:""),P=b.filename,_()}catch(ee){E.toast("Failed to load version: "+ee.message,{type:"error"})}});const H=document.createElement("button");H.className="btn btn-ghost btn-xs",H.style.color="var(--dm-danger,#e55)",H.title="Delete",H.innerHTML='<span data-icon="trash"></span>',H.addEventListener("click",async()=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await L.versions.delete(z,b.filename),E.toast("Version deleted.",{type:"success"}),await F()}catch(ee){E.toast("Failed to delete: "+ee.message,{type:"error"})}}),Q.appendChild(W),Q.appendChild(H),A.appendChild(j),A.appendChild(le),A.appendChild(ce),A.appendChild(de),A.appendChild(V),A.appendChild(Q),fe.appendChild(A)}),U.appendChild(fe),s.appendChild(U),I.scan(s)}v.addEventListener("click",async()=>{N||(N=!0,await F())}),m.addEventListener("click",()=>{J()}),O.addEventListener("click",async()=>{if(!(!P||!await E.confirm("Restore this version? The current page content will be overwritten (a pre-restore snapshot will be saved automatically).")))try{await L.versions.restore(z,P),E.toast("Page restored. Reloading editor\u2026",{type:"success"}),R.navigate("/pages"),setTimeout(()=>R.navigate(`/pages/edit${z}`),300)}catch(g){E.toast("Restore failed: "+g.message,{type:"error"})}}),B.addEventListener("click",async()=>{const g=[...s.querySelectorAll("tbody input[type=checkbox]:checked")].map(y=>y.value);if(!(!g.length||!await E.confirm(`Delete ${g.length} version${g.length>1?"s":""}? This cannot be undone.`)))try{await L.versions.bulkDelete(z,g),E.toast(`${g.length} version${g.length>1?"s":""} deleted.`,{type:"success"}),await F()}catch(y){E.toast("Delete failed: "+y.message,{type:"error"})}}),M.addEventListener("click",()=>{const g=E.slideover({title:"Save Named Version",size:"sm",position:"right"}),y=document.createElement("div");y.style.padding="1rem";const U=document.createElement("label");U.className="form-label",U.textContent="Version Label";const x=document.createElement("input");x.type="text",x.className="form-input",x.placeholder="e.g. Initial design, Before restructure",x.style.marginBottom=".75rem";const f=document.createElement("button");f.className="btn btn-primary",f.textContent="Save Version",f.addEventListener("click",async()=>{const i=x.value.trim();try{await L.versions.create(z,i||null),E.toast("Named version saved.",{type:"success"}),g.close(),N=!1,v.classList.contains("active")&&(N=!0,await F())}catch(w){E.toast("Failed to save version: "+w.message,{type:"error"})}}),y.appendChild(U),y.appendChild(x),y.appendChild(f),g.element.appendChild(y),g.open(),setTimeout(()=>x.focus(),100)})}function Je(e){try{return D(e).format("D MMM YYYY, HH:mm")}catch{return new Date(e).toLocaleString()}}async function Ke(e){const z=E.slideover({title:"Share preview link",size:"md",position:"right"}),v=document.createElement("div");v.style.padding="1rem";const s=document.createElement("p");s.className="form-hint",s.style.marginTop="0",s.textContent="Anyone with the link can view this page even while it is unpublished, without signing in. The link works for this page only, expires on its own, and can be revoked at any time.",v.appendChild(s);const C=document.createElement("label");C.className="form-label",C.textContent="Expires after";const Z=document.createElement("select");Z.className="form-select",[["1h","1 hour"],["24h","24 hours"],["7d","7 days"],["30d","30 days"]].forEach(([_,F])=>{const g=document.createElement("option");g.value=_,g.textContent=F,_==="7d"&&(g.selected=!0),Z.appendChild(g)});const ne=document.createElement("label");ne.className="form-label",ne.style.marginTop=".75rem",ne.textContent="Note (optional)";const ae=document.createElement("input");ae.type="text",ae.className="form-input",ae.placeholder="e.g. For the client sign-off";const m=document.createElement("button");m.className="btn btn-primary",m.style.marginTop=".75rem",m.textContent="Create link";const O=document.createElement("div");O.style.marginTop=".75rem",O.style.display="none";const M=document.createElement("input");M.type="text",M.className="form-input",M.readOnly=!0,M.style.marginBottom=".4rem";const B=document.createElement("button");B.className="btn btn-secondary btn-sm",B.textContent="Copy link",B.addEventListener("click",async()=>{try{await navigator.clipboard.writeText(M.value),E.toast("Link copied to clipboard.",{type:"success"})}catch{M.select(),E.toast("Press Ctrl+C to copy the selected link.",{type:"info"})}}),O.appendChild(M),O.appendChild(B),v.appendChild(C),v.appendChild(Z),v.appendChild(ne),v.appendChild(ae),v.appendChild(m),v.appendChild(O);const N=document.createElement("h4");N.style.cssText="margin:1.5rem 0 .5rem;font-size:.9rem;",N.textContent="Active links",v.appendChild(N);const P=document.createElement("div");v.appendChild(P);const J=async()=>{P.textContent="";let _=[];try{_=await L.pages.previewLinks.list(e)}catch(g){const y=document.createElement("p");y.className="form-hint",y.textContent="Could not load existing links: "+(g.message||"unknown error"),P.appendChild(y);return}const F=_.filter(g=>!g.revokedAt&&!g.expired);if(!F.length){const g=document.createElement("p");g.className="form-hint",g.textContent="No active links for this page.",P.appendChild(g);return}F.forEach(g=>{const y=document.createElement("div");y.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.5rem 0;border-bottom:1px solid var(--dm-border-light);";const U=document.createElement("div");U.style.cssText="flex:1 1 auto;min-width:0;font-size:.82rem;";const x=document.createElement("div");x.style.fontWeight="600",x.textContent=g.label||"Untitled link";const f=document.createElement("div");f.style.opacity=".7";const i=g.useCount===1?"1 view":`${g.useCount||0} views`;f.textContent=`Expires ${Je(g.expiresAt)} - ${i}`,U.appendChild(x),U.appendChild(f);const w=document.createElement("button");w.className="btn btn-ghost btn-sm",w.textContent="Revoke",w.addEventListener("click",async()=>{if(await E.confirm("Revoke this link? Anyone holding it loses access immediately."))try{await L.pages.previewLinks.revoke(g.id),E.toast("Link revoked.",{type:"success"}),await J()}catch(oe){E.toast("Could not revoke: "+(oe.message||"unknown error"),{type:"error"})}}),y.appendChild(U),y.appendChild(w),P.appendChild(y)})};m.addEventListener("click",async()=>{m.disabled=!0,m.textContent="Creating\u2026";try{const _=await L.pages.previewLinks.create(e,Z.value,ae.value.trim());M.value=_.url,O.style.display="",ae.value="",E.toast("Share link created.",{type:"success"}),await J(),M.select()}catch(_){E.toast("Could not create link: "+(_.message||"unknown error"),{type:"error"})}finally{m.disabled=!1,m.textContent="Create link"}}),z.element.appendChild(v),z.open(),await J()}let ge=!1,Le=null,Fe=!1;function Xe(e){return e.split(`
|
|
88
|
+
`).map(z=>z.trimEnd()).join(`
|
|
89
89
|
`).replace(/\n{3,}/g,`
|
|
90
90
|
|
|
91
|
-
`)}const
|
|
92
|
-
`);for(;i.firstChild;)i.removeChild(i.firstChild);p.forEach((b,y)=>{const u=document.createElement("span");u.className="editor-line-number-row";const A=document.createElement("span");A.className="fold-toggle fold-toggle--empty";const L=document.createElement("span");L.className="editor-line-num",L.textContent=String(y+1),u.appendChild(A),u.appendChild(L),i.appendChild(u)}),i.scrollTop=t.scrollTop}{const t=e.find("#css-editor").get(0);t&&t.addEventListener("scroll",()=>{i.scrollTop=t.scrollTop})}const ne=()=>{C.refresh(),i.scrollTop=m.scrollTop};m.addEventListener("input",ne),m.addEventListener("scroll",()=>{i.scrollTop=m.scrollTop});let re=null;const h=()=>{clearTimeout(re),re=setTimeout(async()=>{const t=C.getUnfoldedContent();try{const{html:p}=await k.pages.preview(t);s.html(p,{safe:!1}),I.scan(s.get(0)),s.get(0).querySelectorAll(".tabs").forEach(b=>Domma.elements.tabs(b))}catch{window.marked&&s.html(marked.parse(t))}},400)},x=He(B,e.find("#editor-toolbar"),{spacerDefault:H});Ue(B.get(0));let W=!1,ae="split",oe=null;const Y=document.createElement("button");Y.className="editor-view-btn",Y.type="button";const ie=document.createElement("span");ie.setAttribute("data-icon","css-code"),Y.appendChild(ie);const j=document.createElement("button");j.className="editor-view-btn",j.type="button";const le=document.createElement("span");le.setAttribute("data-icon","code"),j.appendChild(le);let J=!1;const T=document.createElement("button");T.className="editor-view-btn",T.type="button",T.innerHTML='<span data-icon="chevrons-down" data-icon-size="10" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',T.style.cssText="font-size:9px;letter-spacing:-1px;";const z=e.find(".editor-toolbar-right").get(0);z.prepend(T),z.prepend(j),z.prepend(Y),I.scan(Y),I.scan(j),I.scan(T),E.tooltip(Y,{content:"Edit Custom CSS",position:"top"}),E.tooltip(j,{content:"Format Markdown",position:"top"}),E.tooltip(T,{content:"Fold / unfold all shortcodes",position:"top"}),j.addEventListener("click",()=>{const t=B.get(0),p=t.selectionStart,b=Ze(C.getUnfoldedContent());C.unfoldAll(),w=!0,t.value=b,w=!1,t.selectionStart=t.selectionEnd=Math.min(p,b.length),t.dispatchEvent(new Event("input")),C.refresh(),E.toast("Markdown formatted.",{type:"success"})}),T.addEventListener("click",()=>{J?(C.unfoldAll(),T.innerHTML='<span data-icon="chevrons-down" data-icon-size="10" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',I.scan(T),T.classList.remove("active")):(C.foldAll(),T.innerHTML='<span data-icon="chevrons-right" data-icon-size="10" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',I.scan(T),T.classList.add("active")),J=!J});const te=document.createElement("span");te.className="editor-toolbar-sep",z.insertBefore(te,z.children[3]),Y.addEventListener("click",()=>{W=!W;const t=e.find("#markdown-editor"),p=e.find("#css-editor"),b=e.find("#editor-body");if(W){const y=e.find(".editor-view-btn[data-mode].active").get(0);ae=y?y.getAttribute("data-mode"):"split",e.find(".editor-view-btn[data-mode]").removeClass("active"),e.find('.editor-view-btn[data-mode="split"]').addClass("active"),b.removeClass("editor-mode-write editor-mode-preview").addClass("editor-mode-split"),t.hide(),p.show(),v||(p.val(M),v=!0,Ie(p.get(0))),U(),Y.classList.add("active")}else e.find(".editor-view-btn[data-mode]").removeClass("active"),e.find(`.editor-view-btn[data-mode="${ae}"]`).addClass("active"),b.removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${ae}`),p.hide(),t.show(),C.refresh(),Y.classList.remove("active")});const se=Fe();se.viewMode&&se.viewMode!=="split"&&(e.find(".editor-view-btn[data-mode]").removeClass("active"),e.find(`.editor-view-btn[data-mode="${se.viewMode}"]`).addClass("active"),e.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${se.viewMode}`)),se.fullscreen&&e.find(".editor-card").addClass("editor-fullscreen"),e.find("#css-editor").on("input",()=>{U(),clearTimeout(oe),oe=setTimeout(()=>{let t=document.getElementById("preview-custom-css");t||(t=document.createElement("style"),t.id="preview-custom-css",s.get(0).parentNode.insertBefore(t,s.get(0))),t.textContent=e.find("#css-editor").val()},400)}),Oe({image:async t=>{const p=(await k.media.list().catch(()=>[])).filter(u=>/\.(png|jpe?g|gif|webp|svg)$/i.test(u.name)),b=document.createElement("div");if(b.className="media-picker-grid",p.length)p.forEach(u=>{const A=document.createElement("div");A.className="media-picker-item",A.dataset.url=u.url;const L=document.createElement("img");L.src=u.url,L.alt=u.name;const de=document.createElement("span");de.textContent=u.name,A.appendChild(L),A.appendChild(de),b.appendChild(A)});else{const u=document.createElement("p");u.className="text-muted p-3",u.textContent="No images uploaded yet.",b.appendChild(u)}const y=E.slideover({title:"Insert Image",size:"lg",position:"right",content:b});$(y.element).on("click",".media-picker-item",function(){const u=$(this).data("url"),A=$(this).find("span").text();$e(t,``),y.close(),t.dispatchEvent(new Event("input",{bubbles:!0}))}),y.open()},scribe:t=>Ge(t),card:t=>Me.open(t,{onMediaBrowse:()=>k.media.list().catch(()=>[])}),timeline:t=>Re.open(t,{onPreview:async p=>{try{return await k.pages.preview(p)}catch{return null}},onListCollections:()=>k.collections.list().catch(()=>[]),onGetCollection:p=>k.collections.get(p).catch(()=>null)})}),x.onEffects(t=>qe.open(t)),x.onHelp(()=>{_e()}),x.onTutorial(t=>{Ye(t)}),e.find(".editor-view-btn").on("click",function(){const t=$(this).data("mode");t&&(e.find(".editor-view-btn").removeClass("active"),$(this).addClass("active"),e.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${t}`),Be("viewMode",t))}),e.find("#fullscreen-btn").on("click",function(){e.find(".editor-card").toggleClass("editor-fullscreen"),Be("fullscreen",e.find(".editor-card").hasClass("editor-fullscreen"))}),pe=!1,e.find("#quick-switch").prop("disabled",!1),ke&&window.removeEventListener("beforeunload",ke),ke=t=>{pe&&t.preventDefault()},window.addEventListener("beforeunload",ke),ze||(ze=!0,R.use((t,p,b)=>{const y=window.location.hash.startsWith("#/pages/edit")||window.location.hash==="#/pages/new";return!pe||!y?b():E.confirm("You have unsaved changes. Leave this page?").then(u=>{u&&(pe=!1,b())})})),B.on("input",()=>{w||(pe=!0,e.find("#quick-switch").prop("disabled",!0),h())});const ce=e.find("#editor-meta-tabs").get(0);ce&&(ce.addEventListener("input",()=>{pe=!0,e.find("#quick-switch").prop("disabled",!0)}),ce.addEventListener("change",t=>{t.target.id!=="quick-switch"&&(pe=!0,e.find("#quick-switch").prop("disabled",!0))})),h();const ge=t=>({title:e.find("#field-title").val().trim()||"Untitled",description:e.find("#field-description").val().trim(),layout:e.find("#field-layout").val(),status:e.find("#field-status").val(),sortOrder:parseInt(e.find("#field-sort-order").val(),10)||99,showInNav:e.find("#field-show-in-nav").is(":checked"),sidebar:e.find("#field-sidebar").is(":checked"),...e.find("#field-show-breadcrumbs").is(":checked")?{}:{breadcrumbs:!1},...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},tags:_?_.getValue():[],category:e.find("#field-category").val().trim()||null,visibility:e.find("#field-visibility").val()||"public",project:e.find("#field-project").val()||"",seo:{title:e.find("#field-seo-title").val().trim(),description:e.find("#field-seo-desc").val().trim()},dconfig:t,...e.find("#field-theme").val()?{theme:e.find("#field-theme").val()}:{}});(()=>{const t=e.find("#live-preview-frame").get(0),p=e.find("#live-preview-status").get(0),b=e.find("#live-preview-stage").get(0);if(!t)return;let y=null,u=!0,A=!1,L=!1;const de=O=>{p&&(p.textContent=O)},K=()=>{const O=(e.find("#field-dconfig").val()||"").trim();if(!O)return null;try{return JSON.parse(O)}catch{return null}},ve=async()=>{if(!L){L=!0,de("Rendering\u2026");try{const O=(e.find("#page-url-path").val()||"").trim()||f||"/",{html:Ce}=await k.pages.previewFull(O,ge(K()),C.getUnfoldedContent());let ue=0;try{ue=t.contentWindow.scrollY||0}catch{}t.addEventListener("load",function be(){t.removeEventListener("load",be);try{t.contentWindow.scrollTo(0,ue)}catch{}},{once:!0}),t.srcdoc=Ce,u=!1,de("Showing unsaved changes")}catch(O){de("Preview failed - "+(O&&O.message?O.message:"unknown error"))}finally{L=!1}}},he=()=>{u=!0,A&&(clearTimeout(y),y=setTimeout(ve,600))},me=e.find("#live-preview-tab").get(0);me&&me.addEventListener("click",()=>{A=!0,u&&ve()}),e.find("#editor-meta-tabs .tab-item").each(function(){this.id!=="live-preview-tab"&&this.addEventListener("click",()=>{A=!1})}),m.addEventListener("input",he);const fe=e.find("#editor-meta-tabs").get(0);fe&&(fe.addEventListener("input",he),fe.addEventListener("change",he)),e.find("#live-preview-refresh").on("click",()=>ve()),e.find(".live-preview-width").on("click",function(){const O=this.getAttribute("data-width");e.find(".live-preview-width").removeClass("active"),$(this).addClass("active"),O==="full"?t.removeAttribute("data-width"):t.setAttribute("data-width",O),b&&(b.scrollTop=0)})})(),e.find("#share-preview-btn").on("click",async()=>{if(!r){E.toast("Save the page first - a share link needs a page to point at.",{type:"warning"});return}await Ke(f)}),e.find("#save-btn").on("click",async()=>{const t=e.find("#page-url-path").val().trim();if(!t){E.toast("URL path is required.",{type:"warning"});return}const p=e.find("#field-dconfig").val().trim();let b=null;if(p)try{b=JSON.parse(p)}catch{E.toast("DConfig JSON is invalid. Please check the format before saving.",{type:"warning"});return}const y=ge(b);try{e.find("#save-btn").prop("disabled",!0).text("Saving\u2026");const u=C.getUnfoldedContent();if(r){const A={frontmatter:y,body:u};t!==f&&(A.newUrlPath=t),await k.pages.update(f,A),v&&await k.settings.saveCustomCss(e.find("#css-editor").val()),E.toast(v?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),pe=!1,e.find("#quick-switch").prop("disabled",!1),t!==f&&R.navigate(`/pages/edit${t}`)}else await k.pages.create({urlPath:t,frontmatter:y,body:u}),v&&await k.settings.saveCustomCss(e.find("#css-editor").val()),E.toast(v?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),pe=!1,R.navigate("/pages")}catch(u){E.toast(`Save failed: ${u.message||"Unknown error"}`,{type:"error"})}finally{e.find("#save-btn").prop("disabled",!1).text("Save")}}),e.find("#cancel-btn").on("click",()=>R.navigate("/pages")),Domma.icons.scan()}};
|
|
91
|
+
`)}const Me="editor_prefs";function Ne(){return S.get(Me)||{viewMode:"split",fullscreen:!1}}function ze(e,z){const v=Ne();v[e]=z,S.set(Me,v)}export const pageEditorView={templateUrl:"/admin/js/templates/page-editor.html",async onMount(e){const z=window.location.hash.match(/#\/pages\/edit(\/.*)/),v=z?z[1]:null,s=!!v,C=E.loader(e.get(0),{type:"dots"}),Z=[L.layouts.get().catch(()=>({})),L.settings.get().catch(()=>({}))];s&&(Z.push(L.pages.get(v).catch(()=>null)),Z.push(L.pages.list().catch(()=>[])));const[ne,ae,m,O]=await Promise.all(Z);C.destroy(),Ve(e.find("#field-theme").get(0),{includeDefault:!0});const M=ae?.layoutOptions?.spacerSize??40;if(s&&!m){E.toast("Page not found.",{type:"error"}),R.navigate("/pages");return}e.find("#editor-title").text(s?`Edit Page - ${m.title||v}`:"New Page"),s&&e.find("#page-url-path").val(v),m&&(e.find("#field-title").val(m.title||""),e.find("#field-description").val(m.description||""),e.find("#field-status").val(m.status||"draft"),e.find("#field-sort-order").val(m.sortOrder??99),e.find("#field-show-in-nav").prop("checked",!!m.showInNav),e.find("#field-sidebar").prop("checked",!!m.sidebar),e.find("#field-show-breadcrumbs").prop("checked",m.breadcrumbs!==!1),e.find("#field-bundled").prop("checked",!!m.bundled),e.find("#field-category").val(m.category||""),e.find("#field-visibility").val(m.visibility||"public"),e.find("#field-theme").val(m.theme||""),e.find("#field-seo-title").val(m.seo?.title||""),e.find("#field-seo-desc").val(m.seo?.description||""),m.dconfig&&e.find("#field-dconfig").val(JSON.stringify(m.dconfig,null,2)));{const t=e.find("#field-project").get(0);if(t){const l=await L.projects.list().catch(()=>[]);l.forEach(c=>{const h=document.createElement("option");h.value=c.slug,h.textContent=c.name||c.slug,t.appendChild(h)});let u="";if(!s){const{getProjectFromHash:c}=await import("../lib/project-context.js");u=c()||""}if(!u&&m)if(m.project===null)u="";else if(typeof m.project=="string"&&m.project)u=m.project;else{const c=s?v:"";if(c){let h="",p=-1;for(const k of l)k.rootUrl&&(c===k.rootUrl||c.startsWith(k.rootUrl+"/"))&&k.rootUrl.length>p&&(h=k.slug,p=k.rootUrl.length);u=h}}t.value=u}}const B=e.find("#quick-switch");s&&Array.isArray(O)&&O.length&&([...O].sort((t,l)=>(t.title||t.urlPath).localeCompare(l.title||l.urlPath)).forEach(t=>{const l=document.createElement("option");l.value=t.urlPath,l.textContent=`${t.title||"Untitled"} (${t.urlPath})`,t.urlPath===v&&(l.selected=!0),B.get(0).appendChild(l)}),B.css("display",""),B.on("change",function(){const t=this.value;t&&R.navigate("/pages/edit"+t)}));const N=await L.pages.tags().catch(()=>[]),P=e.find("#field-tags").get(0),J=P?E.pillbox(P,{data:N,value:m?.tags||[],creatable:!0,searchable:!0,placeholder:"Add tag\u2026"}):null,_=e.find("#field-layout").empty();if(Object.entries(ne).forEach(([t,l])=>{const u=(m?.layout||"default")===t?"selected":"";_.append(`<option value="${t}" ${u}>${l.label||t}</option>`)}),s){const t=e.find("#view-page-btn").get(0);t.href=v,t.style.display="";const l=e.find("#history-tab").get(0);l.style.display=""}e.find("#live-preview-tab").get(0).style.display="",E.tabs(e.find("#editor-meta-tabs").get(0)),s&&je(e,v);const F=e.find("#markdown-editor"),g=e.find("#markdown-preview");m&&F.val(m.content||"");let y=!1,U="";L.settings.getCustomCss().then(({css:t})=>{U=t||""}).catch(()=>{});let x=!1;const f=F.get(0),i=document.createElement("div");i.className="editor-line-numbers editor-line-numbers--foldable",f.parentElement.insertBefore(i,f);const w=We(f,i,{onFoldChange:()=>{}});w.setGuard(t=>{x=t});function q(){const t=e.find("#css-editor").get(0);if(!t)return;const l=t.value.split(`
|
|
92
|
+
`);for(;i.firstChild;)i.removeChild(i.firstChild);l.forEach((u,c)=>{const h=document.createElement("span");h.className="editor-line-number-row";const p=document.createElement("span");p.className="fold-toggle fold-toggle--empty";const k=document.createElement("span");k.className="editor-line-num",k.textContent=String(c+1),h.appendChild(p),h.appendChild(k),i.appendChild(h)}),i.scrollTop=t.scrollTop}{const t=e.find("#css-editor").get(0);t&&t.addEventListener("scroll",()=>{i.scrollTop=t.scrollTop})}const oe=()=>{w.refresh(),i.scrollTop=f.scrollTop};f.addEventListener("input",oe),f.addEventListener("scroll",()=>{i.scrollTop=f.scrollTop});let fe=null;const b=()=>g.get(0),A=t=>t.replace(/<\/head>/i,"<style>body.dm-cloaked{opacity:1 !important;transition:none !important}</style></head>"),j=()=>{const t=b(),l=t&&t.contentDocument;if(!l||!l.head)return;const u=y&&e.find("#css-editor").val()||"";if(!u)return;let c=l.getElementById("preview-custom-css");c||(c=l.createElement("style"),c.id="preview-custom-css",l.head.appendChild(c)),c.textContent=u},ie=()=>{clearTimeout(fe),fe=setTimeout(async()=>{const t=b();if(!t||e.find("#editor-body").hasClass("editor-mode-write"))return;const l=w.getUnfoldedContent();try{const u=(e.find("#field-dconfig").val()||"").trim();let c=null;if(u)try{c=JSON.parse(u)}catch{c=null}const h=(e.find("#page-url-path").val()||"").trim()||v||"/",{html:p}=await L.pages.previewFull(h,ye(c),l),k=A(p);let te=0;try{te=t.contentWindow.scrollY||0}catch{}t.addEventListener("load",function se(){t.removeEventListener("load",se);try{t.contentWindow.scrollTo(0,te)}catch{}j()},{once:!0}),t.srcdoc=k}catch(u){t.srcdoc='<!doctype html><meta charset="utf-8"><body style="font:14px system-ui;padding:1rem;color:#b91c1c;">Preview failed: '+String(u&&u.message||"unknown error").replace(/[<&]/g,c=>c==="<"?"<":"&")+"</body>"}},500)},le=He(F,e.find("#editor-toolbar"),{spacerDefault:M});qe(F.get(0));let ce=!1,de="split",pe=null;const V=document.createElement("button");V.className="editor-view-btn",V.type="button";const Q=document.createElement("span");Q.setAttribute("data-icon","css-code"),V.appendChild(Q);const W=document.createElement("button");W.className="editor-view-btn",W.type="button";const H=document.createElement("span");H.setAttribute("data-icon","code"),W.appendChild(H);let ee=!1;const Y=document.createElement("button");Y.className="editor-view-btn",Y.type="button",Y.innerHTML='<span data-icon="chevrons-down" data-icon-size="10" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',Y.style.cssText="font-size:9px;letter-spacing:-1px;";const me=e.find(".editor-toolbar-right").get(0);me.prepend(Y),me.prepend(W),me.prepend(V),I.scan(V),I.scan(W),I.scan(Y),E.tooltip(V,{content:"Edit Custom CSS",position:"top"}),E.tooltip(W,{content:"Format Markdown",position:"top"}),E.tooltip(Y,{content:"Fold / unfold all shortcodes",position:"top"}),W.addEventListener("click",()=>{const t=F.get(0),l=t.selectionStart,u=Xe(w.getUnfoldedContent());w.unfoldAll(),x=!0,t.value=u,x=!1,t.selectionStart=t.selectionEnd=Math.min(l,u.length),t.dispatchEvent(new Event("input")),w.refresh(),E.toast("Markdown formatted.",{type:"success"})}),Y.addEventListener("click",()=>{ee?(w.unfoldAll(),Y.innerHTML='<span data-icon="chevrons-down" data-icon-size="10" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',I.scan(Y),Y.classList.remove("active")):(w.foldAll(),Y.innerHTML='<span data-icon="chevrons-right" data-icon-size="10" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',I.scan(Y),Y.classList.add("active")),ee=!ee});const ve=document.createElement("span");ve.className="editor-toolbar-sep",me.insertBefore(ve,me.children[3]),V.addEventListener("click",()=>{ce=!ce;const t=e.find("#markdown-editor"),l=e.find("#css-editor"),u=e.find("#editor-body");if(ce){const c=e.find(".editor-view-btn[data-mode].active").get(0);de=c?c.getAttribute("data-mode"):"split",e.find(".editor-view-btn[data-mode]").removeClass("active"),e.find('.editor-view-btn[data-mode="split"]').addClass("active"),u.removeClass("editor-mode-write editor-mode-preview").addClass("editor-mode-split"),t.hide(),l.show(),y||(l.val(U),y=!0,Ie(l.get(0))),q(),V.classList.add("active")}else e.find(".editor-view-btn[data-mode]").removeClass("active"),e.find(`.editor-view-btn[data-mode="${de}"]`).addClass("active"),u.removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${de}`),l.hide(),t.show(),w.refresh(),V.classList.remove("active")});const ue=Ne();ue.viewMode&&ue.viewMode!=="split"&&(e.find(".editor-view-btn[data-mode]").removeClass("active"),e.find(`.editor-view-btn[data-mode="${ue.viewMode}"]`).addClass("active"),e.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${ue.viewMode}`)),ue.fullscreen&&e.find(".editor-card").addClass("editor-fullscreen"),e.find("#css-editor").on("input",()=>{q(),clearTimeout(pe),pe=setTimeout(()=>{j()},400)}),Oe({image:async t=>{const l=(await L.media.list().catch(()=>[])).filter(h=>/\.(png|jpe?g|gif|webp|svg)$/i.test(h.name)),u=document.createElement("div");if(u.className="media-picker-grid",l.length)l.forEach(h=>{const p=document.createElement("div");p.className="media-picker-item",p.dataset.url=h.url;const k=document.createElement("img");k.src=h.url,k.alt=h.name;const te=document.createElement("span");te.textContent=h.name,p.appendChild(k),p.appendChild(te),u.appendChild(p)});else{const h=document.createElement("p");h.className="text-muted p-3",h.textContent="No images uploaded yet.",u.appendChild(h)}const c=E.slideover({title:"Insert Image",size:"lg",position:"right",content:u});$(c.element).on("click",".media-picker-item",function(){const h=$(this).data("url"),p=$(this).find("span").text();$e(t,``),c.close(),t.dispatchEvent(new Event("input",{bubbles:!0}))}),c.open()},scribe:t=>Ye(t),card:t=>Re.open(t,{onMediaBrowse:()=>L.media.list().catch(()=>[])}),timeline:t=>Be.open(t,{onPreview:async l=>{try{return await L.pages.preview(l)}catch{return null}},onListCollections:()=>L.collections.list().catch(()=>[]),onGetCollection:l=>L.collections.get(l).catch(()=>null)})}),le.onEffects(t=>Ue.open(t)),le.onHelp(()=>{_e()}),le.onTutorial(t=>{Ge(t)}),e.find(".editor-view-btn").on("click",function(){const t=$(this).data("mode");t&&(e.find(".editor-view-btn").removeClass("active"),$(this).addClass("active"),e.find("#editor-body").removeClass("editor-mode-split editor-mode-write editor-mode-preview").addClass(`editor-mode-${t}`),ze("viewMode",t),t!=="write"&&ie())}),e.find("#fullscreen-btn").on("click",function(){e.find(".editor-card").toggleClass("editor-fullscreen"),ze("fullscreen",e.find(".editor-card").hasClass("editor-fullscreen"))}),ge=!1,e.find("#quick-switch").prop("disabled",!1),Le&&window.removeEventListener("beforeunload",Le),Le=t=>{ge&&t.preventDefault()},window.addEventListener("beforeunload",Le),Fe||(Fe=!0,R.use((t,l,u)=>{const c=window.location.hash.startsWith("#/pages/edit")||window.location.hash==="#/pages/new";return!ge||!c?u():E.confirm("You have unsaved changes. Leave this page?").then(h=>{h&&(ge=!1,u())})})),F.on("input",()=>{x||(ge=!0,e.find("#quick-switch").prop("disabled",!0),ie())});const be=e.find("#editor-meta-tabs").get(0);be&&(be.addEventListener("input",()=>{ge=!0,e.find("#quick-switch").prop("disabled",!0)}),be.addEventListener("change",t=>{t.target.id!=="quick-switch"&&(ge=!0,e.find("#quick-switch").prop("disabled",!0))})),ie();const ye=t=>({title:e.find("#field-title").val().trim()||"Untitled",description:e.find("#field-description").val().trim(),layout:e.find("#field-layout").val(),status:e.find("#field-status").val(),sortOrder:parseInt(e.find("#field-sort-order").val(),10)||99,showInNav:e.find("#field-show-in-nav").is(":checked"),sidebar:e.find("#field-sidebar").is(":checked"),...e.find("#field-show-breadcrumbs").is(":checked")?{}:{breadcrumbs:!1},...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},tags:J?J.getValue():[],category:e.find("#field-category").val().trim()||null,visibility:e.find("#field-visibility").val()||"public",project:e.find("#field-project").val()||"",seo:{title:e.find("#field-seo-title").val().trim(),description:e.find("#field-seo-desc").val().trim()},dconfig:t,...e.find("#field-theme").val()?{theme:e.find("#field-theme").val()}:{}});(()=>{const t=e.find("#editor-body").get(0),l=e.find("#editor-divider").get(0);if(!t||!l)return;const u=15,c=85,h=T=>Math.min(c,Math.max(u,T));let p=h(parseFloat(Ne().splitRatio)||50);const k=T=>{t.style.setProperty("--dm-editor-split",p+"%"),l.setAttribute("aria-valuenow",String(Math.round(p))),T&&ze("splitRatio",p)};k(!1);const te=T=>{const re=t.getBoundingClientRect();return re.width?h((T-re.left)/re.width*100):p},se=T=>{p=te(T.clientX),k(!1)},he=()=>{document.removeEventListener("pointermove",se),document.removeEventListener("pointerup",he),t.classList.remove("is-resizing"),l.classList.remove("is-dragging"),k(!0)};l.addEventListener("pointerdown",T=>{window.matchMedia("(max-width: 768px)").matches||(T.preventDefault(),t.classList.add("is-resizing"),l.classList.add("is-dragging"),document.addEventListener("pointermove",se),document.addEventListener("pointerup",he))}),l.addEventListener("dblclick",()=>{p=50,k(!0)}),l.addEventListener("keydown",T=>{const re=T.shiftKey?10:2;let K=p;if(T.key==="ArrowLeft")K=p-re;else if(T.key==="ArrowRight")K=p+re;else if(T.key==="Home")K=u;else if(T.key==="End")K=c;else if(T.key==="Enter"||T.key===" ")K=50;else return;T.preventDefault(),p=h(K),k(!0)})})(),(()=>{const t=e.find("#live-preview-frame").get(0),l=e.find("#live-preview-status").get(0),u=e.find("#live-preview-stage").get(0);if(!t)return;let c=null,h=!0,p=!1,k=!1;const te=G=>{l&&(l.textContent=G)},se=()=>{const G=(e.find("#field-dconfig").val()||"").trim();if(!G)return null;try{return JSON.parse(G)}catch{return null}},he=async()=>{if(!k){k=!0,te("Rendering\u2026");try{const G=(e.find("#page-url-path").val()||"").trim()||v||"/",{html:we}=await L.pages.previewFull(G,ye(se()),w.getUnfoldedContent());let Ce=0;try{Ce=t.contentWindow.scrollY||0}catch{}t.addEventListener("load",function Ee(){t.removeEventListener("load",Ee);try{t.contentWindow.scrollTo(0,Ce)}catch{}},{once:!0}),t.srcdoc=we,h=!1,te("Showing unsaved changes")}catch(G){te("Preview failed - "+(G&&G.message?G.message:"unknown error"))}finally{k=!1}}},T=()=>{h=!0,p&&(clearTimeout(c),c=setTimeout(he,600))},re=e.find("#live-preview-tab").get(0);re&&re.addEventListener("click",()=>{p=!0,h&&he()}),e.find("#editor-meta-tabs .tab-item").each(function(){this.id!=="live-preview-tab"&&this.addEventListener("click",()=>{p=!1})}),f.addEventListener("input",T);const K=e.find("#editor-meta-tabs").get(0);K&&(K.addEventListener("input",T),K.addEventListener("change",T)),e.find("#live-preview-refresh").on("click",()=>he()),e.find(".live-preview-width").on("click",function(){const G=this.getAttribute("data-width");e.find(".live-preview-width").removeClass("active"),$(this).addClass("active"),G==="full"?t.removeAttribute("data-width"):t.setAttribute("data-width",G),u&&(u.scrollTop=0)})})(),e.find("#share-preview-btn").on("click",async()=>{if(!s){E.toast("Save the page first - a share link needs a page to point at.",{type:"warning"});return}await Ke(v)}),e.find("#save-btn").on("click",async()=>{const t=e.find("#page-url-path").val().trim();if(!t){E.toast("URL path is required.",{type:"warning"});return}const l=e.find("#field-dconfig").val().trim();let u=null;if(l)try{u=JSON.parse(l)}catch{E.toast("DConfig JSON is invalid. Please check the format before saving.",{type:"warning"});return}const c=ye(u);try{e.find("#save-btn").prop("disabled",!0).text("Saving\u2026");const h=w.getUnfoldedContent();if(s){const p={frontmatter:c,body:h};t!==v&&(p.newUrlPath=t),await L.pages.update(v,p),y&&await L.settings.saveCustomCss(e.find("#css-editor").val()),E.toast(y?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),ge=!1,e.find("#quick-switch").prop("disabled",!1),t!==v&&R.navigate(`/pages/edit${t}`)}else await L.pages.create({urlPath:t,frontmatter:c,body:h}),y&&await L.settings.saveCustomCss(e.find("#css-editor").val()),E.toast(y?"Page and CSS saved.":"Page saved successfully.",{type:"success"}),ge=!1,R.navigate("/pages")}catch(h){E.toast(`Save failed: ${h.message||"Unknown error"}`,{type:"error"})}finally{e.find("#save-btn").prop("disabled",!1).text("Save")}}),e.find("#cancel-btn").on("click",()=>R.navigate("/pages")),Domma.icons.scan()}};
|
package/package.json
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
(function () {
|
|
4
4
|
if (typeof fetch !== 'function') return;
|
|
5
5
|
|
|
6
|
+
// Preview renders are not visits. The editor previews a page into an
|
|
7
|
+
// iframe where location.pathname is the srcdoc document rather than any
|
|
8
|
+
// real URL, so tracking one both invents a page and inflates the counts.
|
|
9
|
+
if (window.__CMS_PREVIEW__) return;
|
|
10
|
+
|
|
6
11
|
var dnt = navigator.doNotTrack === '1'
|
|
7
12
|
|| window.doNotTrack === '1'
|
|
8
13
|
|| navigator.msDoNotTrack === '1';
|
|
@@ -59,7 +59,8 @@ export async function pagesRoutes(fastify) {
|
|
|
59
59
|
const page = await buildPreviewPage(urlPath, frontmatter, body, {user: request.user || null});
|
|
60
60
|
const html = await renderPage(page, {
|
|
61
61
|
baseUrl: `${request.protocol}://${request.host}`,
|
|
62
|
-
user: request.user || null
|
|
62
|
+
user: request.user || null,
|
|
63
|
+
noTrack: true
|
|
63
64
|
});
|
|
64
65
|
return {html};
|
|
65
66
|
});
|
package/server/server.js
CHANGED
|
@@ -56,8 +56,31 @@ if (MANAGER_SECRET && MANAGER_SECRET.length < 32) {
|
|
|
56
56
|
console.warn(' WARNING: MANAGER_SECRET is set but too short (minimum 32 characters). Manager notifications disabled until fixed.');
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the log level.
|
|
61
|
+
*
|
|
62
|
+
* `config/server.json` → `logging.level` wins; otherwise info in development
|
|
63
|
+
* and warn in production, as before. Made configurable because `warn` hides
|
|
64
|
+
* every 4xx and every `log.info` a plugin writes, so a rejected admin action -
|
|
65
|
+
* a site that fails to create, a certificate that fails to issue - leaves no
|
|
66
|
+
* trace at all and cannot be diagnosed after the fact.
|
|
67
|
+
*
|
|
68
|
+
* An unrecognised value falls back rather than throwing: a typo here must not
|
|
69
|
+
* stop the server booting.
|
|
70
|
+
*/
|
|
71
|
+
function resolveLogLevel() {
|
|
72
|
+
const VALID = ['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent'];
|
|
73
|
+
const fallback = process.env.NODE_ENV === 'development' ? 'info' : 'warn';
|
|
74
|
+
const requested = process.env.LOG_LEVEL || (config.server && config.server.logging && config.server.logging.level);
|
|
75
|
+
if (!requested) return fallback;
|
|
76
|
+
const level = String(requested).toLowerCase().trim();
|
|
77
|
+
if (VALID.includes(level)) return level;
|
|
78
|
+
console.warn(` WARNING: unknown log level "${requested}" - falling back to "${fallback}". Valid: ${VALID.join(', ')}`);
|
|
79
|
+
return fallback;
|
|
80
|
+
}
|
|
81
|
+
|
|
59
82
|
const app = Fastify({
|
|
60
|
-
logger: {level:
|
|
83
|
+
logger: {level: resolveLogLevel()},
|
|
61
84
|
// When running behind a reverse proxy (e.g. domma-cms-manager), trust the
|
|
62
85
|
// X-Forwarded-For header so @fastify/rate-limit keys on the real client IP
|
|
63
86
|
// rather than the proxy's loopback address.
|
|
@@ -88,6 +88,9 @@ async function buildOverlayMenus(menuCtx, user) {
|
|
|
88
88
|
* @param {object} [opts.preview] - Set when rendering an unpublished page for a
|
|
89
89
|
* permitted viewer: `{status, urlPath, user}`. Draws the draft banner. Absent
|
|
90
90
|
* for every normal public render.
|
|
91
|
+
* @param {boolean} [opts.noTrack] - Mark the render as a preview for client-side
|
|
92
|
+
* analytics without drawing a banner. Implied by `opts.preview`; set directly
|
|
93
|
+
* by the editor's full-page preview, which has no banner.
|
|
91
94
|
* @returns {Promise<string>}
|
|
92
95
|
*/
|
|
93
96
|
export async function renderPage(page, opts = {}) {
|
|
@@ -210,7 +213,14 @@ export async function renderPage(page, opts = {}) {
|
|
|
210
213
|
};
|
|
211
214
|
const footerJson = JSON.stringify(footer).replace(/<\/script>/gi, '<\\/script>');
|
|
212
215
|
|
|
216
|
+
// A preview is not a visit. Without this the editor's preview iframe posts a
|
|
217
|
+
// page view on every re-render - recorded under the srcdoc document's path,
|
|
218
|
+
// which is not a page at all - and draft or share-link previews inflate the
|
|
219
|
+
// counts for something nobody has published.
|
|
220
|
+
const noTrack = !!opts.preview || opts.noTrack === true;
|
|
221
|
+
|
|
213
222
|
const vars = {
|
|
223
|
+
previewFlagScript: noTrack ? '<script>window.__CMS_PREVIEW__ = true;</script>' : '',
|
|
214
224
|
seoTitle,
|
|
215
225
|
seoDescription,
|
|
216
226
|
ogImage,
|
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
<meta name="description" content="{{seoDescription}}">
|
|
8
8
|
{{seoTags}}
|
|
9
9
|
|
|
10
|
+
<!-- Set on preview renders (editor preview, draft preview, share link).
|
|
11
|
+
Plugins that record page views or fire outbound beacons must check it:
|
|
12
|
+
a preview is not a visit, and previews render at URLs that are not
|
|
13
|
+
real pages. Emitted before every other injection so both head and
|
|
14
|
+
body-end scripts can read it. -->
|
|
15
|
+
{{previewFlagScript}}
|
|
16
|
+
|
|
10
17
|
<!-- Fonts -->
|
|
11
18
|
{{#if fontLink}}{{fontLink}}{{/if}}
|
|
12
19
|
|