@caretcms/core 0.1.1 → 0.2.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/README.md +101 -18
- package/dist/browser-runtime.d.ts +16 -0
- package/dist/browser-runtime.d.ts.map +1 -1
- package/dist/browser-runtime.js +8 -3
- package/dist/browser-runtime.js.map +1 -1
- package/dist/contracts.d.ts +1 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +1 -0
- package/dist/contracts.js.map +1 -1
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +239 -13
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +17 -6
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +33 -14
- package/dist/loader.js.map +1 -1
- package/dist/markdown/block-context.d.ts +21 -0
- package/dist/markdown/block-context.d.ts.map +1 -0
- package/dist/markdown/block-context.js +27 -0
- package/dist/markdown/block-context.js.map +1 -0
- package/dist/markdown/canonical-body.d.ts +30 -0
- package/dist/markdown/canonical-body.d.ts.map +1 -0
- package/dist/markdown/canonical-body.js +54 -0
- package/dist/markdown/canonical-body.js.map +1 -0
- package/dist/markdown/contracts.d.ts +66 -0
- package/dist/markdown/contracts.d.ts.map +1 -0
- package/dist/markdown/contracts.js +102 -0
- package/dist/markdown/contracts.js.map +1 -0
- package/dist/markdown/html-to-snodes.d.ts +26 -0
- package/dist/markdown/html-to-snodes.d.ts.map +1 -0
- package/dist/markdown/html-to-snodes.js +118 -0
- package/dist/markdown/html-to-snodes.js.map +1 -0
- package/dist/markdown/remark.d.ts +35 -0
- package/dist/markdown/remark.d.ts.map +1 -0
- package/dist/markdown/remark.js +66 -0
- package/dist/markdown/remark.js.map +1 -0
- package/dist/markdown/satteri.d.ts +19 -0
- package/dist/markdown/satteri.d.ts.map +1 -0
- package/dist/markdown/satteri.js +120 -0
- package/dist/markdown/satteri.js.map +1 -0
- package/dist/markdown/serialize.d.ts +60 -0
- package/dist/markdown/serialize.d.ts.map +1 -0
- package/dist/markdown/serialize.js +264 -0
- package/dist/markdown/serialize.js.map +1 -0
- package/dist/markdown/splice.d.ts +32 -0
- package/dist/markdown/splice.d.ts.map +1 -0
- package/dist/markdown/splice.js +44 -0
- package/dist/markdown/splice.js.map +1 -0
- package/dist/markdown/stamp.d.ts +68 -0
- package/dist/markdown/stamp.d.ts.map +1 -0
- package/dist/markdown/stamp.js +131 -0
- package/dist/markdown/stamp.js.map +1 -0
- package/dist/runtime/auth/rate-limiter.d.ts.map +1 -1
- package/dist/runtime/auth/rate-limiter.js +5 -0
- package/dist/runtime/auth/rate-limiter.js.map +1 -1
- package/dist/runtime/auth/session.d.ts +2 -3
- package/dist/runtime/auth/session.d.ts.map +1 -1
- package/dist/runtime/auth/session.js +52 -21
- package/dist/runtime/auth/session.js.map +1 -1
- package/dist/runtime/content.d.ts.map +1 -1
- package/dist/runtime/content.js +4 -2
- package/dist/runtime/content.js.map +1 -1
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/middleware.js +21 -4
- package/dist/runtime/middleware.js.map +1 -1
- package/dist/runtime/mutations/contracts.d.ts +25 -1
- package/dist/runtime/mutations/contracts.d.ts.map +1 -1
- package/dist/runtime/mutations/contracts.js +67 -0
- package/dist/runtime/mutations/contracts.js.map +1 -1
- package/dist/runtime/mutations/engine.d.ts +6 -1
- package/dist/runtime/mutations/engine.d.ts.map +1 -1
- package/dist/runtime/mutations/engine.js +151 -42
- package/dist/runtime/mutations/engine.js.map +1 -1
- package/dist/runtime/providers.d.ts +9 -0
- package/dist/runtime/providers.d.ts.map +1 -1
- package/dist/runtime/providers.js +6 -0
- package/dist/runtime/providers.js.map +1 -1
- package/dist/runtime/publish.d.ts +15 -1
- package/dist/runtime/publish.d.ts.map +1 -1
- package/dist/runtime/publish.js +79 -4
- package/dist/runtime/publish.js.map +1 -1
- package/dist/runtime/rebuild-webhook.d.ts +29 -0
- package/dist/runtime/rebuild-webhook.d.ts.map +1 -0
- package/dist/runtime/rebuild-webhook.js +37 -0
- package/dist/runtime/rebuild-webhook.js.map +1 -0
- package/dist/runtime/request-context.d.ts +9 -1
- package/dist/runtime/request-context.d.ts.map +1 -1
- package/dist/runtime/request-context.js.map +1 -1
- package/dist/runtime/rewrite.d.ts +18 -0
- package/dist/runtime/rewrite.d.ts.map +1 -1
- package/dist/runtime/rewrite.js +118 -4
- package/dist/runtime/rewrite.js.map +1 -1
- package/dist/runtime/rich-allowlist.d.ts +3 -2
- package/dist/runtime/rich-allowlist.d.ts.map +1 -1
- package/dist/runtime/rich-allowlist.js +14 -4
- package/dist/runtime/rich-allowlist.js.map +1 -1
- package/dist/runtime/routes/_helpers.d.ts +7 -0
- package/dist/runtime/routes/_helpers.d.ts.map +1 -1
- package/dist/runtime/routes/_helpers.js +34 -1
- package/dist/runtime/routes/_helpers.js.map +1 -1
- package/dist/runtime/routes/admin-entry.d.ts +1 -0
- package/dist/runtime/routes/admin-entry.d.ts.map +1 -1
- package/dist/runtime/routes/admin-entry.js +3 -2
- package/dist/runtime/routes/admin-entry.js.map +1 -1
- package/dist/runtime/routes/admin.d.ts +1 -0
- package/dist/runtime/routes/admin.d.ts.map +1 -1
- package/dist/runtime/routes/admin.js +20 -13
- package/dist/runtime/routes/admin.js.map +1 -1
- package/dist/runtime/routes/auth-login.d.ts +1 -0
- package/dist/runtime/routes/auth-login.d.ts.map +1 -1
- package/dist/runtime/routes/auth-login.js +1 -0
- package/dist/runtime/routes/auth-login.js.map +1 -1
- package/dist/runtime/routes/auth-logout.d.ts +1 -0
- package/dist/runtime/routes/auth-logout.d.ts.map +1 -1
- package/dist/runtime/routes/auth-logout.js +1 -0
- package/dist/runtime/routes/auth-logout.js.map +1 -1
- package/dist/runtime/routes/auth-session.d.ts +1 -0
- package/dist/runtime/routes/auth-session.d.ts.map +1 -1
- package/dist/runtime/routes/auth-session.js +1 -0
- package/dist/runtime/routes/auth-session.js.map +1 -1
- package/dist/runtime/routes/collection-list.d.ts +1 -0
- package/dist/runtime/routes/collection-list.d.ts.map +1 -1
- package/dist/runtime/routes/collection-list.js +3 -2
- package/dist/runtime/routes/collection-list.js.map +1 -1
- package/dist/runtime/routes/collections-metadata.d.ts +1 -0
- package/dist/runtime/routes/collections-metadata.d.ts.map +1 -1
- package/dist/runtime/routes/collections-metadata.js +3 -2
- package/dist/runtime/routes/collections-metadata.js.map +1 -1
- package/dist/runtime/routes/draft.d.ts +5 -0
- package/dist/runtime/routes/draft.d.ts.map +1 -1
- package/dist/runtime/routes/draft.js +18 -1
- package/dist/runtime/routes/draft.js.map +1 -1
- package/dist/runtime/routes/editor-assets.d.ts +1 -0
- package/dist/runtime/routes/editor-assets.d.ts.map +1 -1
- package/dist/runtime/routes/editor-assets.js +1 -0
- package/dist/runtime/routes/editor-assets.js.map +1 -1
- package/dist/runtime/routes/entries.d.ts +1 -0
- package/dist/runtime/routes/entries.d.ts.map +1 -1
- package/dist/runtime/routes/entries.js +6 -4
- package/dist/runtime/routes/entries.js.map +1 -1
- package/dist/runtime/routes/history.d.ts +1 -0
- package/dist/runtime/routes/history.d.ts.map +1 -1
- package/dist/runtime/routes/history.js +50 -24
- package/dist/runtime/routes/history.js.map +1 -1
- package/dist/runtime/routes/mutate.d.ts +1 -0
- package/dist/runtime/routes/mutate.d.ts.map +1 -1
- package/dist/runtime/routes/mutate.js +42 -7
- package/dist/runtime/routes/mutate.js.map +1 -1
- package/dist/runtime/routes/publish.d.ts +1 -0
- package/dist/runtime/routes/publish.d.ts.map +1 -1
- package/dist/runtime/routes/publish.js +15 -3
- package/dist/runtime/routes/publish.js.map +1 -1
- package/dist/runtime/routes/schema.d.ts +1 -0
- package/dist/runtime/routes/schema.d.ts.map +1 -1
- package/dist/runtime/routes/schema.js +7 -3
- package/dist/runtime/routes/schema.js.map +1 -1
- package/dist/runtime/routes/studio-home.d.ts +1 -0
- package/dist/runtime/routes/studio-home.d.ts.map +1 -1
- package/dist/runtime/routes/studio-home.js +10 -9
- package/dist/runtime/routes/studio-home.js.map +1 -1
- package/dist/runtime/routes/theme-stylesheet.d.ts +1 -0
- package/dist/runtime/routes/theme-stylesheet.d.ts.map +1 -1
- package/dist/runtime/routes/theme-stylesheet.js +12 -1
- package/dist/runtime/routes/theme-stylesheet.js.map +1 -1
- package/dist/runtime/routes/upload.d.ts +1 -0
- package/dist/runtime/routes/upload.d.ts.map +1 -1
- package/dist/runtime/routes/upload.js +1 -0
- package/dist/runtime/routes/upload.js.map +1 -1
- package/dist/runtime/static-bake.d.ts +20 -0
- package/dist/runtime/static-bake.d.ts.map +1 -0
- package/dist/runtime/static-bake.js +58 -0
- package/dist/runtime/static-bake.js.map +1 -0
- package/dist/runtime/storage/atomic-write.d.ts.map +1 -1
- package/dist/runtime/storage/atomic-write.js +8 -3
- package/dist/runtime/storage/atomic-write.js.map +1 -1
- package/dist/runtime/storage/frontmatter-codec.d.ts.map +1 -1
- package/dist/runtime/storage/frontmatter-codec.js +8 -0
- package/dist/runtime/storage/frontmatter-codec.js.map +1 -1
- package/dist/runtime/storage/markdown-adapter.d.ts +19 -0
- package/dist/runtime/storage/markdown-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/markdown-adapter.js +41 -0
- package/dist/runtime/storage/markdown-adapter.js.map +1 -1
- package/dist/runtime/storage/session-overlay-adapter.d.ts +8 -0
- package/dist/runtime/storage/session-overlay-adapter.d.ts.map +1 -1
- package/dist/runtime/storage/session-overlay-adapter.js +24 -2
- package/dist/runtime/storage/session-overlay-adapter.js.map +1 -1
- package/dist/runtime/utils.d.ts +10 -0
- package/dist/runtime/utils.d.ts.map +1 -1
- package/dist/runtime/utils.js +16 -0
- package/dist/runtime/utils.js.map +1 -1
- package/dist/runtime/views/studio-layout.d.ts.map +1 -1
- package/dist/runtime/views/studio-layout.js +11 -10
- package/dist/runtime/views/studio-layout.js.map +1 -1
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/cms/admin-entry.js +36 -2
- package/static/cms/dev-toolbar/app.js +3 -1
- package/static/cms/editor/config.js +10 -0
- package/static/cms/editor/guards.js +1 -1
- package/static/cms/editor/helpers.js +5 -1
- package/static/cms/editor/highlight.js +4 -6
- package/static/cms/editor/image-edit.js +41 -11
- package/static/cms/editor/image.css +7 -1
- package/static/cms/editor/md-block-edit.js +176 -0
- package/static/cms/editor/md-serialize.js +301 -0
- package/static/cms/editor/panel.css +69 -25
- package/static/cms/editor/panel.js +39 -0
- package/static/cms/editor/rich-toolbar.js +4 -3
- package/static/cms/editor/sanitize.js +10 -5
- package/static/cms/editor/sync.js +1 -1
- package/static/cms/editor/text-edit.js +68 -17
- package/static/cms/editor/text-link-interactions.js +4 -4
- package/static/cms/editor/toast.css +114 -2
- package/static/cms/editor/toast.js +121 -22
- package/static/cms/editor/tokens-and-text.css +64 -3
- package/static/cms/editor/toolbar.css +76 -8
- package/static/cms/editor/toolbar.js +173 -64
- package/static/cms/editor.js +16 -3
- package/static/cms/studio-login.css +70 -0
- package/static/cms/studio.css +80 -13
|
@@ -1,29 +1,128 @@
|
|
|
1
|
+
const SUCCESS_SVG =
|
|
2
|
+
'<svg class="cms-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>';
|
|
3
|
+
const ERROR_SVG =
|
|
4
|
+
'<svg class="cms-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>';
|
|
5
|
+
const WARNING_SVG =
|
|
6
|
+
'<svg class="cms-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>';
|
|
7
|
+
|
|
8
|
+
function iconFor(type) {
|
|
9
|
+
if (type === 'success') return SUCCESS_SVG;
|
|
10
|
+
if (type === 'warning') return WARNING_SVG;
|
|
11
|
+
return ERROR_SVG;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Toast controller. Returns a `showToast(message, type)` function with a
|
|
16
|
+
* `.conflict()` method for the two-choice save-conflict prompt.
|
|
17
|
+
*
|
|
18
|
+
* Design notes:
|
|
19
|
+
* - Toasts stack (a container region) instead of one replacing the next, so a
|
|
20
|
+
* burst of saves or an error + a later success don't clobber each other.
|
|
21
|
+
* - Errors and conflict prompts are STICKY and dismissible — a 2.5s auto-hide
|
|
22
|
+
* would let a failure or a data-loss choice vanish before it's read.
|
|
23
|
+
* - The message is always set via textContent, never innerHTML, so a
|
|
24
|
+
* server-provided error string can't inject markup into the editor chrome.
|
|
25
|
+
* - The container is an aria-live region; errors/conflicts are role="alert".
|
|
26
|
+
*/
|
|
1
27
|
export function createToast() {
|
|
2
|
-
let
|
|
28
|
+
let container = null;
|
|
3
29
|
|
|
4
|
-
|
|
5
|
-
if (
|
|
6
|
-
|
|
7
|
-
|
|
30
|
+
function ensureContainer() {
|
|
31
|
+
if (container && document.body.contains(container)) return container;
|
|
32
|
+
container = document.createElement('div');
|
|
33
|
+
container.className = 'cms-toast-stack';
|
|
34
|
+
container.setAttribute('aria-live', 'polite');
|
|
35
|
+
document.body.appendChild(container);
|
|
36
|
+
return container;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function dismiss(toast) {
|
|
40
|
+
if (toast._caretDismissed) return;
|
|
41
|
+
toast._caretDismissed = true;
|
|
42
|
+
toast.classList.add('cms-toast-out');
|
|
43
|
+
setTimeout(() => toast.remove(), 300);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function render(type, { message, sticky, actions, role }) {
|
|
47
|
+
const stack = ensureContainer();
|
|
8
48
|
|
|
9
49
|
const toast = document.createElement('div');
|
|
10
50
|
toast.className = `cms-toast cms-toast-${type}`;
|
|
51
|
+
if (role) toast.setAttribute('role', role);
|
|
52
|
+
if (sticky || (actions && actions.length)) toast.classList.add('cms-toast-interactive');
|
|
53
|
+
|
|
54
|
+
const iconWrap = document.createElement('span');
|
|
55
|
+
iconWrap.className = 'cms-toast-icon-wrap';
|
|
56
|
+
iconWrap.setAttribute('aria-hidden', 'true');
|
|
57
|
+
iconWrap.innerHTML = iconFor(type); // trusted constant SVG only
|
|
58
|
+
toast.appendChild(iconWrap);
|
|
59
|
+
|
|
60
|
+
const msg = document.createElement('span');
|
|
61
|
+
msg.className = 'cms-toast-msg';
|
|
62
|
+
msg.textContent = message; // never innerHTML — message may carry server text
|
|
63
|
+
toast.appendChild(msg);
|
|
64
|
+
|
|
65
|
+
if (actions && actions.length) {
|
|
66
|
+
const group = document.createElement('div');
|
|
67
|
+
group.className = 'cms-toast-actions';
|
|
68
|
+
for (const action of actions) {
|
|
69
|
+
const btn = document.createElement('button');
|
|
70
|
+
btn.type = 'button';
|
|
71
|
+
btn.className = `cms-toast-btn${action.primary ? ' cms-toast-btn-primary' : ''}`;
|
|
72
|
+
btn.textContent = action.label;
|
|
73
|
+
btn.addEventListener('click', () => {
|
|
74
|
+
dismiss(toast);
|
|
75
|
+
try {
|
|
76
|
+
action.onClick();
|
|
77
|
+
} catch (e) {
|
|
78
|
+
/* action errors shouldn't break the toast */
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
group.appendChild(btn);
|
|
82
|
+
}
|
|
83
|
+
toast.appendChild(group);
|
|
84
|
+
} else if (sticky) {
|
|
85
|
+
const close = document.createElement('button');
|
|
86
|
+
close.type = 'button';
|
|
87
|
+
close.className = 'cms-toast-close';
|
|
88
|
+
close.setAttribute('aria-label', 'Dismiss');
|
|
89
|
+
close.textContent = '×';
|
|
90
|
+
close.addEventListener('click', () => dismiss(toast));
|
|
91
|
+
toast.appendChild(close);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
stack.appendChild(toast);
|
|
95
|
+
if (!sticky) setTimeout(() => dismiss(toast), 2500);
|
|
96
|
+
return toast;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function showToast(message, type) {
|
|
100
|
+
const t = type === 'error' ? 'error' : type || 'success';
|
|
101
|
+
return render(t, {
|
|
102
|
+
message,
|
|
103
|
+
sticky: t === 'error',
|
|
104
|
+
role: t === 'error' ? 'alert' : undefined,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Two-choice save-conflict prompt. Sticky so the user's edit is never silently
|
|
109
|
+
// discarded — they explicitly choose to keep theirs or load the latest.
|
|
110
|
+
showToast.conflict = ({
|
|
111
|
+
message,
|
|
112
|
+
onKeepMine,
|
|
113
|
+
onLoadLatest,
|
|
114
|
+
keepLabel = 'Keep mine',
|
|
115
|
+
latestLabel = 'Load latest',
|
|
116
|
+
}) =>
|
|
117
|
+
render('warning', {
|
|
118
|
+
message,
|
|
119
|
+
sticky: true,
|
|
120
|
+
role: 'alert',
|
|
121
|
+
actions: [
|
|
122
|
+
{ label: keepLabel, primary: true, onClick: onKeepMine },
|
|
123
|
+
{ label: latestLabel, onClick: onLoadLatest },
|
|
124
|
+
],
|
|
125
|
+
});
|
|
11
126
|
|
|
12
|
-
|
|
13
|
-
type === 'success'
|
|
14
|
-
? '<svg class="cms-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>'
|
|
15
|
-
: '<svg class="cms-toast-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>';
|
|
16
|
-
|
|
17
|
-
toast.innerHTML = iconSvg + `<span>${message}</span>`;
|
|
18
|
-
document.body.appendChild(toast);
|
|
19
|
-
activeToast = toast;
|
|
20
|
-
|
|
21
|
-
setTimeout(() => {
|
|
22
|
-
toast.classList.add('cms-toast-out');
|
|
23
|
-
setTimeout(() => {
|
|
24
|
-
toast.remove();
|
|
25
|
-
if (activeToast === toast) activeToast = null;
|
|
26
|
-
}, 300);
|
|
27
|
-
}, 2500);
|
|
28
|
-
};
|
|
127
|
+
return showToast;
|
|
29
128
|
}
|
|
@@ -16,14 +16,43 @@
|
|
|
16
16
|
--cms-green: #22c55e;
|
|
17
17
|
--cms-red: #ef4444;
|
|
18
18
|
--cms-yellow: #eab308;
|
|
19
|
+
--cms-amber: #eab308;
|
|
19
20
|
--cms-font: Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
/* ---------------------------------------------------------------------------
|
|
24
|
+
Host-style insulation
|
|
25
|
+
|
|
26
|
+
The editor chrome is injected as direct <body> children on the HOST site, so
|
|
27
|
+
an aggressive host reset (`* {}`, `body {}`, tag selectors) can bleed into it
|
|
28
|
+
— distorting fonts, line-height, letter-spacing, or box model. Pin the chrome
|
|
29
|
+
roots to sane defaults so they render consistently regardless of the host's
|
|
30
|
+
CSS. (Individual controls set their own type where needed.)
|
|
31
|
+
--------------------------------------------------------------------------- */
|
|
32
|
+
.cms-toolbar,
|
|
33
|
+
.cms-toast-stack,
|
|
34
|
+
.cms-toast,
|
|
35
|
+
.cms-link-popover,
|
|
36
|
+
.cms-content-map,
|
|
37
|
+
.cms-link-follow,
|
|
38
|
+
.cms-rich-toolbar,
|
|
39
|
+
.cms-studio-panel {
|
|
40
|
+
box-sizing: border-box;
|
|
41
|
+
font-family: var(--cms-font);
|
|
42
|
+
line-height: normal;
|
|
43
|
+
letter-spacing: normal;
|
|
44
|
+
text-transform: none;
|
|
45
|
+
text-align: left;
|
|
46
|
+
}
|
|
47
|
+
|
|
22
48
|
/* ---------------------------------------------------------------------------
|
|
23
49
|
Text editing affordances — simple blue outline
|
|
24
50
|
--------------------------------------------------------------------------- */
|
|
25
51
|
|
|
26
|
-
|
|
52
|
+
/* Both field bindings (data-caret) and markdown body blocks (data-caret-md)
|
|
53
|
+
carry .cms-editable, so the hover/focus affordances apply to both. */
|
|
54
|
+
[data-caret].cms-editable,
|
|
55
|
+
[data-caret-md].cms-editable {
|
|
27
56
|
cursor: text;
|
|
28
57
|
transition: outline 0.2s, box-shadow 0.2s, background 0.4s;
|
|
29
58
|
outline: 2px dashed transparent;
|
|
@@ -31,16 +60,48 @@
|
|
|
31
60
|
border-radius: 2px;
|
|
32
61
|
}
|
|
33
62
|
|
|
34
|
-
[data-caret].cms-editable:hover
|
|
63
|
+
[data-caret].cms-editable:hover,
|
|
64
|
+
[data-caret-md].cms-editable:hover {
|
|
35
65
|
outline-color: var(--cms-blue-hover);
|
|
36
66
|
}
|
|
37
67
|
|
|
38
|
-
[data-caret].cms-editable:focus
|
|
68
|
+
[data-caret].cms-editable:focus,
|
|
69
|
+
[data-caret-md].cms-editable:focus {
|
|
39
70
|
outline: 2px solid var(--cms-blue);
|
|
40
71
|
outline-offset: 4px;
|
|
41
72
|
box-shadow: 0 0 0 4px var(--cms-blue-dim);
|
|
42
73
|
}
|
|
43
74
|
|
|
75
|
+
/* ---------------------------------------------------------------------------
|
|
76
|
+
Unpublished body draft
|
|
77
|
+
The server rewrite tags blocks whose prose comes from an unpublished draft
|
|
78
|
+
(editor preview only — the public reads the base and never receives this).
|
|
79
|
+
Flag them so a reloaded preview is visibly distinct from live, published
|
|
80
|
+
prose and the editor knows a Publish is still pending.
|
|
81
|
+
--------------------------------------------------------------------------- */
|
|
82
|
+
|
|
83
|
+
[data-caret-md-draft] {
|
|
84
|
+
position: relative;
|
|
85
|
+
background: var(--cms-blue-dim);
|
|
86
|
+
box-shadow: -0.6em 0 0 0 var(--cms-blue-dim);
|
|
87
|
+
border-radius: 2px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
[data-caret-md-draft]::after {
|
|
91
|
+
content: 'Draft';
|
|
92
|
+
position: absolute;
|
|
93
|
+
top: -0.6em;
|
|
94
|
+
right: 0;
|
|
95
|
+
font: 600 10px / 1 var(--cms-font);
|
|
96
|
+
letter-spacing: 0.08em;
|
|
97
|
+
text-transform: uppercase;
|
|
98
|
+
color: #fff;
|
|
99
|
+
background: var(--cms-yellow);
|
|
100
|
+
padding: 3px 6px;
|
|
101
|
+
border-radius: 3px;
|
|
102
|
+
pointer-events: none;
|
|
103
|
+
}
|
|
104
|
+
|
|
44
105
|
/* ---------------------------------------------------------------------------
|
|
45
106
|
Link/button click prevention in editor mode
|
|
46
107
|
--------------------------------------------------------------------------- */
|
|
@@ -78,6 +78,45 @@
|
|
|
78
78
|
display: flex;
|
|
79
79
|
align-items: center;
|
|
80
80
|
gap: 12px;
|
|
81
|
+
min-width: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@media (max-width: 768px) {
|
|
85
|
+
.cms-toolbar-inner {
|
|
86
|
+
padding: 0 12px;
|
|
87
|
+
gap: 8px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.cms-toolbar-left {
|
|
91
|
+
gap: 8px;
|
|
92
|
+
flex-shrink: 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.cms-status-text {
|
|
96
|
+
display: none;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.cms-toolbar-right {
|
|
100
|
+
gap: 6px;
|
|
101
|
+
overflow-x: auto;
|
|
102
|
+
-webkit-overflow-scrolling: touch;
|
|
103
|
+
scrollbar-width: none;
|
|
104
|
+
flex-shrink: 1;
|
|
105
|
+
padding-left: 4px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.cms-toolbar-right::-webkit-scrollbar {
|
|
109
|
+
display: none;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.cms-toolbar-divider {
|
|
113
|
+
display: none;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.cms-toolbar button {
|
|
117
|
+
padding: 6px 10px;
|
|
118
|
+
flex-shrink: 0;
|
|
119
|
+
}
|
|
81
120
|
}
|
|
82
121
|
|
|
83
122
|
/* Shared base for every toolbar button so they can't drift visually. Individual
|
|
@@ -88,13 +127,13 @@
|
|
|
88
127
|
gap: 6px;
|
|
89
128
|
padding: 6px 14px;
|
|
90
129
|
font-family: var(--cms-font);
|
|
91
|
-
font-size:
|
|
130
|
+
font-size: 11px;
|
|
92
131
|
font-weight: 500;
|
|
93
132
|
line-height: 1.2;
|
|
94
|
-
letter-spacing: 0.
|
|
133
|
+
letter-spacing: 0.08em;
|
|
95
134
|
text-transform: uppercase;
|
|
96
135
|
background: transparent;
|
|
97
|
-
color: rgba(255, 255, 255, 0.
|
|
136
|
+
color: rgba(255, 255, 255, 0.72);
|
|
98
137
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
99
138
|
border-radius: 2px;
|
|
100
139
|
cursor: pointer;
|
|
@@ -150,7 +189,7 @@
|
|
|
150
189
|
}
|
|
151
190
|
|
|
152
191
|
.cms-status-text {
|
|
153
|
-
color: rgba(255, 255, 255, 0.
|
|
192
|
+
color: rgba(255, 255, 255, 0.72);
|
|
154
193
|
font-size: 11px;
|
|
155
194
|
font-weight: 400;
|
|
156
195
|
}
|
|
@@ -181,6 +220,17 @@
|
|
|
181
220
|
display: none;
|
|
182
221
|
}
|
|
183
222
|
|
|
223
|
+
/* Draft controls wrapper is transparent to the toolbar's flex layout so its
|
|
224
|
+
buttons keep the row's gap; [hidden] (server delivery, no pending draft)
|
|
225
|
+
still collapses the whole group. */
|
|
226
|
+
.cms-draft-controls {
|
|
227
|
+
display: contents;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.cms-draft-controls[hidden] {
|
|
231
|
+
display: none;
|
|
232
|
+
}
|
|
233
|
+
|
|
184
234
|
/* Draft preview active — amber, signalling "unpublished" */
|
|
185
235
|
.cms-toolbar button.cms-preview-btn-active {
|
|
186
236
|
background: rgba(234, 179, 8, 0.12);
|
|
@@ -188,6 +238,19 @@
|
|
|
188
238
|
color: var(--cms-yellow);
|
|
189
239
|
}
|
|
190
240
|
|
|
241
|
+
/* Publish — primary action on static delivery */
|
|
242
|
+
.cms-toolbar button.cms-go-live-btn {
|
|
243
|
+
background: rgba(34, 197, 94, 0.12);
|
|
244
|
+
border-color: rgba(34, 197, 94, 0.3);
|
|
245
|
+
color: var(--cms-green);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.cms-toolbar button.cms-go-live-btn:hover {
|
|
249
|
+
background: rgba(34, 197, 94, 0.25);
|
|
250
|
+
border-color: rgba(34, 197, 94, 0.5);
|
|
251
|
+
color: var(--cms-green);
|
|
252
|
+
}
|
|
253
|
+
|
|
191
254
|
/* Publish — green */
|
|
192
255
|
.cms-toolbar button.cms-publish-btn {
|
|
193
256
|
background: rgba(34, 197, 94, 0.12);
|
|
@@ -208,8 +271,9 @@
|
|
|
208
271
|
color: var(--cms-red);
|
|
209
272
|
}
|
|
210
273
|
|
|
211
|
-
/* Highlight all mode — show every editable region */
|
|
212
|
-
.cms-highlight-all [data-caret].cms-editable
|
|
274
|
+
/* Highlight all mode — show every editable region (fields AND body blocks) */
|
|
275
|
+
.cms-highlight-all [data-caret].cms-editable,
|
|
276
|
+
.cms-highlight-all [data-caret-md].cms-editable {
|
|
213
277
|
outline-color: var(--cms-blue-hover);
|
|
214
278
|
background: rgba(59, 130, 246, 0.04);
|
|
215
279
|
}
|
|
@@ -223,6 +287,7 @@
|
|
|
223
287
|
transition — motion is suppressed, the information is not. */
|
|
224
288
|
@media (prefers-reduced-motion: reduce) {
|
|
225
289
|
.cms-highlight-all [data-caret].cms-editable,
|
|
290
|
+
.cms-highlight-all [data-caret-md].cms-editable,
|
|
226
291
|
.cms-highlight-all img[data-caret] {
|
|
227
292
|
transition: none;
|
|
228
293
|
}
|
|
@@ -246,8 +311,11 @@
|
|
|
246
311
|
|
|
247
312
|
.cms-nav-link {
|
|
248
313
|
padding: 5px 14px;
|
|
249
|
-
font-
|
|
250
|
-
|
|
314
|
+
font-family: var(--cms-font);
|
|
315
|
+
font-size: 11px;
|
|
316
|
+
font-weight: 500;
|
|
317
|
+
line-height: 1.2;
|
|
318
|
+
letter-spacing: 0.08em;
|
|
251
319
|
text-transform: uppercase;
|
|
252
320
|
text-decoration: none;
|
|
253
321
|
color: rgba(255, 255, 255, 0.35);
|