@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
|
@@ -27,7 +27,7 @@ function MediaPreview({ item }) {
|
|
|
27
27
|
if (isImageMedia(item)) {
|
|
28
28
|
return (_jsx("img", { src: item.url, alt: item.altTag || item.title || item.name || 'Media preview', className: "h-full w-full object-cover", loading: "lazy" }));
|
|
29
29
|
}
|
|
30
|
-
return _jsx(FileImage, { className: "
|
|
30
|
+
return _jsx(FileImage, { className: "text-muted-foreground h-6 w-6 sm:h-8 sm:w-8" });
|
|
31
31
|
}
|
|
32
32
|
function buildMediaApiUrl(folderSel) {
|
|
33
33
|
const base = '/media?pageSize=100';
|
|
@@ -237,49 +237,49 @@ export function MediaBrowser({ onNavigate }) {
|
|
|
237
237
|
: [];
|
|
238
238
|
function SortHeader({ label, sortKey }) {
|
|
239
239
|
const active = sortConfig?.key === sortKey;
|
|
240
|
-
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900
|
|
240
|
+
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900", children: [label, active ? (sortConfig.direction === 'asc' ? (_jsx(ArrowUp, { className: "h-3 w-3" })) : (_jsx(ArrowDown, { className: "h-3 w-3" }))) : (_jsx(ArrowUpDown, { className: "h-3 w-3 text-gray-400" }))] }));
|
|
241
241
|
}
|
|
242
242
|
if (loading) {
|
|
243
|
-
return (_jsx("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
243
|
+
return (_jsx("div", { className: "flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
244
244
|
}
|
|
245
|
-
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
245
|
+
return (_jsxs("div", { className: "flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("button", { type: "button", onClick: () => setSidebarOpen((prev) => !prev), className: "rounded-lg p-1.5 transition-colors hover:bg-gray-100", title: sidebarOpen ? 'Hide folders' : 'Show folders', children: _jsx(FolderInput, { className: "h-5 w-5 text-gray-600" }) }), _jsxs("div", { children: [_jsx("h1", { className: "mb-1 text-xl font-semibold text-gray-900 sm:text-2xl", children: "Media Library" }), _jsxs("p", { className: "text-sm text-gray-600", children: [filteredAndSorted.length, " files"] })] })] }), _jsxs("div", { children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: true, accept: "image/*,video/*,application/pdf,.doc,.docx,.xls,.xlsx", className: "hidden", onChange: (e) => handleUploadFiles(e.target.files) }), _jsxs("button", { onClick: () => fileInputRef.current?.click(), disabled: uploading, className: "flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700 disabled:opacity-50", children: [uploading ? (_jsx(Loader2, { className: "h-4 w-4 animate-spin" })) : (_jsx(Upload, { className: "h-4 w-4" })), uploading ? 'Uploading...' : 'Upload Files'] })] })] }), _jsxs("div", { className: "flex min-h-0 flex-1 gap-4 overflow-hidden", children: [sidebarOpen && (_jsx("div", { className: "flex w-56 shrink-0 flex-col overflow-hidden rounded-lg border border-gray-200 bg-white", children: _jsx(FolderTree, { scope: "media", selected: folderSel, onSelect: (sel) => {
|
|
246
246
|
setFolderSel(sel);
|
|
247
247
|
setSelectedMedia([]);
|
|
248
|
-
}, totalCount: allData.data?.total, uncategorizedCount: uncatData.data?.total, onDropItem: handleDropItem }) })), _jsxs("div", { className: "flex-
|
|
248
|
+
}, totalCount: allData.data?.total, uncategorizedCount: uncatData.data?.total, onDropItem: handleDropItem }) })), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("div", { className: "mb-4 rounded-lg border border-gray-200 bg-white", children: _jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsxs("div", { className: "flex flex-1 items-center gap-3", children: [_jsxs("div", { className: "relative max-w-md flex-1", children: [_jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx("input", { type: "text", placeholder: "Search media...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), 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" })] }), _jsxs("select", { value: filterType, onChange: (e) => setFilterType(e.target.value), className: "rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", children: [_jsx("option", { value: "all", children: "All Types" }), _jsx("option", { value: "image", children: "Images" }), _jsx("option", { value: "video", children: "Videos" }), _jsx("option", { value: "document", children: "Documents" })] })] }), _jsxs("div", { className: "flex items-center gap-1 rounded-lg bg-gray-100 p-1", children: [_jsx("button", { onClick: () => setViewMode('grid'), className: `rounded p-1.5 transition-colors ${viewMode === 'grid' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-600 hover:text-gray-900'}`, children: _jsx(Grid3x3, { className: "h-4 w-4" }) }), _jsx("button", { onClick: () => setViewMode('list'), className: `rounded p-1.5 transition-colors ${viewMode === 'list' ? 'bg-white text-gray-900 shadow-sm' : 'text-gray-600 hover:text-gray-900'}`, children: _jsx(List, { className: "h-4 w-4" }) })] })] }) }), selectedMedia.length > 0 && (_jsx("div", { className: "mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-sm text-blue-900", children: [selectedMedia.length, " file", selectedMedia.length !== 1 ? 's' : '', " selected"] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { onClick: async () => {
|
|
249
249
|
for (const id of selectedMedia)
|
|
250
250
|
await deleteMedia(id);
|
|
251
251
|
setSelectedMedia([]);
|
|
252
|
-
}, className: "px-3 py-1.5 text-sm
|
|
252
|
+
}, className: "rounded-lg bg-red-600 px-3 py-1.5 text-sm text-white transition-colors hover:bg-red-700", children: "Delete Selected" }), _jsx("button", { onClick: () => setSelectedMedia([]), className: "rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm transition-colors hover:bg-gray-50", children: "Cancel" })] })] }) })), filteredAndSorted.length === 0 && !loading ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [_jsx("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100", children: _jsx(ImageIcon, { className: "h-6 w-6 text-gray-400" }) }), _jsx("h3", { className: "mb-1 text-sm font-medium text-gray-900", children: folderSel.type === 'smart' && folderSel.smart === 'uncategorized'
|
|
253
253
|
? 'No uncategorized media'
|
|
254
254
|
: folderSel.type === 'folder'
|
|
255
255
|
? 'No media in this folder'
|
|
256
|
-
: 'No media yet' }), _jsx("p", { className: "text-sm text-gray-500", children: "Upload your first file to get started." })] })) : (_jsxs("div", { className: "flex
|
|
256
|
+
: 'No media yet' }), _jsx("p", { className: "text-sm text-gray-500", children: "Upload your first file to get started." })] })) : (_jsxs("div", { className: "flex min-h-0 flex-1 gap-4 overflow-hidden", children: [_jsx("div", { className: `overflow-hidden rounded-lg border border-gray-200 bg-white transition-all duration-200 ${panelOpen ? 'min-w-0 flex-1' : 'w-full'}`, children: viewMode === 'grid' ? (_jsx("div", { className: `grid h-full gap-2 overflow-y-auto p-2 sm:gap-3 sm:p-3 ${panelOpen
|
|
257
257
|
? 'grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4'
|
|
258
258
|
: 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-8'}`, children: filteredAndSorted.map((item) => {
|
|
259
259
|
const isActive = activeItem?.id === item.id;
|
|
260
260
|
const hasIssues = !item.altTag || !item.title || item.usedOn?.length === 0;
|
|
261
|
-
return (_jsxs("div", { className: `group relative aspect-square rounded-lg border-2
|
|
261
|
+
return (_jsxs("div", { className: `group relative aspect-square cursor-pointer overflow-hidden rounded-lg border-2 transition-all ${isActive
|
|
262
262
|
? 'border-blue-500 ring-2 ring-blue-200'
|
|
263
263
|
: selectedMedia.includes(item.id)
|
|
264
264
|
? 'border-blue-400 ring-1 ring-blue-100'
|
|
265
|
-
: 'border-gray-200 hover:border-gray-300'}`, onClick: () => openDetail(item), draggable: true, onDragStart: (e) => handleDragStart(e, item.id), children: [_jsx("div", { className: "
|
|
266
|
-
? '
|
|
267
|
-
: 'bg-white/80
|
|
268
|
-
}) })) : (_jsx("div", { className: "overflow-y-auto
|
|
265
|
+
: 'border-gray-200 hover:border-gray-300'}`, onClick: () => openDetail(item), draggable: true, onDragStart: (e) => handleDragStart(e, item.id), children: [_jsx("div", { className: "flex h-full w-full items-center justify-center bg-gray-100", children: _jsx(MediaPreview, { item: item }) }), _jsx("div", { className: "absolute inset-0 bg-linear-to-t from-black/60 to-transparent opacity-0 transition-opacity group-hover:opacity-100", children: _jsxs("div", { className: "absolute right-0 bottom-0 left-0 p-2", children: [_jsx("p", { className: "truncate text-xs font-medium text-white", children: item.name }), _jsx("p", { className: "text-xs text-white/80", children: item.size })] }) }), hasIssues && (_jsx("div", { className: "absolute top-1.5 left-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-yellow-500", title: "Needs attention", children: _jsx(AlertTriangle, { className: "h-3 w-3 text-white" }) })), _jsx("div", { className: "absolute top-1.5 right-1.5 opacity-0 transition-opacity group-hover:opacity-100", onClick: (e) => handleCheckbox(e, item.id), children: _jsx("div", { className: `flex h-5 w-5 items-center justify-center rounded border-2 transition-colors ${selectedMedia.includes(item.id)
|
|
266
|
+
? 'border-blue-600 bg-blue-600'
|
|
267
|
+
: 'border-gray-400 bg-white/80'}`, children: selectedMedia.includes(item.id) && (_jsx("svg", { className: "h-3 w-3 text-white", fill: "none", viewBox: "0 0 12 12", children: _jsx("path", { d: "M10 3L4.5 8.5L2 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })) }) })] }, item.id));
|
|
268
|
+
}) })) : (_jsx("div", { className: "h-full overflow-y-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "w-8 px-3 py-2 text-left", children: _jsx("input", { type: "checkbox", checked: selectedMedia.length === filteredAndSorted.length &&
|
|
269
269
|
filteredAndSorted.length > 0, onChange: handleSelectAll, className: "rounded border-gray-300" }) }), _jsx("th", { className: "w-6 px-1 py-2" }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Name", sortKey: "name" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Type", sortKey: "type" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Size", sortKey: "size" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Uploaded", sortKey: "date" }) }), _jsx("th", { className: "px-3 py-2 text-left text-xs font-medium text-gray-700", children: "Status" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((item) => {
|
|
270
270
|
const isActive = activeItem?.id === item.id;
|
|
271
271
|
const hasIssues = !item.altTag || !item.title || item.usedOn?.length === 0;
|
|
272
|
-
return (_jsxs("tr", { className: `transition-colors
|
|
273
|
-
}) })] }) })) }), panelOpen && activeItem && (_jsxs("div", { className: "w-80
|
|
272
|
+
return (_jsxs("tr", { className: `cursor-pointer transition-colors ${isActive ? 'bg-blue-50' : 'hover:bg-gray-50'}`, onClick: () => openDetail(item), draggable: true, onDragStart: (e) => handleDragStart(e, item.id), children: [_jsx("td", { className: "px-3 py-2", onClick: (e) => e.stopPropagation(), children: _jsx("input", { type: "checkbox", checked: selectedMedia.includes(item.id), onChange: () => handleCheckbox({ stopPropagation: () => { } }, item.id), className: "rounded border-gray-300" }) }), _jsx("td", { className: "cursor-grab px-1 py-2", children: _jsx(GripVertical, { className: "h-4 w-4 text-gray-300" }) }), _jsx("td", { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center overflow-hidden rounded bg-gray-100", children: _jsx(MediaPreview, { item: item }) }), _jsx("span", { className: "text-sm font-medium text-gray-900", children: item.name })] }) }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: item.format ?? item.type }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: item.size }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: item.date }), _jsx("td", { className: "px-3 py-2", children: hasIssues ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), " Needs attention"] })) : (_jsx("span", { className: "inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800", children: "Complete" })) })] }, item.id));
|
|
273
|
+
}) })] }) })) }), panelOpen && activeItem && (_jsxs("div", { className: "flex w-80 shrink-0 flex-col overflow-y-auto rounded-lg border border-gray-200 bg-white lg:w-96", children: [_jsxs("div", { className: "sticky top-0 z-10 flex items-center justify-between border-b border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "truncate text-sm font-semibold text-gray-900", children: activeItem.name }), _jsx("button", { onClick: closeDetail, className: "rounded p-1 transition-colors hover:bg-gray-100", "aria-label": "Close panel", children: _jsx(X, { className: "h-4 w-4 text-gray-500" }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsx("div", { className: "border-b border-gray-200 p-4", children: _jsx("div", { className: "flex aspect-video items-center justify-center overflow-hidden rounded-lg bg-gray-100", children: isImageMedia(activeItem) ? (_jsx(MediaPreview, { item: activeItem })) : (_jsx(ImageIcon, { className: "h-12 w-12 text-gray-300" })) }) }), issues.length > 0 && (_jsxs("div", { className: "mx-4 mt-4 rounded-lg border border-yellow-200 bg-yellow-50 p-3", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-yellow-600" }), _jsxs("div", { children: [_jsxs("p", { className: "mb-1 text-xs font-semibold text-yellow-900", children: [issues.length, " issue", issues.length !== 1 ? 's' : '', " found"] }), _jsx("ul", { className: "space-y-0.5", children: issues.map((issue, i) => (_jsxs("li", { className: "text-xs text-yellow-800", children: ["\u2022 ", issue] }, i))) })] })] }), _jsxs("button", { type: "button", onClick: async () => {
|
|
274
274
|
if (!activeItem.altTag)
|
|
275
275
|
await handleAiGenerate('alt');
|
|
276
276
|
if (!activeItem.title)
|
|
277
277
|
await handleAiGenerate('title');
|
|
278
278
|
if (activeItem.sizeBytes > 2000000)
|
|
279
279
|
await handleAiGenerate('optimize');
|
|
280
|
-
}, className: "mt-2 w-full
|
|
280
|
+
}, className: "mt-2 flex w-full items-center justify-center gap-1.5 rounded-lg bg-yellow-600 px-3 py-1.5 text-xs text-white transition-colors hover:bg-yellow-700", children: [_jsx(Sparkles, { className: "h-3.5 w-3.5" }), "AI Fix All Issues"] })] })), _jsxs("div", { className: "space-y-3 border-b border-gray-200 p-4", children: [_jsx("h4", { className: "text-xs font-semibold tracking-wide text-gray-500 uppercase", children: "File Information" }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-0.5 text-xs text-gray-500", children: "Format" }), _jsx("div", { className: "text-sm text-gray-900", children: activeItem.format ?? 'Unknown' })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-0.5 text-xs text-gray-500", children: "File Size" }), _jsxs("div", { className: "flex items-center gap-1 text-sm text-gray-900", children: [activeItem.size, activeItem.sizeBytes > 2000000 && (_jsx("span", { className: "text-xs text-yellow-600", children: "(large)" }))] })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-0.5 text-xs text-gray-500", children: "Dimensions" }), _jsx("div", { className: "text-sm text-gray-900", children: activeItem.dimensions ?? '—' })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-0.5 text-xs text-gray-500", children: "Uploaded" }), _jsx("div", { className: "text-sm text-gray-900", children: activeItem.date })] })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs text-gray-500", children: "URL" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("code", { className: "flex-1 truncate rounded border border-gray-200 bg-gray-50 px-2 py-1.5 text-xs text-gray-700", children: activeItem.url }), _jsx("button", { onClick: handleCopyUrl, className: "shrink-0 rounded p-1.5 transition-colors hover:bg-gray-100", title: "Copy URL", children: _jsx(Copy, { className: "h-3.5 w-3.5 text-gray-500" }) })] })] })] }), _jsxs("div", { className: "space-y-4 border-b border-gray-200 p-4", children: [_jsx("h4", { className: "text-xs font-semibold tracking-wide text-gray-500 uppercase", children: "SEO & Accessibility" }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium text-gray-700", children: "Alt Tag" }), _jsxs("button", { type: "button", onClick: () => handleAiGenerate('alt'), disabled: aiGenerating === 'alt', className: "flex items-center gap-1 text-xs text-indigo-600 transition-colors hover:text-indigo-700 disabled:opacity-50", children: [_jsx(Bot, { className: "h-3.5 w-3.5" }), aiGenerating === 'alt' ? 'Generating...' : 'AI Generate'] })] }), _jsx("textarea", { value: editAlt, onChange: (e) => setEditAlt(e.target.value), placeholder: "Describe this image for accessibility...", rows: 2, className: "w-full resize-none rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none" }), !editAlt && (_jsx("p", { className: "mt-1 text-xs text-red-500", children: "Required for accessibility and SEO" }))] }), _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between", children: [_jsx("label", { className: "text-sm font-medium text-gray-700", children: "Title" }), _jsxs("button", { type: "button", onClick: () => handleAiGenerate('title'), disabled: aiGenerating === 'title', className: "flex items-center gap-1 text-xs text-indigo-600 transition-colors hover:text-indigo-700 disabled:opacity-50", children: [_jsx(Bot, { className: "h-3.5 w-3.5" }), aiGenerating === 'title' ? 'Generating...' : 'AI Generate'] })] }), _jsx("input", { type: "text", value: editTitle, onChange: (e) => setEditTitle(e.target.value), placeholder: "Image title...", 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" })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "File Name" }), _jsx("input", { type: "text", value: editFilename, onChange: (e) => setEditFilename(e.target.value), 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" })] })] }), isImageMedia(activeItem) && activeItem.url && (_jsx("div", { className: "border-b border-gray-200 p-4", children: _jsx(FocalPointPicker, { imageUrl: activeItem.url, focalX: focalX, focalY: focalY, onChange: (x, y) => {
|
|
281
281
|
setFocalX(x);
|
|
282
282
|
setFocalY(y);
|
|
283
|
-
} }) })), _jsxs("div", { className: "
|
|
283
|
+
} }) })), _jsxs("div", { className: "border-b border-gray-200 p-4", children: [_jsxs("h4", { className: "mb-3 text-xs font-semibold tracking-wide text-gray-500 uppercase", children: ["Used On ", activeItem.usedOn && `(${activeItem.usedOn.length})`] }), activeItem.usedOn && activeItem.usedOn.length > 0 ? (_jsx("div", { className: "space-y-2", children: activeItem.usedOn.map((usage, i) => (_jsxs("button", { type: "button", onClick: () => onNavigate?.(usage.path), className: "flex w-full items-center gap-2 rounded-lg border border-gray-200 p-2 text-left transition-colors hover:bg-gray-50", children: [_jsx(Link2, { className: "h-4 w-4 shrink-0 text-gray-400" }), _jsx("span", { className: "flex-1 truncate text-sm text-gray-900", children: usage.page }), _jsx(ExternalLink, { className: "h-3.5 w-3.5 shrink-0 text-gray-400" })] }, i))) })) : (_jsx("div", { className: "rounded-lg border border-orange-200 bg-orange-50 p-3", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-orange-600" }), _jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium text-orange-900", children: "Orphaned media" }), _jsx("p", { className: "mt-0.5 text-xs text-orange-700", children: "This file isn't used on any page. Consider deleting it to save storage." })] })] }) }))] }), _jsxs("div", { className: "space-y-3 p-4", children: [_jsx("h4", { className: "text-xs font-semibold tracking-wide text-gray-500 uppercase", children: "AI Optimization" }), _jsxs("button", { type: "button", onClick: () => handleAiGenerate('optimize'), disabled: aiGenerating === 'optimize', className: "flex w-full items-center gap-2 rounded-lg border border-indigo-200 bg-indigo-50 p-3 text-left transition-colors hover:bg-indigo-100 disabled:opacity-50", children: [_jsx(Sparkles, { className: `h-5 w-5 shrink-0 text-indigo-600 ${aiGenerating === 'optimize' ? 'animate-spin' : ''}` }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-sm font-medium text-indigo-900", children: aiGenerating === 'optimize' ? 'Optimizing...' : 'Optimize Image' }), _jsx("div", { className: "mt-0.5 text-xs text-indigo-700", children: "Compress and convert to modern format (WebP/AVIF)" })] })] }), _jsxs("button", { type: "button", className: "flex w-full items-center gap-2 rounded-lg border border-gray-200 p-3 text-left transition-colors hover:bg-gray-50", children: [_jsx(Bot, { className: "h-5 w-5 shrink-0 text-gray-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "text-sm font-medium text-gray-900", children: "AI Content Analysis" }), _jsx("div", { className: "mt-0.5 text-xs text-gray-600", children: "Detect objects, faces, text, and suggest categories" })] })] })] })] }), _jsxs("div", { className: "sticky bottom-0 flex items-center gap-2 border-t border-gray-200 bg-white p-4", children: [_jsxs("button", { type: "button", onClick: handleSaveDetails, disabled: saving, className: "flex flex-1 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 disabled:opacity-50", children: [saving && _jsx(Loader2, { className: "h-4 w-4 animate-spin" }), saving ? 'Saving...' : 'Save Changes'] }), _jsx("button", { type: "button", className: "rounded-lg p-2 transition-colors hover:bg-gray-100", title: "Download", children: _jsx(Download, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { type: "button", onClick: () => deleteMedia(activeItem.id), className: "rounded-lg p-2 transition-colors hover:bg-gray-100", title: "Delete", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] })] }))] }))] })] })] }));
|
|
284
284
|
}
|
|
285
285
|
//# sourceMappingURL=MediaBrowser.js.map
|
package/dist/views/PageEditor.js
CHANGED
|
@@ -67,8 +67,8 @@ export function PageEditor({ id, onNavigate }) {
|
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
69
|
if (!isNew && loading) {
|
|
70
|
-
return (_jsx("div", { className: "h-full
|
|
70
|
+
return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
71
71
|
}
|
|
72
|
-
return (_jsxs("div", { className: "h-full flex
|
|
72
|
+
return (_jsxs("div", { className: "flex h-full flex-col bg-white", children: [error && (_jsxs("div", { className: "mx-4 mt-3 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error })] })), _jsx("div", { className: "border-b border-gray-200 px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("button", { onClick: () => onNavigate?.('/pages'), className: "inline-flex items-center gap-2 text-sm text-gray-600 transition-colors hover:text-gray-900", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back to Pages"] }), _jsx("div", { className: "flex items-center gap-3", children: _jsxs("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", children: [_jsx(Eye, { className: "h-4 w-4" }), "Preview"] }) })] }) }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsxs("div", { className: "mx-auto max-w-4xl p-3 pr-6 sm:p-4 sm:pr-8", children: [_jsx("input", { type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Page title", 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" }), _jsxs("div", { className: "mb-4", children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-600", children: "URL Slug" }), _jsx("input", { type: "text", value: slug, onChange: (e) => setSlug(e.target.value), placeholder: "url-slug", 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" })] }), _jsxs("div", { className: "rounded-lg border-2 border-dashed border-gray-300 p-8 text-center", children: [_jsx("p", { className: "mb-2 text-gray-500", children: "No blocks added yet" }), _jsx("p", { className: "text-sm text-gray-400", children: "Click \"Add Block\" to start building your page" }), _jsx("button", { className: "mt-4 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700", children: "Add Block" })] })] }) }), _jsx("div", { className: "w-[30%] overflow-y-auto border-l border-gray-200 bg-gray-50", children: _jsxs("div", { className: "space-y-4 p-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-3 text-sm font-semibold text-gray-900", children: "Publish" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-700", children: "Status" }), _jsxs("select", { value: status, onChange: (e) => setStatus(e.target.value), 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", children: [_jsx("option", { value: "draft", children: "Draft" }), _jsx("option", { value: "published", children: "Published" })] })] }), _jsx("button", { onClick: savePage, disabled: saving, 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", children: saving ? 'Saving...' : 'Save Page' }), status === 'draft' && (_jsx("button", { onClick: publishPage, disabled: saving, 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", children: saving ? 'Publishing...' : 'Publish' }))] })] }), _jsx(SEOPanel, { title: title, slug: slug, seoData: seoData, onChange: setSeoData })] }) })] })] }));
|
|
73
73
|
}
|
|
74
74
|
//# sourceMappingURL=PageEditor.js.map
|
package/dist/views/Pages.js
CHANGED
|
@@ -50,11 +50,11 @@ function textValue(value) {
|
|
|
50
50
|
}
|
|
51
51
|
function SeoScoreBadge({ score }) {
|
|
52
52
|
const color = score >= 80 ? 'bg-green-500' : score >= 60 ? 'bg-amber-500' : 'bg-red-500';
|
|
53
|
-
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: `
|
|
53
|
+
return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: `h-2.5 w-2.5 rounded-full ${color}` }), _jsx("span", { className: "text-xs text-gray-600", children: score })] }));
|
|
54
54
|
}
|
|
55
55
|
function FolderBadge({ name }) {
|
|
56
56
|
const colors = getFolderColor(name);
|
|
57
|
-
return (_jsx("span", { className: `inline-flex px-2 py-0.5
|
|
57
|
+
return (_jsx("span", { className: `inline-flex rounded px-2 py-0.5 text-xs font-medium ${colors.bg} ${colors.text}`, children: name }));
|
|
58
58
|
}
|
|
59
59
|
function buildApiUrl(folderSel) {
|
|
60
60
|
const base = '/collections/pages?pageSize=100';
|
|
@@ -169,27 +169,27 @@ export function Pages({ onNavigate }) {
|
|
|
169
169
|
};
|
|
170
170
|
function SortHeader({ label, sortKey }) {
|
|
171
171
|
const active = sortConfig?.key === sortKey;
|
|
172
|
-
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900
|
|
172
|
+
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900", children: [label, active ? (sortConfig.direction === 'asc' ? (_jsx(ArrowUp, { className: "h-3 w-3" })) : (_jsx(ArrowDown, { className: "h-3 w-3" }))) : (_jsx(ArrowUpDown, { className: "h-3 w-3 text-gray-400" }))] }));
|
|
173
173
|
}
|
|
174
174
|
if (loading) {
|
|
175
|
-
return (_jsx("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
175
|
+
return (_jsx("div", { className: "flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
176
176
|
}
|
|
177
|
-
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
177
|
+
return (_jsxs("div", { className: "flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("button", { type: "button", onClick: () => setSidebarOpen((prev) => !prev), className: "rounded-lg p-1.5 transition-colors hover:bg-gray-100", title: sidebarOpen ? 'Hide folders' : 'Show folders', children: _jsx(FolderInput, { className: "h-5 w-5 text-gray-600" }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold text-gray-900 sm:text-2xl", children: "Pages" }), _jsxs("p", { className: "text-sm text-gray-500", children: [totalCount, " page", totalCount !== 1 ? 's' : ''] })] })] }), _jsxs("button", { onClick: () => onNavigate?.('/pages/new'), 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", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "New Page" }), _jsx("span", { className: "sm:hidden", children: "New" })] })] }), _jsxs("div", { className: "flex min-h-0 flex-1 gap-4 overflow-hidden", children: [sidebarOpen && (_jsx("div", { className: "flex w-56 shrink-0 flex-col overflow-hidden rounded-lg border border-gray-200 bg-white", children: _jsx(FolderTree, { scope: "pages", selected: folderSel, onSelect: (sel) => {
|
|
178
178
|
setFolderSel(sel);
|
|
179
179
|
setSelectedPages([]);
|
|
180
|
-
}, totalCount: allData.data?.total, uncategorizedCount: uncatData.data?.total, onDropItem: handleDropItem }) })), _jsxs("div", { className: "flex-
|
|
180
|
+
}, totalCount: allData.data?.total, uncategorizedCount: uncatData.data?.total, onDropItem: handleDropItem }) })), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("div", { className: "mb-4 rounded-lg border border-gray-200 bg-white", children: _jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx("input", { type: "text", placeholder: "Search pages...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), 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" })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [_jsxs("select", { value: filterStatus, onChange: (e) => setFilterStatus(e.target.value), 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", children: [_jsx("option", { value: "all", children: "All Status" }), _jsx("option", { value: "published", children: "Published" }), _jsx("option", { value: "draft", children: "Draft" })] }), _jsxs("select", { value: filterTemplate, onChange: (e) => setFilterTemplate(e.target.value), 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", children: [_jsx("option", { value: "all", children: "All Templates" }), _jsx("option", { value: "landing", children: "Landing" }), _jsx("option", { value: "standard", children: "Standard" }), _jsx("option", { value: "marketing", children: "Marketing" }), _jsx("option", { value: "blog", children: "Blog" })] }), _jsxs("button", { type: "button", 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", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "More Filters" })] })] })] }) }), selectedPages.length > 0 && (_jsx("div", { className: "mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3", children: _jsxs("div", { className: "flex flex-col justify-between gap-2 sm:flex-row sm:items-center", children: [_jsxs("span", { className: "text-sm text-blue-900", children: [selectedPages.length, " page", selectedPages.length !== 1 ? 's' : '', " selected"] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: handleBulkPublish, className: "flex-1 rounded-lg bg-green-600 px-3 py-1.5 text-sm text-white transition-colors hover:bg-green-700 sm:flex-none", children: "Publish" }), _jsx("button", { type: "button", onClick: handleBulkUnpublish, className: "flex-1 rounded-lg bg-yellow-600 px-3 py-1.5 text-sm text-white transition-colors hover:bg-yellow-700 sm:flex-none", children: "Unpublish" }), _jsx("button", { type: "button", onClick: handleBulkDelete, 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", children: "Delete" }), _jsx("button", { type: "button", onClick: () => setSelectedPages([]), 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", children: "Cancel" })] })] }) })), filteredAndSorted.length === 0 && !error ? (_jsxs("div", { className: "flex flex-1 flex-col items-center justify-center rounded-lg border border-gray-200 bg-white p-8 text-center", children: [_jsx("p", { className: "mb-2 text-sm text-gray-500", children: folderSel.type === 'smart' && folderSel.smart === 'uncategorized'
|
|
181
181
|
? 'No uncategorized pages'
|
|
182
182
|
: folderSel.type === 'folder'
|
|
183
183
|
? 'No pages in this folder'
|
|
184
|
-
: 'No pages yet' }), _jsx("button", { onClick: () => onNavigate?.('/pages/new'), className: "px-4 py-2 text-sm
|
|
184
|
+
: 'No pages yet' }), _jsx("button", { onClick: () => onNavigate?.('/pages/new'), className: "rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700", children: "Create your first page" })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white md:block", children: _jsx("div", { className: "h-full overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "w-8 px-3 py-2 text-left", children: _jsx("input", { type: "checkbox", checked: selectedPages.length === filteredAndSorted.length &&
|
|
185
185
|
filteredAndSorted.length > 0, onChange: (e) => handleSelectAll(e.target.checked), className: "rounded border-gray-300" }) }), _jsx("th", { className: "w-6 px-1 py-2" }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Title", sortKey: "title" }) }), _jsx("th", { className: "px-3 py-2 text-left text-xs font-medium text-gray-700", children: "Folder" }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Author", sortKey: "author" }) }), _jsx("th", { className: "px-3 py-2 text-left text-xs font-medium text-gray-700", children: "SEO" }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Status", sortKey: "status" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Date", sortKey: "date" }) }), _jsx("th", { className: "px-3 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((page) => {
|
|
186
186
|
const seoScore = computeSeoScore(page.data);
|
|
187
187
|
const folderName = page.folder?.name ?? page.folderName;
|
|
188
|
-
return (_jsxs("tr", { className: "hover:bg-gray-50
|
|
189
|
-
}) })] }) }) }), _jsx("div", { className: "
|
|
188
|
+
return (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", draggable: true, onDragStart: (e) => handleDragStart(e, page.id), children: [_jsx("td", { className: "px-3 py-2", children: _jsx("input", { type: "checkbox", checked: selectedPages.includes(page.id), onChange: () => handleSelectPage(page.id), className: "rounded border-gray-300" }) }), _jsx("td", { className: "cursor-grab px-1 py-2", children: _jsx(GripVertical, { className: "h-4 w-4 text-gray-300" }) }), _jsx("td", { className: "px-3 py-2", children: _jsx("button", { type: "button", onClick: () => onNavigate?.(`/pages/${page.id}`), className: "text-left text-sm font-medium text-gray-900 hover:text-blue-600", children: page.title }) }), _jsx("td", { className: "px-3 py-2", children: folderName ? (_jsx(FolderBadge, { name: folderName })) : (_jsx("span", { className: "text-xs text-gray-400", children: "\u2014" })) }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: page.author }), _jsx("td", { className: "px-3 py-2", children: _jsx(SeoScoreBadge, { score: seoScore }) }), _jsx("td", { className: "px-3 py-2", children: _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${page.status === 'Published' || page.status === 'PUBLISHED' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`, children: page.status }) }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: page.date }), _jsx("td", { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: () => onNavigate?.(`/pages/${page.id}`), className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Edit", children: _jsx(Pencil, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { type: "button", onClick: () => handleDelete(page.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Delete", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) })] }, page.id));
|
|
189
|
+
}) })] }) }) }), _jsx("div", { className: "flex-1 overflow-auto rounded-lg border border-gray-200 bg-white md:hidden", children: _jsx("div", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((page) => {
|
|
190
190
|
const seoScore = computeSeoScore(page.data);
|
|
191
191
|
const folderName = page.folder?.name ?? page.folderName;
|
|
192
|
-
return (_jsx("div", { className: "p-3", draggable: true, onDragStart: (e) => handleDragStart(e, page.id), children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("input", { type: "checkbox", checked: selectedPages.includes(page.id), onChange: () => handleSelectPage(page.id), className: "rounded border-gray-300
|
|
192
|
+
return (_jsx("div", { className: "p-3", draggable: true, onDragStart: (e) => handleDragStart(e, page.id), children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("input", { type: "checkbox", checked: selectedPages.includes(page.id), onChange: () => handleSelectPage(page.id), className: "mt-1 rounded border-gray-300" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("button", { type: "button", onClick: () => onNavigate?.(`/pages/${page.id}`), className: "mb-1 block text-left text-sm font-medium text-gray-900 hover:text-blue-600", children: page.title }), _jsxs("div", { className: "mb-2 flex flex-wrap items-center gap-2 text-xs text-gray-600", children: [folderName && _jsx(FolderBadge, { name: folderName }), _jsx("span", { children: page.author }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: page.date }), _jsx(SeoScoreBadge, { score: seoScore }), _jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${page.status === 'Published' || page.status === 'PUBLISHED' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`, children: page.status })] })] }), _jsx("button", { type: "button", onClick: () => handleDelete(page.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) }, page.id));
|
|
193
193
|
}) }) })] }))] })] })] }));
|
|
194
194
|
}
|
|
195
195
|
//# sourceMappingURL=Pages.js.map
|
package/dist/views/PostEditor.js
CHANGED
|
@@ -72,8 +72,8 @@ export function PostEditor({ id, onNavigate }) {
|
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
74
|
if (!isNew && loading) {
|
|
75
|
-
return (_jsx("div", { className: "h-full
|
|
75
|
+
return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
76
76
|
}
|
|
77
|
-
return (_jsxs("div", { className: "h-full flex
|
|
77
|
+
return (_jsxs("div", { className: "flex h-full flex-col bg-white", children: [error && (_jsxs("div", { className: "mx-4 mt-3 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error })] })), _jsx("div", { className: "border-b border-gray-200 px-3 py-3 sm:px-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("button", { onClick: () => onNavigate?.('/posts'), className: "inline-flex items-center gap-2 text-sm text-gray-600 transition-colors hover:text-gray-900", children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "Back to Posts" }), _jsx("span", { className: "sm:hidden", children: "Back" })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("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", children: [_jsx(Eye, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "Preview" })] }) })] }) }), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden lg:flex-row", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsxs("div", { className: "mx-auto max-w-4xl p-3 pr-6 sm:p-4 sm:pr-8", children: [_jsx("input", { type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Post title", 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" }), _jsxs("div", { className: "mb-4", children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-600", children: "URL Slug" }), _jsx("input", { type: "text", value: slug, onChange: (e) => setSlug(e.target.value), placeholder: "url-slug", 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" })] }), _jsx("div", { className: "mb-4", children: _jsx(TipTapEditor, { content: content, onChange: setContent }) })] }) }), _jsx("div", { className: "hidden w-[30%] overflow-y-auto border-l border-gray-200 bg-gray-50 lg:block", children: _jsxs("div", { className: "space-y-4 p-4", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-3 text-sm font-semibold text-gray-900", children: "Publish" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-700", children: "Status" }), _jsxs("select", { value: status, onChange: (e) => setStatus(e.target.value), 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", children: [_jsx("option", { value: "draft", children: "Draft" }), _jsx("option", { value: "published", children: "Published" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-700", children: "Publish Date" }), _jsx("input", { type: "datetime-local", 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" })] }), _jsx("button", { onClick: savePost, disabled: saving, 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", children: saving ? 'Saving...' : 'Save Post' }), status === 'draft' && (_jsx("button", { onClick: publishPost, disabled: saving, 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", children: saving ? 'Publishing...' : 'Publish' }))] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-3 text-sm font-semibold text-gray-900", children: "Categories & Tags" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-700", children: "Category" }), _jsxs("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", children: [_jsx("option", { children: "Technology" }), _jsx("option", { children: "Design" }), _jsx("option", { children: "Business" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-xs font-medium text-gray-700", children: "Tags" }), _jsx("input", { type: "text", placeholder: "Add tags...", 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" })] })] })] }), _jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4", children: [_jsx("h3", { className: "mb-3 text-sm font-semibold text-gray-900", children: "Featured Image" }), _jsx("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", children: "Upload Image" })] }), _jsx(SEOPanel, { title: title, slug: slug, content: content, seoData: seoData, onChange: setSeoData })] }) }), _jsx("div", { className: "border-t border-gray-200 bg-white p-3 lg:hidden", children: _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: savePost, disabled: saving, 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", children: saving ? 'Saving...' : 'Save Post' }), status === 'draft' && (_jsx("button", { onClick: publishPost, disabled: saving, 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", children: "Publish" }))] }) })] })] }));
|
|
78
78
|
}
|
|
79
79
|
//# sourceMappingURL=PostEditor.js.map
|
package/dist/views/Posts.js
CHANGED
|
@@ -62,12 +62,12 @@ export function Posts({ onNavigate }) {
|
|
|
62
62
|
};
|
|
63
63
|
function SortHeader({ label, sortKey }) {
|
|
64
64
|
const active = sortConfig?.key === sortKey;
|
|
65
|
-
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900
|
|
65
|
+
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900", children: [label, active ? (sortConfig.direction === 'asc' ? (_jsx(ArrowUp, { className: "h-3 w-3" })) : (_jsx(ArrowDown, { className: "h-3 w-3" }))) : (_jsx(ArrowUpDown, { className: "h-3 w-3 text-gray-400" }))] }));
|
|
66
66
|
}
|
|
67
67
|
if (loading) {
|
|
68
|
-
return (_jsx("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
68
|
+
return (_jsx("div", { className: "flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
69
69
|
}
|
|
70
|
-
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
71
|
-
filteredAndSorted.length > 0, onChange: (e) => handleSelectAll(e.target.checked), className: "rounded border-gray-300" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Title", sortKey: "title" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Author", sortKey: "author" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Category", sortKey: "category" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Status", sortKey: "status" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Date", sortKey: "date" }) }), _jsx("th", { className: "px-3 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((post) => (_jsxs("tr", { className: "hover:bg-gray-50
|
|
70
|
+
return (_jsxs("div", { className: "flex h-full flex-col p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center", children: [_jsxs("div", { children: [_jsx("h1", { className: "mb-1 text-xl font-semibold text-gray-900 sm:text-2xl", children: "Posts" }), _jsxs("p", { className: "text-sm text-gray-600", children: [filteredAndSorted.length, " total posts"] })] }), _jsxs("button", { onClick: () => onNavigate?.('/posts/new'), 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", children: [_jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "New Post" }), _jsx("span", { className: "sm:hidden", children: "New" })] })] }), _jsx("div", { className: "mb-4 rounded-lg border border-gray-200 bg-white", children: _jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx("input", { type: "text", placeholder: "Search posts...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), 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" })] }), _jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [_jsxs("select", { value: filterStatus, onChange: (e) => setFilterStatus(e.target.value), 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", children: [_jsx("option", { value: "all", children: "All Status" }), _jsx("option", { value: "published", children: "Published" }), _jsx("option", { value: "draft", children: "Draft" })] }), _jsxs("select", { value: filterCategory, onChange: (e) => setFilterCategory(e.target.value), 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", children: [_jsx("option", { value: "all", children: "All Categories" }), _jsx("option", { value: "technology", children: "Technology" }), _jsx("option", { value: "design", children: "Design" }), _jsx("option", { value: "business", children: "Business" })] }), _jsxs("button", { type: "button", 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", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), _jsx("span", { className: "hidden sm:inline", children: "More Filters" })] })] })] }) }), selectedPosts.length > 0 && (_jsx("div", { className: "mb-4 rounded-lg border border-blue-200 bg-blue-50 p-3", children: _jsxs("div", { className: "flex flex-col justify-between gap-2 sm:flex-row sm:items-center", children: [_jsxs("span", { className: "text-sm text-blue-900", children: [selectedPosts.length, " post", selectedPosts.length !== 1 ? 's' : '', " selected"] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: handleBulkDelete, 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", children: "Delete" }), _jsx("button", { type: "button", onClick: () => setSelectedPosts([]), 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", children: "Cancel" })] })] }) })), filteredAndSorted.length === 0 && !error ? (_jsxs("div", { className: "flex flex-1 flex-col items-center justify-center rounded-lg border border-gray-200 bg-white p-8 text-center", children: [_jsx("p", { className: "mb-2 text-sm text-gray-500", children: "No posts yet" }), _jsx("button", { onClick: () => onNavigate?.('/posts/new'), className: "rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700", children: "Create your first post" })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "hidden flex-1 overflow-hidden rounded-lg border border-gray-200 bg-white md:block", children: _jsx("div", { className: "h-full overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "sticky top-0 border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "w-8 px-3 py-2 text-left", children: _jsx("input", { type: "checkbox", checked: selectedPosts.length === filteredAndSorted.length &&
|
|
71
|
+
filteredAndSorted.length > 0, onChange: (e) => handleSelectAll(e.target.checked), className: "rounded border-gray-300" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Title", sortKey: "title" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Author", sortKey: "author" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Category", sortKey: "category" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Status", sortKey: "status" }) }), _jsx("th", { className: "px-3 py-2 text-left", children: _jsx(SortHeader, { label: "Date", sortKey: "date" }) }), _jsx("th", { className: "px-3 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((post) => (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", children: [_jsx("td", { className: "px-3 py-2", children: _jsx("input", { type: "checkbox", checked: selectedPosts.includes(post.id), onChange: () => handleSelectPost(post.id), className: "rounded border-gray-300" }) }), _jsx("td", { className: "px-3 py-2", children: _jsx("button", { type: "button", onClick: () => onNavigate?.(`/posts/${post.id}`), className: "text-left text-sm font-medium text-gray-900 hover:text-blue-600", children: post.title }) }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: post.author }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: post.category }), _jsx("td", { className: "px-3 py-2", children: _jsx("span", { 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'}`, children: post.status }) }), _jsx("td", { className: "px-3 py-2 text-sm text-gray-600", children: post.date }), _jsx("td", { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: () => onNavigate?.(`/posts/${post.id}`), className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Edit", children: _jsx(Pencil, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { type: "button", onClick: () => handleDelete(post.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", title: "Delete", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) })] }, post.id))) })] }) }) }), _jsx("div", { className: "flex-1 overflow-auto rounded-lg border border-gray-200 bg-white md:hidden", children: _jsx("div", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((post) => (_jsx("div", { className: "p-3", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("input", { type: "checkbox", checked: selectedPosts.includes(post.id), onChange: () => handleSelectPost(post.id), className: "mt-1 rounded border-gray-300" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("button", { type: "button", onClick: () => onNavigate?.(`/posts/${post.id}`), className: "mb-1 block text-left text-sm font-medium text-gray-900 hover:text-blue-600", children: post.title }), _jsxs("div", { className: "mb-2 flex flex-wrap items-center gap-2 text-xs text-gray-600", children: [_jsx("span", { children: post.author }), _jsx("span", { children: "\u2022" }), _jsx("span", { children: post.date }), _jsx("span", { 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'}`, children: post.status })] })] }), _jsx("button", { type: "button", onClick: () => handleDelete(post.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) }, post.id))) }) })] }))] }));
|
|
72
72
|
}
|
|
73
73
|
//# sourceMappingURL=Posts.js.map
|
package/dist/views/Redirects.js
CHANGED
|
@@ -77,15 +77,15 @@ export function Redirects({ onNavigate }) {
|
|
|
77
77
|
};
|
|
78
78
|
function SortHeader({ label, sortKey }) {
|
|
79
79
|
const active = sortConfig?.key === sortKey;
|
|
80
|
-
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 hover:text-gray-900
|
|
80
|
+
return (_jsxs("button", { type: "button", onClick: () => setSortConfig(toggleSort(sortConfig, sortKey)), className: "flex items-center gap-1 text-xs font-medium text-gray-700 transition-colors hover:text-gray-900", children: [label, active ? (sortConfig.direction === 'asc' ? (_jsx(ArrowUp, { className: "h-3 w-3" })) : (_jsx(ArrowDown, { className: "h-3 w-3" }))) : (_jsx(ArrowUpDown, { className: "h-3 w-3 text-gray-400" }))] }));
|
|
81
81
|
}
|
|
82
82
|
if (loading) {
|
|
83
|
-
return (_jsx("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8
|
|
83
|
+
return (_jsx("div", { className: "flex h-64 items-center justify-center p-3 pr-6 sm:p-4 sm:pr-8", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-blue-600" }) }));
|
|
84
84
|
}
|
|
85
|
-
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "
|
|
85
|
+
return (_jsxs("div", { className: "p-3 pr-6 sm:p-4 sm:pr-8", children: [error && (_jsxs("div", { className: "mb-4 flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-red-600" }), _jsx("span", { className: "flex-1 text-sm text-red-800", children: error }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100", children: "Retry" })] })), _jsxs("div", { className: "mb-4 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "mb-1 text-xl font-semibold text-gray-900 sm:text-2xl", children: "Redirects" }), _jsxs("p", { className: "text-sm text-gray-600", children: [filteredAndSorted.length, " total redirects"] })] }), _jsxs("button", { type: "button", onClick: () => setShowAddDialog(true), className: "flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700", children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Redirect"] })] }), _jsx("div", { className: "mb-4 rounded-lg border border-gray-200 bg-white", children: _jsxs("div", { className: "flex flex-col gap-3 p-3 sm:flex-row", children: [_jsxs("div", { className: "relative flex-1", children: [_jsx(Search, { className: "absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx("input", { type: "text", placeholder: "Search by source or destination URL...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), 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" })] }), _jsxs("select", { value: filterType, onChange: (e) => setFilterType(e.target.value), className: "rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none", children: [_jsx("option", { value: "all", children: "All Types" }), _jsx("option", { value: "301", children: "301 (Permanent)" }), _jsx("option", { value: "302", children: "302 (Temporary)" })] })] }) }), filteredAndSorted.length === 0 && !loading ? (_jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [_jsx("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-gray-100", children: _jsx(ArrowRightLeft, { className: "h-6 w-6 text-gray-400" }) }), _jsx("h3", { className: "mb-1 text-sm font-medium text-gray-900", children: "No redirects yet" }), _jsx("p", { className: "text-sm text-gray-500", children: "Add your first redirect to get started." })] })) : (_jsx("div", { className: "rounded-lg border border-gray-200 bg-white", children: _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full", children: [_jsx("thead", { className: "border-b border-gray-200 bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "px-4 py-2 text-left", children: _jsx(SortHeader, { label: "Source URL", sortKey: "from" }) }), _jsx("th", { className: "px-4 py-2 text-left", children: _jsx(SortHeader, { label: "Destination URL", sortKey: "to" }) }), _jsx("th", { className: "px-4 py-2 text-left", children: _jsx(SortHeader, { label: "Type", sortKey: "type" }) }), _jsx("th", { className: "px-4 py-2 text-left", children: _jsx(SortHeader, { label: "Hits", sortKey: "hits" }) }), _jsx("th", { className: "px-4 py-2 text-left", children: _jsx(SortHeader, { label: "Status", sortKey: "active" }) }), _jsx("th", { className: "px-4 py-2 text-left text-xs font-medium text-gray-700", children: "Actions" })] }) }), _jsx("tbody", { className: "divide-y divide-gray-200", children: filteredAndSorted.map((redirect) => (_jsxs("tr", { className: "transition-colors hover:bg-gray-50", children: [_jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-900", children: redirect.from }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("code", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-900", children: redirect.to }) }), _jsx("td", { className: "px-4 py-3", children: _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${redirect.type === '301'
|
|
86
86
|
? 'bg-blue-100 text-blue-800'
|
|
87
87
|
: 'bg-purple-100 text-purple-800'}`, children: redirect.type }) }), _jsx("td", { className: "px-4 py-3 text-sm text-gray-600", children: redirect.hits.toLocaleString() }), _jsx("td", { className: "px-4 py-3", children: _jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${redirect.active
|
|
88
88
|
? 'bg-green-100 text-green-800'
|
|
89
|
-
: 'bg-gray-100 text-gray-800'}`, children: redirect.active ? 'Active' : 'Inactive' }) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: () => onNavigate?.(`/redirects/${redirect.id}/edit`), className: "rounded p-1.5 transition-colors hover:bg-gray-100", "aria-label": "Edit redirect", children: _jsx(Pencil, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { type: "button", onClick: () => handleDelete(redirect.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", "aria-label": "Delete redirect", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) })] }, redirect.id))) })] }) }) })), _jsx(Dialog.Root, { open: showAddDialog, onOpenChange: setShowAddDialog, children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/50" }), _jsxs(Dialog.Content, { className: "fixed
|
|
89
|
+
: 'bg-gray-100 text-gray-800'}`, children: redirect.active ? 'Active' : 'Inactive' }) }), _jsx("td", { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { type: "button", onClick: () => onNavigate?.(`/redirects/${redirect.id}/edit`), className: "rounded p-1.5 transition-colors hover:bg-gray-100", "aria-label": "Edit redirect", children: _jsx(Pencil, { className: "h-4 w-4 text-gray-600" }) }), _jsx("button", { type: "button", onClick: () => handleDelete(redirect.id), className: "rounded p-1.5 transition-colors hover:bg-gray-100", "aria-label": "Delete redirect", children: _jsx(Trash2, { className: "h-4 w-4 text-red-600" }) })] }) })] }, redirect.id))) })] }) }) })), _jsx(Dialog.Root, { open: showAddDialog, onOpenChange: setShowAddDialog, children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 z-50 bg-black/50" }), _jsxs(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", children: [_jsx(Dialog.Title, { className: "mb-4 text-lg font-semibold text-gray-900", children: "Add Redirect" }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Source URL" }), _jsx("input", { type: "text", value: newRedirect.source, onChange: (e) => setNewRedirect({ ...newRedirect, source: e.target.value }), placeholder: "/old-page", 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", required: true })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Destination URL" }), _jsx("input", { type: "text", value: newRedirect.destination, onChange: (e) => setNewRedirect({ ...newRedirect, destination: e.target.value }), placeholder: "/new-page", 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", required: true })] }), _jsxs("div", { children: [_jsx("label", { className: "mb-1 block text-sm font-medium text-gray-700", children: "Redirect Type" }), _jsxs("select", { value: newRedirect.type, onChange: (e) => setNewRedirect({ ...newRedirect, type: e.target.value }), 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", children: [_jsx("option", { value: "301", children: "301 (Permanent)" }), _jsx("option", { value: "302", children: "302 (Temporary)" })] })] }), _jsxs("div", { className: "flex items-center justify-end gap-3 pt-4", children: [_jsx(Dialog.Close, { asChild: true, children: _jsx("button", { type: "button", className: "rounded-lg border border-gray-300 px-4 py-2 text-sm transition-colors hover:bg-gray-50", children: "Cancel" }) }), _jsx("button", { type: "submit", className: "rounded-lg bg-blue-600 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-700", children: "Add Redirect" })] })] })] })] }) })] }));
|
|
90
90
|
}
|
|
91
91
|
//# sourceMappingURL=Redirects.js.map
|