domma-cms 0.75.0 → 0.76.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/js/app.js +4 -4
- package/admin/js/lib/api-tokens-arrange.js +3 -0
- package/admin/js/lib/effects-arrange.js +3 -0
- package/admin/js/lib/layouts-arrange.js +1 -0
- package/admin/js/lib/my-profile-arrange.js +1 -0
- package/admin/js/lib/notifications-arrange.js +1 -0
- package/admin/js/lib/plugins-arrange.js +2 -0
- package/admin/js/lib/roles-arrange.js +1 -0
- package/admin/js/lib/search-settings-arrange.js +1 -0
- package/admin/js/lib/sidebar-renderer.js +2 -2
- package/admin/js/lib/site-settings-arrange.js +1 -0
- package/admin/js/lib/users-arrange.js +1 -0
- package/admin/js/templates/api-tokens.html +83 -10
- package/admin/js/templates/effects.html +155 -72
- package/admin/js/templates/layouts.html +126 -43
- package/admin/js/templates/my-profile.html +100 -12
- package/admin/js/templates/notifications.html +70 -10
- package/admin/js/templates/plugins.html +100 -28
- package/admin/js/templates/roles.html +78 -7
- package/admin/js/templates/search.html +193 -216
- package/admin/js/templates/settings.html +404 -472
- package/admin/js/templates/users.html +69 -9
- package/admin/js/views/api-tokens.js +62 -8
- package/admin/js/views/effects.js +31 -1
- package/admin/js/views/layouts.js +81 -1
- package/admin/js/views/my-profile.js +1 -1
- package/admin/js/views/notifications.js +18 -1
- package/admin/js/views/plugins.js +97 -39
- package/admin/js/views/roles.js +49 -4
- package/admin/js/views/search.js +7 -1
- package/admin/js/views/settings.js +13 -3
- package/admin/js/views/users.js +13 -4
- package/package.json +1 -1
- package/plugins/_lib/admin/mail/compose-window.js +97 -40
- package/plugins/_lib/admin/mail/contacts.js +4 -1
- package/plugins/_lib/admin/mail/diagnostics-section.js +4 -1
- package/plugins/_lib/admin/mail/folder-tree.js +1 -1
- package/plugins/_lib/admin/mail/image-senders-section.js +69 -90
- package/plugins/_lib/admin/mail/mail.css +1 -1
- package/plugins/_lib/admin/mail/mail.html +1 -1
- package/plugins/_lib/admin/mail/reader-view.js +303 -44
- package/plugins/_lib/admin/mail/when-closed.js +26 -0
- package/plugins/_lib/mail/readRoutes.js +43 -1
- package/plugins/_lib/mail/unreadBadge.js +42 -0
- package/plugins/free-tier.lock.json +5 -5
- package/plugins/mail-reader/CLAUDE.md +1 -0
- package/plugins/mail-reader/plugin.js +3 -1
- package/plugins/mail-reader/plugin.json +5 -4
- package/server/routes/api/api-tokens.js +56 -0
- package/server/routes/api/auth.js +7 -1
- package/server/routes/api/collections.js +13 -1
- package/server/routes/api/effects.js +68 -13
- package/server/routes/api/layouts.js +93 -2
- package/server/routes/api/notifications.js +140 -14
- package/server/routes/api/plugins.js +135 -4
- package/server/routes/api/roles.js +111 -0
- package/server/routes/api/search.js +38 -4
- package/server/routes/api/settings.js +52 -0
- package/server/routes/api/users.js +53 -1
- package/server/server.js +12 -0
- package/server/services/plugins.js +7 -0
- package/server/services/roles.js +3 -0
- package/server/services/search.js +58 -0
- package/server/services/users.js +14 -0
- package/admin/js/templates/plugin-marketplace.html +0 -29
- package/admin/js/views/plugin-marketplace.js +0 -1
|
@@ -1,81 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<!-- System › Effects. Bound with M.applyBindings - see admin/js/views/effects.js, which also inserts the
|
|
2
|
+
row template (the router renders a templateUrl through _.render, eating any {{…}}). No page heading:
|
|
3
|
+
the Tool banner above is the heading, and Save is a banner action. -->
|
|
4
|
+
<div class="fxx">
|
|
5
|
+
<div class="fxx-card fxx-live">
|
|
6
|
+
<div class="fxx-card-title">Live now
|
|
7
|
+
<span data-help-title="Live now" data-help="What the published site uses at the moment - the saved settings, not what is typed below until you Save. Every [reveal] and row reveal without its own duration, animation or threshold uses these."></span></div>
|
|
8
|
+
<div class="fxx-chips">
|
|
9
|
+
<span class="fxx-chip" data-bind-class="saved.value.respectMotion ? 'is-ok' : 'is-warn'" data-bind-text="motionText.value"></span>
|
|
10
|
+
<span class="fxx-chip" data-bind-text="'Reveal: ' + saved.value.defaultAnimation"></span>
|
|
11
|
+
<span class="fxx-chip" data-bind-text="saved.value.defaultDuration + ' ms'"></span>
|
|
12
|
+
<span class="fxx-chip" data-bind-text="'Threshold ' + saved.value.defaultThreshold"></span>
|
|
13
|
+
<span class="fxx-chip is-muted" data-bind-hidden="!defaultsText.value" data-bind-text="defaultsText.value"></span>
|
|
14
|
+
</div>
|
|
7
15
|
</div>
|
|
8
|
-
</div>
|
|
9
16
|
|
|
10
|
-
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
<button class="
|
|
14
|
-
<button class="
|
|
15
|
-
</
|
|
16
|
-
|
|
17
|
+
<p class="fxx-unsaved" data-bind-hidden="!dirty.value">
|
|
18
|
+
<span data-icon="alert-circle" data-icon-size="15"></span> Unsaved changes
|
|
19
|
+
<span class="fxx-spacer"></span>
|
|
20
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard">Discard</button>
|
|
21
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="cannotSave.value">Save</button>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<div class="tabs fxx-tabs">
|
|
25
|
+
<div class="tab-list">
|
|
26
|
+
<button type="button" class="tab-item active">Settings <span class="fxx-dot" data-bind-hidden="!dirty.value" title="Unsaved changes">•</span></button>
|
|
27
|
+
<button type="button" class="tab-item">Effects <span class="fxx-count" data-bind-text="effectCount"></span></button>
|
|
28
|
+
<button type="button" class="tab-item">Guide</button>
|
|
29
|
+
</div>
|
|
17
30
|
|
|
18
|
-
<!-- Settings
|
|
31
|
+
<!-- Settings -->
|
|
19
32
|
<div class="tab-panel active">
|
|
20
|
-
<div class="card
|
|
21
|
-
<div class="card-
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<span class="form-hint">When enabled, JS effects are skipped for users who prefer reduced motion. Content remains visible.</span>
|
|
29
|
-
</div>
|
|
33
|
+
<div class="fxx-card">
|
|
34
|
+
<div class="fxx-card-title">Scroll reveal defaults
|
|
35
|
+
<span data-help-title="Defaults" data-help="Used by [reveal] and [row reveal] when the shortcode does not set its own. A shortcode's own attribute always wins. Ctrl+S saves."></span></div>
|
|
36
|
+
<div class="fxx-grid">
|
|
37
|
+
<div class="fxx-wide fxx-setting">
|
|
38
|
+
<label class="form-label" for="fx-motion">Respect reduced motion
|
|
39
|
+
<span data-help-title="prefers-reduced-motion" data-help="Visitors can ask their device for less motion. With this on, the JavaScript effects are skipped for them and the content simply shows - nothing is hidden. Turn it off only if an effect carries meaning that would otherwise be lost."></span></label>
|
|
40
|
+
<input id="fx-motion" type="checkbox" class="form-switch" data-model="respectMotion.value">
|
|
30
41
|
</div>
|
|
31
|
-
<div
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<option value="fade">Fade</option>
|
|
42
|
-
<option value="slide-up">Slide up</option>
|
|
43
|
-
<option value="slide-down">Slide down</option>
|
|
44
|
-
<option value="zoom">Zoom</option>
|
|
45
|
-
<option value="flip">Flip</option>
|
|
46
|
-
</select>
|
|
47
|
-
</div>
|
|
42
|
+
<div>
|
|
43
|
+
<label class="form-label" for="fx-anim">Reveal animation</label>
|
|
44
|
+
<select id="fx-anim" class="form-input" data-model="defaultAnimation.value">
|
|
45
|
+
<option value="fade">Fade</option>
|
|
46
|
+
<option value="slide-up">Slide up</option>
|
|
47
|
+
<option value="slide-down">Slide down</option>
|
|
48
|
+
<option value="zoom">Zoom</option>
|
|
49
|
+
<option value="flip">Flip</option>
|
|
50
|
+
</select>
|
|
51
|
+
<small class="fxx-err" data-bind-hidden="!animErr.value" data-bind-text="animErr.value"></small>
|
|
48
52
|
</div>
|
|
49
|
-
<div
|
|
50
|
-
<
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
placeholder="0.1">
|
|
55
|
-
<span class="form-hint">Fraction of element visible before reveal fires (0.0-1.0).</span>
|
|
56
|
-
</div>
|
|
53
|
+
<div>
|
|
54
|
+
<label class="form-label" for="fx-duration">Duration (ms)
|
|
55
|
+
<span data-help="How long a reveal takes. 600 ms is a comfortable default; above about 1000 it starts to feel slow."></span></label>
|
|
56
|
+
<input id="fx-duration" type="number" class="form-input" min="1" max="10000" step="50" placeholder="600" data-model="defaultDuration.value">
|
|
57
|
+
<small class="fxx-err" data-bind-hidden="!durErr.value" data-bind-text="durErr.value"></small>
|
|
57
58
|
</div>
|
|
59
|
+
<div>
|
|
60
|
+
<label class="form-label" for="fx-threshold">Threshold
|
|
61
|
+
<span data-help-title="Threshold" data-help="How much of an element must be on screen before it reveals: 0 = as soon as any of it shows, 1 = only once all of it shows. 0.1 suits most pages; tall blocks need a low value or they may never reveal on a small screen."></span></label>
|
|
62
|
+
<input id="fx-threshold" type="number" class="form-input" min="0" max="1" step="0.05" placeholder="0.1" data-model="defaultThreshold.value">
|
|
63
|
+
<small class="fxx-err" data-bind-hidden="!thrErr.value" data-bind-text="thrErr.value"></small>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="fxx-actions">
|
|
67
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="resetDefaults" title="Put back Domma's defaults (then Save)">Domma's defaults</button>
|
|
68
|
+
<span class="fxx-spacer"></span>
|
|
69
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="cannotSave.value">
|
|
70
|
+
<span data-icon="save" data-icon-size="14"></span> Save</button>
|
|
58
71
|
</div>
|
|
59
72
|
</div>
|
|
60
73
|
</div>
|
|
61
74
|
|
|
62
|
-
<!--
|
|
75
|
+
<!-- Effects: the catalogue the page editor inserts from -->
|
|
63
76
|
<div class="tab-panel">
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<button class="btn btn-sm effects-tab-btn" data-fx-tab="examples">Examples</button>
|
|
74
|
-
<button class="btn btn-sm effects-tab-btn" data-fx-tab="celebrations">Celebrations</button>
|
|
77
|
+
<div class="fxx-card">
|
|
78
|
+
<div class="fxx-bar">
|
|
79
|
+
<div class="fxx-seg fxx-cats" role="group" aria-label="Category" data-each="cats.value key=key"></div>
|
|
80
|
+
<input type="search" class="form-input fxx-search" placeholder="Search effects or settings…" aria-label="Search effects" data-model="query.value">
|
|
81
|
+
<span data-help-title="Effects" data-help="Every effect the page editor's Effects button can insert. Click one for its settings and an example; right-click it (or ⋮, or Shift+F10) to copy its shortcode. An effect that works inside [card], [hero] and friends can also be switched on as an attribute of that shortcode."></span>
|
|
82
|
+
</div>
|
|
83
|
+
<p class="fxx-note" data-bind-hidden="rows.value.length">No effects match.</p>
|
|
84
|
+
<div class="fxx-list" data-each="rows.value key=name"></div>
|
|
85
|
+
</div>
|
|
75
86
|
</div>
|
|
76
87
|
|
|
77
|
-
<!--
|
|
78
|
-
<div
|
|
88
|
+
<!-- Guide: the long-form reference -->
|
|
89
|
+
<div class="tab-panel">
|
|
90
|
+
<div class="fxx-card">
|
|
91
|
+
<p class="fxx-note">Use these shortcodes in any page's Markdown. The <strong>Effects</strong> toolbar button in
|
|
92
|
+
the editor inserts them for you.</p>
|
|
93
|
+
<div class="fxx-seg fxx-guide-tabs" role="group" aria-label="Guide section">
|
|
94
|
+
<button type="button" data-on-click="showGuide('entrance')" data-bind-class="guide.value === 'entrance' && 'is-on'">Entrance</button>
|
|
95
|
+
<button type="button" data-on-click="showGuide('animation')" data-bind-class="guide.value === 'animation' && 'is-on'">Animation</button>
|
|
96
|
+
<button type="button" data-on-click="showGuide('text')" data-bind-class="guide.value === 'text' && 'is-on'">Text</button>
|
|
97
|
+
<button type="button" data-on-click="showGuide('visual')" data-bind-class="guide.value === 'visual' && 'is-on'">Visual</button>
|
|
98
|
+
<button type="button" data-on-click="showGuide('examples')" data-bind-class="guide.value === 'examples' && 'is-on'">Examples</button>
|
|
99
|
+
<button type="button" data-on-click="showGuide('celebrations')" data-bind-class="guide.value === 'celebrations' && 'is-on'">Celebrations</button>
|
|
100
|
+
</div>
|
|
101
|
+
<div id="tab-entrance" class="fxx-guide-panel" data-bind-hidden="guide.value !== 'entrance'">
|
|
79
102
|
<h3 class="mb-2">Reveal</h3>
|
|
80
103
|
<p class="text-muted mb-2">Triggers a scroll-activated entrance animation when the element enters the
|
|
81
104
|
viewport.
|
|
@@ -198,7 +221,7 @@ Markdown **works** inside.
|
|
|
198
221
|
</div>
|
|
199
222
|
|
|
200
223
|
<!-- Animation tab -->
|
|
201
|
-
<div id="tab-animation" class="
|
|
224
|
+
<div id="tab-animation" class="fxx-guide-panel" data-bind-hidden="guide.value !== 'animation'">
|
|
202
225
|
<h3 class="mb-2">Breathe</h3>
|
|
203
226
|
<p class="text-muted mb-2">Continuous gentle scaling - makes elements feel alive. Ideal for hero images or
|
|
204
227
|
call-to-action buttons.</p>
|
|
@@ -256,7 +279,7 @@ Content here.
|
|
|
256
279
|
</div>
|
|
257
280
|
|
|
258
281
|
<!-- Text tab -->
|
|
259
|
-
<div id="tab-text" class="
|
|
282
|
+
<div id="tab-text" class="fxx-guide-panel" data-bind-hidden="guide.value !== 'text'">
|
|
260
283
|
<h3 class="mb-2">Typewriter (Scribe)</h3>
|
|
261
284
|
<p class="text-muted mb-2">Types text character by character. Supports a simple one-shot mode or a full
|
|
262
285
|
action script for sequenced multi-step animations.</p>
|
|
@@ -418,7 +441,7 @@ Scrambled reveal text.
|
|
|
418
441
|
</div>
|
|
419
442
|
|
|
420
443
|
<!-- Visual tab -->
|
|
421
|
-
<div id="tab-visual" class="
|
|
444
|
+
<div id="tab-visual" class="fxx-guide-panel" data-bind-hidden="guide.value !== 'visual'">
|
|
422
445
|
<h3 class="mb-2">Ripple</h3>
|
|
423
446
|
<p class="text-muted mb-2">Click-triggered ripple effect on the element. Good for interactive content
|
|
424
447
|
blocks.</p>
|
|
@@ -466,7 +489,7 @@ Content on animated background.
|
|
|
466
489
|
</div>
|
|
467
490
|
|
|
468
491
|
<!-- Examples tab -->
|
|
469
|
-
<div id="tab-examples" class="
|
|
492
|
+
<div id="tab-examples" class="fxx-guide-panel" data-bind-hidden="guide.value !== 'examples'">
|
|
470
493
|
<h3 class="mb-2">Hero section with typewriter</h3>
|
|
471
494
|
<pre class="code-block mb-3">[reveal animation="fade"]
|
|
472
495
|
# Welcome to our site
|
|
@@ -530,7 +553,7 @@ A compelling subheading that draws users in.
|
|
|
530
553
|
</div>
|
|
531
554
|
|
|
532
555
|
<!-- Celebrations tab -->
|
|
533
|
-
<div id="tab-celebrations" class="
|
|
556
|
+
<div id="tab-celebrations" class="fxx-guide-panel" data-bind-hidden="guide.value !== 'celebrations'">
|
|
534
557
|
<h3 class="mb-2">Firework <span class="badge badge-info">CSS only</span></h3>
|
|
535
558
|
<p class="text-muted mb-2">Pure CSS particle effect - no JavaScript required. Works even without the plugin
|
|
536
559
|
enabled. Use self-closing for standalone particles, or wrapping to apply the firework classes to
|
|
@@ -747,6 +770,66 @@ The strips rain down inside this block only.
|
|
|
747
770
|
full-page overlay (<code>position:fixed</code>); the wrapping form attaches the canvas to the
|
|
748
771
|
wrapping div so the parade is constrained to that block.</p>
|
|
749
772
|
</div>
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
</div
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
</div>
|
|
776
|
+
</div>
|
|
777
|
+
|
|
778
|
+
<style>
|
|
779
|
+
.fxx { display: flex; flex-direction: column; gap: .75rem; }
|
|
780
|
+
.fxx [hidden], .fxx-form [hidden] { display: none !important; }
|
|
781
|
+
.fxx-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; }
|
|
782
|
+
.fxx-live { margin-top: 0; }
|
|
783
|
+
.fxx-card-title { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
|
|
784
|
+
.fxx-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
|
|
785
|
+
.fxx-chip { display: inline-flex; align-items: center; font-size: var(--dm-text-xs); font-weight: 600; padding: .1rem .55rem; border-radius: 999px; white-space: nowrap;
|
|
786
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
787
|
+
.fxx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
788
|
+
.fxx-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
789
|
+
.fxx-chip.is-info { background: color-mix(in srgb, var(--dm-primary) 14%, transparent); color: var(--dm-primary); }
|
|
790
|
+
.fxx-chip.is-muted { background: none; font-weight: 400; }
|
|
791
|
+
.fxx-unsaved { margin: 0; display: flex; align-items: center; gap: .5rem; padding: .5rem .8rem; border-radius: var(--dm-radius-md);
|
|
792
|
+
background: color-mix(in srgb, var(--dm-warning) 16%, transparent); color: var(--dm-text); }
|
|
793
|
+
.fxx-dot { color: var(--dm-warning); margin-left: .2rem; }
|
|
794
|
+
.fxx-count { opacity: .65; font-size: var(--dm-text-xs); margin-left: .2rem; }
|
|
795
|
+
.fxx-spacer { flex: 1; }
|
|
796
|
+
.fxx-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .85rem; }
|
|
797
|
+
.fxx-wide { grid-column: 1 / -1; }
|
|
798
|
+
.fxx-setting { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
|
|
799
|
+
.fxx-setting .form-label { margin: 0; }
|
|
800
|
+
.fxx .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
801
|
+
.fxx-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
802
|
+
.fxx-actions { display: flex; align-items: center; gap: .4rem; padding-top: .6rem; border-top: 1px solid var(--dm-border); }
|
|
803
|
+
.fxx-actions .btn, .fxx-unsaved .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
804
|
+
.fxx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
805
|
+
.fxx-bar { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
|
|
806
|
+
.fxx-search { flex: 1; min-width: 10rem; max-width: 22rem; }
|
|
807
|
+
.fxx-seg { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; }
|
|
808
|
+
.fxx-seg button { border: 0; background: none; color: var(--dm-text); padding: .3rem .65rem; cursor: pointer; font: inherit; font-size: var(--dm-text-sm); }
|
|
809
|
+
.fxx-seg button + button { border-left: 1px solid var(--dm-border); }
|
|
810
|
+
.fxx-seg button b { font-weight: 500; opacity: .65; margin-left: .2rem; }
|
|
811
|
+
.fxx-seg button:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); }
|
|
812
|
+
.fxx-seg button.is-on { background: var(--dm-primary); color: var(--dm-primary-text); }
|
|
813
|
+
.fxx-list { display: flex; flex-direction: column; }
|
|
814
|
+
.fxx-row { display: flex; align-items: center; gap: .75rem; padding: .55rem .35rem; border-bottom: 1px solid var(--dm-border); cursor: pointer; }
|
|
815
|
+
.fxx-row:last-child { border-bottom: 0; }
|
|
816
|
+
.fxx-row:hover, .fxx-row:focus-visible { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); outline: none; }
|
|
817
|
+
.fxx-tag { flex-shrink: 0; min-width: 7.5rem; font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-sm); color: var(--dm-primary); }
|
|
818
|
+
.fxx-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
819
|
+
.fxx-main strong, .fxx-main small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
820
|
+
.fxx-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
821
|
+
.fxx-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; }
|
|
822
|
+
.fxx-kebab:hover { color: var(--dm-primary); }
|
|
823
|
+
.fxx-guide-tabs { align-self: flex-start; }
|
|
824
|
+
/* The details slideover */
|
|
825
|
+
.fxx-form { display: flex; flex-direction: column; gap: .85rem; }
|
|
826
|
+
.fxx-form pre { margin: 0; white-space: pre-wrap; word-break: break-word; font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-sm);
|
|
827
|
+
padding: .6rem .75rem; border-radius: var(--dm-radius-md); border: 1px solid var(--dm-border); background: var(--dm-surface-raised, color-mix(in srgb, var(--dm-text) 5%, transparent)); color: var(--dm-text); }
|
|
828
|
+
.fxx-sub { display: flex; align-items: center; gap: .4rem; font-weight: 600; }
|
|
829
|
+
.fxx-attrs { width: 100%; border-collapse: collapse; font-size: var(--dm-text-sm); }
|
|
830
|
+
.fxx-attrs th, .fxx-attrs td { text-align: left; padding: .35rem .4rem; border-bottom: 1px solid var(--dm-border); vertical-align: top; }
|
|
831
|
+
.fxx-attrs th { color: var(--dm-text-muted); font-weight: 500; font-size: var(--dm-text-xs); }
|
|
832
|
+
.fxx-attrs code { color: var(--dm-primary); }
|
|
833
|
+
.fxx-attrs small { display: block; color: var(--dm-text-muted); }
|
|
834
|
+
@media (max-width: 720px) { .fxx-grid { grid-template-columns: 1fr; } .fxx-tag { min-width: 0; } }
|
|
835
|
+
</style>
|
|
@@ -1,49 +1,132 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<!-- Layouts. Bound with M.applyBindings - see admin/views/layouts.js, which also inserts the row template
|
|
2
|
+
(the router renders a templateUrl through _.render, eating any {{…}}). No page heading: the Tool
|
|
3
|
+
banner above is the heading, and New layout is a banner action. -->
|
|
4
|
+
<div class="lyx">
|
|
5
|
+
<div class="tabs lyx-tabs">
|
|
6
|
+
<div class="tab-list">
|
|
7
|
+
<button type="button" class="tab-item active">Layouts <span class="lyx-count" data-bind-text="counts.value.all"></span></button>
|
|
8
|
+
<button type="button" class="tab-item">Options <span class="lyx-dot" data-bind-hidden="!optDirty.value" title="Unsaved changes">●</span></button>
|
|
9
|
+
</div>
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<div class="tab-content">
|
|
11
|
+
<!-- Layouts -->
|
|
12
|
+
<div class="tab-panel active">
|
|
13
|
+
<p class="lyx-note">A layout sets a page's width, background, and whether it has the navbar, footer and sidebar.
|
|
14
|
+
Pages choose one in the page editor; a page that names none uses Default.
|
|
15
|
+
<span data-help-title="Layouts" data-help="The built-in layouts can be edited but not deleted. A layout you make gets a key from its name (Dark Landing becomes dark-landing) - that key is what a page's layout: line names, and it does not change if you rename the layout later. Deleting a layout that pages use leaves those pages on Default."></span></p>
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<button id="create-layout-btn" class="btn btn-primary"><span data-icon="plus"></span> New Layout</button>
|
|
18
|
-
</div>
|
|
19
|
-
<div id="presets-grid" class="presets-grid"></div>
|
|
20
|
-
</div>
|
|
17
|
+
<div class="lyx-alert" data-bind-hidden="!missing.value.length">
|
|
18
|
+
<span data-icon="alert-triangle" data-icon-size="16"></span>
|
|
19
|
+
<span data-bind-text="missingText.value"></span>
|
|
20
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="showMissing">Show them</button>
|
|
21
|
+
</div>
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<input id="spacer-class-input" type="text" class="form-input" style="max-width:240px"
|
|
38
|
-
placeholder="e.g. my-gap">
|
|
39
|
-
<small class="text-muted">Applied to every <code>[spacer /]</code> unless overridden per-instance with
|
|
40
|
-
<code>class="…"</code>.</small>
|
|
41
|
-
</div>
|
|
42
|
-
<button id="save-options-btn" class="btn btn-primary mt-3"><span data-icon="save"></span> Save Options
|
|
43
|
-
</button>
|
|
23
|
+
<div class="lyx-card">
|
|
24
|
+
<div class="lyx-bar">
|
|
25
|
+
<div class="lyx-seg" role="group" aria-label="Show">
|
|
26
|
+
<button type="button" data-on-click="showAll" data-bind-class="filter.value === 'all' && 'is-on'">All <b data-bind-text="counts.value.all"></b></button>
|
|
27
|
+
<button type="button" data-on-click="showBuiltin" data-bind-class="filter.value === 'builtin' && 'is-on'">Built in <b data-bind-text="counts.value.builtin"></b></button>
|
|
28
|
+
<button type="button" data-on-click="showCustom" data-bind-class="filter.value === 'custom' && 'is-on'">Yours <b data-bind-text="counts.value.custom"></b></button>
|
|
29
|
+
</div>
|
|
30
|
+
<input type="search" class="form-input lyx-search" placeholder="Search layouts…" aria-label="Search layouts" data-model="query.value">
|
|
31
|
+
<span data-help-title="The list" data-help="Click a layout to edit it. Right-click it (or ⋮, or Shift+F10) to see the pages that use it, duplicate it, copy the line a page's frontmatter needs, or delete it. The little drawing shows its shape: the navbar and footer bars, how wide the content is, and its background colour."></span>
|
|
32
|
+
</div>
|
|
33
|
+
<p class="lyx-note" data-bind-hidden="!loading.value">Loading…</p>
|
|
34
|
+
<p class="lyx-note is-bad" data-bind-hidden="!loadError.value" data-bind-text="loadError.value"></p>
|
|
35
|
+
<p class="lyx-note" data-bind-hidden="loading.value || loadError.value || rows.value.length">No layouts match.</p>
|
|
36
|
+
<div class="lyx-list" data-each="rows.value key=key"></div>
|
|
37
|
+
</div>
|
|
44
38
|
</div>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
39
|
|
|
48
|
-
|
|
40
|
+
<!-- Options -->
|
|
41
|
+
<div class="tab-panel">
|
|
42
|
+
<div class="lyx-card">
|
|
43
|
+
<div class="lyx-card-title">Spacer shortcode
|
|
44
|
+
<span data-help-title="[spacer /]" data-help="The [spacer /] shortcode puts a vertical gap in a page. These are its defaults; a single spacer can still say size="40" or class="…" for itself."></span></div>
|
|
45
|
+
<div class="lyx-grid">
|
|
46
|
+
<div>
|
|
47
|
+
<label class="form-label" for="lyx-o-size">Default height (px)</label>
|
|
48
|
+
<input id="lyx-o-size" type="number" min="0" max="500" step="1" class="form-input" data-model="spacerSize.value">
|
|
49
|
+
<small class="lyx-err" data-bind-hidden="!optErrSize.value" data-bind-text="optErrSize.value"></small>
|
|
50
|
+
</div>
|
|
51
|
+
<div>
|
|
52
|
+
<label class="form-label" for="lyx-o-class">Default CSS class</label>
|
|
53
|
+
<input id="lyx-o-class" type="text" class="form-input" placeholder="e.g. my-gap" data-model="spacerClass.value">
|
|
54
|
+
<small class="lyx-err" data-bind-hidden="!optErrClass.value" data-bind-text="optErrClass.value"></small>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="lyx-actions">
|
|
58
|
+
<small class="lyx-hint" data-bind-text="optStatus.value"></small>
|
|
59
|
+
<span class="lyx-spacer"></span>
|
|
60
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="resetOptions" data-bind-hidden="!optDirty.value">Discard</button>
|
|
61
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="saveOptions" data-bind-disabled="optCannot.value">
|
|
62
|
+
<span data-icon="save" data-icon-size="13"></span> Save options</button>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
49
67
|
</div>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
.lyx { display: flex; flex-direction: column; gap: .75rem; }
|
|
71
|
+
.lyx [hidden], .lyx-form [hidden] { display: none !important; }
|
|
72
|
+
.lyx-note { margin: 0 0 .6rem; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
73
|
+
.lyx-note.is-bad { color: var(--dm-danger); }
|
|
74
|
+
.lyx-count { opacity: .65; font-size: var(--dm-text-xs); margin-left: .2rem; }
|
|
75
|
+
.lyx-dot { color: var(--dm-warning); font-size: var(--dm-text-xs); margin-left: .25rem; }
|
|
76
|
+
.lyx-alert { display: flex; gap: .5rem; align-items: center; margin: 0 0 .6rem; padding: .5rem .75rem; border-radius: var(--dm-radius-md);
|
|
77
|
+
background: color-mix(in srgb, var(--dm-warning) 16%, transparent); color: var(--dm-text); font-size: var(--dm-text-sm); }
|
|
78
|
+
.lyx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .6rem; }
|
|
79
|
+
.lyx-card-title { display: flex; align-items: center; gap: .3rem; font-weight: 600; }
|
|
80
|
+
.lyx-bar { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
|
|
81
|
+
.lyx-search { flex: 1; min-width: 10rem; max-width: 22rem; }
|
|
82
|
+
.lyx-seg { display: inline-flex; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; }
|
|
83
|
+
.lyx-seg button { border: 0; background: none; color: var(--dm-text); padding: .3rem .7rem; cursor: pointer; font: inherit; font-size: var(--dm-text-sm); }
|
|
84
|
+
.lyx-seg button + button { border-left: 1px solid var(--dm-border); }
|
|
85
|
+
.lyx-seg button b { font-weight: 500; opacity: .65; margin-left: .2rem; }
|
|
86
|
+
.lyx-seg button:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); }
|
|
87
|
+
.lyx-seg button.is-on { background: var(--dm-primary); color: var(--dm-primary-text); }
|
|
88
|
+
.lyx-list { display: flex; flex-direction: column; }
|
|
89
|
+
.lyx-row { display: flex; align-items: center; gap: .75rem; padding: .55rem .35rem; border-bottom: 1px solid var(--dm-border); cursor: pointer; }
|
|
90
|
+
.lyx-row:last-child { border-bottom: 0; }
|
|
91
|
+
.lyx-row:hover, .lyx-row:focus-visible { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); outline: none; }
|
|
92
|
+
/* The little drawing of a layout: navbar, content column, footer, background. */
|
|
93
|
+
.lyx-shape { flex-shrink: 0; width: 3rem; height: 2.2rem; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-sm);
|
|
94
|
+
background: var(--dm-surface); display: flex; flex-direction: column; overflow: hidden; }
|
|
95
|
+
.lyx-shape-nav, .lyx-shape-foot { height: 5px; background: color-mix(in srgb, var(--dm-text-muted) 55%, transparent); }
|
|
96
|
+
.lyx-shape-body { flex: 1; display: flex; justify-content: center; padding: 3px 0; gap: 2px; }
|
|
97
|
+
.lyx-shape-col { background: color-mix(in srgb, var(--dm-primary) 45%, transparent); border-radius: 1px; }
|
|
98
|
+
.lyx-shape-side { width: 18%; background: color-mix(in srgb, var(--dm-text-muted) 35%, transparent); border-radius: 1px; }
|
|
99
|
+
.lyx-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
100
|
+
.lyx-main strong, .lyx-main small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
101
|
+
.lyx-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
102
|
+
.lyx-chips { display: inline-flex; gap: .3rem; flex-shrink: 0; }
|
|
103
|
+
.lyx-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;
|
|
104
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
105
|
+
.lyx-chip.is-info { background: color-mix(in srgb, var(--dm-info, var(--dm-primary)) 14%, transparent); color: var(--dm-info, var(--dm-primary)); }
|
|
106
|
+
.lyx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
107
|
+
.lyx-chip.is-muted { opacity: .7; }
|
|
108
|
+
.lyx-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; }
|
|
109
|
+
.lyx-kebab:hover { color: var(--dm-primary); }
|
|
110
|
+
.lyx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .85rem; }
|
|
111
|
+
.lyx-wide { grid-column: 1 / -1; }
|
|
112
|
+
.lyx-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
113
|
+
.lyx-hint { display: block; color: var(--dm-text-muted); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
114
|
+
.lyx-actions { display: flex; align-items: center; gap: .4rem; padding-top: .6rem; border-top: 1px solid var(--dm-border); }
|
|
115
|
+
.lyx-actions .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
116
|
+
.lyx-spacer { flex: 1; }
|
|
117
|
+
/* The editor slideover */
|
|
118
|
+
.lyx-form { display: flex; flex-direction: column; gap: .85rem; }
|
|
119
|
+
.lyx-form .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
120
|
+
.lyx-switches { display: flex; flex-wrap: wrap; gap: 1.25rem; }
|
|
121
|
+
.lyx-switches label { display: inline-flex; align-items: center; gap: .4rem; cursor: pointer; }
|
|
122
|
+
.lyx-colour { display: flex; align-items: center; gap: .5rem; }
|
|
123
|
+
.lyx-colour input[type="color"] { width: 2.4rem; height: 2rem; padding: 2px; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-sm); background: transparent; cursor: pointer; }
|
|
124
|
+
.lyx-preview { display: flex; align-items: center; gap: .75rem; padding: .6rem; border: 1px dashed var(--dm-border); border-radius: var(--dm-radius-md); }
|
|
125
|
+
.lyx-preview .lyx-shape { width: 5rem; height: 3.6rem; }
|
|
126
|
+
.lyx-pages { display: flex; flex-direction: column; }
|
|
127
|
+
.lyx-pages a { display: flex; justify-content: space-between; gap: .75rem; padding: .45rem .25rem; border-bottom: 1px solid var(--dm-border); color: var(--dm-text); text-decoration: none; }
|
|
128
|
+
.lyx-pages a:last-child { border-bottom: 0; }
|
|
129
|
+
.lyx-pages a:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); }
|
|
130
|
+
.lyx-pages small { color: var(--dm-text-muted); }
|
|
131
|
+
@media (max-width: 640px) { .lyx-grid { grid-template-columns: 1fr; } .lyx-chips .lyx-chip:not(.is-info) { display: none; } }
|
|
132
|
+
</style>
|
|
@@ -1,17 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<!-- My Profile. Bound with M.applyBindings - see admin/views/my-profile.js, which also draws the profile
|
|
2
|
+
fields from the user-profiles schema. No page heading: the Tool banner above is the heading, and Save is
|
|
3
|
+
a banner action (and Ctrl+S). -->
|
|
4
|
+
<div class="mpx">
|
|
5
|
+
<p class="mpx-note is-bad" data-bind-hidden="!loadError.value" data-bind-text="loadError.value"></p>
|
|
6
|
+
<p class="mpx-note" data-bind-hidden="!loading.value">Loading…</p>
|
|
4
7
|
|
|
5
|
-
<div class="
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<
|
|
8
|
+
<div class="mpx-dirty" data-bind-hidden="!dirty.value">
|
|
9
|
+
<span data-icon="edit" data-icon-size="14"></span>
|
|
10
|
+
<span>You have unsaved changes.</span>
|
|
11
|
+
<span class="mpx-spacer"></span>
|
|
12
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard">Discard</button>
|
|
13
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="cannotSave.value">
|
|
14
|
+
<span data-icon="check" data-icon-size="13"></span> Save</button>
|
|
9
15
|
</div>
|
|
10
|
-
</div>
|
|
11
16
|
|
|
12
|
-
<div class="card
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
<div class="mpx-card mpx-you" data-bind-hidden="loading.value || loadError.value">
|
|
18
|
+
<span class="mpx-avatar" aria-hidden="true" data-bind-text="avatar.value"></span>
|
|
19
|
+
<span class="mpx-you-main">
|
|
20
|
+
<strong data-bind-text="shownName.value"></strong>
|
|
21
|
+
<small data-bind-text="shownEmail.value"></small>
|
|
22
|
+
<small class="mpx-facts" data-bind-text="factsText.value"></small>
|
|
23
|
+
</span>
|
|
24
|
+
<span class="mpx-chips">
|
|
25
|
+
<span class="mpx-chip is-ok" data-bind-text="rolesText.value" title="Your role - an administrator sets it"></span>
|
|
26
|
+
<span class="mpx-chip" data-bind-text="accessText.value" title="What you can see in the admin"></span>
|
|
27
|
+
</span>
|
|
28
|
+
<span data-help-title="Your account" data-help="Your role and which projects you can see are set by an administrator, under System › Users - they cannot be changed here. Everything below is yours to change."></span>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="mpx-card" data-bind-hidden="loading.value || loadError.value">
|
|
32
|
+
<div class="mpx-card-title">Account
|
|
33
|
+
<span data-help="Your name is how you appear in the admin and on anything you author. Your email is what you sign in with, and where password resets are sent."></span></div>
|
|
34
|
+
<div class="mpx-grid">
|
|
35
|
+
<div>
|
|
36
|
+
<label class="form-label" for="mpx-name">Full name <span class="text-danger">*</span></label>
|
|
37
|
+
<input id="mpx-name" type="text" class="form-input" maxlength="100" autocomplete="name" placeholder="Jane Smith" data-model="name.value">
|
|
38
|
+
<small class="mpx-err" data-bind-hidden="!err.value.name" data-bind-text="err.value.name"></small>
|
|
39
|
+
</div>
|
|
40
|
+
<div>
|
|
41
|
+
<label class="form-label" for="mpx-email">Email <span class="text-danger">*</span></label>
|
|
42
|
+
<input id="mpx-email" type="email" class="form-input" maxlength="200" autocomplete="email" placeholder="jane@example.com" data-model="email.value">
|
|
43
|
+
<small class="mpx-err" data-bind-hidden="!err.value.email" data-bind-text="err.value.email"></small>
|
|
44
|
+
<small class="mpx-hint" data-bind-hidden="!emailChanged.value">You will sign in with the new address from now on.</small>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="mpx-card" data-bind-hidden="loading.value || loadError.value">
|
|
50
|
+
<div class="mpx-card-title">Password
|
|
51
|
+
<span data-help-title="Changing your password" data-help="Leave both boxes empty to keep your current password. A new one needs at least 8 characters, typed twice. It is never kept as a draft - if you leave the screen, you type it again."></span></div>
|
|
52
|
+
<div class="mpx-grid">
|
|
53
|
+
<div>
|
|
54
|
+
<label class="form-label" for="mpx-pw">New password</label>
|
|
55
|
+
<input id="mpx-pw" type="password" data-bind-type="showPw.value ? 'text' : 'password'" class="form-input" autocomplete="new-password" placeholder="Leave empty to keep it" data-model="password.value">
|
|
56
|
+
<small class="mpx-err" data-bind-hidden="!err.value.password" data-bind-text="err.value.password"></small>
|
|
57
|
+
</div>
|
|
58
|
+
<div>
|
|
59
|
+
<label class="form-label" for="mpx-pw2">Type it again</label>
|
|
60
|
+
<input id="mpx-pw2" type="password" data-bind-type="showPw.value ? 'text' : 'password'" class="form-input" autocomplete="new-password" data-model="confirm.value">
|
|
61
|
+
<small class="mpx-err" data-bind-hidden="!err.value.confirm" data-bind-text="err.value.confirm"></small>
|
|
62
|
+
<small class="mpx-hint is-ok" data-bind-hidden="!pwMatch.value">✓ They match.</small>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<label class="mpx-show"><input type="checkbox" data-model="showPw.value"> Show what I type</label>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="mpx-card" data-bind-hidden="loading.value || loadError.value || !hasProfile.value">
|
|
69
|
+
<div class="mpx-card-title">Profile
|
|
70
|
+
<span data-help="Extra details about you. Which ones are asked for is set by an administrator (the User Profiles collection)."></span></div>
|
|
71
|
+
<div class="mpx-grid mpx-profile"></div>
|
|
16
72
|
</div>
|
|
17
73
|
</div>
|
|
74
|
+
|
|
75
|
+
<style>
|
|
76
|
+
.mpx { display: flex; flex-direction: column; gap: .75rem; max-width: 60rem; }
|
|
77
|
+
.mpx [hidden] { display: none !important; }
|
|
78
|
+
.mpx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
79
|
+
.mpx-note.is-bad { color: var(--dm-danger); }
|
|
80
|
+
.mpx-dirty { display: flex; align-items: center; gap: .5rem; padding: .5rem .8rem; border-radius: var(--dm-radius-md);
|
|
81
|
+
background: color-mix(in srgb, var(--dm-warning) 14%, transparent); color: var(--dm-text); position: sticky; top: 0; z-index: 2; }
|
|
82
|
+
.mpx-dirty .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
83
|
+
.mpx-spacer { flex: 1; }
|
|
84
|
+
.mpx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .8rem .9rem; display: flex; flex-direction: column; gap: .7rem; }
|
|
85
|
+
.mpx-card-title { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
|
|
86
|
+
.mpx-you { flex-direction: row; align-items: center; gap: .9rem; flex-wrap: wrap; }
|
|
87
|
+
.mpx-avatar { display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; border-radius: 50%; flex-shrink: 0;
|
|
88
|
+
font-weight: 700; color: var(--dm-primary); background: color-mix(in srgb, var(--dm-primary) 14%, transparent); }
|
|
89
|
+
.mpx-you-main { flex: 1; min-width: 12rem; display: flex; flex-direction: column; }
|
|
90
|
+
.mpx-you-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
91
|
+
.mpx-facts { margin-top: .15rem; }
|
|
92
|
+
.mpx-chips { display: inline-flex; gap: .3rem; flex-wrap: wrap; }
|
|
93
|
+
.mpx-chip { display: inline-flex; align-items: center; font-size: var(--dm-text-xs); font-weight: 600; padding: .1rem .55rem; border-radius: 999px; white-space: nowrap;
|
|
94
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
95
|
+
.mpx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
96
|
+
.mpx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
|
|
97
|
+
.mpx-wide { grid-column: 1 / -1; }
|
|
98
|
+
.mpx .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
99
|
+
.mpx-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
100
|
+
.mpx-hint { display: block; color: var(--dm-text-muted); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
101
|
+
.mpx-hint.is-ok { color: var(--dm-success); }
|
|
102
|
+
.mpx-show { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--dm-text-sm); color: var(--dm-text-muted); cursor: pointer; width: fit-content; }
|
|
103
|
+
.mpx-check { display: inline-flex; align-items: center; gap: .4rem; cursor: pointer; margin-right: .8rem; }
|
|
104
|
+
@media (max-width: 640px) { .mpx-grid { grid-template-columns: 1fr; } }
|
|
105
|
+
</style>
|