@jhits/plugin-blog 0.0.19 → 0.0.20
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/api/categories.d.ts.map +1 -1
- package/dist/api/categories.js +42 -38
- package/dist/api/handler.d.ts +1 -26
- package/dist/api/handler.d.ts.map +1 -1
- package/dist/api/handler.js +81 -490
- package/dist/api/router.d.ts +0 -5
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +8 -35
- package/dist/api/service.d.ts +80 -0
- package/dist/api/service.d.ts.map +1 -0
- package/dist/api/service.js +219 -0
- package/dist/hooks/useAutoSave.d.ts +10 -0
- package/dist/hooks/useAutoSave.d.ts.map +1 -0
- package/dist/hooks/useAutoSave.js +57 -0
- package/dist/hooks/useCategories.d.ts +1 -1
- package/dist/hooks/useCategories.d.ts.map +1 -1
- package/dist/hooks/useCategories.js +15 -46
- package/dist/index.d.ts +24 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -201
- package/dist/init.d.ts +20 -7
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +8 -7
- package/dist/lib/blocks/BlockRenderer.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/ColumnsBlock.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/ColumnsBlock.js +30 -113
- package/dist/lib/layouts/blocks/SectionBlock.d.ts.map +1 -1
- package/dist/lib/layouts/blocks/SectionBlock.js +9 -21
- package/dist/lib/layouts/index.d.ts +3 -3
- package/dist/lib/layouts/index.js +4 -4
- package/dist/lib/mappers/apiMapper.d.ts +10 -0
- package/dist/lib/mappers/apiMapper.d.ts.map +1 -1
- package/dist/lib/mappers/apiMapper.js +47 -32
- package/dist/lib/rich-text/RichTextEditor.d.ts +4 -2
- package/dist/lib/rich-text/RichTextEditor.d.ts.map +1 -1
- package/dist/lib/rich-text/RichTextEditor.js +12 -9
- package/dist/lib/utils/config-resolver.d.ts +28 -0
- package/dist/lib/utils/config-resolver.d.ts.map +1 -0
- package/dist/lib/utils/config-resolver.js +46 -0
- package/dist/lib/utils/tree.d.ts +29 -0
- package/dist/lib/utils/tree.d.ts.map +1 -0
- package/dist/lib/utils/tree.js +129 -0
- package/dist/state/EditorContext.d.ts +3 -25
- package/dist/state/EditorContext.d.ts.map +1 -1
- package/dist/state/EditorContext.js +124 -174
- package/dist/state/reducer.d.ts +1 -5
- package/dist/state/reducer.d.ts.map +1 -1
- package/dist/state/reducer.js +128 -521
- package/dist/state/types.d.ts +12 -1
- package/dist/state/types.d.ts.map +1 -1
- package/dist/types/block.d.ts +9 -0
- package/dist/types/block.d.ts.map +1 -1
- package/dist/types/post.d.ts +17 -1
- package/dist/types/post.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.d.ts +5 -6
- package/dist/views/CanvasEditor/BlockWrapper.d.ts.map +1 -1
- package/dist/views/CanvasEditor/BlockWrapper.js +56 -264
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts +5 -3
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -1
- package/dist/views/CanvasEditor/CanvasEditorView.js +55 -315
- package/dist/views/CanvasEditor/EditorBody.d.ts +6 -8
- package/dist/views/CanvasEditor/EditorBody.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorBody.js +34 -482
- package/dist/views/CanvasEditor/EditorHeader.d.ts.map +1 -1
- package/dist/views/CanvasEditor/EditorHeader.js +27 -63
- package/dist/views/CanvasEditor/LayoutContainer.d.ts.map +1 -1
- package/dist/views/CanvasEditor/LayoutContainer.js +49 -70
- package/dist/views/CanvasEditor/components/CustomBlockItem.js +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts +15 -3
- package/dist/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorCanvas.js +40 -18
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts +5 -1
- package/dist/views/CanvasEditor/components/EditorLibrary.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorLibrary.js +11 -7
- package/dist/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/EditorSidebar.js +32 -14
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -6
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/FeaturedMediaSection.js +17 -128
- package/dist/views/CanvasEditor/components/JSONInspector.d.ts +9 -0
- package/dist/views/CanvasEditor/components/JSONInspector.d.ts.map +1 -0
- package/dist/views/CanvasEditor/components/JSONInspector.js +56 -0
- package/dist/views/CanvasEditor/components/LibraryItem.js +2 -2
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -4
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/PrivacySettingsSection.js +6 -28
- package/dist/views/CanvasEditor/components/index.d.ts +2 -0
- package/dist/views/CanvasEditor/components/index.d.ts.map +1 -1
- package/dist/views/CanvasEditor/components/index.js +1 -0
- package/dist/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/useHeroBlock.js +15 -18
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts +3 -0
- package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts.map +1 -1
- package/dist/views/CanvasEditor/hooks/usePostLoader.js +12 -13
- package/dist/views/CanvasEditor/hooks/useUnsavedChanges.js +0 -4
- package/dist/views/PostManager/EmptyState.d.ts +1 -1
- package/dist/views/PostManager/EmptyState.js +4 -4
- package/dist/views/PostManager/FilterDropdown.d.ts +21 -0
- package/dist/views/PostManager/FilterDropdown.d.ts.map +1 -0
- package/dist/views/PostManager/FilterDropdown.js +28 -0
- package/dist/views/PostManager/LanguageFlags.d.ts.map +1 -1
- package/dist/views/PostManager/LanguageFlags.js +4 -1
- package/dist/views/PostManager/PostCards.d.ts.map +1 -1
- package/dist/views/PostManager/PostCards.js +23 -40
- package/dist/views/PostManager/PostFilters.d.ts.map +1 -1
- package/dist/views/PostManager/PostFilters.js +34 -3
- package/dist/views/PostManager/PostManagerView.d.ts +1 -2
- package/dist/views/PostManager/PostManagerView.d.ts.map +1 -1
- package/dist/views/PostManager/PostManagerView.js +30 -96
- package/dist/views/PostManager/PostStats.d.ts.map +1 -1
- package/dist/views/PostManager/PostStats.js +10 -10
- package/dist/views/PostManager/PostTable.d.ts.map +1 -1
- package/dist/views/PostManager/PostTable.js +23 -40
- package/dist/views/Settings/SettingsView.d.ts +1 -1
- package/dist/views/Settings/SettingsView.d.ts.map +1 -1
- package/dist/views/Settings/SettingsView.js +12 -39
- package/dist/views/SlugSEO/SlugSEOManagerView.d.ts.map +1 -1
- package/dist/views/SlugSEO/SlugSEOManagerView.js +2 -2
- package/package.json +42 -6
- package/src/api/categories.ts +48 -52
- package/src/api/handler.ts +87 -594
- package/src/api/router.ts +15 -65
- package/src/api/service.ts +241 -0
- package/src/hooks/useAutoSave.ts +64 -0
- package/src/hooks/useCategories.ts +19 -47
- package/src/index.tsx +79 -293
- package/src/init.tsx +24 -11
- package/src/lib/blocks/BlockRenderer.tsx +1 -0
- package/src/lib/layouts/blocks/ColumnsBlock.tsx +60 -173
- package/src/lib/layouts/blocks/SectionBlock.tsx +22 -26
- package/src/lib/layouts/index.ts +4 -4
- package/src/lib/mappers/apiMapper.ts +63 -32
- package/src/lib/rich-text/RichTextEditor.tsx +16 -9
- package/src/lib/utils/config-resolver.ts +64 -0
- package/src/lib/utils/tree.ts +150 -0
- package/src/state/EditorContext.tsx +153 -232
- package/src/state/reducer.ts +141 -606
- package/src/state/types.ts +14 -1
- package/src/types/block.ts +10 -0
- package/src/types/post.ts +19 -1
- package/src/views/CanvasEditor/BlockWrapper.tsx +130 -460
- package/src/views/CanvasEditor/CanvasEditorView.tsx +145 -420
- package/src/views/CanvasEditor/EditorBody.tsx +98 -610
- package/src/views/CanvasEditor/EditorHeader.tsx +176 -196
- package/src/views/CanvasEditor/LayoutContainer.tsx +74 -89
- package/src/views/CanvasEditor/components/CustomBlockItem.tsx +7 -8
- package/src/views/CanvasEditor/components/EditorCanvas.tsx +139 -84
- package/src/views/CanvasEditor/components/EditorLibrary.tsx +25 -10
- package/src/views/CanvasEditor/components/EditorSidebar.tsx +196 -127
- package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +78 -210
- package/src/views/CanvasEditor/components/JSONInspector.tsx +125 -0
- package/src/views/CanvasEditor/components/LibraryItem.tsx +5 -6
- package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +73 -124
- package/src/views/CanvasEditor/components/index.ts +2 -1
- package/src/views/CanvasEditor/hooks/useHeroBlock.ts +15 -18
- package/src/views/CanvasEditor/hooks/usePostLoader.ts +21 -13
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.ts +4 -4
- package/src/views/PostManager/EmptyState.tsx +9 -10
- package/src/views/PostManager/FilterDropdown.tsx +95 -0
- package/src/views/PostManager/LanguageFlags.tsx +6 -2
- package/src/views/PostManager/PostCards.tsx +127 -133
- package/src/views/PostManager/PostFilters.tsx +73 -68
- package/src/views/PostManager/PostManagerView.tsx +132 -179
- package/src/views/PostManager/PostStats.tsx +21 -20
- package/src/views/PostManager/PostTable.tsx +137 -165
- package/src/views/Settings/SettingsView.tsx +64 -180
- package/src/views/SlugSEO/SlugSEOManagerView.tsx +59 -44
- package/src/hooks/index.d.ts +0 -8
- package/src/hooks/index.d.ts.map +0 -1
- package/src/hooks/useBlog.d.ts +0 -31
- package/src/hooks/useBlog.d.ts.map +0 -1
- package/src/hooks/useBlogs.d.ts +0 -39
- package/src/hooks/useBlogs.d.ts.map +0 -1
- package/src/hooks/useCategories.d.ts +0 -9
- package/src/hooks/useCategories.d.ts.map +0 -1
- package/src/lib/blocks/BlockRenderer.d.ts +0 -54
- package/src/lib/blocks/BlockRenderer.d.ts.map +0 -1
- package/src/lib/config-storage.d.ts +0 -30
- package/src/lib/config-storage.d.ts.map +0 -1
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/ColumnsBlock.d.ts.map +0 -1
- package/src/lib/layouts/blocks/SectionBlock.d.ts +0 -25
- package/src/lib/layouts/blocks/SectionBlock.d.ts.map +0 -1
- package/src/lib/layouts/index.d.ts +0 -23
- package/src/lib/layouts/index.d.ts.map +0 -1
- package/src/lib/layouts/registerLayoutBlocks.d.ts +0 -9
- package/src/lib/layouts/registerLayoutBlocks.d.ts.map +0 -1
- package/src/lib/mappers/apiMapper.d.ts +0 -66
- package/src/lib/mappers/apiMapper.d.ts.map +0 -1
- package/src/lib/rich-text/RichTextEditor.d.ts +0 -45
- package/src/lib/rich-text/RichTextEditor.d.ts.map +0 -1
- package/src/lib/rich-text/RichTextPreview.d.ts +0 -16
- package/src/lib/rich-text/RichTextPreview.d.ts.map +0 -1
- package/src/lib/rich-text/index.d.ts +0 -9
- package/src/lib/rich-text/index.d.ts.map +0 -1
- package/src/lib/utils/blockHelpers.d.ts +0 -23
- package/src/lib/utils/blockHelpers.d.ts.map +0 -1
- package/src/lib/utils/configValidation.d.ts +0 -23
- package/src/lib/utils/configValidation.d.ts.map +0 -1
- package/src/registry/BlockRegistry.d.ts +0 -62
- package/src/registry/BlockRegistry.d.ts.map +0 -1
- package/src/registry/index.d.ts +0 -6
- package/src/registry/index.d.ts.map +0 -1
- package/src/state/EditorContext.d.ts +0 -45
- package/src/state/EditorContext.d.ts.map +0 -1
- package/src/state/index.d.ts +0 -7
- package/src/state/index.d.ts.map +0 -1
- package/src/state/reducer.d.ts +0 -11
- package/src/state/reducer.d.ts.map +0 -1
- package/src/state/types.d.ts +0 -162
- package/src/state/types.d.ts.map +0 -1
- package/src/types/block.d.ts +0 -221
- package/src/types/block.d.ts.map +0 -1
- package/src/types/index.d.ts +0 -8
- package/src/types/index.d.ts.map +0 -1
- package/src/types/post.d.ts +0 -136
- package/src/types/post.d.ts.map +0 -1
- package/src/utils/client.d.ts +0 -48
- package/src/utils/client.d.ts.map +0 -1
- package/src/views/CanvasEditor/BlockWrapper.d.ts +0 -16
- package/src/views/CanvasEditor/BlockWrapper.d.ts.map +0 -1
- package/src/views/CanvasEditor/CanvasEditorView.d.ts +0 -14
- package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorBody.d.ts +0 -22
- package/src/views/CanvasEditor/EditorBody.d.ts.map +0 -1
- package/src/views/CanvasEditor/EditorHeader.d.ts +0 -18
- package/src/views/CanvasEditor/EditorHeader.d.ts.map +0 -1
- package/src/views/CanvasEditor/LayoutContainer.d.ts +0 -17
- package/src/views/CanvasEditor/LayoutContainer.d.ts.map +0 -1
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +0 -13
- package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts +0 -14
- package/src/views/CanvasEditor/components/CustomBlockItem.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts +0 -29
- package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts +0 -7
- package/src/views/CanvasEditor/components/EditorLibrary.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts +0 -13
- package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts +0 -6
- package/src/views/CanvasEditor/components/ErrorBanner.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -25
- package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/LibraryItem.d.ts +0 -14
- package/src/views/CanvasEditor/components/LibraryItem.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -15
- package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +0 -1
- package/src/views/CanvasEditor/components/index.d.ts +0 -21
- package/src/views/CanvasEditor/components/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/index.d.ts +0 -10
- package/src/views/CanvasEditor/hooks/index.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts +0 -8
- package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +0 -3
- package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts +0 -5
- package/src/views/CanvasEditor/hooks/usePostLoader.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +0 -2
- package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +0 -1
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +0 -25
- package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +0 -1
- package/src/views/CanvasEditor/index.d.ts +0 -16
- package/src/views/CanvasEditor/index.d.ts.map +0 -1
- package/src/views/PostManager/EmptyState.d.ts +0 -10
- package/src/views/PostManager/EmptyState.d.ts.map +0 -1
- package/src/views/PostManager/PostActionsMenu.d.ts +0 -12
- package/src/views/PostManager/PostActionsMenu.d.ts.map +0 -1
- package/src/views/PostManager/PostCards.d.ts +0 -15
- package/src/views/PostManager/PostCards.d.ts.map +0 -1
- package/src/views/PostManager/PostFilters.d.ts +0 -16
- package/src/views/PostManager/PostFilters.d.ts.map +0 -1
- package/src/views/PostManager/PostManagerView.d.ts +0 -11
- package/src/views/PostManager/PostManagerView.d.ts.map +0 -1
- package/src/views/PostManager/PostStats.d.ts +0 -11
- package/src/views/PostManager/PostStats.d.ts.map +0 -1
- package/src/views/PostManager/PostTable.d.ts +0 -15
- package/src/views/PostManager/PostTable.d.ts.map +0 -1
- package/src/views/PostManager/index.d.ts +0 -12
- package/src/views/PostManager/index.d.ts.map +0 -1
- package/src/views/Preview/PreviewBridgeView.d.ts +0 -12
- package/src/views/Preview/PreviewBridgeView.d.ts.map +0 -1
- package/src/views/Preview/index.d.ts +0 -6
- package/src/views/Preview/index.d.ts.map +0 -1
- package/src/views/Settings/SettingsView.d.ts +0 -10
- package/src/views/Settings/SettingsView.d.ts.map +0 -1
- package/src/views/Settings/index.d.ts +0 -6
- package/src/views/Settings/index.d.ts.map +0 -1
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts +0 -12
- package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +0 -1
- package/src/views/SlugSEO/index.d.ts +0 -6
- package/src/views/SlugSEO/index.d.ts.map +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { Globe, Search, Box } from 'lucide-react';
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { Globe, Search, Box, Hash, X, Shield, Key, Users, Layout, Type, Image as ImageIcon } from 'lucide-react';
|
|
5
5
|
import { FeaturedMediaSection, PrivacySettingsSection } from './index';
|
|
6
|
+
import { useEditor } from '../../../state/EditorContext';
|
|
7
|
+
import { useCategories } from '../../../hooks/useCategories';
|
|
6
8
|
import type { Block } from '../../../types/block';
|
|
7
9
|
import type { PostMetadata, SEOMetadata } from '../../../types/post';
|
|
8
10
|
|
|
@@ -25,157 +27,224 @@ export function EditorSidebar({
|
|
|
25
27
|
onSEOUpdate,
|
|
26
28
|
onMetadataUpdate,
|
|
27
29
|
}: EditorSidebarProps) {
|
|
30
|
+
const [newTag, setNewTag] = useState('');
|
|
31
|
+
const { state } = useEditor();
|
|
32
|
+
const { categories: existingCategories } = useCategories(state.currentLanguage || undefined);
|
|
33
|
+
|
|
34
|
+
const handleTagAdd = (e: React.KeyboardEvent) => {
|
|
35
|
+
if (e.key === 'Enter' && newTag.trim()) {
|
|
36
|
+
const tag = newTag.trim();
|
|
37
|
+
if (!metadata.tags?.includes(tag)) {
|
|
38
|
+
onMetadataUpdate({
|
|
39
|
+
tags: [...(metadata.tags || []), tag]
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
setNewTag('');
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleTagRemove = (tagToRemove: string) => {
|
|
47
|
+
onMetadataUpdate({
|
|
48
|
+
tags: (metadata.tags || []).filter(t => t !== tagToRemove)
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
|
|
28
52
|
return (
|
|
29
|
-
<div className="p-8 w-
|
|
30
|
-
{/*
|
|
31
|
-
<section>
|
|
32
|
-
<div className="
|
|
33
|
-
<
|
|
34
|
-
<label className="text-[10px] uppercase tracking-[0.2em] text-neutral-500 dark:text-neutral-400 font-black">
|
|
35
|
-
SEO Settings
|
|
36
|
-
</label>
|
|
53
|
+
<div className="p-8 w-96 min-w-0 max-w-full space-y-10 overflow-y-auto max-h-full custom-scrollbar">
|
|
54
|
+
{/* 1. PUBLISHING STATUS SECTION */}
|
|
55
|
+
<section className="p-6 bg-primary/5 border border-primary/20 rounded-[2rem] relative overflow-hidden">
|
|
56
|
+
<div className="absolute top-0 right-0 p-4 opacity-10">
|
|
57
|
+
<Globe size={60} className="text-primary" />
|
|
37
58
|
</div>
|
|
38
|
-
<div className="
|
|
39
|
-
<div>
|
|
40
|
-
<label className="text-[10px]
|
|
41
|
-
|
|
59
|
+
<div className="relative z-10">
|
|
60
|
+
<div className="flex items-center justify-between mb-4">
|
|
61
|
+
<label className="text-[10px] font-black text-primary uppercase tracking-[0.3em]">
|
|
62
|
+
Publication Status
|
|
42
63
|
</label>
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
</p>
|
|
64
|
+
<span className={`px-3 py-1 rounded-full text-[9px] font-black uppercase tracking-widest border shadow-sm ${
|
|
65
|
+
status === 'published'
|
|
66
|
+
? 'bg-emerald-500 text-white border-emerald-400'
|
|
67
|
+
: status === 'not-translated'
|
|
68
|
+
? 'bg-blue-500 text-white border-blue-400'
|
|
69
|
+
: 'bg-amber-500 text-white border-amber-400'
|
|
70
|
+
}`}>
|
|
71
|
+
{status === 'not-translated' ? 'Not Translated' : status}
|
|
72
|
+
</span>
|
|
53
73
|
</div>
|
|
54
|
-
<div>
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
<div className="space-y-4">
|
|
75
|
+
<div className="bg-dashboard-card/50 p-4 rounded-2xl border border-dashboard-border/50">
|
|
76
|
+
<span className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] block mb-2">Live Endpoint</span>
|
|
77
|
+
<div className="text-[11px] font-mono text-dashboard-text leading-relaxed break-all bg-white/5 p-2 rounded-lg border border-white/5">
|
|
78
|
+
/blog/<span className="text-primary font-bold">{slug || 'untitled-publication'}</span>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
<p className="text-[10px] text-dashboard-text-secondary leading-relaxed italic opacity-70">
|
|
82
|
+
{status === 'published'
|
|
83
|
+
? 'This publication is live across all connected digital touchpoints.'
|
|
84
|
+
: status === 'not-translated'
|
|
85
|
+
? 'This language edition has not been created yet. Save it as a draft to begin.'
|
|
86
|
+
: 'Your article is currently private. Only editorial staff can view and modify it.'}
|
|
67
87
|
</p>
|
|
68
88
|
</div>
|
|
69
|
-
<div>
|
|
70
|
-
<label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
|
|
71
|
-
Keywords (comma-separated)
|
|
72
|
-
</label>
|
|
73
|
-
<input
|
|
74
|
-
type="text"
|
|
75
|
-
value={seo.keywords?.join(', ') || ''}
|
|
76
|
-
onChange={(e) => {
|
|
77
|
-
const keywords = e.target.value.split(',').map(k => k.trim()).filter(k => k);
|
|
78
|
-
onSEOUpdate({ keywords });
|
|
79
|
-
}}
|
|
80
|
-
placeholder="keyword1, keyword2, keyword3"
|
|
81
|
-
className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
<div>
|
|
85
|
-
<label className="text-[10px] text-neutral-500 dark:text-neutral-400 uppercase font-bold block mb-2">
|
|
86
|
-
Open Graph Image URL
|
|
87
|
-
</label>
|
|
88
|
-
<input
|
|
89
|
-
type="url"
|
|
90
|
-
value={seo.ogImage || ''}
|
|
91
|
-
onChange={(e) => onSEOUpdate({ ogImage: e.target.value })}
|
|
92
|
-
placeholder="https://example.com/image.jpg"
|
|
93
|
-
className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
|
|
94
|
-
/>
|
|
95
|
-
</div>
|
|
96
89
|
</div>
|
|
97
90
|
</section>
|
|
98
91
|
|
|
99
|
-
{/*
|
|
100
|
-
<section className="
|
|
101
|
-
<div className="flex items-center gap-3
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
{/* 2. CLASSIFICATION SECTION */}
|
|
93
|
+
<section className="space-y-6">
|
|
94
|
+
<div className="flex items-center gap-3">
|
|
95
|
+
<div className="size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
|
|
96
|
+
<Box size={14} />
|
|
97
|
+
</div>
|
|
98
|
+
<label className="text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]">
|
|
99
|
+
Classification
|
|
105
100
|
</label>
|
|
106
101
|
</div>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<div className="
|
|
110
|
-
|
|
102
|
+
|
|
103
|
+
<div className="space-y-4 p-6 bg-dashboard-card/30 rounded-[2rem] border border-dashboard-border/50">
|
|
104
|
+
<div className="group">
|
|
105
|
+
<label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
|
|
106
|
+
Primary Category
|
|
107
|
+
</label>
|
|
108
|
+
<div className="relative">
|
|
109
|
+
<Layout size={12} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-dashboard-text-secondary group-focus-within:text-primary transition-colors" />
|
|
110
|
+
<input
|
|
111
|
+
type="text"
|
|
112
|
+
list="category-suggestions"
|
|
113
|
+
value={metadata.categories?.[0] || ''}
|
|
114
|
+
onChange={(e) => onMetadataUpdate({ categories: e.target.value.trim() ? [e.target.value.trim()] : [] })}
|
|
115
|
+
placeholder="e.g. Technology, Lifestyle"
|
|
116
|
+
className="w-full pl-10 pr-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
|
|
117
|
+
/>
|
|
118
|
+
<datalist id="category-suggestions">
|
|
119
|
+
{existingCategories.map(cat => (
|
|
120
|
+
<option key={cat} value={cat} />
|
|
121
|
+
))}
|
|
122
|
+
</datalist>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div className="group">
|
|
127
|
+
<label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
|
|
128
|
+
Article Tags
|
|
129
|
+
</label>
|
|
130
|
+
<div className="flex flex-wrap gap-2 mb-3">
|
|
131
|
+
{metadata.tags?.map((tag) => (
|
|
132
|
+
<span
|
|
133
|
+
key={tag}
|
|
134
|
+
className="inline-flex items-center gap-2 px-3 py-1.5 bg-primary/10 border border-primary/20 rounded-full text-[9px] font-black text-primary uppercase tracking-widest group/tag hover:bg-primary/20 transition-all"
|
|
135
|
+
>
|
|
136
|
+
{tag}
|
|
137
|
+
<button
|
|
138
|
+
onClick={() => handleTagRemove(tag)}
|
|
139
|
+
className="text-primary/40 hover:text-primary transition-colors"
|
|
140
|
+
>
|
|
141
|
+
<X size={10} strokeWidth={3} />
|
|
142
|
+
</button>
|
|
143
|
+
</span>
|
|
144
|
+
))}
|
|
145
|
+
</div>
|
|
146
|
+
<div className="relative">
|
|
147
|
+
<Hash size={12} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-dashboard-text-secondary group-focus-within:text-primary transition-colors" />
|
|
148
|
+
<input
|
|
149
|
+
type="text"
|
|
150
|
+
value={newTag}
|
|
151
|
+
onChange={(e) => setNewTag(e.target.value)}
|
|
152
|
+
onKeyDown={handleTagAdd}
|
|
153
|
+
placeholder="Add tag + Enter"
|
|
154
|
+
className="w-full pl-10 pr-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
111
157
|
</div>
|
|
112
158
|
</div>
|
|
113
159
|
</section>
|
|
114
160
|
|
|
115
|
-
{/*
|
|
116
|
-
<
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
161
|
+
{/* 3. FEATURED MEDIA */}
|
|
162
|
+
<div className="p-6 bg-dashboard-card/30 rounded-[2rem] border border-dashboard-border/50">
|
|
163
|
+
<FeaturedMediaSection
|
|
164
|
+
featuredImage={metadata.featuredImage}
|
|
165
|
+
heroBlock={heroBlock}
|
|
166
|
+
slug={slug}
|
|
167
|
+
onUpdate={(image) => onMetadataUpdate({ featuredImage: image })}
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{/* 4. SEO OPTIMIZATION */}
|
|
172
|
+
<section className="space-y-6">
|
|
173
|
+
<div className="flex items-center gap-3">
|
|
174
|
+
<div className="size-8 rounded-xl bg-primary/10 flex items-center justify-center text-primary border border-primary/20">
|
|
175
|
+
<Search size={14} />
|
|
176
|
+
</div>
|
|
177
|
+
<label className="text-[10px] font-black text-dashboard-text uppercase tracking-[0.3em]">
|
|
178
|
+
SEO & Meta
|
|
121
179
|
</label>
|
|
122
180
|
</div>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
181
|
+
|
|
182
|
+
<div className="space-y-5 p-6 bg-dashboard-card/30 rounded-[2.5rem] border border-dashboard-border/50">
|
|
183
|
+
<div className="group">
|
|
184
|
+
<label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
|
|
185
|
+
Search Engine Title
|
|
127
186
|
</label>
|
|
128
187
|
<input
|
|
129
188
|
type="text"
|
|
130
|
-
value={
|
|
131
|
-
onChange={(e) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
categories: category ? [category] : []
|
|
135
|
-
});
|
|
136
|
-
}}
|
|
137
|
-
placeholder="Enter category (required for publishing)"
|
|
138
|
-
className="w-full px-3 py-2 text-xs bg-dashboard-card border border-dashboard-border rounded-lg outline-none focus:border-primary transition-all text-dashboard-text"
|
|
189
|
+
value={seo.title || ''}
|
|
190
|
+
onChange={(e) => onSEOUpdate({ title: e.target.value })}
|
|
191
|
+
placeholder="Defaults to article title"
|
|
192
|
+
className="w-full px-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
|
|
139
193
|
/>
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
194
|
+
<div className="flex justify-between mt-1.5 px-1">
|
|
195
|
+
<p className="text-[8px] font-black text-dashboard-text-secondary uppercase opacity-40">Optimized: 60 chars</p>
|
|
196
|
+
<p className={`text-[9px] font-mono ${ (seo.title?.length || 0) > 60 ? 'text-red-500' : 'text-primary'}`}>
|
|
197
|
+
{seo.title?.length || 0}/60
|
|
198
|
+
</p>
|
|
199
|
+
</div>
|
|
143
200
|
</div>
|
|
144
|
-
</div>
|
|
145
|
-
</section>
|
|
146
201
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
202
|
+
<div className="group">
|
|
203
|
+
<label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
|
|
204
|
+
Meta Description
|
|
205
|
+
</label>
|
|
206
|
+
<textarea
|
|
207
|
+
value={seo.description || ''}
|
|
208
|
+
onChange={(e) => onSEOUpdate({ description: e.target.value })}
|
|
209
|
+
placeholder="Write a compelling summary..."
|
|
210
|
+
rows={4}
|
|
211
|
+
className="w-full px-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all resize-none"
|
|
212
|
+
/>
|
|
213
|
+
<div className="flex justify-between mt-1.5 px-1">
|
|
214
|
+
<p className="text-[8px] font-black text-dashboard-text-secondary uppercase opacity-40">Recommended: 160 chars</p>
|
|
215
|
+
<p className={`text-[9px] font-mono ${ (seo.description?.length || 0) > 160 ? 'text-red-500' : 'text-primary'}`}>
|
|
216
|
+
{seo.description?.length || 0}/160
|
|
217
|
+
</p>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
160
220
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
221
|
+
<div className="group">
|
|
222
|
+
<label className="text-[9px] font-black text-dashboard-text-secondary uppercase tracking-[0.2em] mb-2 block px-1 group-focus-within:text-primary transition-colors">
|
|
223
|
+
Social Media Asset (OG Image)
|
|
224
|
+
</label>
|
|
225
|
+
<div className="relative">
|
|
226
|
+
<ImageIcon size={12} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-dashboard-text-secondary group-focus-within:text-primary transition-colors" />
|
|
227
|
+
<input
|
|
228
|
+
type="url"
|
|
229
|
+
value={seo.ogImage || ''}
|
|
230
|
+
onChange={(e) => onSEOUpdate({ ogImage: e.target.value })}
|
|
231
|
+
placeholder="https://..."
|
|
232
|
+
className="w-full pl-10 pr-4 py-3 bg-dashboard-bg/50 border border-dashboard-border/50 rounded-xl text-xs font-bold text-dashboard-text placeholder:text-dashboard-text-secondary/30 outline-none focus:border-primary/40 focus:bg-primary/[0.02] transition-all"
|
|
233
|
+
/>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
170
236
|
</div>
|
|
171
|
-
<p className="text-[11px] text-neutral-500 dark:text-neutral-400 leading-relaxed italic">
|
|
172
|
-
{status === 'draft'
|
|
173
|
-
? 'This post is private. Only you can see it until you hit publish.'
|
|
174
|
-
: status === 'published'
|
|
175
|
-
? 'This post is live and visible to everyone.'
|
|
176
|
-
: 'This post is scheduled for publication.'}
|
|
177
|
-
</p>
|
|
178
237
|
</section>
|
|
238
|
+
|
|
239
|
+
{/* 5. PRIVACY & SECURITY */}
|
|
240
|
+
<div className="p-6 bg-dashboard-card/30 rounded-[2.5rem] border border-dashboard-border/50">
|
|
241
|
+
<PrivacySettingsSection
|
|
242
|
+
privacy={metadata.privacy}
|
|
243
|
+
onUpdate={(privacy) => onMetadataUpdate({ privacy })}
|
|
244
|
+
/>
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
<div className="pb-10" />
|
|
179
248
|
</div>
|
|
180
249
|
);
|
|
181
250
|
}
|