@actuate-media/cms-admin 0.9.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.d.ts +18 -0
- package/dist/components/SchedulePublishDialog.d.ts.map +1 -0
- package/dist/components/SchedulePublishDialog.js +106 -0
- package/dist/components/SchedulePublishDialog.js.map +1 -0
- package/dist/components/SharePreviewLinkDialog.d.ts +17 -0
- package/dist/components/SharePreviewLinkDialog.d.ts.map +1 -0
- package/dist/components/SharePreviewLinkDialog.js +83 -0
- package/dist/components/SharePreviewLinkDialog.js.map +1 -0
- 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 +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -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.d.ts.map +1 -1
- package/dist/views/ApiKeys.js +13 -11
- package/dist/views/ApiKeys.js.map +1 -1
- 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.d.ts.map +1 -1
- package/dist/views/DocumentEdit.js +17 -5
- package/dist/views/DocumentEdit.js.map +1 -1
- 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 +241 -0
- package/src/components/SharePreviewLinkDialog.tsx +227 -0
- 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 +32 -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 +90 -10
- 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
package/src/views/PostEditor.tsx
CHANGED
|
@@ -86,59 +86,59 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
|
|
|
86
86
|
|
|
87
87
|
if (!isNew && loading) {
|
|
88
88
|
return (
|
|
89
|
-
<div className="h-full
|
|
90
|
-
<Loader2 className="
|
|
89
|
+
<div className="flex h-full items-center justify-center">
|
|
90
|
+
<Loader2 className="h-6 w-6 animate-spin text-blue-600" />
|
|
91
91
|
</div>
|
|
92
92
|
)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
return (
|
|
96
|
-
<div className="h-full flex
|
|
96
|
+
<div className="flex h-full flex-col bg-white">
|
|
97
97
|
{error && (
|
|
98
98
|
<div className="mx-4 mt-3 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
|
|
99
|
-
<AlertTriangle className="
|
|
100
|
-
<span className="text-sm text-red-800
|
|
99
|
+
<AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
|
|
100
|
+
<span className="flex-1 text-sm text-red-800">{error}</span>
|
|
101
101
|
</div>
|
|
102
102
|
)}
|
|
103
103
|
|
|
104
|
-
<div className="border-b border-gray-200 px-3 sm:px-4
|
|
104
|
+
<div className="border-b border-gray-200 px-3 py-3 sm:px-4">
|
|
105
105
|
<div className="flex items-center justify-between">
|
|
106
106
|
<button
|
|
107
107
|
onClick={() => onNavigate?.('/posts')}
|
|
108
|
-
className="inline-flex items-center gap-2 text-sm text-gray-600 hover:text-gray-900
|
|
108
|
+
className="inline-flex items-center gap-2 text-sm text-gray-600 transition-colors hover:text-gray-900"
|
|
109
109
|
>
|
|
110
|
-
<ArrowLeft className="
|
|
110
|
+
<ArrowLeft className="h-4 w-4" />
|
|
111
111
|
<span className="hidden sm:inline">Back to Posts</span>
|
|
112
112
|
<span className="sm:hidden">Back</span>
|
|
113
113
|
</button>
|
|
114
114
|
<div className="flex items-center gap-2">
|
|
115
|
-
<button className="
|
|
116
|
-
<Eye className="
|
|
115
|
+
<button className="flex items-center gap-2 rounded-lg border border-gray-300 px-3 py-1.5 text-sm transition-colors hover:bg-gray-50">
|
|
116
|
+
<Eye className="h-4 w-4" />
|
|
117
117
|
<span className="hidden sm:inline">Preview</span>
|
|
118
118
|
</button>
|
|
119
119
|
</div>
|
|
120
120
|
</div>
|
|
121
121
|
</div>
|
|
122
122
|
|
|
123
|
-
<div className="flex-1 overflow-hidden
|
|
123
|
+
<div className="flex flex-1 flex-col overflow-hidden lg:flex-row">
|
|
124
124
|
<div className="flex-1 overflow-y-auto">
|
|
125
|
-
<div className="max-w-4xl
|
|
125
|
+
<div className="mx-auto max-w-4xl p-3 pr-6 sm:p-4 sm:pr-8">
|
|
126
126
|
<input
|
|
127
127
|
type="text"
|
|
128
128
|
value={title}
|
|
129
129
|
onChange={(e) => setTitle(e.target.value)}
|
|
130
130
|
placeholder="Post title"
|
|
131
|
-
className="w-full
|
|
131
|
+
className="mb-4 w-full border-none px-0 text-2xl font-bold placeholder:text-gray-300 focus:ring-0 focus:outline-none sm:text-3xl"
|
|
132
132
|
/>
|
|
133
133
|
|
|
134
134
|
<div className="mb-4">
|
|
135
|
-
<label className="block text-xs font-medium text-gray-600
|
|
135
|
+
<label className="mb-1 block text-xs font-medium text-gray-600">URL Slug</label>
|
|
136
136
|
<input
|
|
137
137
|
type="text"
|
|
138
138
|
value={slug}
|
|
139
139
|
onChange={(e) => setSlug(e.target.value)}
|
|
140
140
|
placeholder="url-slug"
|
|
141
|
-
className="w-full px-3 py-1.5 text-sm
|
|
141
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
142
142
|
/>
|
|
143
143
|
</div>
|
|
144
144
|
|
|
@@ -148,35 +148,35 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
|
|
|
148
148
|
</div>
|
|
149
149
|
</div>
|
|
150
150
|
|
|
151
|
-
<div className="hidden
|
|
152
|
-
<div className="
|
|
153
|
-
<div className="
|
|
154
|
-
<h3 className="font-semibold text-gray-900
|
|
151
|
+
<div className="hidden w-[30%] overflow-y-auto border-l border-gray-200 bg-gray-50 lg:block">
|
|
152
|
+
<div className="space-y-4 p-4">
|
|
153
|
+
<div className="rounded-lg border border-gray-200 bg-white p-4">
|
|
154
|
+
<h3 className="mb-3 text-sm font-semibold text-gray-900">Publish</h3>
|
|
155
155
|
<div className="space-y-3">
|
|
156
156
|
<div>
|
|
157
|
-
<label className="block text-xs font-medium text-gray-700
|
|
157
|
+
<label className="mb-1 block text-xs font-medium text-gray-700">Status</label>
|
|
158
158
|
<select
|
|
159
159
|
value={status}
|
|
160
160
|
onChange={(e) => setStatus(e.target.value as 'draft' | 'published')}
|
|
161
|
-
className="w-full px-3 py-1.5 text-sm
|
|
161
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
162
162
|
>
|
|
163
163
|
<option value="draft">Draft</option>
|
|
164
164
|
<option value="published">Published</option>
|
|
165
165
|
</select>
|
|
166
166
|
</div>
|
|
167
167
|
<div>
|
|
168
|
-
<label className="block text-xs font-medium text-gray-700
|
|
168
|
+
<label className="mb-1 block text-xs font-medium text-gray-700">
|
|
169
169
|
Publish Date
|
|
170
170
|
</label>
|
|
171
171
|
<input
|
|
172
172
|
type="datetime-local"
|
|
173
|
-
className="w-full px-3 py-1.5 text-sm
|
|
173
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
174
174
|
/>
|
|
175
175
|
</div>
|
|
176
176
|
<button
|
|
177
177
|
onClick={savePost}
|
|
178
178
|
disabled={saving}
|
|
179
|
-
className="w-full
|
|
179
|
+
className="w-full rounded-lg bg-blue-600 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
|
|
180
180
|
>
|
|
181
181
|
{saving ? 'Saving...' : 'Save Post'}
|
|
182
182
|
</button>
|
|
@@ -184,7 +184,7 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
|
|
|
184
184
|
<button
|
|
185
185
|
onClick={publishPost}
|
|
186
186
|
disabled={saving}
|
|
187
|
-
className="w-full
|
|
187
|
+
className="w-full rounded-lg bg-green-600 py-2 text-sm font-medium text-white transition-colors hover:bg-green-700 disabled:opacity-50"
|
|
188
188
|
>
|
|
189
189
|
{saving ? 'Publishing...' : 'Publish'}
|
|
190
190
|
</button>
|
|
@@ -192,31 +192,31 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
|
|
|
192
192
|
</div>
|
|
193
193
|
</div>
|
|
194
194
|
|
|
195
|
-
<div className="
|
|
196
|
-
<h3 className="font-semibold text-gray-900
|
|
195
|
+
<div className="rounded-lg border border-gray-200 bg-white p-4">
|
|
196
|
+
<h3 className="mb-3 text-sm font-semibold text-gray-900">Categories & Tags</h3>
|
|
197
197
|
<div className="space-y-3">
|
|
198
198
|
<div>
|
|
199
|
-
<label className="block text-xs font-medium text-gray-700
|
|
200
|
-
<select className="w-full px-3 py-1.5 text-sm
|
|
199
|
+
<label className="mb-1 block text-xs font-medium text-gray-700">Category</label>
|
|
200
|
+
<select className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none">
|
|
201
201
|
<option>Technology</option>
|
|
202
202
|
<option>Design</option>
|
|
203
203
|
<option>Business</option>
|
|
204
204
|
</select>
|
|
205
205
|
</div>
|
|
206
206
|
<div>
|
|
207
|
-
<label className="block text-xs font-medium text-gray-700
|
|
207
|
+
<label className="mb-1 block text-xs font-medium text-gray-700">Tags</label>
|
|
208
208
|
<input
|
|
209
209
|
type="text"
|
|
210
210
|
placeholder="Add tags..."
|
|
211
|
-
className="w-full px-3 py-1.5 text-sm
|
|
211
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
212
212
|
/>
|
|
213
213
|
</div>
|
|
214
214
|
</div>
|
|
215
215
|
</div>
|
|
216
216
|
|
|
217
|
-
<div className="
|
|
218
|
-
<h3 className="font-semibold text-gray-900
|
|
219
|
-
<button className="w-full
|
|
217
|
+
<div className="rounded-lg border border-gray-200 bg-white p-4">
|
|
218
|
+
<h3 className="mb-3 text-sm font-semibold text-gray-900">Featured Image</h3>
|
|
219
|
+
<button className="w-full rounded-lg border-2 border-dashed border-gray-300 py-2 text-sm text-gray-600 transition-colors hover:border-gray-400">
|
|
220
220
|
Upload Image
|
|
221
221
|
</button>
|
|
222
222
|
</div>
|
|
@@ -231,12 +231,12 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
|
|
|
231
231
|
</div>
|
|
232
232
|
</div>
|
|
233
233
|
|
|
234
|
-
<div className="
|
|
234
|
+
<div className="border-t border-gray-200 bg-white p-3 lg:hidden">
|
|
235
235
|
<div className="flex gap-2">
|
|
236
236
|
<button
|
|
237
237
|
onClick={savePost}
|
|
238
238
|
disabled={saving}
|
|
239
|
-
className="flex-1
|
|
239
|
+
className="flex-1 rounded-lg bg-blue-600 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
|
|
240
240
|
>
|
|
241
241
|
{saving ? 'Saving...' : 'Save Post'}
|
|
242
242
|
</button>
|
|
@@ -244,7 +244,7 @@ export function PostEditor({ id, onNavigate }: PostEditorProps) {
|
|
|
244
244
|
<button
|
|
245
245
|
onClick={publishPost}
|
|
246
246
|
disabled={saving}
|
|
247
|
-
className="flex-1
|
|
247
|
+
className="flex-1 rounded-lg bg-green-600 py-2 text-sm font-medium text-white transition-colors hover:bg-green-700 disabled:opacity-50"
|
|
248
248
|
>
|
|
249
249
|
Publish
|
|
250
250
|
</button>
|
package/src/views/Posts.tsx
CHANGED
|
@@ -98,17 +98,17 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
98
98
|
<button
|
|
99
99
|
type="button"
|
|
100
100
|
onClick={() => setSortConfig(toggleSort(sortConfig, sortKey))}
|
|
101
|
-
className="flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900
|
|
101
|
+
className="flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900"
|
|
102
102
|
>
|
|
103
103
|
{label}
|
|
104
104
|
{active ? (
|
|
105
105
|
sortConfig!.direction === 'asc' ? (
|
|
106
|
-
<ArrowUp className="
|
|
106
|
+
<ArrowUp className="h-3 w-3" />
|
|
107
107
|
) : (
|
|
108
|
-
<ArrowDown className="
|
|
108
|
+
<ArrowDown className="h-3 w-3" />
|
|
109
109
|
)
|
|
110
110
|
) : (
|
|
111
|
-
<ArrowUpDown className="
|
|
111
|
+
<ArrowUpDown className="h-3 w-3 text-gray-400" />
|
|
112
112
|
)}
|
|
113
113
|
</button>
|
|
114
114
|
)
|
|
@@ -116,59 +116,59 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
116
116
|
|
|
117
117
|
if (loading) {
|
|
118
118
|
return (
|
|
119
|
-
<div className="p-3 pr-6 sm:p-4 sm:pr-8
|
|
120
|
-
<Loader2 className="
|
|
119
|
+
<div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
|
|
120
|
+
<Loader2 className="h-6 w-6 animate-spin text-blue-600" />
|
|
121
121
|
</div>
|
|
122
122
|
)
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
return (
|
|
126
|
-
<div className="p-3 pr-6 sm:p-4 sm:pr-8
|
|
126
|
+
<div className="flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8">
|
|
127
127
|
{error && (
|
|
128
128
|
<div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
|
|
129
|
-
<AlertTriangle className="
|
|
130
|
-
<span className="text-sm text-red-800
|
|
129
|
+
<AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
|
|
130
|
+
<span className="flex-1 text-sm text-red-800">{error}</span>
|
|
131
131
|
<button
|
|
132
132
|
onClick={refetch}
|
|
133
|
-
className="px-3 py-1 text-sm text-red-700
|
|
133
|
+
className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
|
|
134
134
|
>
|
|
135
135
|
Retry
|
|
136
136
|
</button>
|
|
137
137
|
</div>
|
|
138
138
|
)}
|
|
139
139
|
|
|
140
|
-
<div className="flex flex-col sm:flex-row sm:items-center
|
|
140
|
+
<div className="mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
|
|
141
141
|
<div>
|
|
142
|
-
<h1 className="
|
|
142
|
+
<h1 className="mb-1 text-xl font-semibold text-gray-900 sm:text-2xl">Posts</h1>
|
|
143
143
|
<p className="text-sm text-gray-600">{filteredAndSorted.length} total posts</p>
|
|
144
144
|
</div>
|
|
145
145
|
<button
|
|
146
146
|
onClick={() => onNavigate?.('/posts/new')}
|
|
147
|
-
className="flex items-center justify-center gap-2 px-4 py-2
|
|
147
|
+
className="flex items-center justify-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
|
|
148
148
|
>
|
|
149
|
-
<Plus className="
|
|
149
|
+
<Plus className="h-4 w-4" />
|
|
150
150
|
<span className="hidden sm:inline">New Post</span>
|
|
151
151
|
<span className="sm:hidden">New</span>
|
|
152
152
|
</button>
|
|
153
153
|
</div>
|
|
154
154
|
|
|
155
|
-
<div className="
|
|
156
|
-
<div className="
|
|
155
|
+
<div className="mb-4 rounded-lg border border-gray-200 bg-white">
|
|
156
|
+
<div className="flex flex-col gap-3 p-3">
|
|
157
157
|
<div className="relative">
|
|
158
|
-
<Search className="absolute
|
|
158
|
+
<Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
|
|
159
159
|
<input
|
|
160
160
|
type="text"
|
|
161
161
|
placeholder="Search posts..."
|
|
162
162
|
value={searchQuery}
|
|
163
163
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
164
|
-
className="w-full
|
|
164
|
+
className="w-full rounded-lg border border-gray-300 py-2 pr-3 pl-9 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
165
165
|
/>
|
|
166
166
|
</div>
|
|
167
|
-
<div className="flex flex-col sm:flex-row
|
|
167
|
+
<div className="flex flex-col gap-2 sm:flex-row">
|
|
168
168
|
<select
|
|
169
169
|
value={filterStatus}
|
|
170
170
|
onChange={(e) => setFilterStatus(e.target.value)}
|
|
171
|
-
className="flex-1
|
|
171
|
+
className="flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
172
172
|
>
|
|
173
173
|
<option value="all">All Status</option>
|
|
174
174
|
<option value="published">Published</option>
|
|
@@ -177,7 +177,7 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
177
177
|
<select
|
|
178
178
|
value={filterCategory}
|
|
179
179
|
onChange={(e) => setFilterCategory(e.target.value)}
|
|
180
|
-
className="flex-1
|
|
180
|
+
className="flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
181
181
|
>
|
|
182
182
|
<option value="all">All Categories</option>
|
|
183
183
|
<option value="technology">Technology</option>
|
|
@@ -186,9 +186,9 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
186
186
|
</select>
|
|
187
187
|
<button
|
|
188
188
|
type="button"
|
|
189
|
-
className="flex items-center justify-center gap-2 px-3 py-2 text-sm
|
|
189
|
+
className="flex items-center justify-center gap-2 rounded-lg border border-gray-300 px-3 py-2 text-sm transition-colors hover:bg-gray-50"
|
|
190
190
|
>
|
|
191
|
-
<SlidersHorizontal className="
|
|
191
|
+
<SlidersHorizontal className="h-4 w-4" />
|
|
192
192
|
<span className="hidden sm:inline">More Filters</span>
|
|
193
193
|
</button>
|
|
194
194
|
</div>
|
|
@@ -196,8 +196,8 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
196
196
|
</div>
|
|
197
197
|
|
|
198
198
|
{selectedPosts.length > 0 && (
|
|
199
|
-
<div className="
|
|
200
|
-
<div className="flex flex-col sm:flex-row sm:items-center
|
|
199
|
+
<div className="mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3">
|
|
200
|
+
<div className="flex flex-col justify-between gap-2 sm:flex-row sm:items-center">
|
|
201
201
|
<span className="text-sm text-blue-900">
|
|
202
202
|
{selectedPosts.length} post{selectedPosts.length !== 1 ? 's' : ''} selected
|
|
203
203
|
</span>
|
|
@@ -205,14 +205,14 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
205
205
|
<button
|
|
206
206
|
type="button"
|
|
207
207
|
onClick={handleBulkDelete}
|
|
208
|
-
className="flex-1
|
|
208
|
+
className="flex-1 rounded-lg bg-red-600 px-3 py-1.5 text-sm text-white transition-colors hover:bg-red-700 sm:flex-none"
|
|
209
209
|
>
|
|
210
210
|
Delete
|
|
211
211
|
</button>
|
|
212
212
|
<button
|
|
213
213
|
type="button"
|
|
214
214
|
onClick={() => setSelectedPosts([])}
|
|
215
|
-
className="flex-1
|
|
215
|
+
className="flex-1 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm transition-colors hover:bg-gray-50 sm:flex-none"
|
|
216
216
|
>
|
|
217
217
|
Cancel
|
|
218
218
|
</button>
|
|
@@ -222,21 +222,21 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
222
222
|
)}
|
|
223
223
|
|
|
224
224
|
{filteredAndSorted.length === 0 && !error ? (
|
|
225
|
-
<div className="
|
|
226
|
-
<p className="text-sm text-gray-500
|
|
225
|
+
<div className="flex flex-1 flex-col items-center justify-center rounded-lg border border-gray-200 bg-white p-8 text-center">
|
|
226
|
+
<p className="mb-2 text-sm text-gray-500">No posts yet</p>
|
|
227
227
|
<button
|
|
228
228
|
onClick={() => onNavigate?.('/posts/new')}
|
|
229
|
-
className="px-4 py-2 text-sm
|
|
229
|
+
className="rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700"
|
|
230
230
|
>
|
|
231
231
|
Create your first post
|
|
232
232
|
</button>
|
|
233
233
|
</div>
|
|
234
234
|
) : (
|
|
235
235
|
<>
|
|
236
|
-
<div className="hidden
|
|
237
|
-
<div className="overflow-x-auto
|
|
236
|
+
<div className="hidden flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white md:block">
|
|
237
|
+
<div className="h-full overflow-x-auto">
|
|
238
238
|
<table className="w-full">
|
|
239
|
-
<thead className="
|
|
239
|
+
<thead className="sticky top-0 border-b border-gray-200 bg-gray-50">
|
|
240
240
|
<tr>
|
|
241
241
|
<th className="w-8 px-3 py-2 text-left">
|
|
242
242
|
<input
|
|
@@ -271,7 +271,7 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
271
271
|
</thead>
|
|
272
272
|
<tbody className="divide-y divide-gray-200">
|
|
273
273
|
{filteredAndSorted.map((post: any) => (
|
|
274
|
-
<tr key={post.id} className="hover:bg-gray-50
|
|
274
|
+
<tr key={post.id} className="transition-colors hover:bg-gray-50">
|
|
275
275
|
<td className="px-3 py-2">
|
|
276
276
|
<input
|
|
277
277
|
type="checkbox"
|
|
@@ -284,7 +284,7 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
284
284
|
<button
|
|
285
285
|
type="button"
|
|
286
286
|
onClick={() => onNavigate?.(`/posts/${post.id}`)}
|
|
287
|
-
className="font-medium text-gray-900 hover:text-blue-600
|
|
287
|
+
className="text-left text-sm font-medium text-gray-900 hover:text-blue-600"
|
|
288
288
|
>
|
|
289
289
|
{post.title}
|
|
290
290
|
</button>
|
|
@@ -293,7 +293,7 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
293
293
|
<td className="px-3 py-2 text-sm text-gray-600">{post.category}</td>
|
|
294
294
|
<td className="px-3 py-2">
|
|
295
295
|
<span
|
|
296
|
-
className={`inline-flex items-center px-2 py-0.5
|
|
296
|
+
className={`inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${post.status === 'Published' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
|
|
297
297
|
>
|
|
298
298
|
{post.status}
|
|
299
299
|
</span>
|
|
@@ -304,18 +304,18 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
304
304
|
<button
|
|
305
305
|
type="button"
|
|
306
306
|
onClick={() => onNavigate?.(`/posts/${post.id}`)}
|
|
307
|
-
className="p-1.5 hover:bg-gray-100
|
|
307
|
+
className="rounded p-1.5 transition-colors hover:bg-gray-100"
|
|
308
308
|
title="Edit"
|
|
309
309
|
>
|
|
310
|
-
<Pencil className="
|
|
310
|
+
<Pencil className="h-4 w-4 text-gray-600" />
|
|
311
311
|
</button>
|
|
312
312
|
<button
|
|
313
313
|
type="button"
|
|
314
314
|
onClick={() => handleDelete(post.id)}
|
|
315
|
-
className="p-1.5 hover:bg-gray-100
|
|
315
|
+
className="rounded p-1.5 transition-colors hover:bg-gray-100"
|
|
316
316
|
title="Delete"
|
|
317
317
|
>
|
|
318
|
-
<Trash2 className="
|
|
318
|
+
<Trash2 className="h-4 w-4 text-red-600" />
|
|
319
319
|
</button>
|
|
320
320
|
</div>
|
|
321
321
|
</td>
|
|
@@ -326,7 +326,7 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
326
326
|
</div>
|
|
327
327
|
</div>
|
|
328
328
|
|
|
329
|
-
<div className="
|
|
329
|
+
<div className="flex-1 overflow-auto rounded-lg border border-gray-200 bg-white md:hidden">
|
|
330
330
|
<div className="divide-y divide-gray-200">
|
|
331
331
|
{filteredAndSorted.map((post: any) => (
|
|
332
332
|
<div key={post.id} className="p-3">
|
|
@@ -335,22 +335,22 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
335
335
|
type="checkbox"
|
|
336
336
|
checked={selectedPosts.includes(post.id)}
|
|
337
337
|
onChange={() => handleSelectPost(post.id)}
|
|
338
|
-
className="rounded border-gray-300
|
|
338
|
+
className="mt-1 rounded border-gray-300"
|
|
339
339
|
/>
|
|
340
|
-
<div className="
|
|
340
|
+
<div className="min-w-0 flex-1">
|
|
341
341
|
<button
|
|
342
342
|
type="button"
|
|
343
343
|
onClick={() => onNavigate?.(`/posts/${post.id}`)}
|
|
344
|
-
className="
|
|
344
|
+
className="mb-1 block text-left text-sm font-medium text-gray-900 hover:text-blue-600"
|
|
345
345
|
>
|
|
346
346
|
{post.title}
|
|
347
347
|
</button>
|
|
348
|
-
<div className="flex flex-wrap items-center gap-2 text-xs text-gray-600
|
|
348
|
+
<div className="mb-2 flex flex-wrap items-center gap-2 text-xs text-gray-600">
|
|
349
349
|
<span>{post.author}</span>
|
|
350
350
|
<span>•</span>
|
|
351
351
|
<span>{post.date}</span>
|
|
352
352
|
<span
|
|
353
|
-
className={`px-2 py-0.5
|
|
353
|
+
className={`rounded-full px-2 py-0.5 text-xs font-medium ${post.status === 'Published' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}
|
|
354
354
|
>
|
|
355
355
|
{post.status}
|
|
356
356
|
</span>
|
|
@@ -359,9 +359,9 @@ export function Posts({ onNavigate }: PostsProps) {
|
|
|
359
359
|
<button
|
|
360
360
|
type="button"
|
|
361
361
|
onClick={() => handleDelete(post.id)}
|
|
362
|
-
className="p-1.5 hover:bg-gray-100
|
|
362
|
+
className="rounded p-1.5 transition-colors hover:bg-gray-100"
|
|
363
363
|
>
|
|
364
|
-
<Trash2 className="
|
|
364
|
+
<Trash2 className="h-4 w-4 text-red-600" />
|
|
365
365
|
</button>
|
|
366
366
|
</div>
|
|
367
367
|
</div>
|
package/src/views/Redirects.tsx
CHANGED
|
@@ -101,17 +101,17 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
101
101
|
<button
|
|
102
102
|
type="button"
|
|
103
103
|
onClick={() => setSortConfig(toggleSort(sortConfig, sortKey))}
|
|
104
|
-
className="flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900
|
|
104
|
+
className="flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900"
|
|
105
105
|
>
|
|
106
106
|
{label}
|
|
107
107
|
{active ? (
|
|
108
108
|
sortConfig!.direction === 'asc' ? (
|
|
109
|
-
<ArrowUp className="
|
|
109
|
+
<ArrowUp className="h-3 w-3" />
|
|
110
110
|
) : (
|
|
111
|
-
<ArrowDown className="
|
|
111
|
+
<ArrowDown className="h-3 w-3" />
|
|
112
112
|
)
|
|
113
113
|
) : (
|
|
114
|
-
<ArrowUpDown className="
|
|
114
|
+
<ArrowUpDown className="h-3 w-3 text-gray-400" />
|
|
115
115
|
)}
|
|
116
116
|
</button>
|
|
117
117
|
)
|
|
@@ -119,8 +119,8 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
119
119
|
|
|
120
120
|
if (loading) {
|
|
121
121
|
return (
|
|
122
|
-
<div className="p-3 pr-6 sm:p-4 sm:pr-8
|
|
123
|
-
<Loader2 className="
|
|
122
|
+
<div className="flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8">
|
|
123
|
+
<Loader2 className="h-6 w-6 animate-spin text-blue-600" />
|
|
124
124
|
</div>
|
|
125
125
|
)
|
|
126
126
|
}
|
|
@@ -129,11 +129,11 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
129
129
|
<div className="p-3 pr-6 sm:p-4 sm:pr-8">
|
|
130
130
|
{error && (
|
|
131
131
|
<div className="mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
|
|
132
|
-
<AlertTriangle className="
|
|
133
|
-
<span className="text-sm text-red-800
|
|
132
|
+
<AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
|
|
133
|
+
<span className="flex-1 text-sm text-red-800">{error}</span>
|
|
134
134
|
<button
|
|
135
135
|
onClick={refetch}
|
|
136
|
-
className="px-3 py-1 text-sm text-red-700
|
|
136
|
+
className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
|
|
137
137
|
>
|
|
138
138
|
Retry
|
|
139
139
|
</button>
|
|
@@ -155,22 +155,22 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
155
155
|
</button>
|
|
156
156
|
</div>
|
|
157
157
|
|
|
158
|
-
<div className="
|
|
159
|
-
<div className="
|
|
158
|
+
<div className="mb-4 rounded-lg border border-gray-200 bg-white">
|
|
159
|
+
<div className="flex flex-col gap-3 p-3 sm:flex-row">
|
|
160
160
|
<div className="relative flex-1">
|
|
161
|
-
<Search className="absolute
|
|
161
|
+
<Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" />
|
|
162
162
|
<input
|
|
163
163
|
type="text"
|
|
164
164
|
placeholder="Search by source or destination URL..."
|
|
165
165
|
value={searchQuery}
|
|
166
166
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
167
|
-
className="w-full
|
|
167
|
+
className="w-full rounded-lg border border-gray-300 py-2 pr-3 pl-9 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
168
168
|
/>
|
|
169
169
|
</div>
|
|
170
170
|
<select
|
|
171
171
|
value={filterType}
|
|
172
172
|
onChange={(e) => setFilterType(e.target.value)}
|
|
173
|
-
className="
|
|
173
|
+
className="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
174
174
|
>
|
|
175
175
|
<option value="all">All Types</option>
|
|
176
176
|
<option value="301">301 (Permanent)</option>
|
|
@@ -181,10 +181,10 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
181
181
|
|
|
182
182
|
{filteredAndSorted.length === 0 && !loading ? (
|
|
183
183
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
184
|
-
<div className="
|
|
185
|
-
<ArrowRightLeft className="
|
|
184
|
+
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100">
|
|
185
|
+
<ArrowRightLeft className="h-6 w-6 text-gray-400" />
|
|
186
186
|
</div>
|
|
187
|
-
<h3 className="text-sm font-medium text-gray-900
|
|
187
|
+
<h3 className="mb-1 text-sm font-medium text-gray-900">No redirects yet</h3>
|
|
188
188
|
<p className="text-sm text-gray-500">Add your first redirect to get started.</p>
|
|
189
189
|
</div>
|
|
190
190
|
) : (
|
|
@@ -280,7 +280,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
280
280
|
<Dialog.Root open={showAddDialog} onOpenChange={setShowAddDialog}>
|
|
281
281
|
<Dialog.Portal>
|
|
282
282
|
<Dialog.Overlay className="fixed inset-0 z-50 bg-black/50" />
|
|
283
|
-
<Dialog.Content className="fixed
|
|
283
|
+
<Dialog.Content className="fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-lg">
|
|
284
284
|
<Dialog.Title className="mb-4 text-lg font-semibold text-gray-900">
|
|
285
285
|
Add Redirect
|
|
286
286
|
</Dialog.Title>
|
|
@@ -292,7 +292,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
292
292
|
value={newRedirect.source}
|
|
293
293
|
onChange={(e) => setNewRedirect({ ...newRedirect, source: e.target.value })}
|
|
294
294
|
placeholder="/old-page"
|
|
295
|
-
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:
|
|
295
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
296
296
|
required
|
|
297
297
|
/>
|
|
298
298
|
</div>
|
|
@@ -305,7 +305,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
305
305
|
value={newRedirect.destination}
|
|
306
306
|
onChange={(e) => setNewRedirect({ ...newRedirect, destination: e.target.value })}
|
|
307
307
|
placeholder="/new-page"
|
|
308
|
-
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:
|
|
308
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
309
309
|
required
|
|
310
310
|
/>
|
|
311
311
|
</div>
|
|
@@ -318,7 +318,7 @@ export function Redirects({ onNavigate }: RedirectsProps) {
|
|
|
318
318
|
onChange={(e) =>
|
|
319
319
|
setNewRedirect({ ...newRedirect, type: e.target.value as '301' | '302' })
|
|
320
320
|
}
|
|
321
|
-
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:
|
|
321
|
+
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
322
322
|
>
|
|
323
323
|
<option value="301">301 (Permanent)</option>
|
|
324
324
|
<option value="302">302 (Temporary)</option>
|