@actuate-media/cms-admin 0.10.0 → 0.11.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/dist/AdminRoot.d.ts.map +1 -1
- package/dist/AdminRoot.js +8 -5
- package/dist/AdminRoot.js.map +1 -1
- package/dist/__tests__/layout/primitives.test.d.ts +2 -0
- package/dist/__tests__/layout/primitives.test.d.ts.map +1 -0
- package/dist/__tests__/layout/primitives.test.js +34 -0
- package/dist/__tests__/layout/primitives.test.js.map +1 -0
- package/dist/__tests__/lib/cv.test.d.ts +2 -0
- package/dist/__tests__/lib/cv.test.d.ts.map +1 -0
- package/dist/__tests__/lib/cv.test.js +66 -0
- package/dist/__tests__/lib/cv.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/assets/actuate-logo.d.ts +36 -0
- package/dist/assets/actuate-logo.d.ts.map +1 -0
- package/dist/assets/actuate-logo.js +15 -0
- package/dist/assets/actuate-logo.js.map +1 -0
- package/dist/components/Breadcrumbs.js +2 -2
- package/dist/components/CommandPalette.js +10 -10
- package/dist/components/ContentOverviewChart.js +3 -3
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/FocalPointPicker.js +2 -2
- package/dist/components/FolderTree.js +20 -20
- package/dist/components/LivePreview.js +3 -3
- package/dist/components/LocaleSwitcher.js +1 -1
- package/dist/components/MediaPickerModal.js +4 -4
- package/dist/components/PresenceIndicator.js +1 -1
- package/dist/components/SEOConfigPanel.d.ts +2 -0
- package/dist/components/SEOConfigPanel.d.ts.map +1 -0
- package/dist/components/SEOConfigPanel.js +174 -0
- package/dist/components/SEOConfigPanel.js.map +1 -0
- package/dist/components/SEOPanel.js +9 -9
- package/dist/components/SEOPerformance.js +2 -2
- package/dist/components/SchedulePublishDialog.js +1 -1
- package/dist/components/SharePreviewLinkDialog.js +1 -1
- package/dist/components/TipTapEditor.js +5 -5
- package/dist/components/VersionHistory.js +2 -2
- package/dist/components/ui/Badge.d.ts +33 -3
- package/dist/components/ui/Badge.d.ts.map +1 -1
- package/dist/components/ui/Badge.js +42 -8
- package/dist/components/ui/Badge.js.map +1 -1
- package/dist/components/ui/Button.d.ts +19 -8
- package/dist/components/ui/Button.d.ts.map +1 -1
- package/dist/components/ui/Button.js +35 -14
- package/dist/components/ui/Button.js.map +1 -1
- package/dist/components/ui/Card.d.ts +26 -0
- package/dist/components/ui/Card.d.ts.map +1 -0
- package/dist/components/ui/Card.js +45 -0
- package/dist/components/ui/Card.js.map +1 -0
- package/dist/components/ui/DataTable.js +1 -1
- package/dist/components/ui/Input.d.ts +15 -0
- package/dist/components/ui/Input.d.ts.map +1 -0
- package/dist/components/ui/Input.js +23 -0
- package/dist/components/ui/Input.js.map +1 -0
- package/dist/components/ui/SearchInput.js +1 -1
- package/dist/components/ui/Select.d.ts +16 -0
- package/dist/components/ui/Select.d.ts.map +1 -0
- package/dist/components/ui/Select.js +25 -0
- package/dist/components/ui/Select.js.map +1 -0
- package/dist/components/ui/Toast.js +1 -1
- package/dist/components/ui/index.d.ts +10 -4
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +5 -2
- package/dist/components/ui/index.js.map +1 -1
- package/dist/fields/BlockBuilderField.js +3 -3
- package/dist/fields/DateField.js +1 -1
- package/dist/fields/RelationshipField.js +3 -3
- package/dist/fields/TextField.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/Header.js +1 -1
- package/dist/layout/Layout.d.ts +14 -0
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js +17 -11
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +21 -11
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/layout/primitives/AdminShell.d.ts +43 -0
- package/dist/layout/primitives/AdminShell.d.ts.map +1 -0
- package/dist/layout/primitives/AdminShell.js +51 -0
- package/dist/layout/primitives/AdminShell.js.map +1 -0
- package/dist/layout/primitives/Box.d.ts +19 -0
- package/dist/layout/primitives/Box.d.ts.map +1 -0
- package/dist/layout/primitives/Box.js +12 -0
- package/dist/layout/primitives/Box.js.map +1 -0
- package/dist/layout/primitives/Cluster.d.ts +27 -0
- package/dist/layout/primitives/Cluster.d.ts.map +1 -0
- package/dist/layout/primitives/Cluster.js +37 -0
- package/dist/layout/primitives/Cluster.js.map +1 -0
- package/dist/layout/primitives/Grid.d.ts +45 -0
- package/dist/layout/primitives/Grid.d.ts.map +1 -0
- package/dist/layout/primitives/Grid.js +59 -0
- package/dist/layout/primitives/Grid.js.map +1 -0
- package/dist/layout/primitives/PageContainer.d.ts +36 -0
- package/dist/layout/primitives/PageContainer.d.ts.map +1 -0
- package/dist/layout/primitives/PageContainer.js +41 -0
- package/dist/layout/primitives/PageContainer.js.map +1 -0
- package/dist/layout/primitives/Split.d.ts +34 -0
- package/dist/layout/primitives/Split.d.ts.map +1 -0
- package/dist/layout/primitives/Split.js +27 -0
- package/dist/layout/primitives/Split.js.map +1 -0
- package/dist/layout/primitives/Stack.d.ts +23 -0
- package/dist/layout/primitives/Stack.d.ts.map +1 -0
- package/dist/layout/primitives/Stack.js +34 -0
- package/dist/layout/primitives/Stack.js.map +1 -0
- package/dist/layout/primitives/index.d.ts +30 -0
- package/dist/layout/primitives/index.d.ts.map +1 -0
- package/dist/layout/primitives/index.js +22 -0
- package/dist/layout/primitives/index.js.map +1 -0
- package/dist/layout/primitives/tokens.d.ts +48 -0
- package/dist/layout/primitives/tokens.d.ts.map +1 -0
- package/dist/layout/primitives/tokens.js +54 -0
- package/dist/layout/primitives/tokens.js.map +1 -0
- package/dist/lib/cv.d.ts +53 -0
- package/dist/lib/cv.d.ts.map +1 -0
- package/dist/lib/cv.js +39 -0
- package/dist/lib/cv.js.map +1 -0
- package/dist/views/ApiKeys.js +7 -7
- package/dist/views/CollectionList.js +8 -8
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +333 -78
- package/dist/views/Dashboard.js.map +1 -1
- package/dist/views/DocumentEdit.js +3 -3
- package/dist/views/ForgotPassword.js +2 -2
- package/dist/views/FormEditor.js +5 -5
- package/dist/views/FormSubmissions.js +6 -6
- package/dist/views/Forms.js +2 -2
- package/dist/views/Login.d.ts +16 -1
- package/dist/views/Login.d.ts.map +1 -1
- package/dist/views/Login.js +17 -7
- package/dist/views/Login.js.map +1 -1
- package/dist/views/MediaBrowser.js +16 -16
- package/dist/views/PageEditor.js +2 -2
- package/dist/views/Pages.js +10 -10
- package/dist/views/PostEditor.js +2 -2
- package/dist/views/Posts.js +4 -4
- package/dist/views/Redirects.js +4 -4
- package/dist/views/ResetPassword.js +2 -2
- package/dist/views/SEO.js +6 -6
- package/dist/views/ScriptTagEditor.js +4 -4
- package/dist/views/ScriptTags.js +2 -2
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +9 -8
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/SetupWizard.js +2 -2
- package/dist/views/Users.js +4 -4
- package/dist/views/page-builder/AIBlockAssist.js +1 -1
- package/dist/views/page-builder/AIGenerateDialog.js +10 -10
- package/dist/views/page-builder/BlockEditor.js +10 -10
- package/dist/views/page-builder/BlockPicker.js +4 -4
- package/dist/views/page-builder/BottomBar.js +1 -1
- package/dist/views/page-builder/BuilderToolbar.js +2 -2
- package/dist/views/page-builder/ContextPanel.js +2 -2
- package/dist/views/page-builder/DesignScore.js +9 -9
- package/dist/views/page-builder/NodeSettings.js +8 -8
- package/dist/views/page-builder/PageBuilder.js +3 -3
- package/dist/views/page-builder/PageSettings.js +1 -1
- package/dist/views/page-builder/PageTemplates.js +2 -2
- package/dist/views/page-builder/SEOPanel.js +13 -13
- package/dist/views/page-builder/SavedSections.js +5 -5
- package/dist/views/page-builder/TemplatePicker.js +2 -2
- package/dist/views/page-builder/block-renderers/CTAPreview.js +5 -5
- package/dist/views/page-builder/block-renderers/CardsPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/CodePreview.js +1 -1
- package/dist/views/page-builder/block-renderers/FAQPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/FallbackPreview.js +1 -1
- package/dist/views/page-builder/block-renderers/FormPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/GalleryPreview.js +5 -5
- package/dist/views/page-builder/block-renderers/HeroPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/ImagePreview.js +3 -3
- package/dist/views/page-builder/block-renderers/TextPreview.js +3 -3
- package/dist/views/page-builder/block-renderers/VideoPreview.js +4 -4
- package/dist/views/page-builder/canvas/BlockRenderer.js +1 -1
- package/dist/views/page-builder/canvas/BuilderCanvas.js +3 -3
- package/dist/views/page-builder/canvas/ColumnRenderer.js +2 -2
- package/dist/views/page-builder/canvas/ContainerRenderer.js +2 -2
- package/dist/views/page-builder/canvas/RowRenderer.js +2 -2
- package/dist/views/page-builder/canvas/SectionRenderer.js +2 -2
- package/package.json +6 -2
- package/src/AdminRoot.tsx +21 -11
- package/src/__tests__/layout/primitives.test.ts +37 -0
- package/src/__tests__/lib/cv.test.ts +74 -0
- package/src/assets/actuate-logo.tsx +72 -0
- package/src/components/Breadcrumbs.tsx +6 -6
- package/src/components/CommandPalette.tsx +34 -34
- package/src/components/ContentOverviewChart.tsx +3 -3
- package/src/components/ErrorBoundary.tsx +3 -3
- package/src/components/FocalPointPicker.tsx +4 -4
- package/src/components/FolderTree.tsx +38 -38
- package/src/components/LivePreview.tsx +16 -16
- package/src/components/LocaleSwitcher.tsx +7 -7
- package/src/components/MediaPickerModal.tsx +21 -21
- package/src/components/PresenceIndicator.tsx +2 -2
- package/src/components/SEOConfigPanel.tsx +582 -0
- package/src/components/SEOPanel.tsx +46 -46
- package/src/components/SEOPerformance.tsx +21 -21
- package/src/components/SchedulePublishDialog.tsx +4 -4
- package/src/components/SharePreviewLinkDialog.tsx +1 -1
- package/src/components/TipTapEditor.tsx +33 -33
- package/src/components/VersionHistory.tsx +16 -16
- package/src/components/ui/Badge.tsx +66 -14
- package/src/components/ui/Button.tsx +70 -33
- package/src/components/ui/Card.tsx +101 -0
- package/src/components/ui/DataTable.tsx +1 -1
- package/src/components/ui/Input.tsx +35 -0
- package/src/components/ui/SearchInput.tsx +4 -4
- package/src/components/ui/Select.tsx +56 -0
- package/src/components/ui/Toast.tsx +1 -1
- package/src/components/ui/index.ts +18 -4
- package/src/fields/BlockBuilderField.tsx +3 -3
- package/src/fields/DateField.tsx +1 -1
- package/src/fields/RelationshipField.tsx +10 -10
- package/src/fields/TextField.tsx +1 -1
- package/src/index.ts +28 -0
- package/src/layout/Header.tsx +28 -28
- package/src/layout/Layout.tsx +39 -46
- package/src/layout/Sidebar.tsx +37 -64
- package/src/layout/primitives/AdminShell.tsx +118 -0
- package/src/layout/primitives/Box.tsx +30 -0
- package/src/layout/primitives/Cluster.tsx +74 -0
- package/src/layout/primitives/Grid.tsx +120 -0
- package/src/layout/primitives/PageContainer.tsx +96 -0
- package/src/layout/primitives/Split.tsx +73 -0
- package/src/layout/primitives/Stack.tsx +67 -0
- package/src/layout/primitives/index.ts +36 -0
- package/src/layout/primitives/tokens.ts +76 -0
- package/src/lib/cv.ts +96 -0
- package/src/styles/build-input.css +1 -1
- package/src/views/ApiKeys.tsx +57 -57
- package/src/views/CollectionList.tsx +30 -30
- package/src/views/Dashboard.tsx +737 -186
- package/src/views/DocumentEdit.tsx +9 -9
- package/src/views/ForgotPassword.tsx +18 -18
- package/src/views/FormEditor.tsx +75 -75
- package/src/views/FormSubmissions.tsx +76 -76
- package/src/views/Forms.tsx +27 -27
- package/src/views/Login.tsx +65 -25
- package/src/views/MediaBrowser.tsx +127 -127
- package/src/views/PageEditor.tsx +25 -25
- package/src/views/Pages.tsx +59 -59
- package/src/views/PostEditor.tsx +37 -37
- package/src/views/Posts.tsx +48 -48
- package/src/views/Redirects.tsx +21 -21
- package/src/views/ResetPassword.tsx +28 -28
- package/src/views/SEO.tsx +144 -144
- package/src/views/ScriptTagEditor.tsx +24 -24
- package/src/views/ScriptTags.tsx +10 -10
- package/src/views/Settings.tsx +88 -80
- package/src/views/SetupWizard.tsx +28 -28
- package/src/views/Users.tsx +20 -20
- package/src/views/page-builder/AIBlockAssist.tsx +1 -1
- package/src/views/page-builder/AIGenerateDialog.tsx +63 -63
- package/src/views/page-builder/BlockEditor.tsx +26 -26
- package/src/views/page-builder/BlockPicker.tsx +22 -22
- package/src/views/page-builder/BottomBar.tsx +8 -8
- package/src/views/page-builder/BuilderToolbar.tsx +17 -17
- package/src/views/page-builder/ContextPanel.tsx +3 -3
- package/src/views/page-builder/DesignScore.tsx +21 -21
- package/src/views/page-builder/NodeSettings.tsx +27 -27
- package/src/views/page-builder/PageBuilder.tsx +11 -11
- package/src/views/page-builder/PageSettings.tsx +4 -4
- package/src/views/page-builder/PageTemplates.tsx +18 -18
- package/src/views/page-builder/SEOPanel.tsx +53 -53
- package/src/views/page-builder/SavedSections.tsx +37 -37
- package/src/views/page-builder/TemplatePicker.tsx +17 -17
- package/src/views/page-builder/block-renderers/CTAPreview.tsx +13 -13
- package/src/views/page-builder/block-renderers/CardsPreview.tsx +5 -5
- package/src/views/page-builder/block-renderers/CodePreview.tsx +6 -6
- package/src/views/page-builder/block-renderers/FAQPreview.tsx +13 -13
- package/src/views/page-builder/block-renderers/FallbackPreview.tsx +3 -3
- package/src/views/page-builder/block-renderers/FormPreview.tsx +20 -20
- package/src/views/page-builder/block-renderers/GalleryPreview.tsx +8 -8
- package/src/views/page-builder/block-renderers/HeroPreview.tsx +16 -16
- package/src/views/page-builder/block-renderers/ImagePreview.tsx +4 -4
- package/src/views/page-builder/block-renderers/TextPreview.tsx +14 -14
- package/src/views/page-builder/block-renderers/VideoPreview.tsx +12 -12
- package/src/views/page-builder/canvas/BlockRenderer.tsx +4 -4
- package/src/views/page-builder/canvas/BuilderCanvas.tsx +6 -6
- package/src/views/page-builder/canvas/ColumnRenderer.tsx +3 -3
- package/src/views/page-builder/canvas/ContainerRenderer.tsx +2 -2
- package/src/views/page-builder/canvas/RowRenderer.tsx +2 -2
- package/src/views/page-builder/canvas/SectionRenderer.tsx +2 -2
|
@@ -438,10 +438,10 @@ function Section({
|
|
|
438
438
|
badge?: React.ReactNode
|
|
439
439
|
}) {
|
|
440
440
|
return (
|
|
441
|
-
<div className="border border-[var(--border)]
|
|
441
|
+
<div className="overflow-hidden rounded-lg border border-[var(--border)]">
|
|
442
442
|
<button
|
|
443
443
|
onClick={() => onToggle(id)}
|
|
444
|
-
className="flex items-center justify-between
|
|
444
|
+
className="flex w-full items-center justify-between px-4 py-2.5 text-left text-sm font-medium text-[var(--foreground)] transition-colors hover:bg-[var(--muted)]"
|
|
445
445
|
>
|
|
446
446
|
<span className="flex items-center gap-2">
|
|
447
447
|
{icon}
|
|
@@ -454,7 +454,7 @@ function Section({
|
|
|
454
454
|
<ChevronDown className="h-4 w-4 text-[var(--muted-foreground)]" />
|
|
455
455
|
)}
|
|
456
456
|
</button>
|
|
457
|
-
{expanded && <div className="px-4 pb-4
|
|
457
|
+
{expanded && <div className="px-4 pt-1 pb-4">{children}</div>}
|
|
458
458
|
</div>
|
|
459
459
|
)
|
|
460
460
|
}
|
|
@@ -472,9 +472,9 @@ function ToggleSwitch({
|
|
|
472
472
|
}) {
|
|
473
473
|
return (
|
|
474
474
|
<div className="flex items-center justify-between gap-3">
|
|
475
|
-
<div className="
|
|
475
|
+
<div className="min-w-0 flex-1">
|
|
476
476
|
<label className="text-sm font-medium text-[var(--foreground)]">{label}</label>
|
|
477
|
-
<p className="text-xs text-[var(--muted-foreground)]
|
|
477
|
+
<p className="mt-0.5 text-xs text-[var(--muted-foreground)]">{description}</p>
|
|
478
478
|
</div>
|
|
479
479
|
<button
|
|
480
480
|
type="button"
|
|
@@ -484,7 +484,7 @@ function ToggleSwitch({
|
|
|
484
484
|
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full transition-colors ${checked ? 'bg-[var(--primary)]' : 'bg-[var(--muted)]'}`}
|
|
485
485
|
>
|
|
486
486
|
<span
|
|
487
|
-
className={`pointer-events-none block h-5 w-5 rounded-full bg-white shadow-sm transition-transform
|
|
487
|
+
className={`pointer-events-none mt-0.5 block h-5 w-5 rounded-full bg-white shadow-sm transition-transform ${checked ? 'translate-x-[22px]' : 'translate-x-0.5'}`}
|
|
488
488
|
/>
|
|
489
489
|
</button>
|
|
490
490
|
</div>
|
|
@@ -510,18 +510,18 @@ function InputField({
|
|
|
510
510
|
}) {
|
|
511
511
|
return (
|
|
512
512
|
<div>
|
|
513
|
-
<label className="block text-xs font-medium text-[var(--muted-foreground)]
|
|
513
|
+
<label className="mb-1 block text-xs font-medium text-[var(--muted-foreground)]">
|
|
514
514
|
{label}
|
|
515
515
|
</label>
|
|
516
516
|
<input
|
|
517
517
|
type={type}
|
|
518
518
|
value={value}
|
|
519
519
|
onChange={(e) => onChange(e.target.value)}
|
|
520
|
-
className="w-full
|
|
520
|
+
className="w-full rounded-lg border border-[var(--border)] bg-[var(--background)] px-3 py-1.5 text-sm text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:ring-2 focus:ring-[var(--primary)] focus:outline-none"
|
|
521
521
|
placeholder={placeholder}
|
|
522
522
|
/>
|
|
523
523
|
{charCount !== undefined && charTarget && (
|
|
524
|
-
<p className="
|
|
524
|
+
<p className="mt-1 text-xs text-[var(--muted-foreground)]">
|
|
525
525
|
{charCount} chars {charTarget}
|
|
526
526
|
</p>
|
|
527
527
|
)}
|
|
@@ -548,18 +548,18 @@ function TextareaField({
|
|
|
548
548
|
}) {
|
|
549
549
|
return (
|
|
550
550
|
<div>
|
|
551
|
-
<label className="block text-xs font-medium text-[var(--muted-foreground)]
|
|
551
|
+
<label className="mb-1 block text-xs font-medium text-[var(--muted-foreground)]">
|
|
552
552
|
{label}
|
|
553
553
|
</label>
|
|
554
554
|
<textarea
|
|
555
555
|
value={value}
|
|
556
556
|
onChange={(e) => onChange(e.target.value)}
|
|
557
557
|
rows={rows}
|
|
558
|
-
className="w-full
|
|
558
|
+
className="w-full resize-none rounded-lg border border-[var(--border)] bg-[var(--background)] px-3 py-1.5 text-sm text-[var(--foreground)] placeholder:text-[var(--muted-foreground)] focus:ring-2 focus:ring-[var(--primary)] focus:outline-none"
|
|
559
559
|
placeholder={placeholder}
|
|
560
560
|
/>
|
|
561
561
|
{charCount !== undefined && charTarget && (
|
|
562
|
-
<p className="
|
|
562
|
+
<p className="mt-1 text-xs text-[var(--muted-foreground)]">
|
|
563
563
|
{charCount} chars {charTarget}
|
|
564
564
|
</p>
|
|
565
565
|
)}
|
|
@@ -622,24 +622,24 @@ export function SEOPanel({
|
|
|
622
622
|
return (
|
|
623
623
|
<div className="rounded-lg border border-[var(--border)] bg-[var(--card)]">
|
|
624
624
|
{/* Header */}
|
|
625
|
-
<div className="flex items-center justify-between
|
|
626
|
-
<h3 className="font-semibold text-[var(--foreground)]
|
|
627
|
-
<Search className="
|
|
625
|
+
<div className="flex items-center justify-between border-b border-[var(--border)] px-4 py-3">
|
|
626
|
+
<h3 className="flex items-center gap-2 text-sm font-semibold text-[var(--foreground)]">
|
|
627
|
+
<Search className="h-4 w-4" />
|
|
628
628
|
SEO
|
|
629
629
|
</h3>
|
|
630
630
|
<button
|
|
631
631
|
onClick={() => update({ metaTitle: title, ogTitle: '', ogDescription: '' })}
|
|
632
|
-
className="text-xs text-[var(--primary)] hover:opacity-80
|
|
632
|
+
className="flex items-center gap-1 text-xs text-[var(--primary)] hover:opacity-80"
|
|
633
633
|
>
|
|
634
|
-
<RefreshCw className="
|
|
634
|
+
<RefreshCw className="h-3 w-3" />
|
|
635
635
|
Reset
|
|
636
636
|
</button>
|
|
637
637
|
</div>
|
|
638
638
|
|
|
639
639
|
{/* Score */}
|
|
640
|
-
<div className="flex items-center gap-4
|
|
640
|
+
<div className="flex items-center gap-4 border-b border-[var(--border)] px-4 py-3">
|
|
641
641
|
<ScoreRing score={score} />
|
|
642
|
-
<div className="text-xs text-[var(--muted-foreground)]
|
|
642
|
+
<div className="space-y-0.5 text-xs text-[var(--muted-foreground)]">
|
|
643
643
|
<div className="flex items-center gap-1.5">
|
|
644
644
|
<CheckCircle2 className="h-3 w-3 text-green-500" /> {goodCount} passed
|
|
645
645
|
</div>
|
|
@@ -653,7 +653,7 @@ export function SEOPanel({
|
|
|
653
653
|
</div>
|
|
654
654
|
|
|
655
655
|
{/* Sections */}
|
|
656
|
-
<div className="
|
|
656
|
+
<div className="space-y-2 p-3">
|
|
657
657
|
{/* SEO Analysis */}
|
|
658
658
|
<Section
|
|
659
659
|
id="analysis"
|
|
@@ -672,7 +672,7 @@ export function SEOPanel({
|
|
|
672
672
|
<div key={c.id} className="flex items-start gap-2 py-1">
|
|
673
673
|
<StatusDot status={c.status} />
|
|
674
674
|
<div className="min-w-0">
|
|
675
|
-
<p className="text-sm text-[var(--foreground)]
|
|
675
|
+
<p className="text-sm leading-snug text-[var(--foreground)]">{c.label}</p>
|
|
676
676
|
<p className="text-xs text-[var(--muted-foreground)]">{c.detail}</p>
|
|
677
677
|
</div>
|
|
678
678
|
</div>
|
|
@@ -719,8 +719,8 @@ export function SEOPanel({
|
|
|
719
719
|
<span
|
|
720
720
|
className={
|
|
721
721
|
readability.passiveEstimate > 15
|
|
722
|
-
? 'text-amber-500
|
|
723
|
-
: 'text-green-500
|
|
722
|
+
? 'font-medium text-amber-500'
|
|
723
|
+
: 'font-medium text-green-500'
|
|
724
724
|
}
|
|
725
725
|
>
|
|
726
726
|
{readability.passiveEstimate}%
|
|
@@ -781,7 +781,7 @@ export function SEOPanel({
|
|
|
781
781
|
<div>
|
|
782
782
|
<label
|
|
783
783
|
id="robots-policy-label"
|
|
784
|
-
className="mb-1 block text-xs font-medium
|
|
784
|
+
className="text-muted-foreground mb-1 block text-xs font-medium"
|
|
785
785
|
>
|
|
786
786
|
Robots Policy
|
|
787
787
|
</label>
|
|
@@ -794,21 +794,21 @@ export function SEOPanel({
|
|
|
794
794
|
>
|
|
795
795
|
<Select.Trigger
|
|
796
796
|
aria-labelledby="robots-policy-label"
|
|
797
|
-
className="flex w-full items-center justify-between rounded-lg border
|
|
797
|
+
className="border-border bg-background text-foreground focus:ring-primary flex w-full items-center justify-between rounded-lg border px-3 py-1.5 text-sm focus:ring-2 focus:outline-none"
|
|
798
798
|
>
|
|
799
799
|
<Select.Value />
|
|
800
800
|
<Select.Icon>
|
|
801
|
-
<ChevronDown className="h-4 w-4
|
|
801
|
+
<ChevronDown className="text-muted-foreground h-4 w-4" />
|
|
802
802
|
</Select.Icon>
|
|
803
803
|
</Select.Trigger>
|
|
804
804
|
<Select.Portal>
|
|
805
|
-
<Select.Content className="z-50 overflow-hidden rounded-lg border
|
|
805
|
+
<Select.Content className="border-border bg-card z-50 overflow-hidden rounded-lg border shadow-md">
|
|
806
806
|
<Select.Viewport className="p-1">
|
|
807
807
|
{ROBOTS_POLICY_OPTIONS.map((option) => (
|
|
808
808
|
<Select.Item
|
|
809
809
|
key={option.value}
|
|
810
810
|
value={option.value}
|
|
811
|
-
className="relative flex cursor-pointer
|
|
811
|
+
className="text-foreground hover:bg-muted focus:bg-muted relative flex cursor-pointer items-center rounded-md py-1.5 pr-3 pl-8 text-sm outline-none select-none"
|
|
812
812
|
>
|
|
813
813
|
<Select.ItemIndicator className="absolute left-2 inline-flex items-center">
|
|
814
814
|
<Check className="h-4 w-4" />
|
|
@@ -820,7 +820,7 @@ export function SEOPanel({
|
|
|
820
820
|
</Select.Content>
|
|
821
821
|
</Select.Portal>
|
|
822
822
|
</Select.Root>
|
|
823
|
-
<p className="mt-1 text-xs
|
|
823
|
+
<p className="text-muted-foreground mt-1 text-xs">
|
|
824
824
|
Use inheritance for most pages. Override only when a page needs different
|
|
825
825
|
index/follow behavior.
|
|
826
826
|
</p>
|
|
@@ -836,14 +836,14 @@ export function SEOPanel({
|
|
|
836
836
|
expanded={expandedSections.includes('preview')}
|
|
837
837
|
onToggle={toggleSection}
|
|
838
838
|
>
|
|
839
|
-
<div className="rounded-lg border border-[var(--border)]
|
|
840
|
-
<div className="text-sm text-blue-600 hover:underline
|
|
839
|
+
<div className="rounded-lg border border-[var(--border)] bg-[var(--background)] p-3">
|
|
840
|
+
<div className="line-clamp-1 cursor-pointer text-sm text-blue-600 hover:underline">
|
|
841
841
|
{metaTitle || title || 'Page Title'}
|
|
842
842
|
</div>
|
|
843
|
-
<div className="text-xs text-green-700
|
|
843
|
+
<div className="mt-1 truncate text-xs text-green-700">
|
|
844
844
|
{siteUrl}/{slug}
|
|
845
845
|
</div>
|
|
846
|
-
<div className="text-sm text-[var(--muted-foreground)]
|
|
846
|
+
<div className="mt-1 line-clamp-2 text-sm text-[var(--muted-foreground)]">
|
|
847
847
|
{metaDesc ||
|
|
848
848
|
'Add a meta description to see how this page will appear in search results.'}
|
|
849
849
|
</div>
|
|
@@ -880,8 +880,8 @@ export function SEOPanel({
|
|
|
880
880
|
type="url"
|
|
881
881
|
/>
|
|
882
882
|
|
|
883
|
-
<div className="border-t border-[var(--border)] pt-3
|
|
884
|
-
<p className="text-xs font-medium text-[var(--muted-foreground)]
|
|
883
|
+
<div className="mt-3 border-t border-[var(--border)] pt-3">
|
|
884
|
+
<p className="mb-2 text-xs font-medium text-[var(--muted-foreground)]">
|
|
885
885
|
Twitter / X Overrides
|
|
886
886
|
</p>
|
|
887
887
|
<div className="space-y-3">
|
|
@@ -910,31 +910,31 @@ export function SEOPanel({
|
|
|
910
910
|
|
|
911
911
|
{/* Social preview card */}
|
|
912
912
|
<div className="mt-3">
|
|
913
|
-
<p className="text-xs font-medium text-[var(--muted-foreground)]
|
|
913
|
+
<p className="mb-2 text-xs font-medium text-[var(--muted-foreground)]">
|
|
914
914
|
Social Preview
|
|
915
915
|
</p>
|
|
916
|
-
<div className="rounded-lg border border-[var(--border)]
|
|
916
|
+
<div className="overflow-hidden rounded-lg border border-[var(--border)] bg-[var(--muted)]">
|
|
917
917
|
{seoData.ogImage ? (
|
|
918
|
-
<div className="aspect-video
|
|
918
|
+
<div className="flex aspect-video items-center justify-center overflow-hidden bg-[var(--muted)]">
|
|
919
919
|
<img
|
|
920
920
|
src={seoData.ogImage}
|
|
921
921
|
alt="OG preview"
|
|
922
|
-
className="
|
|
922
|
+
className="h-full w-full object-cover"
|
|
923
923
|
/>
|
|
924
924
|
</div>
|
|
925
925
|
) : (
|
|
926
|
-
<div className="aspect-video bg-[var(--muted)]
|
|
926
|
+
<div className="flex aspect-video items-center justify-center bg-[var(--muted)] text-sm text-[var(--muted-foreground)]">
|
|
927
927
|
No OG image set
|
|
928
928
|
</div>
|
|
929
929
|
)}
|
|
930
930
|
<div className="p-3">
|
|
931
|
-
<div className="text-sm font-medium text-[var(--foreground)]
|
|
931
|
+
<div className="line-clamp-1 text-sm font-medium text-[var(--foreground)]">
|
|
932
932
|
{displayTitle}
|
|
933
933
|
</div>
|
|
934
|
-
<div className="text-xs text-[var(--muted-foreground)]
|
|
934
|
+
<div className="mt-1 line-clamp-2 text-xs text-[var(--muted-foreground)]">
|
|
935
935
|
{displayDesc.slice(0, 100)}
|
|
936
936
|
</div>
|
|
937
|
-
<div className="text-xs text-[var(--muted-foreground)]
|
|
937
|
+
<div className="mt-1 truncate text-xs text-[var(--muted-foreground)]">
|
|
938
938
|
{siteUrl}
|
|
939
939
|
</div>
|
|
940
940
|
</div>
|
|
@@ -959,19 +959,19 @@ export function SEOPanel({
|
|
|
959
959
|
onChange={(v) => update({ isCornerstone: v })}
|
|
960
960
|
/>
|
|
961
961
|
{seoData.isCornerstone && (
|
|
962
|
-
<div className="flex items-center gap-1.5
|
|
962
|
+
<div className="flex items-center gap-1.5 rounded-md bg-amber-50 px-2.5 py-1.5 text-xs text-amber-600">
|
|
963
963
|
<Star className="h-3.5 w-3.5" />
|
|
964
964
|
Cornerstone content is held to stricter SEO standards
|
|
965
965
|
</div>
|
|
966
966
|
)}
|
|
967
967
|
<div>
|
|
968
|
-
<label className="block text-xs font-medium text-[var(--muted-foreground)]
|
|
968
|
+
<label className="mb-1 block text-xs font-medium text-[var(--muted-foreground)]">
|
|
969
969
|
Schema Type
|
|
970
970
|
</label>
|
|
971
971
|
<select
|
|
972
972
|
value={seoData.schemaType ?? 'Article'}
|
|
973
973
|
onChange={(e) => update({ schemaType: e.target.value })}
|
|
974
|
-
className="w-full
|
|
974
|
+
className="w-full rounded-lg border border-[var(--border)] bg-[var(--background)] px-3 py-1.5 text-sm text-[var(--foreground)] focus:ring-2 focus:ring-[var(--primary)] focus:outline-none"
|
|
975
975
|
>
|
|
976
976
|
{SCHEMA_TYPES.map((t) => (
|
|
977
977
|
<option key={t} value={t}>
|
|
@@ -27,7 +27,7 @@ function ScoreBadge({ score }: { score: number }) {
|
|
|
27
27
|
const bg = score >= 80 ? 'bg-green-50' : score >= 60 ? 'bg-amber-50' : 'bg-red-50'
|
|
28
28
|
return (
|
|
29
29
|
<span
|
|
30
|
-
className={`inline-flex items-center justify-center
|
|
30
|
+
className={`inline-flex h-9 w-9 items-center justify-center rounded-full text-sm font-semibold ${color} ${bg}`}
|
|
31
31
|
>
|
|
32
32
|
{score}
|
|
33
33
|
</span>
|
|
@@ -53,10 +53,10 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
53
53
|
const visible = topContent.slice(page * perPage, (page + 1) * perPage)
|
|
54
54
|
|
|
55
55
|
return (
|
|
56
|
-
<div className="
|
|
57
|
-
<div className="
|
|
56
|
+
<div className="rounded-lg border border-gray-200 bg-white">
|
|
57
|
+
<div className="flex items-center justify-between border-b border-gray-200 p-4">
|
|
58
58
|
<div className="flex items-center gap-2">
|
|
59
|
-
<Search className="
|
|
59
|
+
<Search className="h-4 w-4 text-gray-500" />
|
|
60
60
|
<h2 className="text-sm font-semibold text-gray-900">SEO Performance</h2>
|
|
61
61
|
</div>
|
|
62
62
|
{totalIssues > 0 && (
|
|
@@ -66,25 +66,25 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
66
66
|
)}
|
|
67
67
|
</div>
|
|
68
68
|
|
|
69
|
-
<div className="grid grid-cols-1
|
|
70
|
-
<div className="lg:col-span-7
|
|
71
|
-
<h3 className="text-sm font-medium text-gray-700
|
|
69
|
+
<div className="grid grid-cols-1 divide-y divide-gray-200 lg:grid-cols-12 lg:divide-x lg:divide-y-0">
|
|
70
|
+
<div className="p-4 lg:col-span-7">
|
|
71
|
+
<h3 className="mb-3 text-sm font-medium text-gray-700">Top Performing Content</h3>
|
|
72
72
|
<div className="space-y-2">
|
|
73
73
|
{visible.map((item) => (
|
|
74
74
|
<div key={item.id} className="flex items-center justify-between py-2">
|
|
75
|
-
<div className="
|
|
76
|
-
<p className="text-sm font-medium text-gray-900
|
|
75
|
+
<div className="mr-3 min-w-0 flex-1">
|
|
76
|
+
<p className="truncate text-sm font-medium text-gray-900">{item.title}</p>
|
|
77
77
|
<p className="text-xs text-gray-500 capitalize">{item.collection}</p>
|
|
78
78
|
</div>
|
|
79
79
|
<ScoreBadge score={item.score} />
|
|
80
80
|
</div>
|
|
81
81
|
))}
|
|
82
82
|
{visible.length === 0 && (
|
|
83
|
-
<p className="text-sm text-gray-400
|
|
83
|
+
<p className="py-4 text-center text-sm text-gray-400">No published content yet</p>
|
|
84
84
|
)}
|
|
85
85
|
</div>
|
|
86
86
|
{topContent.length > perPage && (
|
|
87
|
-
<div className="flex items-center justify-between
|
|
87
|
+
<div className="mt-3 flex items-center justify-between border-t border-gray-100 pt-3 text-xs text-gray-500">
|
|
88
88
|
<span>
|
|
89
89
|
Showing {page * perPage + 1}-{Math.min((page + 1) * perPage, topContent.length)} of{' '}
|
|
90
90
|
{topContent.length}
|
|
@@ -93,9 +93,9 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
93
93
|
<button
|
|
94
94
|
onClick={() => setPage(Math.max(0, page - 1))}
|
|
95
95
|
disabled={page === 0}
|
|
96
|
-
className="p-1
|
|
96
|
+
className="rounded p-1 hover:bg-gray-100 disabled:opacity-30"
|
|
97
97
|
>
|
|
98
|
-
<ChevronLeft className="
|
|
98
|
+
<ChevronLeft className="h-3.5 w-3.5" />
|
|
99
99
|
</button>
|
|
100
100
|
<span>
|
|
101
101
|
Page {page + 1} of {totalPages}
|
|
@@ -103,21 +103,21 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
103
103
|
<button
|
|
104
104
|
onClick={() => setPage(Math.min(totalPages - 1, page + 1))}
|
|
105
105
|
disabled={page >= totalPages - 1}
|
|
106
|
-
className="p-1
|
|
106
|
+
className="rounded p-1 hover:bg-gray-100 disabled:opacity-30"
|
|
107
107
|
>
|
|
108
|
-
<ChevronRight className="
|
|
108
|
+
<ChevronRight className="h-3.5 w-3.5" />
|
|
109
109
|
</button>
|
|
110
110
|
</div>
|
|
111
111
|
</div>
|
|
112
112
|
)}
|
|
113
113
|
</div>
|
|
114
114
|
|
|
115
|
-
<div className="lg:col-span-5
|
|
116
|
-
<h3 className="text-sm font-medium text-gray-700
|
|
115
|
+
<div className="p-4 lg:col-span-5">
|
|
116
|
+
<h3 className="mb-3 text-sm font-medium text-gray-700">SEO Issues</h3>
|
|
117
117
|
<div className="space-y-3">
|
|
118
118
|
<div className="flex items-center justify-between">
|
|
119
119
|
<div className="flex items-center gap-2">
|
|
120
|
-
<FileWarning className="
|
|
120
|
+
<FileWarning className="h-4 w-4 text-red-400" />
|
|
121
121
|
<span className="text-sm text-gray-700">Missing meta descriptions</span>
|
|
122
122
|
</div>
|
|
123
123
|
<span className="text-sm font-semibold text-gray-900">
|
|
@@ -126,7 +126,7 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
126
126
|
</div>
|
|
127
127
|
<div className="flex items-center justify-between">
|
|
128
128
|
<div className="flex items-center gap-2">
|
|
129
|
-
<LinkIcon className="
|
|
129
|
+
<LinkIcon className="h-4 w-4 text-red-400" />
|
|
130
130
|
<span className="text-sm text-gray-700">Broken internal links</span>
|
|
131
131
|
</div>
|
|
132
132
|
<span className="text-sm font-semibold text-gray-900">
|
|
@@ -135,7 +135,7 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
135
135
|
</div>
|
|
136
136
|
<div className="flex items-center justify-between">
|
|
137
137
|
<div className="flex items-center gap-2">
|
|
138
|
-
<ImageOff className="
|
|
138
|
+
<ImageOff className="h-4 w-4 text-red-400" />
|
|
139
139
|
<span className="text-sm text-gray-700">Missing alt text</span>
|
|
140
140
|
</div>
|
|
141
141
|
<span className="text-sm font-semibold text-gray-900">{issues.missingAltText}</span>
|
|
@@ -144,7 +144,7 @@ export function SEOPerformance({ onNavigate }: SEOPerformanceProps) {
|
|
|
144
144
|
{totalIssues > 0 && (
|
|
145
145
|
<button
|
|
146
146
|
onClick={() => onNavigate?.('/seo')}
|
|
147
|
-
className="mt-4 text-sm text-blue-600 hover:text-blue-700
|
|
147
|
+
className="mt-4 text-sm font-medium text-blue-600 hover:text-blue-700"
|
|
148
148
|
>
|
|
149
149
|
View All Issues
|
|
150
150
|
</button>
|
|
@@ -156,13 +156,13 @@ export function SchedulePublishDialog({
|
|
|
156
156
|
<div className="space-y-1.5">
|
|
157
157
|
<label className="text-sm font-medium text-gray-700">Publish at</label>
|
|
158
158
|
<div className="relative">
|
|
159
|
-
<Clock className="pointer-events-none absolute
|
|
159
|
+
<Clock className="pointer-events-none absolute top-2.5 left-2.5 h-4 w-4 text-gray-400" />
|
|
160
160
|
<input
|
|
161
161
|
type="datetime-local"
|
|
162
162
|
value={publishAt}
|
|
163
163
|
onChange={(e) => setPublishAt(e.target.value)}
|
|
164
164
|
min={toLocalDateTimeInput(new Date(Date.now() + 60 * 1000))}
|
|
165
|
-
className="w-full rounded-md border border-gray-300 bg-white py-2 pl-9
|
|
165
|
+
className="w-full rounded-md border border-gray-300 bg-white py-2 pr-3 pl-9 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
|
166
166
|
/>
|
|
167
167
|
</div>
|
|
168
168
|
<p className="text-xs text-gray-500">
|
|
@@ -184,13 +184,13 @@ export function SchedulePublishDialog({
|
|
|
184
184
|
<div className="space-y-1.5">
|
|
185
185
|
<label className="text-sm font-medium text-gray-700">Unpublish at</label>
|
|
186
186
|
<div className="relative">
|
|
187
|
-
<Clock className="pointer-events-none absolute
|
|
187
|
+
<Clock className="pointer-events-none absolute top-2.5 left-2.5 h-4 w-4 text-gray-400" />
|
|
188
188
|
<input
|
|
189
189
|
type="datetime-local"
|
|
190
190
|
value={unpublishAt}
|
|
191
191
|
onChange={(e) => setUnpublishAt(e.target.value)}
|
|
192
192
|
min={publishAt || toLocalDateTimeInput(new Date(Date.now() + 60 * 1000))}
|
|
193
|
-
className="w-full rounded-md border border-gray-300 bg-white py-2 pl-9
|
|
193
|
+
className="w-full rounded-md border border-gray-300 bg-white py-2 pr-3 pl-9 text-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
|
194
194
|
/>
|
|
195
195
|
</div>
|
|
196
196
|
</div>
|
|
@@ -174,7 +174,7 @@ export function SharePreviewLinkDialog({
|
|
|
174
174
|
|
|
175
175
|
{previewUrl ? (
|
|
176
176
|
<div className="space-y-2 rounded-lg border border-gray-200 bg-gray-50 p-3">
|
|
177
|
-
<label className="text-xs font-medium
|
|
177
|
+
<label className="text-xs font-medium tracking-wide text-gray-500 uppercase">
|
|
178
178
|
Preview URL
|
|
179
179
|
</label>
|
|
180
180
|
<div className="flex items-stretch gap-2">
|