@actuate-media/cms-admin 0.56.0 → 0.56.2
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 +12 -0
- package/dist/__tests__/components/posts-badges.test.js +3 -3
- package/dist/__tests__/components/posts-badges.test.js.map +1 -1
- package/dist/actuate-admin.css +1 -1
- package/dist/components/AICoauthorBubbleMenu.js +2 -2
- package/dist/components/AICoauthorBubbleMenu.js.map +1 -1
- package/dist/components/Breadcrumbs.js +2 -2
- package/dist/components/Breadcrumbs.js.map +1 -1
- package/dist/components/CoauthorResultPopover.d.ts.map +1 -1
- package/dist/components/CoauthorResultPopover.js +1 -1
- package/dist/components/CoauthorResultPopover.js.map +1 -1
- package/dist/components/CommandPalette.d.ts.map +1 -1
- package/dist/components/CommandPalette.js +11 -11
- package/dist/components/CommandPalette.js.map +1 -1
- package/dist/components/CommentSidePanel.js +11 -11
- package/dist/components/CommentSidePanel.js.map +1 -1
- package/dist/components/ContentOverviewChart.js +2 -2
- package/dist/components/ContentOverviewChart.js.map +1 -1
- package/dist/components/FocalPointPicker.js +1 -1
- package/dist/components/FocalPointPicker.js.map +1 -1
- package/dist/components/LivePreview.d.ts.map +1 -1
- package/dist/components/LivePreview.js +5 -5
- package/dist/components/LivePreview.js.map +1 -1
- package/dist/components/LogoPlaceholder.js +1 -1
- package/dist/components/LogoPlaceholder.js.map +1 -1
- package/dist/components/MentionableTextarea.js +3 -3
- package/dist/components/MentionableTextarea.js.map +1 -1
- package/dist/components/NotificationBell.js +1 -1
- package/dist/components/NotificationBell.js.map +1 -1
- package/dist/components/OfflineStatus.js +8 -8
- package/dist/components/OfflineStatus.js.map +1 -1
- package/dist/components/PresenceChips.d.ts.map +1 -1
- package/dist/components/PresenceChips.js +10 -6
- package/dist/components/PresenceChips.js.map +1 -1
- package/dist/components/SEOConfigPanel.d.ts.map +1 -1
- package/dist/components/SEOConfigPanel.js +10 -10
- package/dist/components/SEOConfigPanel.js.map +1 -1
- package/dist/components/SEOPanel.js +12 -12
- package/dist/components/SEOPanel.js.map +1 -1
- package/dist/components/SEOPerformance.d.ts.map +1 -1
- package/dist/components/SEOPerformance.js +3 -3
- package/dist/components/SEOPerformance.js.map +1 -1
- package/dist/components/TipTapEditor.js +6 -6
- package/dist/components/TipTapEditor.js.map +1 -1
- package/dist/components/pages/tag-badges.js +6 -6
- package/dist/components/pages/tag-badges.js.map +1 -1
- package/dist/components/posts/badges.d.ts +0 -4
- package/dist/components/posts/badges.d.ts.map +1 -1
- package/dist/components/posts/badges.js +28 -42
- package/dist/components/posts/badges.js.map +1 -1
- package/dist/components/ui/Badge.js +5 -5
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Toast.d.ts.map +1 -1
- package/dist/components/ui/Toast.js +4 -4
- package/dist/components/ui/Toast.js.map +1 -1
- package/dist/fields/ComponentBlockField.js +2 -2
- package/dist/fields/ComponentBlockField.js.map +1 -1
- package/dist/fields/FieldRenderer.js +1 -1
- package/dist/fields/FieldRenderer.js.map +1 -1
- package/dist/fields/PropInput.js +1 -1
- package/dist/fields/PropInput.js.map +1 -1
- package/dist/fields/RelationshipField.js +5 -5
- package/dist/fields/RelationshipField.js.map +1 -1
- package/dist/fields/ToggleField.js +1 -1
- package/dist/fields/ToggleField.js.map +1 -1
- package/dist/views/Dashboard.js +5 -5
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.d.ts.map +1 -1
- package/dist/views/DocumentEdit.js +5 -5
- package/dist/views/DocumentEdit.js.map +1 -1
- package/dist/views/ForgotPassword.d.ts.map +1 -1
- package/dist/views/ForgotPassword.js +3 -2
- package/dist/views/ForgotPassword.js.map +1 -1
- package/dist/views/FormEditor.d.ts.map +1 -1
- package/dist/views/FormEditor.js +5 -5
- package/dist/views/FormEditor.js.map +1 -1
- package/dist/views/Login.d.ts.map +1 -1
- package/dist/views/Login.js +17 -17
- package/dist/views/Login.js.map +1 -1
- package/dist/views/PageEditor.d.ts.map +1 -1
- package/dist/views/PageEditor.js +2 -2
- package/dist/views/PageEditor.js.map +1 -1
- package/dist/views/Pages/PagesListView.js +6 -6
- package/dist/views/Pages/PagesListView.js.map +1 -1
- package/dist/views/Pages.d.ts.map +1 -1
- package/dist/views/Pages.js +16 -19
- package/dist/views/Pages.js.map +1 -1
- package/dist/views/ResetPassword.d.ts.map +1 -1
- package/dist/views/ResetPassword.js +3 -2
- package/dist/views/ResetPassword.js.map +1 -1
- package/dist/views/Settings.js +2 -2
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SetupWizard.d.ts.map +1 -1
- package/dist/views/SetupWizard.js +6 -5
- package/dist/views/SetupWizard.js.map +1 -1
- package/dist/views/page-builder/DesignScore.js +12 -12
- package/dist/views/page-builder/DesignScore.js.map +1 -1
- package/dist/views/page-builder/SEOPanel.js +9 -9
- package/dist/views/page-builder/SEOPanel.js.map +1 -1
- package/dist/views/page-editor/EditorCanvas.js +1 -1
- package/dist/views/page-editor/EditorCanvas.js.map +1 -1
- package/dist/views/page-editor/EditorTopBar.js +2 -2
- package/dist/views/page-editor/EditorTopBar.js.map +1 -1
- package/dist/views/page-editor/PagePreview.js +1 -1
- package/dist/views/page-editor/PagePreview.js.map +1 -1
- package/dist/views/page-editor/SectionInspector.js +1 -1
- package/dist/views/page-editor/SectionInspector.js.map +1 -1
- package/dist/views/page-editor/SitePreviewFrame.js +1 -1
- package/dist/views/page-editor/SitePreviewFrame.js.map +1 -1
- package/dist/views/page-editor/sections/ArticleBodySection.js +1 -1
- package/dist/views/page-editor/sections/ArticleBodySection.js.map +1 -1
- package/dist/views/page-editor/sections/AuthorBioSection.js +2 -2
- package/dist/views/page-editor/sections/AuthorBioSection.js.map +1 -1
- package/dist/views/page-editor/sections/ByTheNumbersSection.js +1 -1
- package/dist/views/page-editor/sections/ByTheNumbersSection.js.map +1 -1
- package/dist/views/page-editor/sections/CtaBannerSection.js +1 -1
- package/dist/views/page-editor/sections/CtaBannerSection.js.map +1 -1
- package/dist/views/page-editor/sections/EmbedSection.d.ts.map +1 -1
- package/dist/views/page-editor/sections/EmbedSection.js +1 -1
- package/dist/views/page-editor/sections/EmbedSection.js.map +1 -1
- package/dist/views/page-editor/sections/FeatureHighlightSection.d.ts.map +1 -1
- package/dist/views/page-editor/sections/FeatureHighlightSection.js +2 -2
- package/dist/views/page-editor/sections/FeatureHighlightSection.js.map +1 -1
- package/dist/views/page-editor/sections/GallerySection.d.ts.map +1 -1
- package/dist/views/page-editor/sections/GallerySection.js +1 -1
- package/dist/views/page-editor/sections/GallerySection.js.map +1 -1
- package/dist/views/page-editor/sections/HeroBannerSection.js +1 -1
- package/dist/views/page-editor/sections/HeroBannerSection.js.map +1 -1
- package/dist/views/page-editor/sections/MissionSection.d.ts.map +1 -1
- package/dist/views/page-editor/sections/MissionSection.js +1 -1
- package/dist/views/page-editor/sections/MissionSection.js.map +1 -1
- package/dist/views/page-editor/sections/PullQuoteSection.js +1 -1
- package/dist/views/page-editor/sections/PullQuoteSection.js.map +1 -1
- package/dist/views/page-editor/sections/RelatedPostsSection.js +1 -1
- package/dist/views/page-editor/sections/RelatedPostsSection.js.map +1 -1
- package/dist/views/page-editor/sections/SectionRenderer.js +1 -1
- package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
- package/dist/views/page-editor/sections/parts.js +6 -6
- package/dist/views/page-editor/sections/parts.js.map +1 -1
- package/dist/views/post-editor/PostEditorCanvas.js +2 -2
- package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
- package/dist/views/post-editor/PostHeader.js +2 -2
- package/dist/views/post-editor/PostHeader.js.map +1 -1
- package/dist/views/post-editor/PostHeaderPanel.js +1 -1
- package/dist/views/post-editor/PostHeaderPanel.js.map +1 -1
- package/dist/views/post-editor/PostPreview.js +1 -1
- package/dist/views/post-editor/PostPreview.js.map +1 -1
- package/dist/views/profile/AccountSecurity.js +1 -1
- package/dist/views/profile/AccountSecurity.js.map +1 -1
- package/dist/views/settings/components.js +1 -1
- package/dist/views/settings/components.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/components/posts-badges.test.tsx +3 -3
- package/src/components/AICoauthorBubbleMenu.tsx +4 -4
- package/src/components/Breadcrumbs.tsx +5 -5
- package/src/components/CoauthorResultPopover.tsx +26 -23
- package/src/components/CommandPalette.tsx +41 -39
- package/src/components/CommentSidePanel.tsx +20 -20
- package/src/components/ContentOverviewChart.tsx +4 -4
- package/src/components/FocalPointPicker.tsx +2 -2
- package/src/components/LivePreview.tsx +20 -17
- package/src/components/LogoPlaceholder.tsx +1 -1
- package/src/components/MentionableTextarea.tsx +5 -5
- package/src/components/NotificationBell.tsx +10 -10
- package/src/components/OfflineStatus.tsx +8 -8
- package/src/components/PresenceChips.tsx +12 -8
- package/src/components/SEOConfigPanel.tsx +40 -38
- package/src/components/SEOPanel.tsx +15 -15
- package/src/components/SEOPerformance.tsx +25 -23
- package/src/components/TipTapEditor.tsx +7 -7
- package/src/components/pages/tag-badges.tsx +6 -6
- package/src/components/posts/badges.tsx +28 -46
- package/src/components/ui/Badge.tsx +5 -5
- package/src/components/ui/Toast.tsx +4 -5
- package/src/fields/ComponentBlockField.tsx +2 -2
- package/src/fields/FieldRenderer.tsx +1 -1
- package/src/fields/PropInput.tsx +1 -1
- package/src/fields/RelationshipField.tsx +5 -5
- package/src/fields/ToggleField.tsx +1 -1
- package/src/views/Dashboard.tsx +5 -5
- package/src/views/DocumentEdit.tsx +13 -11
- package/src/views/ForgotPassword.tsx +21 -18
- package/src/views/FormEditor.tsx +74 -69
- package/src/views/Login.tsx +45 -39
- package/src/views/PageEditor.tsx +26 -22
- package/src/views/Pages/PagesListView.tsx +6 -6
- package/src/views/Pages.tsx +64 -65
- package/src/views/ResetPassword.tsx +32 -29
- package/src/views/Settings.tsx +2 -2
- package/src/views/SetupWizard.tsx +42 -33
- package/src/views/page-builder/DesignScore.tsx +12 -12
- package/src/views/page-builder/SEOPanel.tsx +12 -12
- package/src/views/page-editor/EditorCanvas.tsx +1 -1
- package/src/views/page-editor/EditorTopBar.tsx +2 -2
- package/src/views/page-editor/PagePreview.tsx +1 -1
- package/src/views/page-editor/SectionInspector.tsx +1 -1
- package/src/views/page-editor/SitePreviewFrame.tsx +1 -1
- package/src/views/page-editor/sections/ArticleBodySection.tsx +5 -5
- package/src/views/page-editor/sections/AuthorBioSection.tsx +6 -6
- package/src/views/page-editor/sections/ByTheNumbersSection.tsx +5 -5
- package/src/views/page-editor/sections/CtaBannerSection.tsx +1 -1
- package/src/views/page-editor/sections/EmbedSection.tsx +6 -4
- package/src/views/page-editor/sections/FeatureHighlightSection.tsx +7 -5
- package/src/views/page-editor/sections/GallerySection.tsx +6 -4
- package/src/views/page-editor/sections/HeroBannerSection.tsx +2 -2
- package/src/views/page-editor/sections/MissionSection.tsx +4 -2
- package/src/views/page-editor/sections/PullQuoteSection.tsx +4 -4
- package/src/views/page-editor/sections/RelatedPostsSection.tsx +5 -5
- package/src/views/page-editor/sections/SectionRenderer.tsx +2 -2
- package/src/views/page-editor/sections/parts.tsx +6 -6
- package/src/views/post-editor/PostEditorCanvas.tsx +4 -4
- package/src/views/post-editor/PostHeader.tsx +5 -5
- package/src/views/post-editor/PostHeaderPanel.tsx +1 -1
- package/src/views/post-editor/PostPreview.tsx +1 -1
- package/src/views/profile/AccountSecurity.tsx +1 -1
- package/src/views/settings/components.tsx +1 -1
|
@@ -155,13 +155,16 @@ export function LivePreview({
|
|
|
155
155
|
|
|
156
156
|
if (!previewSrc) {
|
|
157
157
|
return (
|
|
158
|
-
<div className="flex h-full flex-col items-center justify-center rounded-lg border border-dashed
|
|
159
|
-
<p className="text-
|
|
158
|
+
<div className="border-border bg-muted flex h-full flex-col items-center justify-center rounded-lg border border-dashed p-8">
|
|
159
|
+
<p className="text-muted-foreground text-center text-sm">
|
|
160
160
|
{!documentId
|
|
161
161
|
? 'Save the document first to enable preview'
|
|
162
162
|
: 'Configure a preview URL in the collection settings to enable live preview'}
|
|
163
163
|
</p>
|
|
164
|
-
<button
|
|
164
|
+
<button
|
|
165
|
+
onClick={onClose}
|
|
166
|
+
className="text-muted-foreground hover:text-muted-foreground mt-4 text-xs"
|
|
167
|
+
>
|
|
165
168
|
Close Preview
|
|
166
169
|
</button>
|
|
167
170
|
</div>
|
|
@@ -169,8 +172,8 @@ export function LivePreview({
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
return (
|
|
172
|
-
<div className="flex h-full flex-col border-l
|
|
173
|
-
<div className="flex items-center justify-between border-b
|
|
175
|
+
<div className="border-border bg-card flex h-full flex-col border-l">
|
|
176
|
+
<div className="border-border bg-muted flex items-center justify-between border-b px-3 py-2">
|
|
174
177
|
<div className="flex items-center gap-1">
|
|
175
178
|
{(
|
|
176
179
|
[
|
|
@@ -182,14 +185,14 @@ export function LivePreview({
|
|
|
182
185
|
<button
|
|
183
186
|
key={vp}
|
|
184
187
|
onClick={() => setViewport(vp)}
|
|
185
|
-
className={`rounded p-1.5 ${viewport === vp ? 'bg-
|
|
188
|
+
className={`rounded p-1.5 ${viewport === vp ? 'bg-card text-primary shadow-sm' : 'text-muted-foreground hover:text-muted-foreground'}`}
|
|
186
189
|
title={vp}
|
|
187
190
|
>
|
|
188
191
|
<Icon className="h-4 w-4" />
|
|
189
192
|
</button>
|
|
190
193
|
))}
|
|
191
194
|
<span
|
|
192
|
-
className="ml-2 inline-flex items-center gap-1 rounded-full
|
|
195
|
+
className="bg-card text-muted-foreground ml-2 inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium"
|
|
193
196
|
title={
|
|
194
197
|
streamStatus === 'connected'
|
|
195
198
|
? 'Live preview is streaming updates from the server.'
|
|
@@ -202,19 +205,19 @@ export function LivePreview({
|
|
|
202
205
|
>
|
|
203
206
|
{streamStatus === 'connected' ? (
|
|
204
207
|
<>
|
|
205
|
-
<Wifi className="h-3 w-3
|
|
208
|
+
<Wifi className="text-success h-3 w-3" aria-hidden /> Live
|
|
206
209
|
</>
|
|
207
210
|
) : streamStatus === 'connecting' ? (
|
|
208
211
|
<>
|
|
209
|
-
<Wifi className="h-3 w-3 animate-pulse
|
|
212
|
+
<Wifi className="text-info h-3 w-3 animate-pulse" aria-hidden /> Connecting
|
|
210
213
|
</>
|
|
211
214
|
) : streamStatus === 'offline' ? (
|
|
212
215
|
<>
|
|
213
|
-
<WifiOff className="h-3 w-3
|
|
216
|
+
<WifiOff className="text-warning h-3 w-3" aria-hidden /> Reconnecting
|
|
214
217
|
</>
|
|
215
218
|
) : (
|
|
216
219
|
<>
|
|
217
|
-
<WifiOff className="h-3 w-3
|
|
220
|
+
<WifiOff className="text-muted-foreground h-3 w-3" aria-hidden /> Idle
|
|
218
221
|
</>
|
|
219
222
|
)}
|
|
220
223
|
</span>
|
|
@@ -222,21 +225,21 @@ export function LivePreview({
|
|
|
222
225
|
<div className="flex items-center gap-1">
|
|
223
226
|
<button
|
|
224
227
|
onClick={handleRefresh}
|
|
225
|
-
className="
|
|
228
|
+
className="text-muted-foreground hover:text-muted-foreground rounded p-1.5"
|
|
226
229
|
title="Refresh"
|
|
227
230
|
>
|
|
228
231
|
<RefreshCw className="h-4 w-4" />
|
|
229
232
|
</button>
|
|
230
233
|
<button
|
|
231
234
|
onClick={handleOpenExternal}
|
|
232
|
-
className="
|
|
235
|
+
className="text-muted-foreground hover:text-muted-foreground rounded p-1.5"
|
|
233
236
|
title="Open in new tab"
|
|
234
237
|
>
|
|
235
238
|
<ExternalLink className="h-4 w-4" />
|
|
236
239
|
</button>
|
|
237
240
|
<button
|
|
238
241
|
onClick={onClose}
|
|
239
|
-
className="
|
|
242
|
+
className="text-muted-foreground hover:text-muted-foreground rounded p-1.5"
|
|
240
243
|
title="Close"
|
|
241
244
|
>
|
|
242
245
|
<X className="h-4 w-4" />
|
|
@@ -244,20 +247,20 @@ export function LivePreview({
|
|
|
244
247
|
</div>
|
|
245
248
|
</div>
|
|
246
249
|
|
|
247
|
-
<div className="flex flex-1 justify-center overflow-auto
|
|
250
|
+
<div className="bg-muted flex flex-1 justify-center overflow-auto p-4">
|
|
248
251
|
<div
|
|
249
252
|
style={{ width: VIEWPORT_WIDTHS[viewport], maxWidth: '100%', transition: 'width 0.3s' }}
|
|
250
253
|
className="relative"
|
|
251
254
|
>
|
|
252
255
|
{loading && (
|
|
253
|
-
<div className="absolute inset-0 z-10 flex items-center justify-center rounded-lg
|
|
256
|
+
<div className="bg-card/80 absolute inset-0 z-10 flex items-center justify-center rounded-lg">
|
|
254
257
|
<div className="h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600" />
|
|
255
258
|
</div>
|
|
256
259
|
)}
|
|
257
260
|
<iframe
|
|
258
261
|
ref={iframeRef}
|
|
259
262
|
src={previewSrc}
|
|
260
|
-
className="h-full w-full rounded-lg border
|
|
263
|
+
className="border-border bg-card h-full w-full rounded-lg border shadow-lg"
|
|
261
264
|
style={{ minHeight: '600px' }}
|
|
262
265
|
onLoad={() => setLoading(false)}
|
|
263
266
|
title="Page Preview"
|
|
@@ -25,7 +25,7 @@ export function LogoPlaceholder({ tone, label }: LogoPlaceholderProps) {
|
|
|
25
25
|
role="img"
|
|
26
26
|
aria-label="Logo placeholder"
|
|
27
27
|
title="Add a logo in Settings → Appearance"
|
|
28
|
-
className="mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-lg border border-dashed
|
|
28
|
+
className="border-border text-muted-foreground mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-lg border border-dashed"
|
|
29
29
|
>
|
|
30
30
|
<ImagePlus className="h-6 w-6" aria-hidden="true" />
|
|
31
31
|
</span>
|
|
@@ -283,11 +283,11 @@ export function MentionableTextarea({
|
|
|
283
283
|
id={pickerId}
|
|
284
284
|
role="listbox"
|
|
285
285
|
aria-label="Mention a teammate"
|
|
286
|
-
className="absolute top-full left-0 z-30 mt-1 max-h-56 w-64 overflow-y-auto rounded border
|
|
286
|
+
className="border-border bg-card absolute top-full left-0 z-30 mt-1 max-h-56 w-64 overflow-y-auto rounded border shadow-lg"
|
|
287
287
|
data-testid={testId ? `${testId}-picker` : 'mention-picker'}
|
|
288
288
|
>
|
|
289
289
|
{picker.users.length === 0 ? (
|
|
290
|
-
<p className="px-3 py-2 text-xs
|
|
290
|
+
<p className="text-muted-foreground px-3 py-2 text-xs">
|
|
291
291
|
{picker.query ? 'No matches' : 'Type a name…'}
|
|
292
292
|
</p>
|
|
293
293
|
) : (
|
|
@@ -309,13 +309,13 @@ export function MentionableTextarea({
|
|
|
309
309
|
onMouseEnter={() => setPicker((s) => ({ ...s, highlight: idx }))}
|
|
310
310
|
className={`block w-full px-3 py-1.5 text-left text-xs ${
|
|
311
311
|
idx === picker.highlight
|
|
312
|
-
? 'bg-
|
|
313
|
-
: 'text-
|
|
312
|
+
? 'bg-info/10 text-foreground'
|
|
313
|
+
: 'text-foreground hover:bg-accent'
|
|
314
314
|
}`}
|
|
315
315
|
data-testid={testId ? `${testId}-picker-row-${u.id}` : `mention-row-${u.id}`}
|
|
316
316
|
>
|
|
317
317
|
<div className="font-medium">{formatLabel(u)}</div>
|
|
318
|
-
<div className="text-[10px]
|
|
318
|
+
<div className="text-muted-foreground text-[10px]">{u.email}</div>
|
|
319
319
|
</button>
|
|
320
320
|
</li>
|
|
321
321
|
))}
|
|
@@ -246,7 +246,7 @@ export function NotificationBell({
|
|
|
246
246
|
<div className={`relative ${className ?? ''}`} data-testid="notification-bell">
|
|
247
247
|
<button
|
|
248
248
|
type="button"
|
|
249
|
-
className="
|
|
249
|
+
className="text-muted-foreground hover:bg-accent hover:text-foreground relative rounded p-1.5"
|
|
250
250
|
aria-label="Notifications"
|
|
251
251
|
aria-haspopup="menu"
|
|
252
252
|
aria-expanded={open}
|
|
@@ -256,7 +256,7 @@ export function NotificationBell({
|
|
|
256
256
|
<BellIcon />
|
|
257
257
|
{unread > 0 && (
|
|
258
258
|
<span
|
|
259
|
-
className="absolute -top-0.5 -right-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full
|
|
259
|
+
className="bg-destructive absolute -top-0.5 -right-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-medium text-white"
|
|
260
260
|
data-testid="bell-badge"
|
|
261
261
|
>
|
|
262
262
|
{unread > 99 ? '99+' : unread}
|
|
@@ -266,14 +266,14 @@ export function NotificationBell({
|
|
|
266
266
|
{open && (
|
|
267
267
|
<div
|
|
268
268
|
role="menu"
|
|
269
|
-
className="absolute right-0 z-50 mt-1 w-80 rounded border
|
|
269
|
+
className="border-border bg-card absolute right-0 z-50 mt-1 w-80 rounded border shadow-lg"
|
|
270
270
|
data-testid="bell-dropdown"
|
|
271
271
|
>
|
|
272
272
|
<header className="flex items-center justify-between border-b border-gray-100 px-3 py-2">
|
|
273
|
-
<span className="text-sm font-medium
|
|
273
|
+
<span className="text-foreground text-sm font-medium">Notifications</span>
|
|
274
274
|
<button
|
|
275
275
|
type="button"
|
|
276
|
-
className="text-
|
|
276
|
+
className="text-muted-foreground hover:text-foreground text-xs disabled:opacity-50"
|
|
277
277
|
onClick={handleMarkAll}
|
|
278
278
|
disabled={unread === 0}
|
|
279
279
|
data-testid="bell-mark-all"
|
|
@@ -283,9 +283,9 @@ export function NotificationBell({
|
|
|
283
283
|
</header>
|
|
284
284
|
<div className="max-h-80 overflow-y-auto" aria-busy={loading} data-testid="bell-list">
|
|
285
285
|
{loading ? (
|
|
286
|
-
<p className="px-3 py-2 text-xs
|
|
286
|
+
<p className="text-muted-foreground px-3 py-2 text-xs">Loading…</p>
|
|
287
287
|
) : items.length === 0 ? (
|
|
288
|
-
<p className="px-3 py-2 text-xs
|
|
288
|
+
<p className="text-muted-foreground px-3 py-2 text-xs">All caught up.</p>
|
|
289
289
|
) : (
|
|
290
290
|
<ul>
|
|
291
291
|
{items.map((n) => (
|
|
@@ -293,15 +293,15 @@ export function NotificationBell({
|
|
|
293
293
|
<button
|
|
294
294
|
type="button"
|
|
295
295
|
role="menuitem"
|
|
296
|
-
className={`block w-full px-3 py-2 text-left text-xs
|
|
297
|
-
n.readAt ? 'text-
|
|
296
|
+
className={`hover:bg-accent block w-full px-3 py-2 text-left text-xs ${
|
|
297
|
+
n.readAt ? 'text-muted-foreground' : 'text-foreground font-medium'
|
|
298
298
|
}`}
|
|
299
299
|
onClick={() => handleClickRow(n)}
|
|
300
300
|
data-testid={`bell-row-${n.id}`}
|
|
301
301
|
data-read={n.readAt ? 'true' : 'false'}
|
|
302
302
|
>
|
|
303
303
|
<div>{notificationSummary(n)}</div>
|
|
304
|
-
<div className="mt-0.5 text-[10px]
|
|
304
|
+
<div className="text-muted-foreground mt-0.5 text-[10px]">{n.createdAt}</div>
|
|
305
305
|
</button>
|
|
306
306
|
</li>
|
|
307
307
|
))}
|
|
@@ -51,17 +51,17 @@ export function OfflineStatus({ connection, offline }: OfflineStatusProps): Reac
|
|
|
51
51
|
export type OfflineTone = 'good' | 'warn' | 'info' | 'bad'
|
|
52
52
|
|
|
53
53
|
const TONE_CLASSES: Record<OfflineTone, string> = {
|
|
54
|
-
good: 'bg-
|
|
55
|
-
warn: 'bg-
|
|
56
|
-
info: 'bg-
|
|
57
|
-
bad: 'bg-
|
|
54
|
+
good: 'bg-success/10 text-emerald-700',
|
|
55
|
+
warn: 'bg-warning/10 text-warning',
|
|
56
|
+
info: 'bg-info/10 text-info',
|
|
57
|
+
bad: 'bg-destructive/10 text-destructive',
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const DOT_CLASSES: Record<OfflineTone, string> = {
|
|
61
|
-
good: 'bg-
|
|
62
|
-
warn: 'bg-
|
|
63
|
-
info: 'bg-
|
|
64
|
-
bad: 'bg-
|
|
61
|
+
good: 'bg-success',
|
|
62
|
+
warn: 'bg-warning',
|
|
63
|
+
info: 'bg-info',
|
|
64
|
+
bad: 'bg-destructive',
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
@@ -70,7 +70,7 @@ export function PresenceChips({
|
|
|
70
70
|
>
|
|
71
71
|
{status && <StatusPill status={status} />}
|
|
72
72
|
{shown.length === 0 && status !== 'connecting' && (
|
|
73
|
-
<span className="text-
|
|
73
|
+
<span className="text-muted-foreground" data-testid="presence-empty">
|
|
74
74
|
You're the only one here
|
|
75
75
|
</span>
|
|
76
76
|
)}
|
|
@@ -79,7 +79,7 @@ export function PresenceChips({
|
|
|
79
79
|
))}
|
|
80
80
|
{overflow > 0 && (
|
|
81
81
|
<span
|
|
82
|
-
className="
|
|
82
|
+
className="bg-muted text-foreground rounded-full px-2 py-0.5"
|
|
83
83
|
data-testid="presence-overflow"
|
|
84
84
|
>
|
|
85
85
|
+{overflow}
|
|
@@ -91,14 +91,18 @@ export function PresenceChips({
|
|
|
91
91
|
|
|
92
92
|
function StatusPill({ status }: { status: CollaborationStatus }) {
|
|
93
93
|
const palette: Record<CollaborationStatus, { dot: string; label: string; text: string }> = {
|
|
94
|
-
connected: { dot: 'bg-
|
|
95
|
-
connecting: { dot: 'bg-amber-400 animate-pulse', label: 'Connecting', text: 'text-
|
|
96
|
-
disconnected: {
|
|
94
|
+
connected: { dot: 'bg-success', label: 'Live', text: 'text-emerald-700' },
|
|
95
|
+
connecting: { dot: 'bg-amber-400 animate-pulse', label: 'Connecting', text: 'text-warning' },
|
|
96
|
+
disconnected: {
|
|
97
|
+
dot: 'bg-muted-foreground/30',
|
|
98
|
+
label: 'Offline',
|
|
99
|
+
text: 'text-muted-foreground',
|
|
100
|
+
},
|
|
97
101
|
}
|
|
98
102
|
const cfg = palette[status]
|
|
99
103
|
return (
|
|
100
104
|
<span
|
|
101
|
-
className={`inline-flex items-center gap-1 rounded-full
|
|
105
|
+
className={`bg-muted inline-flex items-center gap-1 rounded-full px-2 py-0.5 ${cfg.text}`}
|
|
102
106
|
data-testid={`presence-status-${status}`}
|
|
103
107
|
>
|
|
104
108
|
<span className={`h-1.5 w-1.5 rounded-full ${cfg.dot}`} />
|
|
@@ -111,7 +115,7 @@ function Chip({ name, color, avatarUrl }: { name: string; color: string; avatarU
|
|
|
111
115
|
const initials = nameToInitials(name)
|
|
112
116
|
return (
|
|
113
117
|
<span
|
|
114
|
-
className="inline-flex items-center gap-1 rounded-full
|
|
118
|
+
className="bg-card inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 ring-1 ring-gray-200"
|
|
115
119
|
title={name}
|
|
116
120
|
data-testid="presence-chip"
|
|
117
121
|
>
|
|
@@ -131,7 +135,7 @@ function Chip({ name, color, avatarUrl }: { name: string; color: string; avatarU
|
|
|
131
135
|
{initials}
|
|
132
136
|
</span>
|
|
133
137
|
)}
|
|
134
|
-
<span className="max-w-[80px] truncate
|
|
138
|
+
<span className="text-foreground max-w-[80px] truncate">{name}</span>
|
|
135
139
|
</span>
|
|
136
140
|
)
|
|
137
141
|
}
|
|
@@ -192,7 +192,7 @@ export function SEOConfigPanel() {
|
|
|
192
192
|
|
|
193
193
|
if (loading) {
|
|
194
194
|
return (
|
|
195
|
-
<div className="flex items-center gap-2 py-8 text-sm
|
|
195
|
+
<div className="text-muted-foreground flex items-center gap-2 py-8 text-sm">
|
|
196
196
|
<Loader2 className="h-4 w-4 animate-spin" /> Loading SEO defaults…
|
|
197
197
|
</div>
|
|
198
198
|
)
|
|
@@ -200,12 +200,12 @@ export function SEOConfigPanel() {
|
|
|
200
200
|
|
|
201
201
|
if (error) {
|
|
202
202
|
return (
|
|
203
|
-
<div className="
|
|
203
|
+
<div className="border-destructive/30 bg-destructive/10 text-destructive rounded-lg border p-4 text-sm">
|
|
204
204
|
<div className="mb-2 font-medium">Failed to load SEO config</div>
|
|
205
205
|
<div className="font-mono text-xs">{error}</div>
|
|
206
206
|
<button
|
|
207
207
|
onClick={() => void load()}
|
|
208
|
-
className="mt-3 inline-flex items-center gap-1.5 rounded-md border
|
|
208
|
+
className="border-destructive bg-card text-destructive hover:bg-destructive/10 mt-3 inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-xs font-medium"
|
|
209
209
|
>
|
|
210
210
|
<RefreshCw className="h-3.5 w-3.5" /> Retry
|
|
211
211
|
</button>
|
|
@@ -217,21 +217,23 @@ export function SEOConfigPanel() {
|
|
|
217
217
|
<div className="space-y-6">
|
|
218
218
|
<div className="flex items-start justify-between gap-4">
|
|
219
219
|
<div>
|
|
220
|
-
<p className="text-
|
|
220
|
+
<p className="text-muted-foreground text-sm">
|
|
221
221
|
Edit the SEO defaults that flow into{' '}
|
|
222
|
-
<code className="
|
|
223
|
-
<code className="
|
|
224
|
-
<code className="
|
|
225
|
-
<code className="
|
|
222
|
+
<code className="bg-muted rounded px-1 py-0.5 text-[11px]">/sitemap.xml</code>,{' '}
|
|
223
|
+
<code className="bg-muted rounded px-1 py-0.5 text-[11px]">/robots.txt</code>,{' '}
|
|
224
|
+
<code className="bg-muted rounded px-1 py-0.5 text-[11px]">/og.png</code>, and the{' '}
|
|
225
|
+
<code className="bg-muted rounded px-1 py-0.5 text-[11px]">/resolve</code> meta +
|
|
226
226
|
JSON-LD response. Empty fields fall back to{' '}
|
|
227
|
-
<code className="
|
|
227
|
+
<code className="bg-muted rounded px-1 py-0.5 text-[11px]">actuate.config.ts</code>.
|
|
228
228
|
</p>
|
|
229
|
-
{updatedAt &&
|
|
229
|
+
{updatedAt && (
|
|
230
|
+
<p className="text-muted-foreground mt-1 text-xs">Last saved: {updatedAt}</p>
|
|
231
|
+
)}
|
|
230
232
|
</div>
|
|
231
233
|
<button
|
|
232
234
|
onClick={handleSave}
|
|
233
235
|
disabled={saving}
|
|
234
|
-
className="inline-flex shrink-0 items-center gap-1.5 rounded-md
|
|
236
|
+
className="bg-primary hover:bg-primary/90 inline-flex shrink-0 items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium text-white shadow-sm disabled:opacity-50"
|
|
235
237
|
>
|
|
236
238
|
{saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
|
|
237
239
|
Save SEO defaults
|
|
@@ -239,10 +241,10 @@ export function SEOConfigPanel() {
|
|
|
239
241
|
</div>
|
|
240
242
|
|
|
241
243
|
{/* Site-wide section */}
|
|
242
|
-
<section className="
|
|
243
|
-
<header className="flex items-center gap-2 border-b
|
|
244
|
-
<Globe className="h-4 w-4
|
|
245
|
-
<h3 className="text-sm font-medium
|
|
244
|
+
<section className="border-border bg-card rounded-lg border">
|
|
245
|
+
<header className="border-border flex items-center gap-2 border-b px-4 py-3">
|
|
246
|
+
<Globe className="text-primary h-4 w-4" />
|
|
247
|
+
<h3 className="text-foreground text-sm font-medium">Site-wide defaults</h3>
|
|
246
248
|
</header>
|
|
247
249
|
<div className="grid grid-cols-1 gap-4 p-4 md:grid-cols-2">
|
|
248
250
|
<Field
|
|
@@ -330,11 +332,11 @@ export function SEOConfigPanel() {
|
|
|
330
332
|
</section>
|
|
331
333
|
|
|
332
334
|
{/* Per-collection section */}
|
|
333
|
-
<section className="
|
|
334
|
-
<header className="flex items-center gap-2 border-b
|
|
335
|
-
<FileText className="h-4 w-4
|
|
336
|
-
<h3 className="text-sm font-medium
|
|
337
|
-
<span className="text-
|
|
335
|
+
<section className="border-border bg-card rounded-lg border">
|
|
336
|
+
<header className="border-border flex items-center gap-2 border-b px-4 py-3">
|
|
337
|
+
<FileText className="text-primary h-4 w-4" />
|
|
338
|
+
<h3 className="text-foreground text-sm font-medium">Per-collection defaults</h3>
|
|
339
|
+
<span className="text-muted-foreground text-xs">
|
|
338
340
|
— shown placeholders are the static defaults
|
|
339
341
|
</span>
|
|
340
342
|
</header>
|
|
@@ -346,14 +348,14 @@ export function SEOConfigPanel() {
|
|
|
346
348
|
<div key={col.slug} className="p-4">
|
|
347
349
|
<div className="mb-3 flex items-baseline justify-between gap-4">
|
|
348
350
|
<div>
|
|
349
|
-
<h4 className="text-sm font-medium
|
|
350
|
-
<p className="text-
|
|
351
|
-
<code className="
|
|
351
|
+
<h4 className="text-foreground text-sm font-medium">{col.label}</h4>
|
|
352
|
+
<p className="text-muted-foreground text-xs">
|
|
353
|
+
<code className="bg-muted rounded px-1 py-0.5">{col.slug}</code>
|
|
352
354
|
{col.urlPrefix !== undefined && (
|
|
353
355
|
<>
|
|
354
356
|
{' '}
|
|
355
357
|
prefix:{' '}
|
|
356
|
-
<code className="
|
|
358
|
+
<code className="bg-muted rounded px-1 py-0.5">/{col.urlPrefix}</code>
|
|
357
359
|
</>
|
|
358
360
|
)}{' '}
|
|
359
361
|
— {col.type}
|
|
@@ -414,7 +416,7 @@ export function SEOConfigPanel() {
|
|
|
414
416
|
)
|
|
415
417
|
})}
|
|
416
418
|
{data?.collections.length === 0 && (
|
|
417
|
-
<div className="p-4 text-sm
|
|
419
|
+
<div className="text-muted-foreground p-4 text-sm">
|
|
418
420
|
No collections configured in <code>actuate.config.ts</code>.
|
|
419
421
|
</div>
|
|
420
422
|
)}
|
|
@@ -425,7 +427,7 @@ export function SEOConfigPanel() {
|
|
|
425
427
|
<button
|
|
426
428
|
onClick={handleSave}
|
|
427
429
|
disabled={saving}
|
|
428
|
-
className="inline-flex items-center gap-1.5 rounded-md
|
|
430
|
+
className="bg-primary hover:bg-primary/90 inline-flex items-center gap-1.5 rounded-md px-4 py-2 text-sm font-medium text-white shadow-sm disabled:opacity-50"
|
|
429
431
|
>
|
|
430
432
|
{saving ? <Loader2 className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
|
|
431
433
|
Save SEO defaults
|
|
@@ -465,15 +467,15 @@ function Field({
|
|
|
465
467
|
}) {
|
|
466
468
|
return (
|
|
467
469
|
<div>
|
|
468
|
-
<label className="mb-1 block text-xs font-medium
|
|
470
|
+
<label className="text-foreground mb-1 block text-xs font-medium">{label}</label>
|
|
469
471
|
<input
|
|
470
472
|
type="text"
|
|
471
473
|
value={value}
|
|
472
474
|
placeholder={placeholder}
|
|
473
475
|
onChange={(e) => onChange(e.target.value)}
|
|
474
|
-
className="w-full rounded-md border
|
|
476
|
+
className="border-border text-foreground focus-visible:border-ring focus-visible:ring-ring/50 w-full rounded-md border px-2.5 py-1.5 text-sm placeholder-gray-400 focus:ring-1 focus:outline-none"
|
|
475
477
|
/>
|
|
476
|
-
{hint && <p className="mt-1 text-[11px]
|
|
478
|
+
{hint && <p className="text-muted-foreground mt-1 text-[11px]">{hint}</p>}
|
|
477
479
|
</div>
|
|
478
480
|
)
|
|
479
481
|
}
|
|
@@ -499,7 +501,7 @@ function NumberField({
|
|
|
499
501
|
}) {
|
|
500
502
|
return (
|
|
501
503
|
<div>
|
|
502
|
-
<label className="mb-1 block text-xs font-medium
|
|
504
|
+
<label className="text-foreground mb-1 block text-xs font-medium">{label}</label>
|
|
503
505
|
<input
|
|
504
506
|
type="number"
|
|
505
507
|
value={value ?? ''}
|
|
@@ -513,9 +515,9 @@ function NumberField({
|
|
|
513
515
|
const n = Number(raw)
|
|
514
516
|
if (Number.isFinite(n)) onChange(n)
|
|
515
517
|
}}
|
|
516
|
-
className="w-full rounded-md border
|
|
518
|
+
className="border-border text-foreground focus-visible:border-ring focus-visible:ring-ring/50 w-full rounded-md border px-2.5 py-1.5 text-sm placeholder-gray-400 focus:ring-1 focus:outline-none"
|
|
517
519
|
/>
|
|
518
|
-
{hint && <p className="mt-1 text-[11px]
|
|
520
|
+
{hint && <p className="text-muted-foreground mt-1 text-[11px]">{hint}</p>}
|
|
519
521
|
</div>
|
|
520
522
|
)
|
|
521
523
|
}
|
|
@@ -537,11 +539,11 @@ function Select({
|
|
|
537
539
|
}) {
|
|
538
540
|
return (
|
|
539
541
|
<div>
|
|
540
|
-
<label className="mb-1 block text-xs font-medium
|
|
542
|
+
<label className="text-foreground mb-1 block text-xs font-medium">{label}</label>
|
|
541
543
|
<select
|
|
542
544
|
value={value}
|
|
543
545
|
onChange={(e) => onChange(e.target.value)}
|
|
544
|
-
className="
|
|
546
|
+
className="border-border bg-card text-foreground focus-visible:border-ring focus-visible:ring-ring/50 w-full rounded-md border px-2.5 py-1.5 text-sm focus:ring-1 focus:outline-none"
|
|
545
547
|
>
|
|
546
548
|
{options.map((opt) => (
|
|
547
549
|
<option key={opt} value={opt}>
|
|
@@ -549,7 +551,7 @@ function Select({
|
|
|
549
551
|
</option>
|
|
550
552
|
))}
|
|
551
553
|
</select>
|
|
552
|
-
{hint && <p className="mt-1 text-[11px]
|
|
554
|
+
{hint && <p className="text-muted-foreground mt-1 text-[11px]">{hint}</p>}
|
|
553
555
|
</div>
|
|
554
556
|
)
|
|
555
557
|
}
|
|
@@ -566,16 +568,16 @@ function Toggle({
|
|
|
566
568
|
hint?: string
|
|
567
569
|
}) {
|
|
568
570
|
return (
|
|
569
|
-
<label className="flex cursor-pointer items-center gap-2 text-sm
|
|
571
|
+
<label className="text-foreground flex cursor-pointer items-center gap-2 text-sm">
|
|
570
572
|
<input
|
|
571
573
|
type="checkbox"
|
|
572
574
|
checked={checked}
|
|
573
575
|
onChange={(e) => onChange(e.target.checked)}
|
|
574
|
-
className="
|
|
576
|
+
className="border-border text-primary focus-visible:ring-ring/50 h-4 w-4 rounded"
|
|
575
577
|
/>
|
|
576
578
|
<span>
|
|
577
579
|
{label}
|
|
578
|
-
{hint && <span className="ml-1 text-[11px]
|
|
580
|
+
{hint && <span className="text-muted-foreground ml-1 text-[11px]">— {hint}</span>}
|
|
579
581
|
</span>
|
|
580
582
|
</label>
|
|
581
583
|
)
|
|
@@ -387,9 +387,9 @@ function computeOverallScore(checks: SEOCheck[]): number {
|
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
function StatusDot({ status }: { status: 'good' | 'ok' | 'bad' }) {
|
|
390
|
-
if (status === 'good') return <CheckCircle2 className="h-4 w-4 shrink-0
|
|
391
|
-
if (status === 'ok') return <AlertCircle className="h-4 w-4 shrink-0
|
|
392
|
-
return <XCircle className="h-4 w-4 shrink-0
|
|
390
|
+
if (status === 'good') return <CheckCircle2 className="text-success h-4 w-4 shrink-0" />
|
|
391
|
+
if (status === 'ok') return <AlertCircle className="text-warning h-4 w-4 shrink-0" />
|
|
392
|
+
return <XCircle className="text-destructive h-4 w-4 shrink-0" />
|
|
393
393
|
}
|
|
394
394
|
|
|
395
395
|
function ScoreRing({ score }: { score: number }) {
|
|
@@ -486,7 +486,7 @@ function ToggleSwitch({
|
|
|
486
486
|
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full transition-colors ${checked ? 'bg-[var(--primary)]' : 'bg-[var(--muted)]'}`}
|
|
487
487
|
>
|
|
488
488
|
<span
|
|
489
|
-
className={`pointer-events-none mt-0.5 block h-5 w-5 rounded-full
|
|
489
|
+
className={`bg-card pointer-events-none mt-0.5 block h-5 w-5 rounded-full shadow-sm transition-transform ${checked ? 'translate-x-[22px]' : 'translate-x-0.5'}`}
|
|
490
490
|
/>
|
|
491
491
|
</button>
|
|
492
492
|
</div>
|
|
@@ -616,10 +616,10 @@ export function SEOPanel({
|
|
|
616
616
|
: 'Very difficult'
|
|
617
617
|
const fleschColor =
|
|
618
618
|
readability.fleschScore >= 60
|
|
619
|
-
? 'text-
|
|
619
|
+
? 'text-success'
|
|
620
620
|
: readability.fleschScore >= 30
|
|
621
|
-
? 'text-
|
|
622
|
-
: 'text-
|
|
621
|
+
? 'text-warning'
|
|
622
|
+
: 'text-destructive'
|
|
623
623
|
|
|
624
624
|
return (
|
|
625
625
|
<div className="rounded-lg border border-[var(--border)] bg-[var(--card)]">
|
|
@@ -643,13 +643,13 @@ export function SEOPanel({
|
|
|
643
643
|
<ScoreRing score={score} />
|
|
644
644
|
<div className="space-y-0.5 text-xs text-[var(--muted-foreground)]">
|
|
645
645
|
<div className="flex items-center gap-1.5">
|
|
646
|
-
<CheckCircle2 className="h-3 w-3
|
|
646
|
+
<CheckCircle2 className="text-success h-3 w-3" /> {goodCount} passed
|
|
647
647
|
</div>
|
|
648
648
|
<div className="flex items-center gap-1.5">
|
|
649
|
-
<AlertCircle className="h-3 w-3
|
|
649
|
+
<AlertCircle className="text-warning h-3 w-3" /> {okCount} improvements
|
|
650
650
|
</div>
|
|
651
651
|
<div className="flex items-center gap-1.5">
|
|
652
|
-
<XCircle className="h-3 w-3
|
|
652
|
+
<XCircle className="text-destructive h-3 w-3" /> {badCount} issues
|
|
653
653
|
</div>
|
|
654
654
|
</div>
|
|
655
655
|
</div>
|
|
@@ -723,8 +723,8 @@ export function SEOPanel({
|
|
|
723
723
|
<span
|
|
724
724
|
className={
|
|
725
725
|
readability.passiveEstimate > 15
|
|
726
|
-
? 'font-medium
|
|
727
|
-
: 'font-medium
|
|
726
|
+
? 'text-warning font-medium'
|
|
727
|
+
: 'text-success font-medium'
|
|
728
728
|
}
|
|
729
729
|
>
|
|
730
730
|
{readability.passiveEstimate}%
|
|
@@ -849,10 +849,10 @@ export function SEOPanel({
|
|
|
849
849
|
onToggle={toggleSection}
|
|
850
850
|
>
|
|
851
851
|
<div className="rounded-lg border border-[var(--border)] bg-[var(--background)] p-3">
|
|
852
|
-
<div className="line-clamp-1 cursor-pointer text-sm
|
|
852
|
+
<div className="text-primary line-clamp-1 cursor-pointer text-sm hover:underline">
|
|
853
853
|
{metaTitle || title || 'Page Title'}
|
|
854
854
|
</div>
|
|
855
|
-
<div className="mt-1 truncate text-xs
|
|
855
|
+
<div className="text-success mt-1 truncate text-xs">
|
|
856
856
|
{siteUrl}/{slug}
|
|
857
857
|
</div>
|
|
858
858
|
<div className="mt-1 line-clamp-2 text-sm text-[var(--muted-foreground)]">
|
|
@@ -971,7 +971,7 @@ export function SEOPanel({
|
|
|
971
971
|
onChange={(v) => update({ isCornerstone: v })}
|
|
972
972
|
/>
|
|
973
973
|
{seoData.isCornerstone && (
|
|
974
|
-
<div className="flex items-center gap-1.5 rounded-md
|
|
974
|
+
<div className="text-warning bg-warning/10 flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs">
|
|
975
975
|
<Star className="h-3.5 w-3.5" />
|
|
976
976
|
Cornerstone content is held to stricter SEO standards
|
|
977
977
|
</div>
|