domma-cms 0.76.0 → 0.77.1
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,112 +1,123 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</
|
|
1
|
+
<!-- Context menu editor. Bound with M.applyBindings - see admin/js/views/context-menu-editor.js, which also
|
|
2
|
+
inserts the Items row template (the router renders a templateUrl through _.render, eating any {{…}}).
|
|
3
|
+
No page heading or Back button: the Tool banner carries the name ("Context Menus › <menu>"), Save and
|
|
4
|
+
"All context menus". -->
|
|
5
|
+
<div class="cmx">
|
|
6
|
+
<p class="cmx-intro">
|
|
7
|
+
A context menu is not placed on a page the way a nav menu is. It attaches to a <strong>region</strong>
|
|
8
|
+
and opens when someone right-clicks inside it. So there are two questions to answer: which region, and
|
|
9
|
+
what the menu offers. Everything else has a sensible default.
|
|
10
|
+
<span data-help-title="Nested menus" data-help="Menus can sit inside one another. A right-click picks the INNERMOST menu covering the spot clicked, never the one that happened to load first. A menu that does not apply to a page is not sent to that page at all."></span>
|
|
11
|
+
</p>
|
|
8
12
|
|
|
9
|
-
<div
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
and opens when someone right-clicks inside it. So there are two questions to answer: which region, and
|
|
14
|
-
what the menu offers. Everything else has a sensible default.
|
|
15
|
-
</p>
|
|
13
|
+
<div class="cmx-alert is-bad" data-bind-hidden="!serverError.value">
|
|
14
|
+
<strong>Not saved.</strong>
|
|
15
|
+
<div class="cmx-server-errors" data-each="serverErrors.value key=key"></div>
|
|
16
|
+
</div>
|
|
16
17
|
|
|
17
|
-
<div class="
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
<button class="
|
|
22
|
-
<button class="
|
|
23
|
-
|
|
24
|
-
<button class="tab-item">Scope</button>
|
|
18
|
+
<div class="cmx-unsaved" data-bind-hidden="!dirty.value">
|
|
19
|
+
<span class="cmx-dot" aria-hidden="true"></span>
|
|
20
|
+
<span>Unsaved changes<span data-bind-text="problemText.value"></span></span>
|
|
21
|
+
<span class="cmx-spacer"></span>
|
|
22
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard" data-bind-hidden="isNew">Discard</button>
|
|
23
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="saving.value">
|
|
24
|
+
<span data-icon="save" data-icon-size="13"></span> <span data-bind-text="saveText.value">Save</span></button>
|
|
25
25
|
</div>
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<div class="
|
|
30
|
-
<div class="
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
<div class="row ctx-workspace">
|
|
28
|
+
<div class="col-8">
|
|
29
|
+
<div class="tabs cmx-tabs" id="ctx-tabs">
|
|
30
|
+
<div class="tab-list">
|
|
31
|
+
<button type="button" class="tab-item active">Binding <span class="cmx-tab-dot" data-bind-hidden="!tabBad.value.binding" title="Something here needs fixing"></span></button>
|
|
32
|
+
<button type="button" class="tab-item">Items <span class="cmx-count" data-bind-text="items.value.length"></span> <span class="cmx-tab-dot" data-bind-hidden="!tabBad.value.items" title="Something here needs fixing"></span></button>
|
|
33
|
+
<button type="button" class="tab-item">Appearance <span class="cmx-tab-dot" data-bind-hidden="!tabBad.value.appearance" title="Something here needs fixing"></span></button>
|
|
34
|
+
<button type="button" class="tab-item">Scope</button>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<!-- Binding -->
|
|
38
|
+
<div class="tab-panel active">
|
|
39
|
+
<div class="cmx-card">
|
|
40
|
+
<div class="cmx-card-title">Where it binds</div>
|
|
41
|
+
<div class="cmx-grid">
|
|
42
|
+
<div>
|
|
43
|
+
<label class="form-label" for="ctx-name">Name <span class="text-danger">*</span>
|
|
44
|
+
<span data-help="Your label for this menu in the admin list. Visitors never see it."></span></label>
|
|
45
|
+
<input class="form-input" id="ctx-name" type="text" maxlength="80" placeholder="Entry actions" data-model="name.value">
|
|
46
|
+
<small class="cmx-err" data-bind-hidden="!err.value.name" data-bind-text="err.value.name"></small>
|
|
37
47
|
</div>
|
|
38
|
-
<div
|
|
39
|
-
<label class="form-label" for="ctx-slug">Slug
|
|
40
|
-
|
|
41
|
-
<
|
|
48
|
+
<div>
|
|
49
|
+
<label class="form-label" for="ctx-slug">Slug
|
|
50
|
+
<span data-help="The filename this menu is saved as. Made from the name as you type; fixed once created, because the file is the record."></span></label>
|
|
51
|
+
<input class="form-input font-mono" id="ctx-slug" type="text" maxlength="64" placeholder="entry-actions" data-model="slug.value" data-bind-disabled="notNew">
|
|
52
|
+
<small class="cmx-err" data-bind-hidden="!err.value.slug" data-bind-text="err.value.slug"></small>
|
|
53
|
+
<small class="cmx-hint" data-bind-hidden="!notNew">Fixed - it is the file's name.</small>
|
|
42
54
|
</div>
|
|
43
|
-
<div class="
|
|
44
|
-
<label class="form-label" for="ctx-selector">Container selector<
|
|
45
|
-
|
|
46
|
-
<
|
|
55
|
+
<div class="cmx-wide">
|
|
56
|
+
<label class="form-label" for="ctx-selector">Container selector <span class="text-danger">*</span>
|
|
57
|
+
<span data-help-title="Container selector" data-help="A CSS selector for the region, e.g. #product-grid, .entry-card or main. Right-clicks anywhere inside it are offered to this menu. body, html, * and :root are refused, because they would swallow every other menu on the page."></span></label>
|
|
58
|
+
<input class="form-input font-mono" id="ctx-selector" type="text" placeholder="#product-grid" data-model="selector.value">
|
|
59
|
+
<small class="cmx-err" data-bind-hidden="!err.value.selector" data-bind-text="err.value.selector"></small>
|
|
47
60
|
</div>
|
|
48
|
-
<div
|
|
49
|
-
<label class="form-label" for="ctx-match">Match
|
|
50
|
-
|
|
51
|
-
<
|
|
61
|
+
<div>
|
|
62
|
+
<label class="form-label" for="ctx-match">Match <small class="cmx-hint-inline">(optional)</small>
|
|
63
|
+
<span data-help="Narrows it: only claim the click when it landed on something matching this, e.g. [data-entry-id] to answer on rows but not the space between them. Blank means the whole container."></span></label>
|
|
64
|
+
<input class="form-input font-mono" id="ctx-match" type="text" placeholder="[data-entry-id]" data-model="match.value">
|
|
52
65
|
</div>
|
|
53
|
-
<div
|
|
54
|
-
<label class="form-label" for="ctx-exclude">Exclude
|
|
55
|
-
|
|
56
|
-
<
|
|
66
|
+
<div>
|
|
67
|
+
<label class="form-label" for="ctx-exclude">Exclude <small class="cmx-hint-inline">(optional)</small>
|
|
68
|
+
<span data-help="Holes in the region. A right-click on one of these falls through to whatever encloses it - useful for links and inputs, where the browser's own menu is more use."></span></label>
|
|
69
|
+
<input class="form-input font-mono" id="ctx-exclude" type="text" placeholder="a, button, input" data-model="exclude.value">
|
|
57
70
|
</div>
|
|
58
71
|
</div>
|
|
59
72
|
</div>
|
|
60
|
-
</div>
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<div class="
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<select class="form-select" id="ctx-inherit">
|
|
74
|
+
<div class="cmx-card">
|
|
75
|
+
<div class="cmx-card-title">Behaviour</div>
|
|
76
|
+
<div class="cmx-grid">
|
|
77
|
+
<div class="cmx-wide">
|
|
78
|
+
<label class="form-label" for="ctx-inherit">When nested inside another menu
|
|
79
|
+
<span data-help="Show my items, then theirs puts the outer menu's items after yours; the reverse puts them before; Show only my items hides the outer menu's."></span></label>
|
|
80
|
+
<select class="form-select" id="ctx-inherit" data-model="inherit.value">
|
|
69
81
|
<option value="append">Show my items, then theirs (default)</option>
|
|
70
82
|
<option value="prepend">Show their items, then mine</option>
|
|
71
83
|
<option value="false">Show only my items</option>
|
|
72
84
|
</select>
|
|
73
85
|
</div>
|
|
74
|
-
<div class="
|
|
75
|
-
<label class="form-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
<small class="text-muted">Turn this off to park a menu without deleting it. A disabled menu is never sent to the browser.</small>
|
|
86
|
+
<div class="cmx-setting cmx-wide">
|
|
87
|
+
<label class="form-label" for="ctx-enabled">Enabled
|
|
88
|
+
<span data-help="Off parks a menu without deleting it. A disabled menu is never sent to the browser."></span></label>
|
|
89
|
+
<input type="checkbox" class="form-switch" id="ctx-enabled" data-model="enabled.value">
|
|
79
90
|
</div>
|
|
80
91
|
</div>
|
|
81
92
|
</div>
|
|
82
93
|
</div>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
<!-- Items -->
|
|
96
|
+
<div class="tab-panel">
|
|
97
|
+
<div class="cmx-card">
|
|
98
|
+
<div class="cmx-card-title">Items
|
|
99
|
+
<span data-help-title="Items" data-help="What the menu offers when it opens, top to bottom. An Item does something when clicked, a Divider draws a line, a Heading labels a group. Click an item to edit it; right-click it (or ⋮, or Shift+F10) to move, duplicate, add beside it or remove it. Alt+↑ / Alt+↓ move the focused item. A menu of nothing but dividers and headings is refused, because there would be nothing to click."></span>
|
|
100
|
+
<span class="cmx-spacer"></span>
|
|
101
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="addHeader"><span data-icon="type" data-icon-size="13"></span> Heading</button>
|
|
102
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="addDivider"><span data-icon="minus" data-icon-size="13"></span> Divider</button>
|
|
103
|
+
<button type="button" class="btn btn-sm btn-secondary" id="ctx-add-item" data-on-click="addItem"><span data-icon="plus" data-icon-size="13"></span> Add item</button>
|
|
104
|
+
</div>
|
|
105
|
+
<p class="cmx-note" data-bind-hidden="items.value.length">No items yet. Every menu needs at least one.</p>
|
|
106
|
+
<p class="cmx-err" data-bind-hidden="!err.value.items" data-bind-text="err.value.items"></p>
|
|
107
|
+
<div class="cmx-list" id="ctx-items" data-each="rows.value key=key"></div>
|
|
108
|
+
</div>
|
|
96
109
|
</div>
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
99
110
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<select class="form-select" id="ctx-accent">
|
|
111
|
+
<!-- Appearance -->
|
|
112
|
+
<div class="tab-panel">
|
|
113
|
+
<div class="cmx-card">
|
|
114
|
+
<div class="cmx-card-title">Appearance
|
|
115
|
+
<span data-help="How the panel looks when it opens. Leave anything on its default to inherit the site theme - usually what you want, so the menu matches everything around it."></span></div>
|
|
116
|
+
<div class="cmx-grid">
|
|
117
|
+
<div>
|
|
118
|
+
<label class="form-label" for="ctx-accent">Accent
|
|
119
|
+
<span data-help="Tints the border and the hover wash. Labels keep the theme's text colour so they stay readable."></span></label>
|
|
120
|
+
<select class="form-select" id="ctx-accent" data-model="accent.value">
|
|
110
121
|
<option value="">Theme default</option>
|
|
111
122
|
<option value="primary">Primary</option>
|
|
112
123
|
<option value="success">Success</option>
|
|
@@ -114,29 +125,11 @@
|
|
|
114
125
|
<option value="warning">Warning</option>
|
|
115
126
|
<option value="info">Info</option>
|
|
116
127
|
</select>
|
|
117
|
-
<small class="
|
|
118
|
-
</div>
|
|
119
|
-
<div class="form-group">
|
|
120
|
-
<label class="form-label" for="ctx-transition">Transition</label>
|
|
121
|
-
<select class="form-select" id="ctx-transition">
|
|
122
|
-
<option value="">Default (scale)</option>
|
|
123
|
-
<option value="fade">Fade</option>
|
|
124
|
-
<option value="slide">Slide</option>
|
|
125
|
-
<option value="none">None</option>
|
|
126
|
-
</select>
|
|
128
|
+
<small class="cmx-err" data-bind-hidden="!err.value.accent" data-bind-text="err.value.accent"></small>
|
|
127
129
|
</div>
|
|
128
|
-
<div
|
|
129
|
-
<label class="form-label" for="ctx-density">Density</label>
|
|
130
|
-
<select class="form-select" id="ctx-density">
|
|
131
|
-
<option value="">Comfortable</option>
|
|
132
|
-
<option value="compact">Compact</option>
|
|
133
|
-
</select>
|
|
134
|
-
</div>
|
|
135
|
-
</div>
|
|
136
|
-
<div class="col-6">
|
|
137
|
-
<div class="form-group">
|
|
130
|
+
<div>
|
|
138
131
|
<label class="form-label" for="ctx-radius">Corner radius</label>
|
|
139
|
-
<select class="form-select" id="ctx-radius">
|
|
132
|
+
<select class="form-select" id="ctx-radius" data-model="radius.value">
|
|
140
133
|
<option value="">Default</option>
|
|
141
134
|
<option value="none">Square</option>
|
|
142
135
|
<option value="sm">Small</option>
|
|
@@ -145,9 +138,18 @@
|
|
|
145
138
|
<option value="xl">Extra large</option>
|
|
146
139
|
</select>
|
|
147
140
|
</div>
|
|
148
|
-
<div
|
|
141
|
+
<div>
|
|
142
|
+
<label class="form-label" for="ctx-transition">Transition</label>
|
|
143
|
+
<select class="form-select" id="ctx-transition" data-model="transition.value">
|
|
144
|
+
<option value="">Default (scale)</option>
|
|
145
|
+
<option value="fade">Fade</option>
|
|
146
|
+
<option value="slide">Slide</option>
|
|
147
|
+
<option value="none">None</option>
|
|
148
|
+
</select>
|
|
149
|
+
</div>
|
|
150
|
+
<div>
|
|
149
151
|
<label class="form-label" for="ctx-shadow">Shadow</label>
|
|
150
|
-
<select class="form-select" id="ctx-shadow">
|
|
152
|
+
<select class="form-select" id="ctx-shadow" data-model="shadow.value">
|
|
151
153
|
<option value="">Default</option>
|
|
152
154
|
<option value="none">None</option>
|
|
153
155
|
<option value="sm">Small</option>
|
|
@@ -156,57 +158,115 @@
|
|
|
156
158
|
<option value="xl">Extra large</option>
|
|
157
159
|
</select>
|
|
158
160
|
</div>
|
|
159
|
-
<div
|
|
160
|
-
<label class="form-label" for="ctx-
|
|
161
|
-
<
|
|
162
|
-
|
|
161
|
+
<div>
|
|
162
|
+
<label class="form-label" for="ctx-density">Density</label>
|
|
163
|
+
<select class="form-select" id="ctx-density" data-model="density.value">
|
|
164
|
+
<option value="">Comfortable</option>
|
|
165
|
+
<option value="compact">Compact</option>
|
|
166
|
+
</select>
|
|
167
|
+
</div>
|
|
168
|
+
<div>
|
|
169
|
+
<label class="form-label" for="ctx-opacity">Opacity
|
|
170
|
+
<span data-help="Below 100 the panel lets the page show through, with a blurred backdrop; text stays fully opaque. Much under 80 gets hard to read over busy content."></span></label>
|
|
171
|
+
<input class="form-input" id="ctx-opacity" type="number" min="20" max="100" placeholder="100" data-model="opacity.value">
|
|
172
|
+
<small class="cmx-err" data-bind-hidden="!err.value.opacity" data-bind-text="err.value.opacity"></small>
|
|
163
173
|
</div>
|
|
164
174
|
</div>
|
|
165
175
|
</div>
|
|
166
176
|
</div>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
177
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
<input class="form-input" id="ctx-pages" type="text" placeholder="/shop/*, /about">
|
|
180
|
-
<small class="text-muted">Comma separated. Supports a trailing <code>/*</code>. Leave empty for site-wide.</small>
|
|
178
|
+
<!-- Scope -->
|
|
179
|
+
<div class="tab-panel">
|
|
180
|
+
<div class="cmx-card">
|
|
181
|
+
<div class="cmx-card-title">Scope
|
|
182
|
+
<span data-help="Which pages carry this menu. Leave BOTH blank and it applies site-wide. A menu that does not apply to a page is not sent to that page at all."></span></div>
|
|
183
|
+
<div class="cmx-grid">
|
|
184
|
+
<div>
|
|
185
|
+
<label class="form-label" for="ctx-pages">Pages
|
|
186
|
+
<span data-help="Comma separated URL paths. A trailing /* covers everything under it, so /shop/* covers the whole shop. Blank means every page."></span></label>
|
|
187
|
+
<input class="form-input font-mono" id="ctx-pages" type="text" placeholder="/shop/*, /about" data-model="pages.value">
|
|
181
188
|
</div>
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
<
|
|
186
|
-
<input class="form-input" id="ctx-projects" type="text" placeholder="core, shop">
|
|
187
|
-
<small class="text-muted">Comma separated project slugs.</small>
|
|
189
|
+
<div>
|
|
190
|
+
<label class="form-label" for="ctx-projects">Projects
|
|
191
|
+
<span data-help="Comma separated project slugs. The menu then applies only to pages belonging to those projects."></span></label>
|
|
192
|
+
<input class="form-input font-mono" id="ctx-projects" type="text" placeholder="core, shop" data-model="projects.value">
|
|
188
193
|
</div>
|
|
189
194
|
</div>
|
|
195
|
+
<p class="cmx-note" data-bind-text="scopeText.value"></p>
|
|
190
196
|
</div>
|
|
191
197
|
</div>
|
|
192
198
|
</div>
|
|
193
|
-
|
|
194
|
-
</div>
|
|
195
|
-
|
|
196
|
-
</div><!-- /col-8 -->
|
|
199
|
+
</div><!-- /col-8 -->
|
|
197
200
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
<!-- One preview, beside the tabs rather than inside them: four copies would be four elements sharing
|
|
202
|
+
#ctx-preview, and the menu binds by selector. Sticky, so it stays put while a long Items tab scrolls. -->
|
|
203
|
+
<div class="col-4">
|
|
204
|
+
<div class="cmx-card ctx-preview-card">
|
|
205
|
+
<div class="cmx-card-title">Try it
|
|
206
|
+
<span data-help="The real menu, built from what you have entered and updating as you type - the component itself, not a drawing of it. Its actions do nothing here."></span></div>
|
|
207
|
+
<div class="cmx-chips" data-each="chips.value key=text"></div>
|
|
208
|
+
<div id="ctx-preview" class="cmx-preview" tabindex="0">
|
|
209
|
+
<span data-bind-text="previewText.value">Right-click to preview</span>
|
|
210
|
+
</div>
|
|
208
211
|
</div>
|
|
209
212
|
</div>
|
|
210
|
-
</div
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
</div><!-- /ctx-workspace -->
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<style>
|
|
217
|
+
.cmx { display: flex; flex-direction: column; gap: .75rem; }
|
|
218
|
+
.cmx [hidden], .cmx-form [hidden] { display: none !important; }
|
|
219
|
+
.cmx-intro { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
220
|
+
.cmx-alert { margin: 0; padding: .6rem .8rem; border-radius: var(--dm-radius-md); background: color-mix(in srgb, var(--dm-danger) 12%, transparent); color: var(--dm-text); border: 1px solid color-mix(in srgb, var(--dm-danger) 35%, transparent); }
|
|
221
|
+
.cmx-alert small, .cmx-server-errors div { display: block; font-size: var(--dm-text-sm); }
|
|
222
|
+
.cmx-unsaved { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: .5rem; padding: .45rem .75rem; border-radius: var(--dm-radius-md);
|
|
223
|
+
background: color-mix(in srgb, var(--dm-warning) 14%, var(--dm-surface)); border: 1px solid color-mix(in srgb, var(--dm-warning) 40%, transparent); color: var(--dm-text); font-size: var(--dm-text-sm); }
|
|
224
|
+
.cmx-unsaved .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
225
|
+
.cmx-dot { width: .55rem; height: .55rem; border-radius: 50%; background: var(--dm-warning); flex-shrink: 0; }
|
|
226
|
+
.cmx-spacer { flex: 1; }
|
|
227
|
+
.cmx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .7rem; margin-top: .75rem; background: var(--dm-surface); }
|
|
228
|
+
.cmx-card-title { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
|
|
229
|
+
.cmx-card-title .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
230
|
+
.cmx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
|
|
231
|
+
.cmx-wide { grid-column: 1 / -1; }
|
|
232
|
+
.cmx .form-label, .cmx-form .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
233
|
+
.cmx-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
234
|
+
p.cmx-err { margin: 0; }
|
|
235
|
+
.cmx-hint, .cmx-hint-inline { color: var(--dm-text-muted); font-size: var(--dm-text-xs); font-weight: 400; }
|
|
236
|
+
.cmx-hint { display: block; margin-top: .25rem; }
|
|
237
|
+
.cmx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
238
|
+
.cmx-setting { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
|
|
239
|
+
.cmx-setting .form-label { margin: 0; }
|
|
240
|
+
.cmx-count { opacity: .65; font-size: var(--dm-text-xs); margin-left: .15rem; }
|
|
241
|
+
.cmx-tab-dot { display: inline-block; width: .45rem; height: .45rem; border-radius: 50%; background: var(--dm-danger); margin-left: .25rem; vertical-align: middle; }
|
|
242
|
+
.cmx-list { display: flex; flex-direction: column; }
|
|
243
|
+
.cmx-row { display: flex; align-items: center; gap: .6rem; padding: .5rem .35rem; border-bottom: 1px solid var(--dm-border); cursor: pointer; }
|
|
244
|
+
.cmx-row:last-child { border-bottom: 0; }
|
|
245
|
+
.cmx-row:hover, .cmx-row:focus-visible { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); outline: none; }
|
|
246
|
+
.cmx-row.is-divider .cmx-main strong { color: var(--dm-text-muted); letter-spacing: .1em; font-weight: 400; }
|
|
247
|
+
.cmx-row.is-header .cmx-main strong { text-transform: uppercase; font-size: var(--dm-text-xs); letter-spacing: .05em; color: var(--dm-text-muted); }
|
|
248
|
+
.cmx-row.is-bad { box-shadow: inset 3px 0 0 var(--dm-danger); }
|
|
249
|
+
.cmx-icon { width: 1.4rem; display: inline-flex; justify-content: center; color: var(--dm-text-muted); flex-shrink: 0; }
|
|
250
|
+
.cmx-type { font-size: var(--dm-text-xs); color: var(--dm-text-muted); min-width: 4rem; flex-shrink: 0; }
|
|
251
|
+
.cmx-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
252
|
+
.cmx-main strong, .cmx-main small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
253
|
+
.cmx-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
254
|
+
.cmx-main small.cmx-bad { color: var(--dm-danger); }
|
|
255
|
+
.cmx-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;
|
|
256
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
257
|
+
.cmx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
258
|
+
.cmx-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
259
|
+
.cmx-chip.is-danger { background: color-mix(in srgb, var(--dm-danger) 14%, transparent); color: var(--dm-danger); }
|
|
260
|
+
.cmx-chips { display: flex; flex-wrap: wrap; gap: .3rem; }
|
|
261
|
+
.cmx-move { display: inline-flex; gap: .1rem; flex-shrink: 0; }
|
|
262
|
+
.cmx-move button, .cmx-kebab { border: 0; background: none; cursor: pointer; color: var(--dm-text-muted); border-radius: var(--dm-radius-sm); padding: 0 .35rem; font-size: var(--dm-text-base); line-height: 1.6; }
|
|
263
|
+
.cmx-move button:hover:not(:disabled), .cmx-kebab:hover { color: var(--dm-primary); }
|
|
264
|
+
.cmx-move button:disabled { opacity: .3; cursor: default; }
|
|
265
|
+
.cmx-kebab { font-size: var(--dm-text-lg); }
|
|
266
|
+
.cmx-preview { padding: 2rem 1rem; text-align: center; border: 1px dashed var(--dm-border); border-radius: var(--dm-radius-md); color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
267
|
+
/* The item panel (slideover) */
|
|
268
|
+
.cmx-form { display: flex; flex-direction: column; gap: .85rem; }
|
|
269
|
+
.cmx-form .cmx-actions { display: flex; align-items: center; gap: .4rem; padding-top: .6rem; border-top: 1px solid var(--dm-border); }
|
|
270
|
+
.cmx-form .cmx-actions .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
271
|
+
@media (max-width: 640px) { .cmx-grid { grid-template-columns: 1fr; } .cmx-type { display: none; } }
|
|
272
|
+
</style>
|