domma-cms 0.76.0 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/lib/action-editor-arrange.js +1 -0
- package/admin/js/lib/api-endpoint-editor-arrange.js +2 -0
- package/admin/js/lib/block-editor-arrange.js +2 -0
- package/admin/js/lib/collection-editor-arrange.js +3 -0
- package/admin/js/lib/collection-entries-arrange.js +1 -0
- package/admin/js/lib/component-editor-arrange.js +27 -0
- package/admin/js/lib/context-menu-editor-arrange.js +1 -0
- package/admin/js/lib/dashboard-arrange.js +1 -0
- package/admin/js/lib/form-editor-arrange.js +1 -0
- package/admin/js/lib/form-submissions-arrange.js +2 -0
- package/admin/js/lib/menu-editor-arrange.js +2 -0
- package/admin/js/lib/page-editor-arrange.js +1 -0
- package/admin/js/lib/plugin-code-arrange.js +1 -0
- package/admin/js/lib/project-page-arrange.js +1 -0
- package/admin/js/lib/role-editor-arrange.js +3 -0
- package/admin/js/lib/user-editor-arrange.js +1 -0
- package/admin/js/lib/view-editor-arrange.js +14 -0
- package/admin/js/templates/action-editor.html +223 -147
- package/admin/js/templates/api-endpoint-editor.html +172 -117
- package/admin/js/templates/block-editor.html +194 -203
- package/admin/js/templates/collection-editor.html +191 -113
- package/admin/js/templates/collection-entries.html +99 -36
- package/admin/js/templates/component-editor.html +128 -126
- package/admin/js/templates/context-menu-editor.html +208 -148
- package/admin/js/templates/dashboard.html +184 -22
- package/admin/js/templates/form-editor.html +41 -26
- package/admin/js/templates/form-submissions.html +78 -26
- package/admin/js/templates/menu-editor.html +57 -17
- package/admin/js/templates/menu-locations.html +54 -11
- package/admin/js/templates/page-editor.html +47 -26
- package/admin/js/templates/plugin-code.html +91 -73
- package/admin/js/templates/project-detail.html +83 -145
- package/admin/js/templates/project-settings.html +88 -53
- package/admin/js/templates/role-editor.html +158 -83
- package/admin/js/templates/user-editor.html +150 -14
- package/admin/js/templates/view-editor.html +203 -180
- package/admin/js/templates/view-preview.html +45 -45
- package/admin/js/views/action-editor.js +7 -1
- package/admin/js/views/api-endpoint-editor.js +2 -3
- package/admin/js/views/block-editor.js +14 -8
- package/admin/js/views/collection-editor.js +64 -5
- package/admin/js/views/collection-entries.js +50 -1
- package/admin/js/views/component-editor.js +2 -28
- package/admin/js/views/context-menu-editor.js +54 -55
- package/admin/js/views/dashboard.js +7 -1
- package/admin/js/views/form-editor.js +7 -7
- package/admin/js/views/form-submissions.js +11 -1
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/login.js +2 -2
- package/admin/js/views/menu-editor.js +21 -43
- package/admin/js/views/menu-locations.js +16 -1
- package/admin/js/views/page-editor.js +26 -26
- package/admin/js/views/plugin-code.js +23 -4
- package/admin/js/views/project-detail.js +9 -1
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/role-editor.js +11 -3
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/view-editor.js +1 -1
- package/admin/js/views/view-preview.js +1 -1
- package/package.json +1 -1
- package/server/routes/api/dashboard.js +32 -4
- package/server/routes/api/forms.js +104 -13
- package/server/routes/api/users.js +12 -2
- package/server/routes/api/views.js +55 -1
- package/server/services/components.js +9 -0
- package/server/services/users.js +2 -2
- package/server/services/views.js +14 -0
- package/admin/js/templates/dashboard/activity-feed.html +0 -3
- package/admin/js/templates/dashboard/cache.html +0 -32
- package/admin/js/templates/dashboard/health-detail.html +0 -2
- package/admin/js/templates/dashboard/journeys.html +0 -17
- package/admin/js/templates/dashboard/kpi-strip.html +0 -34
- package/admin/js/templates/dashboard/spike-feed.html +0 -3
- package/admin/js/templates/dashboard/top-pages.html +0 -3
- package/admin/js/templates/dashboard/traffic-chart.html +0 -3
- package/admin/js/views/block-editor-enhance.js +0 -1
- package/admin/js/views/dashboard/lib/escape.js +0 -1
- package/admin/js/views/dashboard/widgets/activity-feed.js +0 -1
- package/admin/js/views/dashboard/widgets/cache.js +0 -1
- package/admin/js/views/dashboard/widgets/health-detail.js +0 -1
- package/admin/js/views/dashboard/widgets/journeys.js +0 -1
- package/admin/js/views/dashboard/widgets/kpi-strip.js +0 -1
- package/admin/js/views/dashboard/widgets/spike-feed.js +0 -6
- package/admin/js/views/dashboard/widgets/top-pages.js +0 -1
- package/admin/js/views/dashboard/widgets/traffic-chart.js +0 -1
|
@@ -1,228 +1,219 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<!-- Block editor. Bound with M.applyBindings - see admin/js/views/block-editor.js, which also inserts the
|
|
2
|
+
sample-data row template (the router renders a templateUrl through _.render, eating any {{…}} - so the
|
|
3
|
+
placeholder text below is written as {{…}}). No page heading: the Tool banner above
|
|
4
|
+
is the heading ("Blocks › <name>"), and All blocks, Copy shortcode and Save are banner actions.
|
|
5
|
+
#block-editor-body stays: admin.css lifts the view-width cap on it. -->
|
|
6
|
+
<div class="bex-page">
|
|
7
|
+
<div class="bex">
|
|
8
|
+
<div class="bex-bar">
|
|
9
|
+
<div class="bex-ident">
|
|
10
|
+
<strong data-bind-text="titleText"></strong>
|
|
11
|
+
<small data-bind-text="metaText.value"></small>
|
|
12
|
+
<span class="bex-chip is-warn" data-bind-hidden="!dirty.value" title="Changes not saved yet">Unsaved</span>
|
|
13
|
+
</div>
|
|
14
|
+
<span class="bex-spacer"></span>
|
|
15
|
+
<select id="block-quick-switch" class="form-input form-input--sm bex-switch" aria-label="Open another block" title="Open another block" data-bind-hidden="isNew">
|
|
16
|
+
<option value="">Open another block…</option>
|
|
8
17
|
</select>
|
|
9
|
-
<a href="#/blocks" class="btn btn-ghost btn-sm">
|
|
10
|
-
<span data-icon="arrow-left"></span> All Blocks
|
|
11
|
-
</a>
|
|
12
|
-
<button id="save-block-btn" class="btn btn-primary">
|
|
13
|
-
<span data-icon="save"></span> Save Block
|
|
14
|
-
</button>
|
|
15
18
|
</div>
|
|
16
|
-
</div>
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
<
|
|
20
|
+
<div class="bex-unsaved" data-bind-hidden="!dirty.value">
|
|
21
|
+
<span data-icon="alert-circle" data-icon-size="15"></span>
|
|
22
|
+
<span>You have unsaved changes.</span>
|
|
23
|
+
<span class="bex-spacer"></span>
|
|
24
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard">Discard</button>
|
|
25
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="cannotSave.value">
|
|
26
|
+
<span data-icon="save" data-icon-size="13"></span> Save</button>
|
|
23
27
|
</div>
|
|
24
|
-
<div class="card-body" style="max-width:420px;">
|
|
25
|
-
<label class="form-label">Name <span style="color:var(--dm-danger,#f87171);">*</span></label>
|
|
26
|
-
<input id="block-name" type="text" class="form-input" placeholder="e.g. feedback-card">
|
|
27
|
-
<small class="text-muted">Lowercase letters, digits, and hyphens only. Cannot be changed after creation.</small>
|
|
28
|
-
<div class="mt-3">
|
|
29
|
-
<label class="form-label">Project</label>
|
|
30
|
-
<select id="block-project" class="form-input">
|
|
31
|
-
<option value="">- none -</option>
|
|
32
|
-
</select>
|
|
33
|
-
<small class="text-muted">Tag this block to a project for grouping.</small>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="mt-3">
|
|
36
|
-
<label class="form-check-label" title="Included in fresh installs via the seed script">
|
|
37
|
-
<input id="block-bundled" type="checkbox" class="form-check"> Bundled
|
|
38
|
-
</label>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
28
|
|
|
43
|
-
<!--
|
|
44
|
-
<div class="
|
|
45
|
-
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
</button>
|
|
66
|
-
<button type="button" class="btn btn-ghost btn-sm" data-action="paste" title="Paste (Ctrl+V)">
|
|
67
|
-
<span data-icon="clipboard"></span>
|
|
68
|
-
</button>
|
|
69
|
-
<span class="editor-toolbar-sep"></span>
|
|
70
|
-
<button type="button" class="btn btn-ghost btn-sm" data-action="select-all" title="Select All (Ctrl+A)">
|
|
71
|
-
<span data-icon="maximise-2"></span>
|
|
72
|
-
</button>
|
|
73
|
-
<button type="button" class="btn btn-ghost btn-sm" data-action="format" title="Format HTML">
|
|
74
|
-
<span data-icon="code"></span> Format
|
|
75
|
-
</button>
|
|
76
|
-
|
|
77
|
-
<!-- View mode toggles (right side) -->
|
|
78
|
-
<div class="editor-toolbar-right">
|
|
79
|
-
<span id="block-cursor-pos"
|
|
80
|
-
style="font-size:.75rem;color:var(--dm-text-muted,#888);margin-right:.5rem;">Ln 1, Col 1</span>
|
|
81
|
-
<span class="editor-toolbar-sep"></span>
|
|
82
|
-
<button type="button" class="editor-view-btn" data-mode="write" title="Edit only">
|
|
83
|
-
<span data-icon="edit-2"></span>
|
|
84
|
-
</button>
|
|
85
|
-
<button type="button" class="editor-view-btn active" data-mode="split" title="Split view">
|
|
86
|
-
<span data-icon="columns"></span>
|
|
87
|
-
</button>
|
|
88
|
-
<button type="button" class="editor-view-btn" data-mode="preview" title="Preview only">
|
|
89
|
-
<span data-icon="eye"></span>
|
|
90
|
-
</button>
|
|
29
|
+
<!-- Details -->
|
|
30
|
+
<div class="bex-card">
|
|
31
|
+
<div class="bex-card-title">Details</div>
|
|
32
|
+
<div class="bex-grid">
|
|
33
|
+
<div>
|
|
34
|
+
<label class="form-label" for="block-name">Name <span class="text-danger">*</span>
|
|
35
|
+
<span data-help-title="Name" data-help="The block's id - what a shortcode names (block="…") and what its CSS is scoped to. Lowercase letters, digits and hyphens; it cannot be changed once the block exists, and a new block cannot take a name already in use."></span></label>
|
|
36
|
+
<input id="block-name" type="text" class="form-input font-mono" maxlength="80" placeholder="e.g. feedback-card"
|
|
37
|
+
data-model="name.value" data-bind-disabled="notNew" autocomplete="off">
|
|
38
|
+
<small class="bex-err" data-bind-hidden="!nameErr.value" data-bind-text="nameErr.value"></small>
|
|
39
|
+
</div>
|
|
40
|
+
<div>
|
|
41
|
+
<label class="form-label" for="block-project">Project
|
|
42
|
+
<span data-help="Files the block under a project - for the project's sidebar section and access scope. Optional."></span></label>
|
|
43
|
+
<select id="block-project" class="form-input" data-model="project.value">
|
|
44
|
+
<option value="">- none -</option>
|
|
45
|
+
</select>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="bex-setting">
|
|
48
|
+
<label class="form-label" for="block-bundled">Bundled
|
|
49
|
+
<span data-help="Shipped with fresh installs by the seed script. Leave it off for a block that belongs to this site only."></span></label>
|
|
50
|
+
<input id="block-bundled" type="checkbox" class="form-switch" data-model="bundled.value">
|
|
91
51
|
</div>
|
|
92
52
|
</div>
|
|
53
|
+
</div>
|
|
93
54
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
55
|
+
<!-- Template HTML + preview -->
|
|
56
|
+
<div class="bex-card bex-editor-card">
|
|
57
|
+
<div class="bex-card-title">Template HTML
|
|
58
|
+
<span data-help-title="Template" data-help="The block's HTML. {{field}} inserts an entry's value (HTML-escaped); {{field:DD MMM YYYY}} formats it as a date. The preview fills each placeholder from the sample values beside it. HTML comments are stripped when the block is rendered."></span>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="bex-toolbar" role="toolbar" aria-label="Template tools">
|
|
61
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="undo" title="Undo (Ctrl+Z)" aria-label="Undo"><span data-icon="corner-up-left" data-icon-size="14"></span></button>
|
|
62
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="redo" title="Redo (Ctrl+Y)" aria-label="Redo"><span data-icon="corner-up-right" data-icon-size="14"></span></button>
|
|
63
|
+
<span class="bex-sep"></span>
|
|
64
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="cut" title="Cut (Ctrl+X)" aria-label="Cut"><span data-icon="scissors" data-icon-size="14"></span></button>
|
|
65
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="copy" title="Copy (Ctrl+C)" aria-label="Copy"><span data-icon="copy" data-icon-size="14"></span></button>
|
|
66
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="paste" title="Paste (Ctrl+V)" aria-label="Paste"><span data-icon="clipboard" data-icon-size="14"></span></button>
|
|
67
|
+
<span class="bex-sep"></span>
|
|
68
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="select-all" title="Select all (Ctrl+A)" aria-label="Select all"><span data-icon="maximize-2" data-icon-size="14"></span></button>
|
|
69
|
+
<button type="button" class="btn btn-ghost btn-sm" data-action="format" title="Indent the HTML by nesting"><span data-icon="code" data-icon-size="14"></span> Format</button>
|
|
70
|
+
<span class="bex-spacer"></span>
|
|
71
|
+
<small class="bex-cursor" data-bind-text="cursor.value"></small>
|
|
72
|
+
<div class="bex-seg" role="group" aria-label="Show">
|
|
73
|
+
<button type="button" data-on-click="setWrite" data-bind-class="mode.value === 'write' && 'is-on'" title="Template only">Edit</button>
|
|
74
|
+
<button type="button" data-on-click="setSplit" data-bind-class="mode.value === 'split' && 'is-on'" title="Template and preview">Split</button>
|
|
75
|
+
<button type="button" data-on-click="setPreview" data-bind-class="mode.value === 'preview' && 'is-on'" title="Preview only">Preview</button>
|
|
103
76
|
</div>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
background:var(--dm-background-alt,rgba(0,0,0,.1));
|
|
114
|
-
flex-shrink:0;">
|
|
115
|
-
<p class="text-muted" style="font-size:.8rem;margin:0;">
|
|
116
|
-
Write some template HTML to populate sample data fields.
|
|
117
|
-
</p>
|
|
77
|
+
</div>
|
|
78
|
+
<div id="block-editor-body" data-bind-class="modeCls.value">
|
|
79
|
+
<div class="bex-pane bex-write"></div>
|
|
80
|
+
<div class="bex-pane bex-preview">
|
|
81
|
+
<div class="bex-samples-wrap">
|
|
82
|
+
<div class="bex-samples-title">Sample values
|
|
83
|
+
<span data-help-title="Sample values" data-help="One per placeholder the template uses, so the preview shows something real. They are only for the preview - nothing here is saved. Right-click one (or ⋮, or Shift+F10) to insert its placeholder, copy it or reset the sample."></span></div>
|
|
84
|
+
<p class="bex-note" data-bind-hidden="!noSamples.value" data-bind-text="noSamplesText"></p>
|
|
85
|
+
<div class="bex-samples" data-each="sampleRows.value key=key"></div>
|
|
118
86
|
</div>
|
|
119
|
-
|
|
120
|
-
<div id="block-preview-output" style="flex:1;overflow-y:auto;padding:1rem;"></div>
|
|
87
|
+
<div id="block-preview-output" class="bex-output" aria-label="Preview"></div>
|
|
121
88
|
</div>
|
|
122
|
-
|
|
123
89
|
</div>
|
|
124
90
|
</div>
|
|
125
|
-
</div>
|
|
126
91
|
|
|
127
|
-
<!-- Custom CSS -->
|
|
128
|
-
<div class="card
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<
|
|
135
|
-
Your CSS is automatically scoped to
|
|
136
|
-
<code class="dm-code-inline" id="block-css-scope-hint" style="font-size:.9em;">[data-block="…"]</code>.
|
|
137
|
-
Use CSS nesting for child rules.
|
|
138
|
-
<strong>Note:</strong>
|
|
139
|
-
<code class="dm-code-inline" style="font-size:.9em;">@keyframes</code>,
|
|
140
|
-
<code class="dm-code-inline" style="font-size:.9em;">@font-face</code>, and
|
|
141
|
-
<code class="dm-code-inline" style="font-size:.9em;">@import</code>
|
|
142
|
-
cannot be scoped - use site-wide Custom CSS in Settings for those.
|
|
143
|
-
</p>
|
|
144
|
-
<textarea id="block-css"
|
|
145
|
-
class="editor-textarea"
|
|
146
|
-
spellcheck="false"
|
|
147
|
-
style="font-family:var(--dm-font-mono,monospace);min-height:240px;width:100%;"
|
|
148
|
-
placeholder="/* Example:
|
|
149
|
-
color: var(--dm-primary);
|
|
150
|
-
h2 { font-size: 1.5rem; }
|
|
151
|
-
.highlight { background: yellow; } */"></textarea>
|
|
92
|
+
<!-- Custom CSS -->
|
|
93
|
+
<div class="bex-card">
|
|
94
|
+
<div class="bex-card-title">Custom CSS
|
|
95
|
+
<span data-help-title="Custom CSS" data-help="Scoped to this block automatically - the rules below are wrapped in [data-block="name"] { … }, so use nesting for child rules. @keyframes, @font-face and @import cannot be scoped: put those in Site Settings › Custom CSS. Up to 50 KB."></span>
|
|
96
|
+
</div>
|
|
97
|
+
<p class="bex-note">Scoped to <code class="dm-code-inline" id="block-css-scope-hint" data-bind-text="scopeHint.value"></code>.</p>
|
|
98
|
+
<div class="bex-css"></div>
|
|
99
|
+
<small class="bex-err" data-bind-hidden="!cssErr.value" data-bind-text="cssErr.value"></small>
|
|
152
100
|
</div>
|
|
101
|
+
|
|
153
102
|
</div>
|
|
154
103
|
|
|
155
|
-
<!--
|
|
156
|
-
|
|
157
|
-
<
|
|
158
|
-
<
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
</
|
|
177
|
-
<
|
|
178
|
-
<
|
|
179
|
-
<
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
<
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
<
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
applies moment-style date formatting when the value parses as a date.
|
|
193
|
-
E.g. <code class="dm-code-inline">{{_createdAt:DD MMM YYYY}}</code> →
|
|
194
|
-
<em>05 Jan 2026</em>, or
|
|
195
|
-
<code class="dm-code-inline">{{_createdAt:HH:mm}}</code> →
|
|
196
|
-
<em>14:30</em>.
|
|
197
|
-
</td>
|
|
198
|
-
</tr>
|
|
199
|
-
</tbody>
|
|
200
|
-
</table>
|
|
201
|
-
<p style="margin-top:.5rem;"><strong>Format tokens:</strong>
|
|
202
|
-
<code class="dm-code-inline">YYYY</code> <code class="dm-code-inline">YY</code>
|
|
203
|
-
<code class="dm-code-inline">MMMM</code> <code class="dm-code-inline">MMM</code>
|
|
204
|
-
<code class="dm-code-inline">MM</code> <code class="dm-code-inline">M</code>
|
|
205
|
-
<code class="dm-code-inline">DD</code> <code class="dm-code-inline">D</code>
|
|
206
|
-
<code class="dm-code-inline">dddd</code> <code class="dm-code-inline">ddd</code>
|
|
207
|
-
<code class="dm-code-inline">HH</code> <code class="dm-code-inline">H</code>
|
|
208
|
-
<code class="dm-code-inline">hh</code> <code class="dm-code-inline">h</code>
|
|
209
|
-
<code class="dm-code-inline">mm</code> <code class="dm-code-inline">m</code>
|
|
210
|
-
<code class="dm-code-inline">ss</code> <code class="dm-code-inline">s</code>
|
|
211
|
-
<code class="dm-code-inline">A</code> <code class="dm-code-inline">a</code>
|
|
212
|
-
- any literal character that isn't one of these tokens passes through unchanged
|
|
213
|
-
(so <code class="dm-code-inline">DD/MM/YYYY</code>, <code class="dm-code-inline">HH:mm</code>,
|
|
214
|
-
and <code class="dm-code-inline">dddd D MMMM YYYY</code> all work).
|
|
215
|
-
</p>
|
|
216
|
-
<p><strong>Use in a shortcode:</strong></p>
|
|
217
|
-
<pre class="dm-code-block">[collection slug="feedback" display="block" block="feedback-card" /]
|
|
104
|
+
<!-- Outside the bound root (.bex): the reference is full of literal placeholders, which the binder would flag as un-interpolated. -->
|
|
105
|
+
<!-- Placeholder reference -->
|
|
106
|
+
<details class="bex-card bex-ref">
|
|
107
|
+
<summary class="bex-card-title">Placeholder reference</summary>
|
|
108
|
+
<div class="bex-ref-body">
|
|
109
|
+
<p>Use <code class="dm-code-inline">{{fieldName}}</code> to insert entry field values. Values are HTML-escaped
|
|
110
|
+
automatically to prevent XSS.</p>
|
|
111
|
+
<table class="table bex-ref-table">
|
|
112
|
+
<thead><tr><th>Placeholder</th><th>Value</th></tr></thead>
|
|
113
|
+
<tbody>
|
|
114
|
+
<tr><td><code class="dm-code-inline">{{fieldName}}</code></td>
|
|
115
|
+
<td>Any entry field - e.g. <code class="dm-code-inline">{{title}}</code>, <code class="dm-code-inline">{{rating}}</code>,
|
|
116
|
+
<code class="dm-code-inline">{{message}}</code></td></tr>
|
|
117
|
+
<tr><td><code class="dm-code-inline">{{_id}}</code></td><td>Entry UUID</td></tr>
|
|
118
|
+
<tr><td><code class="dm-code-inline">{{_createdAt}}</code></td><td>Creation timestamp (ISO 8601 by default)</td></tr>
|
|
119
|
+
<tr><td><code class="dm-code-inline">{{_updatedAt}}</code></td><td>Last-updated timestamp (ISO 8601 by default)</td></tr>
|
|
120
|
+
<tr><td><code class="dm-code-inline">{{field:FORMAT}}</code></td>
|
|
121
|
+
<td>Any placeholder with a <code class="dm-code-inline">:FORMAT</code> suffix applies moment-style date formatting when
|
|
122
|
+
the value parses as a date. E.g. <code class="dm-code-inline">{{_createdAt:DD MMM YYYY}}</code> →
|
|
123
|
+
<em>05 Jan 2026</em>, or <code class="dm-code-inline">{{_createdAt:HH:mm}}</code> → <em>14:30</em>.</td></tr>
|
|
124
|
+
</tbody>
|
|
125
|
+
</table>
|
|
126
|
+
<p><strong>Format tokens:</strong>
|
|
127
|
+
<code class="dm-code-inline">YYYY</code> <code class="dm-code-inline">YY</code>
|
|
128
|
+
<code class="dm-code-inline">MMMM</code> <code class="dm-code-inline">MMM</code>
|
|
129
|
+
<code class="dm-code-inline">MM</code> <code class="dm-code-inline">M</code>
|
|
130
|
+
<code class="dm-code-inline">DD</code> <code class="dm-code-inline">D</code>
|
|
131
|
+
<code class="dm-code-inline">dddd</code> <code class="dm-code-inline">ddd</code>
|
|
132
|
+
<code class="dm-code-inline">HH</code> <code class="dm-code-inline">H</code>
|
|
133
|
+
<code class="dm-code-inline">hh</code> <code class="dm-code-inline">h</code>
|
|
134
|
+
<code class="dm-code-inline">mm</code> <code class="dm-code-inline">m</code>
|
|
135
|
+
<code class="dm-code-inline">ss</code> <code class="dm-code-inline">s</code>
|
|
136
|
+
<code class="dm-code-inline">A</code> <code class="dm-code-inline">a</code>
|
|
137
|
+
- any other character passes through unchanged (so <code class="dm-code-inline">DD/MM/YYYY</code>,
|
|
138
|
+
<code class="dm-code-inline">HH:mm</code> and <code class="dm-code-inline">dddd D MMMM YYYY</code> all work).</p>
|
|
139
|
+
<p><strong>Use in a shortcode:</strong></p>
|
|
140
|
+
<pre class="dm-code-block">[collection slug="feedback" display="block" block="feedback-card" /]
|
|
218
141
|
[view slug="my-view" display="block" block="feedback-card" /]</pre>
|
|
219
|
-
|
|
220
|
-
|
|
142
|
+
<p><strong>Example block template:</strong></p>
|
|
143
|
+
<pre class="dm-code-block"><div class="card mb-3">
|
|
221
144
|
<div class="card-body">
|
|
222
145
|
<h3>{{name}}</h3>
|
|
223
146
|
<p>{{message}}</p>
|
|
224
147
|
<small>Rating: {{rating}} &mdash; {{_createdAt}}</small>
|
|
225
148
|
</div>
|
|
226
149
|
</div></pre>
|
|
227
|
-
|
|
150
|
+
</div>
|
|
151
|
+
</details>
|
|
228
152
|
</div>
|
|
153
|
+
<style>
|
|
154
|
+
.bex-page { display: flex; flex-direction: column; gap: .75rem; }
|
|
155
|
+
.bex { display: flex; flex-direction: column; gap: .75rem; }
|
|
156
|
+
.bex [hidden] { display: none !important; }
|
|
157
|
+
.bex-bar { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
|
|
158
|
+
.bex-ident { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; min-width: 0; }
|
|
159
|
+
.bex-ident strong { font-family: var(--dm-font-mono, monospace); }
|
|
160
|
+
.bex-ident small, .bex-note, .bex-cursor { color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
161
|
+
.bex-note { margin: 0; }
|
|
162
|
+
.bex-cursor { font-size: var(--dm-text-xs); font-variant-numeric: tabular-nums; }
|
|
163
|
+
.bex-spacer { flex: 1; }
|
|
164
|
+
.bex-switch { width: auto; max-width: 16rem; }
|
|
165
|
+
.bex-chip { display: inline-flex; align-items: center; font-size: var(--dm-text-xs); font-weight: 600; padding: .1rem .5rem; border-radius: 999px; white-space: nowrap;
|
|
166
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
167
|
+
.bex-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
168
|
+
.bex-unsaved { display: flex; align-items: center; gap: .5rem; padding: .5rem .75rem; border-radius: var(--dm-radius-md);
|
|
169
|
+
background: color-mix(in srgb, var(--dm-warning) 12%, transparent); border: 1px solid color-mix(in srgb, var(--dm-warning) 35%, transparent);
|
|
170
|
+
position: sticky; top: 0; z-index: 5; }
|
|
171
|
+
.bex-unsaved .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
172
|
+
.bex-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .6rem;
|
|
173
|
+
background: var(--dm-surface); }
|
|
174
|
+
.bex-card-title { display: flex; align-items: center; gap: .3rem; font-weight: 600; }
|
|
175
|
+
.bex-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr); gap: .85rem; align-items: start; }
|
|
176
|
+
.bex-grid .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
177
|
+
.bex-setting { display: flex; flex-direction: column; gap: .35rem; }
|
|
178
|
+
.bex-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
179
|
+
.bex-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem; padding-bottom: .5rem; border-bottom: 1px solid var(--dm-border); }
|
|
180
|
+
.bex-toolbar .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
181
|
+
.bex-sep { width: 1px; align-self: stretch; margin: .2rem .3rem; background: var(--dm-border); }
|
|
182
|
+
.bex-seg { display: inline-flex; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; margin-left: .5rem; }
|
|
183
|
+
.bex-seg button { border: 0; background: none; color: var(--dm-text); padding: .25rem .65rem; cursor: pointer; font: inherit; font-size: var(--dm-text-sm); }
|
|
184
|
+
.bex-seg button + button { border-left: 1px solid var(--dm-border); }
|
|
185
|
+
.bex-seg button:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); }
|
|
186
|
+
.bex-seg button.is-on { background: var(--dm-primary); color: var(--dm-primary-text); }
|
|
187
|
+
.bex-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0; height: min(70vh, 820px); min-height: 460px;
|
|
188
|
+
border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; }
|
|
189
|
+
.bex-body.is-write { grid-template-columns: minmax(0, 1fr); }
|
|
190
|
+
.bex-body.is-write .bex-preview { display: none; }
|
|
191
|
+
.bex-body.is-preview { grid-template-columns: minmax(0, 1fr); }
|
|
192
|
+
.bex-body.is-preview .bex-write { display: none; }
|
|
193
|
+
.bex-pane { min-width: 0; min-height: 0; overflow: hidden; }
|
|
194
|
+
.bex-write { border-right: 1px solid var(--dm-border); }
|
|
195
|
+
.bex-body.is-write .bex-write { border-right: 0; }
|
|
196
|
+
.bex-preview { display: flex; flex-direction: column; }
|
|
197
|
+
.bex-samples-wrap { flex-shrink: 0; max-height: 40%; overflow-y: auto; padding: .6rem .75rem; border-bottom: 1px solid var(--dm-border);
|
|
198
|
+
background: var(--dm-surface-raised, color-mix(in srgb, var(--dm-text) 4%, transparent)); display: flex; flex-direction: column; gap: .4rem; }
|
|
199
|
+
.bex-samples-title { display: flex; align-items: center; gap: .3rem; font-size: var(--dm-text-sm); font-weight: 600; }
|
|
200
|
+
.bex-samples { display: flex; flex-direction: column; gap: .3rem; }
|
|
201
|
+
.bex-sample { display: flex; align-items: center; gap: .5rem; border-radius: var(--dm-radius-sm); }
|
|
202
|
+
.bex-sample:focus-visible { outline: 2px solid var(--dm-primary); outline-offset: 1px; }
|
|
203
|
+
.bex-sample-label { font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-xs); color: var(--dm-text-muted); flex: 0 0 9.5rem; text-align: right;
|
|
204
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
205
|
+
.bex-sample input { flex: 1; min-width: 0; }
|
|
206
|
+
.bex-kebab { border: 0; background: none; cursor: pointer; font-size: var(--dm-text-lg); color: var(--dm-text-muted); border-radius: var(--dm-radius-sm); padding: 0 .3rem; }
|
|
207
|
+
.bex-kebab:hover { color: var(--dm-primary); }
|
|
208
|
+
.bex-output { flex: 1; overflow-y: auto; padding: 1rem; background: var(--dm-background, var(--dm-surface)); }
|
|
209
|
+
.bex-css { height: 260px; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; }
|
|
210
|
+
.bex-ref summary { cursor: pointer; list-style: revert; }
|
|
211
|
+
.bex-ref-body { font-size: var(--dm-text-sm); line-height: 1.7; }
|
|
212
|
+
.bex-ref-table { max-width: 40rem; margin: .5rem 0; }
|
|
213
|
+
@media (max-width: 900px) {
|
|
214
|
+
.bex-grid { grid-template-columns: 1fr; }
|
|
215
|
+
.bex-body, .bex-body.is-split { grid-template-columns: minmax(0, 1fr); height: auto; }
|
|
216
|
+
.bex-body .bex-write { height: 55vh; border-right: 0; border-bottom: 1px solid var(--dm-border); }
|
|
217
|
+
.bex-body .bex-preview { min-height: 40vh; }
|
|
218
|
+
}
|
|
219
|
+
</style>
|