@actuate-media/cms-admin 0.72.2 → 0.73.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/CHANGELOG.md +39 -0
- package/dist/__tests__/components/resizable-aside.test.d.ts +2 -0
- package/dist/__tests__/components/resizable-aside.test.d.ts.map +1 -0
- package/dist/__tests__/components/resizable-aside.test.js +77 -0
- package/dist/__tests__/components/resizable-aside.test.js.map +1 -0
- package/dist/__tests__/components/toggle.test.d.ts +2 -0
- package/dist/__tests__/components/toggle.test.d.ts.map +1 -0
- package/dist/__tests__/components/toggle.test.js +17 -0
- package/dist/__tests__/components/toggle.test.js.map +1 -0
- package/dist/__tests__/views/post-fields-modal.render.test.js +38 -0
- package/dist/__tests__/views/post-fields-modal.render.test.js.map +1 -1
- package/dist/actuate-admin.css +1 -1
- package/dist/components/MediaPickerModal.d.ts.map +1 -1
- package/dist/components/MediaPickerModal.js +1 -1
- package/dist/components/MediaPickerModal.js.map +1 -1
- package/dist/components/TagInput.js +1 -1
- package/dist/components/TagInput.js.map +1 -1
- package/dist/components/ui/Modal.d.ts +17 -1
- package/dist/components/ui/Modal.d.ts.map +1 -1
- package/dist/components/ui/Modal.js +29 -3
- package/dist/components/ui/Modal.js.map +1 -1
- package/dist/components/ui/ResizableAside.d.ts +38 -0
- package/dist/components/ui/ResizableAside.d.ts.map +1 -0
- package/dist/components/ui/ResizableAside.js +209 -0
- package/dist/components/ui/ResizableAside.js.map +1 -0
- package/dist/components/ui/Toggle.d.ts.map +1 -1
- package/dist/components/ui/Toggle.js +4 -3
- package/dist/components/ui/Toggle.js.map +1 -1
- package/dist/fields/RichTextField.d.ts +3 -1
- package/dist/fields/RichTextField.d.ts.map +1 -1
- package/dist/fields/RichTextField.js +2 -2
- package/dist/fields/RichTextField.js.map +1 -1
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +1 -1
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/page-editor/PageSectionEditor.js +1 -1
- package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
- package/dist/views/page-editor/SectionInspector.d.ts +4 -1
- package/dist/views/page-editor/SectionInspector.d.ts.map +1 -1
- package/dist/views/page-editor/SectionInspector.js +14 -3
- package/dist/views/page-editor/SectionInspector.js.map +1 -1
- package/dist/views/post-editor/PostFieldsModal.d.ts +1 -1
- package/dist/views/post-editor/PostFieldsModal.d.ts.map +1 -1
- package/dist/views/post-editor/PostFieldsModal.js +152 -13
- package/dist/views/post-editor/PostFieldsModal.js.map +1 -1
- package/dist/views/post-editor/PostHeaderPanel.d.ts.map +1 -1
- package/dist/views/post-editor/PostHeaderPanel.js +2 -1
- package/dist/views/post-editor/PostHeaderPanel.js.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
- package/dist/views/post-editor/PostSectionEditor.js +6 -1
- package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
- package/dist/views/post-editor/PostTemplateEditor.js +1 -1
- package/dist/views/post-editor/PostTemplateEditor.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/components/resizable-aside.test.tsx +130 -0
- package/src/__tests__/components/toggle.test.tsx +17 -0
- package/src/__tests__/views/post-fields-modal.render.test.tsx +54 -0
- package/src/components/MediaPickerModal.tsx +6 -2
- package/src/components/TagInput.tsx +1 -1
- package/src/components/ui/Modal.tsx +46 -3
- package/src/components/ui/ResizableAside.tsx +317 -0
- package/src/components/ui/Toggle.tsx +4 -3
- package/src/fields/RichTextField.tsx +4 -1
- package/src/styles/actuate-tokens.css +7 -2
- package/src/views/Dashboard.tsx +2 -1
- package/src/views/page-editor/PageSectionEditor.tsx +1 -1
- package/src/views/page-editor/SectionInspector.tsx +54 -26
- package/src/views/post-editor/PostFieldsModal.tsx +412 -174
- package/src/views/post-editor/PostHeaderPanel.tsx +15 -11
- package/src/views/post-editor/PostSectionEditor.tsx +9 -1
- package/src/views/post-editor/PostTemplateEditor.tsx +1 -1
|
@@ -8,6 +8,8 @@ export interface RichTextFieldProps {
|
|
|
8
8
|
onChange: (value: string) => void
|
|
9
9
|
required?: boolean
|
|
10
10
|
helpText?: string
|
|
11
|
+
/** Passed through to the underlying editor shell (e.g. max-height). */
|
|
12
|
+
className?: string
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export function RichTextField({
|
|
@@ -16,6 +18,7 @@ export function RichTextField({
|
|
|
16
18
|
onChange,
|
|
17
19
|
required,
|
|
18
20
|
helpText,
|
|
21
|
+
className,
|
|
19
22
|
}: RichTextFieldProps) {
|
|
20
23
|
return (
|
|
21
24
|
<div>
|
|
@@ -23,7 +26,7 @@ export function RichTextField({
|
|
|
23
26
|
{label}
|
|
24
27
|
{required && <span className="ml-0.5 text-[var(--destructive)]">*</span>}
|
|
25
28
|
</label>
|
|
26
|
-
<TipTapEditor content={value} onChange={onChange} />
|
|
29
|
+
<TipTapEditor content={value} onChange={onChange} className={className} />
|
|
27
30
|
{helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
|
|
28
31
|
</div>
|
|
29
32
|
)
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
/* Text */
|
|
15
15
|
--txt: #1a1827;
|
|
16
16
|
--sub: #6b6878;
|
|
17
|
-
|
|
17
|
+
/* Deviates from tokens.json's #B0ADBE (2.2:1 on white — illegible). The
|
|
18
|
+
admin uses --muted as real text (section labels, hints, icons), so it
|
|
19
|
+
must meet WCAG AA (>=4.5:1) on --card and --bg while staying one step
|
|
20
|
+
lighter than --sub to preserve the text hierarchy. */
|
|
21
|
+
--muted: #716e83;
|
|
18
22
|
|
|
19
23
|
/* Accent */
|
|
20
24
|
--acc: #7c3aed;
|
|
@@ -79,7 +83,8 @@
|
|
|
79
83
|
|
|
80
84
|
--txt: #eae8f5;
|
|
81
85
|
--sub: #8e8ba8;
|
|
82
|
-
|
|
86
|
+
/* Same AA deviation as light mode (tokens.json #504E68 is 2.1:1 on card). */
|
|
87
|
+
--muted: #8784a2;
|
|
83
88
|
|
|
84
89
|
--acc: #9d71f0;
|
|
85
90
|
--acc-l: #231950;
|
package/src/views/Dashboard.tsx
CHANGED
|
@@ -585,7 +585,8 @@ export function Dashboard({ config, session, onNavigate }: DashboardProps) {
|
|
|
585
585
|
<h1 className="text-foreground">
|
|
586
586
|
{greeting}, {userName} <span aria-hidden>👋</span>
|
|
587
587
|
</h1>
|
|
588
|
-
|
|
588
|
+
{/* data-volatile: the literal date changes daily — visual tests mask it. */}
|
|
589
|
+
<p className="text-muted-foreground text-sm" data-volatile>
|
|
589
590
|
{dateStr}
|
|
590
591
|
{totalIssues > 0 && (
|
|
591
592
|
<span className="hidden sm:inline">
|
|
@@ -19,7 +19,9 @@ import {
|
|
|
19
19
|
} from '@dnd-kit/sortable'
|
|
20
20
|
import { CSS } from '@dnd-kit/utilities'
|
|
21
21
|
import { MediaPickerModal } from '../../components/MediaPickerModal.js'
|
|
22
|
+
import { InspectorExpandButton, ResizableAside } from '../../components/ui/ResizableAside.js'
|
|
22
23
|
import { Toggle } from '../../components/ui/Toggle.js'
|
|
24
|
+
import { RichTextField } from '../../fields/RichTextField.js'
|
|
23
25
|
import type { PageSection } from '../../lib/page-editor-service.js'
|
|
24
26
|
import type { ResolvedRepeater, SectionSettings } from './section-types.js'
|
|
25
27
|
import {
|
|
@@ -37,11 +39,37 @@ interface SectionInspectorProps {
|
|
|
37
39
|
onSettingsChange: (patch: Partial<SectionSettings>) => void
|
|
38
40
|
onMetaChange: (patch: { name?: string; internalLabel?: string }) => void
|
|
39
41
|
onToggleVisibility: () => void
|
|
42
|
+
/** Post body field — shown when editing an Article Body section bound to the post field. */
|
|
43
|
+
postBody?: string
|
|
44
|
+
onPostBodyChange?: (html: string) => void
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
const LABEL = 'text-foreground mb-1 block text-xs font-medium'
|
|
43
48
|
const INPUT =
|
|
44
49
|
'border-input bg-input-background text-foreground focus-visible:ring-ring w-full rounded-md border px-2.5 py-1.5 text-sm focus-visible:ring-2 focus-visible:outline-none'
|
|
50
|
+
const INSPECTOR_SHELL = 'bg-card border-border flex h-full flex-col border-l'
|
|
51
|
+
|
|
52
|
+
function InspectorHeaderActions({
|
|
53
|
+
onClose,
|
|
54
|
+
closeLabel = 'Close inspector',
|
|
55
|
+
}: {
|
|
56
|
+
onClose: () => void
|
|
57
|
+
closeLabel?: string
|
|
58
|
+
}) {
|
|
59
|
+
return (
|
|
60
|
+
<div className="flex shrink-0 items-center gap-0.5">
|
|
61
|
+
<InspectorExpandButton />
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
onClick={onClose}
|
|
65
|
+
aria-label={closeLabel}
|
|
66
|
+
className="text-muted-foreground hover:text-foreground hover:bg-accent flex h-9 w-9 items-center justify-center rounded-md md:h-7 md:w-7"
|
|
67
|
+
>
|
|
68
|
+
<X className="h-4 w-4" aria-hidden />
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
45
73
|
|
|
46
74
|
export function SectionInspector({
|
|
47
75
|
section,
|
|
@@ -51,8 +79,17 @@ export function SectionInspector({
|
|
|
51
79
|
onSettingsChange,
|
|
52
80
|
onMetaChange,
|
|
53
81
|
onToggleVisibility,
|
|
82
|
+
postBody,
|
|
83
|
+
onPostBodyChange,
|
|
54
84
|
}: SectionInspectorProps) {
|
|
55
85
|
const def = getSectionType(section.sectionType)
|
|
86
|
+
const bodySource = String(section.content.source ?? 'field')
|
|
87
|
+
const editPostBodyField =
|
|
88
|
+
section.sectionType === 'article-body' &&
|
|
89
|
+
bodySource === 'field' &&
|
|
90
|
+
onPostBodyChange !== undefined
|
|
91
|
+
const contentFields =
|
|
92
|
+
def?.fields.filter((field) => !(editPostBodyField && field.key === 'body')) ?? []
|
|
56
93
|
|
|
57
94
|
// Escape closes the inspector.
|
|
58
95
|
useEffect(() => {
|
|
@@ -67,24 +104,17 @@ export function SectionInspector({
|
|
|
67
104
|
// editable controls, so the externally-managed content is never altered here.
|
|
68
105
|
if (section.unmanaged) {
|
|
69
106
|
return (
|
|
70
|
-
<
|
|
107
|
+
<ResizableAside
|
|
71
108
|
role="dialog"
|
|
72
109
|
aria-label={`${section.name} (read-only)`}
|
|
73
|
-
className=
|
|
110
|
+
className={INSPECTOR_SHELL}
|
|
74
111
|
>
|
|
75
112
|
<div className="border-border flex items-center justify-between border-b px-4 py-3">
|
|
76
113
|
<div className="min-w-0">
|
|
77
114
|
<h2 className="text-foreground truncate text-sm font-medium">{section.name}</h2>
|
|
78
115
|
<p className="text-muted-foreground text-xs">Managed outside the editor</p>
|
|
79
116
|
</div>
|
|
80
|
-
<
|
|
81
|
-
type="button"
|
|
82
|
-
onClick={onClose}
|
|
83
|
-
aria-label="Close inspector"
|
|
84
|
-
className="text-muted-foreground hover:text-foreground hover:bg-accent rounded p-1"
|
|
85
|
-
>
|
|
86
|
-
<X className="h-4 w-4" aria-hidden />
|
|
87
|
-
</button>
|
|
117
|
+
<InspectorHeaderActions onClose={onClose} />
|
|
88
118
|
</div>
|
|
89
119
|
<div className="flex-1 space-y-3 overflow-y-auto p-4">
|
|
90
120
|
<div className="border-border bg-muted text-muted-foreground space-y-2 rounded-md border p-3 text-sm">
|
|
@@ -106,29 +136,18 @@ export function SectionInspector({
|
|
|
106
136
|
</p>
|
|
107
137
|
</div>
|
|
108
138
|
</div>
|
|
109
|
-
</
|
|
139
|
+
</ResizableAside>
|
|
110
140
|
)
|
|
111
141
|
}
|
|
112
142
|
|
|
113
143
|
return (
|
|
114
|
-
<
|
|
115
|
-
role="dialog"
|
|
116
|
-
aria-label={`Edit ${section.name}`}
|
|
117
|
-
className="bg-card border-border flex h-full w-80 shrink-0 flex-col border-l"
|
|
118
|
-
>
|
|
144
|
+
<ResizableAside role="dialog" aria-label={`Edit ${section.name}`} className={INSPECTOR_SHELL}>
|
|
119
145
|
<div className="border-border flex items-center justify-between border-b px-4 py-3">
|
|
120
146
|
<div className="min-w-0">
|
|
121
147
|
<h2 className="text-foreground truncate text-sm font-medium">{section.name}</h2>
|
|
122
148
|
<p className="text-muted-foreground text-xs">{def?.name ?? 'Section'}</p>
|
|
123
149
|
</div>
|
|
124
|
-
<
|
|
125
|
-
type="button"
|
|
126
|
-
onClick={onClose}
|
|
127
|
-
aria-label="Close inspector"
|
|
128
|
-
className="text-muted-foreground hover:text-foreground hover:bg-accent rounded p-1"
|
|
129
|
-
>
|
|
130
|
-
<X className="h-4 w-4" aria-hidden />
|
|
131
|
-
</button>
|
|
150
|
+
<InspectorHeaderActions onClose={onClose} />
|
|
132
151
|
</div>
|
|
133
152
|
|
|
134
153
|
<div className="flex-1 space-y-6 overflow-y-auto p-4">
|
|
@@ -143,7 +162,16 @@ export function SectionInspector({
|
|
|
143
162
|
<legend className="text-muted-foreground mb-2 text-[10px] font-medium tracking-wider uppercase">
|
|
144
163
|
Content
|
|
145
164
|
</legend>
|
|
146
|
-
{
|
|
165
|
+
{editPostBodyField && (
|
|
166
|
+
<RichTextField
|
|
167
|
+
label="Body"
|
|
168
|
+
value={postBody ?? ''}
|
|
169
|
+
onChange={onPostBodyChange}
|
|
170
|
+
className="[&_.ProseMirror]:min-h-[240px]"
|
|
171
|
+
helpText="Main article copy — rendered in the canvas preview and on the live site."
|
|
172
|
+
/>
|
|
173
|
+
)}
|
|
174
|
+
{contentFields.map((field) => (
|
|
147
175
|
<ContentField
|
|
148
176
|
key={field.key}
|
|
149
177
|
field={field}
|
|
@@ -294,7 +322,7 @@ export function SectionInspector({
|
|
|
294
322
|
</div>
|
|
295
323
|
</fieldset>
|
|
296
324
|
</div>
|
|
297
|
-
</
|
|
325
|
+
</ResizableAside>
|
|
298
326
|
)
|
|
299
327
|
}
|
|
300
328
|
|