@jhits/plugin-blog 0.0.1
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/README.md +216 -0
- package/package.json +57 -0
- package/src/api/README.md +224 -0
- package/src/api/categories.ts +43 -0
- package/src/api/check-title.ts +60 -0
- package/src/api/handler.ts +419 -0
- package/src/api/index.ts +33 -0
- package/src/api/route.ts +116 -0
- package/src/api/router.ts +114 -0
- package/src/api-server.ts +11 -0
- package/src/config.ts +161 -0
- package/src/hooks/README.md +91 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/useBlog.ts +85 -0
- package/src/hooks/useBlogs.ts +123 -0
- package/src/index.server.ts +12 -0
- package/src/index.tsx +354 -0
- package/src/init.tsx +72 -0
- package/src/lib/blocks/BlockRenderer.tsx +141 -0
- package/src/lib/blocks/index.ts +6 -0
- package/src/lib/index.ts +9 -0
- package/src/lib/layouts/blocks/ColumnsBlock.tsx +134 -0
- package/src/lib/layouts/blocks/SectionBlock.tsx +104 -0
- package/src/lib/layouts/blocks/index.ts +8 -0
- package/src/lib/layouts/index.ts +52 -0
- package/src/lib/layouts/registerLayoutBlocks.ts +59 -0
- package/src/lib/mappers/apiMapper.ts +223 -0
- package/src/lib/migration/index.ts +6 -0
- package/src/lib/migration/mapper.ts +140 -0
- package/src/lib/rich-text/RichTextEditor.tsx +826 -0
- package/src/lib/rich-text/RichTextPreview.tsx +210 -0
- package/src/lib/rich-text/index.ts +10 -0
- package/src/lib/utils/blockHelpers.ts +72 -0
- package/src/lib/utils/configValidation.ts +137 -0
- package/src/lib/utils/index.ts +8 -0
- package/src/lib/utils/slugify.ts +79 -0
- package/src/registry/BlockRegistry.ts +142 -0
- package/src/registry/index.ts +11 -0
- package/src/state/EditorContext.tsx +277 -0
- package/src/state/index.ts +8 -0
- package/src/state/reducer.ts +694 -0
- package/src/state/types.ts +160 -0
- package/src/types/block.ts +269 -0
- package/src/types/index.ts +15 -0
- package/src/types/post.ts +165 -0
- package/src/utils/README.md +75 -0
- package/src/utils/client.ts +122 -0
- package/src/utils/index.ts +9 -0
- package/src/views/CanvasEditor/BlockWrapper.tsx +459 -0
- package/src/views/CanvasEditor/CanvasEditorView.tsx +917 -0
- package/src/views/CanvasEditor/EditorBody.tsx +475 -0
- package/src/views/CanvasEditor/EditorHeader.tsx +179 -0
- package/src/views/CanvasEditor/LayoutContainer.tsx +494 -0
- package/src/views/CanvasEditor/SaveConfirmationModal.tsx +233 -0
- package/src/views/CanvasEditor/components/CustomBlockItem.tsx +92 -0
- package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +130 -0
- package/src/views/CanvasEditor/components/LibraryItem.tsx +80 -0
- package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +212 -0
- package/src/views/CanvasEditor/components/index.ts +17 -0
- package/src/views/CanvasEditor/index.ts +16 -0
- package/src/views/PostManager/EmptyState.tsx +42 -0
- package/src/views/PostManager/PostActionsMenu.tsx +112 -0
- package/src/views/PostManager/PostCards.tsx +192 -0
- package/src/views/PostManager/PostFilters.tsx +80 -0
- package/src/views/PostManager/PostManagerView.tsx +280 -0
- package/src/views/PostManager/PostStats.tsx +81 -0
- package/src/views/PostManager/PostTable.tsx +225 -0
- package/src/views/PostManager/index.ts +15 -0
- package/src/views/Preview/PreviewBridgeView.tsx +64 -0
- package/src/views/Preview/index.ts +7 -0
- package/src/views/README.md +82 -0
- package/src/views/Settings/SettingsView.tsx +298 -0
- package/src/views/Settings/index.ts +7 -0
- package/src/views/SlugSEO/SlugSEOManagerView.tsx +94 -0
- package/src/views/SlugSEO/index.ts +7 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration Mapper
|
|
3
|
+
* Utility functions for converting legacy data to block-based format
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Block } from '../../types/block';
|
|
7
|
+
import { BlogPost } from '../../types/post';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Legacy Post Structure (example - adjust based on your actual legacy format)
|
|
11
|
+
*/
|
|
12
|
+
export interface LegacyPost {
|
|
13
|
+
id?: string;
|
|
14
|
+
title: string;
|
|
15
|
+
content: string; // HTML string
|
|
16
|
+
slug?: string;
|
|
17
|
+
excerpt?: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Convert HTML string to blocks
|
|
23
|
+
* This is a basic implementation - can be enhanced with more sophisticated parsing
|
|
24
|
+
*/
|
|
25
|
+
export function htmlToBlocks(html: string): Block[] {
|
|
26
|
+
// This is a simplified parser - you may want to use a proper HTML parser
|
|
27
|
+
// like htmlparser2 or cheerio for production use
|
|
28
|
+
|
|
29
|
+
const blocks: Block[] = [];
|
|
30
|
+
let blockIdCounter = 0;
|
|
31
|
+
|
|
32
|
+
function generateId(): string {
|
|
33
|
+
return `block-${Date.now()}-${blockIdCounter++}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Simple regex-based parsing (for demonstration)
|
|
37
|
+
// In production, use a proper HTML parser
|
|
38
|
+
|
|
39
|
+
// Extract headings
|
|
40
|
+
const headingRegex = /<h([1-6])[^>]*>(.*?)<\/h[1-6]>/gi;
|
|
41
|
+
let match;
|
|
42
|
+
let lastIndex = 0;
|
|
43
|
+
|
|
44
|
+
while ((match = headingRegex.exec(html)) !== null) {
|
|
45
|
+
// Add text before heading as paragraph if exists
|
|
46
|
+
const textBefore = html.substring(lastIndex, match.index).trim();
|
|
47
|
+
if (textBefore) {
|
|
48
|
+
blocks.push({
|
|
49
|
+
id: generateId(),
|
|
50
|
+
type: 'paragraph',
|
|
51
|
+
data: { text: textBefore.replace(/<[^>]+>/g, '') },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Add heading
|
|
56
|
+
blocks.push({
|
|
57
|
+
id: generateId(),
|
|
58
|
+
type: 'heading',
|
|
59
|
+
data: {
|
|
60
|
+
text: match[2].replace(/<[^>]+>/g, ''),
|
|
61
|
+
level: parseInt(match[1], 10),
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
lastIndex = match.index + match[0].length;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Add remaining text as paragraph
|
|
69
|
+
const remainingText = html.substring(lastIndex).trim();
|
|
70
|
+
if (remainingText) {
|
|
71
|
+
blocks.push({
|
|
72
|
+
id: generateId(),
|
|
73
|
+
type: 'paragraph',
|
|
74
|
+
data: { text: remainingText.replace(/<[^>]+>/g, '') },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// If no blocks were created, create a single paragraph with the HTML content
|
|
79
|
+
if (blocks.length === 0) {
|
|
80
|
+
blocks.push({
|
|
81
|
+
id: generateId(),
|
|
82
|
+
type: 'paragraph',
|
|
83
|
+
data: { text: html.replace(/<[^>]+>/g, '') },
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return blocks;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Map legacy post to new BlogPost format
|
|
92
|
+
*/
|
|
93
|
+
export function mapLegacyPostToBlogPost(
|
|
94
|
+
legacyPost: LegacyPost,
|
|
95
|
+
options?: {
|
|
96
|
+
defaultStatus?: 'draft' | 'published' | 'scheduled';
|
|
97
|
+
authorId?: string;
|
|
98
|
+
}
|
|
99
|
+
): BlogPost {
|
|
100
|
+
const blocks = legacyPost.content
|
|
101
|
+
? htmlToBlocks(legacyPost.content)
|
|
102
|
+
: [];
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
id: legacyPost.id || `post-${Date.now()}`,
|
|
106
|
+
title: legacyPost.title || 'Untitled Post',
|
|
107
|
+
slug: legacyPost.slug || legacyPost.title?.toLowerCase().replace(/\s+/g, '-') || 'untitled',
|
|
108
|
+
blocks,
|
|
109
|
+
seo: {
|
|
110
|
+
title: legacyPost.title,
|
|
111
|
+
description: legacyPost.excerpt || '',
|
|
112
|
+
},
|
|
113
|
+
publication: {
|
|
114
|
+
status: options?.defaultStatus || 'draft',
|
|
115
|
+
date: new Date().toISOString(),
|
|
116
|
+
authorId: options?.authorId,
|
|
117
|
+
},
|
|
118
|
+
metadata: {
|
|
119
|
+
excerpt: legacyPost.excerpt || '',
|
|
120
|
+
categories: [],
|
|
121
|
+
tags: [],
|
|
122
|
+
},
|
|
123
|
+
createdAt: new Date().toISOString(),
|
|
124
|
+
updatedAt: new Date().toISOString(),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Batch convert multiple legacy posts
|
|
130
|
+
*/
|
|
131
|
+
export function mapLegacyPostsToBlogPosts(
|
|
132
|
+
legacyPosts: LegacyPost[],
|
|
133
|
+
options?: {
|
|
134
|
+
defaultStatus?: 'draft' | 'published' | 'scheduled';
|
|
135
|
+
authorId?: string;
|
|
136
|
+
}
|
|
137
|
+
): BlogPost[] {
|
|
138
|
+
return legacyPosts.map(post => mapLegacyPostToBlogPost(post, options));
|
|
139
|
+
}
|
|
140
|
+
|