@blocklet/pages-kit-block-studio 0.1.4 → 0.1.7
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/lib/cjs/constants/index.js +12 -1
- package/lib/cjs/constants/new-block-template/@metadata.json +59 -0
- package/lib/cjs/constants/new-block-template/index.tsx +89 -0
- package/lib/cjs/middlewares/init-block-studio-router.js +42 -0
- package/lib/cjs/plugins/vite-plugin-html-transform.js +46 -11
- package/lib/cjs/tsconfig.tsbuildinfo +1 -1
- package/lib/cjs/utils/generate-wrapper-code.js +21 -25
- package/lib/cjs/utils/helper.js +20 -12
- package/lib/esm/constants/index.js +8 -0
- package/lib/esm/constants/new-block-template/@metadata.json +59 -0
- package/lib/esm/constants/new-block-template/index.tsx +89 -0
- package/lib/esm/middlewares/init-block-studio-router.js +43 -1
- package/lib/esm/plugins/vite-plugin-html-transform.js +46 -11
- package/lib/esm/tsconfig.tsbuildinfo +1 -1
- package/lib/esm/utils/generate-wrapper-code.js +21 -25
- package/lib/esm/utils/helper.js +10 -6
- package/lib/types/constants/index.d.ts +7 -0
- package/lib/types/tsconfig.tsbuildinfo +1 -1
- package/lib/types/utils/helper.d.ts +2 -4
- package/package.json +9 -6
- package/tsconfig.json +3 -1
|
@@ -275,12 +275,10 @@ function getCustomComponentPropertyType(type) {
|
|
|
275
275
|
}
|
|
276
276
|
const ALLOWED_PROPERTY_TYPES = ['string', 'multiline', 'url', 'json', 'yaml'];
|
|
277
277
|
function generatePageDataTypes(state) {
|
|
278
|
-
const
|
|
278
|
+
const pageTypeDefinitions = Object.values(state.pages)
|
|
279
279
|
.map((page) => {
|
|
280
|
-
// check if the page is a template page
|
|
281
280
|
if (!page.isTemplate)
|
|
282
281
|
return null;
|
|
283
|
-
// 将 slug 转换为有效的 TypeScript 类型名
|
|
284
282
|
const typeName = `Page${page.slug
|
|
285
283
|
.replace(/^\//, '')
|
|
286
284
|
.split('/')
|
|
@@ -331,8 +329,7 @@ ${properties}
|
|
|
331
329
|
})
|
|
332
330
|
.filter(Boolean)
|
|
333
331
|
.join('\n');
|
|
334
|
-
|
|
335
|
-
export interface ${typeName} {
|
|
332
|
+
const typeDefinition = `interface ${typeName} {
|
|
336
333
|
title?: string;
|
|
337
334
|
image?: string;
|
|
338
335
|
description?: string;
|
|
@@ -340,29 +337,28 @@ export interface ${typeName} {
|
|
|
340
337
|
${sectionTypes}
|
|
341
338
|
};
|
|
342
339
|
}`;
|
|
340
|
+
return {
|
|
341
|
+
typeName,
|
|
342
|
+
typeDefinition,
|
|
343
|
+
};
|
|
343
344
|
})
|
|
344
|
-
.filter(Boolean)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
.split('/')
|
|
354
|
-
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
355
|
-
.join('')
|
|
356
|
-
.replace(/[^a-zA-Z0-9]/g, '')}Data`;
|
|
357
|
-
return typeName;
|
|
358
|
-
})
|
|
359
|
-
.filter(Boolean)
|
|
360
|
-
.join(' | ');
|
|
345
|
+
.filter(Boolean);
|
|
346
|
+
// Generate type definitions string
|
|
347
|
+
const typeDefinitions = pageTypeDefinitions.map((def) => `export ${def === null || def === void 0 ? void 0 : def.typeDefinition}`).join('\n\n');
|
|
348
|
+
// Generate string literals for each type
|
|
349
|
+
const typeStrings = pageTypeDefinitions
|
|
350
|
+
.map((def) => `export const ${def === null || def === void 0 ? void 0 : def.typeName}String = \`${def === null || def === void 0 ? void 0 : def.typeDefinition}\`;`)
|
|
351
|
+
.join('\n\n');
|
|
352
|
+
// Generate union type
|
|
353
|
+
const pageUnionTypes = pageTypeDefinitions.map((def) => def === null || def === void 0 ? void 0 : def.typeName).join(' | ');
|
|
361
354
|
return `
|
|
362
|
-
//
|
|
363
|
-
${
|
|
355
|
+
// Page data type definitions
|
|
356
|
+
${typeDefinitions}
|
|
357
|
+
|
|
358
|
+
// String versions of type definitions
|
|
359
|
+
${typeStrings}
|
|
364
360
|
|
|
365
|
-
//
|
|
361
|
+
// Union type of all page data types
|
|
366
362
|
export type PageDataUnion = ${pageUnionTypes || 'never'};`;
|
|
367
363
|
}
|
|
368
364
|
exports.default = generateWrapperCode;
|
package/lib/cjs/utils/helper.js
CHANGED
|
@@ -32,6 +32,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
35
38
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
39
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
40
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -45,7 +48,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
45
48
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
49
|
};
|
|
47
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.getBlockCode = exports.isPagesKitBlockStudio = exports.getPreviewImageRelativePath = exports.downloadAsset = exports.isMetadataFile = exports.isDev = exports.isPathSafe = exports.
|
|
51
|
+
exports.safeParse = exports.getBlockCode = exports.isPagesKitBlockStudio = exports.getPreviewImageRelativePath = exports.downloadAsset = exports.isMetadataFile = exports.isDev = exports.isPathSafe = exports.logger = void 0;
|
|
49
52
|
exports.setBlockEntryFilesPattern = setBlockEntryFilesPattern;
|
|
50
53
|
exports.getBlockEntryFilesPattern = getBlockEntryFilesPattern;
|
|
51
54
|
exports.findComponentFiles = findComponentFiles;
|
|
@@ -64,14 +67,10 @@ const promises_2 = require("stream/promises");
|
|
|
64
67
|
const ufo_1 = require("ufo");
|
|
65
68
|
const yaml = __importStar(require("yaml"));
|
|
66
69
|
const constants_1 = require("../constants");
|
|
70
|
+
__exportStar(require("../constants"), exports);
|
|
67
71
|
exports.logger = console;
|
|
68
|
-
exports.libDir = 'lib';
|
|
69
|
-
exports.METADATA_FILE_NAME = '@metadata.json';
|
|
70
|
-
exports.PREVIEW_IMAGE_DIR = '@preview-images';
|
|
71
|
-
exports.NANOID_LENGTH = 16;
|
|
72
|
-
const DEFAULT_BLOCK_ENTRY_FILES_PATTERN = 'src/**/index.{ts,tsx,html}';
|
|
73
72
|
if (!process.env.BLOCK_ENTRY_FILES_PATTERN) {
|
|
74
|
-
process.env.BLOCK_ENTRY_FILES_PATTERN = DEFAULT_BLOCK_ENTRY_FILES_PATTERN;
|
|
73
|
+
process.env.BLOCK_ENTRY_FILES_PATTERN = constants_1.DEFAULT_BLOCK_ENTRY_FILES_PATTERN;
|
|
75
74
|
}
|
|
76
75
|
function normalizePattern(pattern) {
|
|
77
76
|
return pattern.replace(/^[/\\]+/, ''); // Remove leading slashes
|
|
@@ -80,7 +79,7 @@ function setBlockEntryFilesPattern(pattern) {
|
|
|
80
79
|
process.env.BLOCK_ENTRY_FILES_PATTERN = normalizePattern(pattern);
|
|
81
80
|
}
|
|
82
81
|
function getBlockEntryFilesPattern() {
|
|
83
|
-
return process.env.BLOCK_ENTRY_FILES_PATTERN || DEFAULT_BLOCK_ENTRY_FILES_PATTERN;
|
|
82
|
+
return process.env.BLOCK_ENTRY_FILES_PATTERN || constants_1.DEFAULT_BLOCK_ENTRY_FILES_PATTERN;
|
|
84
83
|
}
|
|
85
84
|
function findComponentFiles(options = {}) {
|
|
86
85
|
const { cwd = process.cwd(), filter } = options;
|
|
@@ -124,7 +123,7 @@ const isPathSafe = (filePath) => {
|
|
|
124
123
|
exports.isPathSafe = isPathSafe;
|
|
125
124
|
exports.isDev = process.env.BLOCKLET_MODE === 'development';
|
|
126
125
|
const isMetadataFile = (filePath) => {
|
|
127
|
-
return filePath.endsWith(
|
|
126
|
+
return filePath.endsWith(constants_1.METADATA_FILE_NAME);
|
|
128
127
|
};
|
|
129
128
|
exports.isMetadataFile = isMetadataFile;
|
|
130
129
|
const downloadAsset = (_a) => __awaiter(void 0, [_a], void 0, function* ({ asset, savePath, componentDid, }) {
|
|
@@ -155,7 +154,7 @@ const downloadAsset = (_a) => __awaiter(void 0, [_a], void 0, function* ({ asset
|
|
|
155
154
|
});
|
|
156
155
|
exports.downloadAsset = downloadAsset;
|
|
157
156
|
const getPreviewImageRelativePath = (name) => {
|
|
158
|
-
return path_1.default.join(
|
|
157
|
+
return path_1.default.join(constants_1.PREVIEW_IMAGE_DIR, name);
|
|
159
158
|
};
|
|
160
159
|
exports.getPreviewImageRelativePath = getPreviewImageRelativePath;
|
|
161
160
|
function initializeMetadata(tempFilePath) {
|
|
@@ -164,7 +163,7 @@ function initializeMetadata(tempFilePath) {
|
|
|
164
163
|
throw new Error('File path is required');
|
|
165
164
|
}
|
|
166
165
|
// file path is metadata file
|
|
167
|
-
const filePath = (0, exports.isMetadataFile)(tempFilePath) ? tempFilePath : path_1.default.join((0, path_1.dirname)(tempFilePath),
|
|
166
|
+
const filePath = (0, exports.isMetadataFile)(tempFilePath) ? tempFilePath : path_1.default.join((0, path_1.dirname)(tempFilePath), constants_1.METADATA_FILE_NAME);
|
|
168
167
|
if (!filePath) {
|
|
169
168
|
throw new Error('File path is required');
|
|
170
169
|
}
|
|
@@ -182,7 +181,7 @@ function initializeMetadata(tempFilePath) {
|
|
|
182
181
|
}
|
|
183
182
|
// Add id if not exists
|
|
184
183
|
if (!metadata.id) {
|
|
185
|
-
metadata.id = (0, nanoid_1.nanoid)(
|
|
184
|
+
metadata.id = (0, nanoid_1.nanoid)(constants_1.NANOID_LENGTH);
|
|
186
185
|
}
|
|
187
186
|
// Add createdAt if not exists
|
|
188
187
|
if (!metadata.createdAt) {
|
|
@@ -227,3 +226,12 @@ const getBlockCode = (filePath) => {
|
|
|
227
226
|
return fs_1.default.readFileSync(codeFile, 'utf8');
|
|
228
227
|
};
|
|
229
228
|
exports.getBlockCode = getBlockCode;
|
|
229
|
+
const safeParse = (text) => {
|
|
230
|
+
try {
|
|
231
|
+
return JSON.parse(text);
|
|
232
|
+
}
|
|
233
|
+
catch (_a) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
exports.safeParse = safeParse;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import path from 'path';
|
|
1
2
|
export const PAGES_KIT_DID = 'z8iZiDFg3vkkrPwsiba1TLXy3H9XHzFERsP8o';
|
|
2
3
|
export const PAGES_KIT_RESOURCE_TYPE = 'page';
|
|
3
4
|
export const PAGES_KIT_BLOCK_STUDIO_DID = 'z2qa7rr3eUyVnWp2PCxEVARuUfLFh6cE5V2xV';
|
|
4
5
|
export const PAGES_KIT_BLOCK_STUDIO_RESOURCE_TYPE = 'page';
|
|
5
6
|
export const MEDIA_KIT_DID = 'z8ia1mAXo8ZE7ytGF36L5uBf9kD2kenhqFGp9';
|
|
6
7
|
export const MEDIA_KIT_RESOURCE_TYPE = 'imgpack';
|
|
8
|
+
export const NEW_BLOCK_TEMPLATE_PATH = path.join(__dirname, 'new-block-template', 'index.tsx');
|
|
9
|
+
export const NEW_BLOCK_TEMPLATE_METADATA_PATH = path.join(__dirname, 'new-block-template', '@metadata.json');
|
|
10
|
+
export const libDir = 'lib';
|
|
11
|
+
export const METADATA_FILE_NAME = '@metadata.json';
|
|
12
|
+
export const PREVIEW_IMAGE_DIR = '@preview-images';
|
|
13
|
+
export const NANOID_LENGTH = 16;
|
|
14
|
+
export const DEFAULT_BLOCK_ENTRY_FILES_PATTERN = 'src/**/index.{ts,tsx,html}';
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"properties": {
|
|
3
|
+
"gs1rn5jmxfvpxptx": {
|
|
4
|
+
"index": 0,
|
|
5
|
+
"data": {
|
|
6
|
+
"id": "gs1rn5jmxfvpxptx",
|
|
7
|
+
"key": "title",
|
|
8
|
+
"locales": {
|
|
9
|
+
"zh": {
|
|
10
|
+
"name": "Title"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"9ajrz12ik7esfk1z": {
|
|
16
|
+
"index": 1,
|
|
17
|
+
"data": {
|
|
18
|
+
"id": "9ajrz12ik7esfk1z",
|
|
19
|
+
"key": "description",
|
|
20
|
+
"locales": {
|
|
21
|
+
"zh": {
|
|
22
|
+
"name": "Description",
|
|
23
|
+
"defaultValue": "Welcome to Pages Kit Block Studio"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"3ckcfvf6b7zyskk8": {
|
|
29
|
+
"index": 2,
|
|
30
|
+
"data": {
|
|
31
|
+
"id": "3ckcfvf6b7zyskk8",
|
|
32
|
+
"key": "logo",
|
|
33
|
+
"type": "url",
|
|
34
|
+
"locales": {
|
|
35
|
+
"zh": {
|
|
36
|
+
"defaultValue": {
|
|
37
|
+
"url": "/.well-known/service/blocklet/logo?imageFilter=convert&f=png&h=80",
|
|
38
|
+
"mediaKitUrl": "/.well-known/service/blocklet/logo?imageFilter=convert&f=png&h=80"
|
|
39
|
+
},
|
|
40
|
+
"name": "Logo"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"x3lqht8ikble1itx": {
|
|
46
|
+
"index": 3,
|
|
47
|
+
"data": {
|
|
48
|
+
"id": "x3lqht8ikble1itx",
|
|
49
|
+
"key": "copyright",
|
|
50
|
+
"locales": {
|
|
51
|
+
"zh": {
|
|
52
|
+
"defaultValue": "Powered by Pages Kit Block Studio"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"visible": false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface HelloWorldProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
logo?: string | { url: string };
|
|
6
|
+
description?: string;
|
|
7
|
+
copyright?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// default export
|
|
11
|
+
export default function HelloWorld({ title = 'Hello World', logo, description, copyright }: HelloWorldProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
style={{
|
|
15
|
+
display: 'flex',
|
|
16
|
+
flexDirection: 'column',
|
|
17
|
+
alignItems: 'center',
|
|
18
|
+
padding: '16px 0',
|
|
19
|
+
}}>
|
|
20
|
+
{title && <h1>{title}</h1>}
|
|
21
|
+
{logo && (
|
|
22
|
+
<img
|
|
23
|
+
src={typeof logo === 'object' ? logo.url : logo}
|
|
24
|
+
alt="logo"
|
|
25
|
+
style={{
|
|
26
|
+
margin: '16px 0',
|
|
27
|
+
maxWidth: '200px',
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
)}
|
|
31
|
+
{description && (
|
|
32
|
+
<div
|
|
33
|
+
style={{
|
|
34
|
+
color: '#666',
|
|
35
|
+
marginTop: '8px',
|
|
36
|
+
}}>
|
|
37
|
+
{description}
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
{copyright && (
|
|
41
|
+
<div
|
|
42
|
+
style={{
|
|
43
|
+
color: '#999',
|
|
44
|
+
fontSize: '12px',
|
|
45
|
+
marginTop: '16px',
|
|
46
|
+
}}>
|
|
47
|
+
{copyright}
|
|
48
|
+
</div>
|
|
49
|
+
)}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// export edit component
|
|
55
|
+
export const EditComponent: React.FC<HelloWorldProps & { onChange?: (value: HelloWorldProps) => void }> = ({
|
|
56
|
+
onChange,
|
|
57
|
+
...props
|
|
58
|
+
}) => {
|
|
59
|
+
return (
|
|
60
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
61
|
+
<div
|
|
62
|
+
style={{
|
|
63
|
+
fontSize: '14px',
|
|
64
|
+
fontWeight: 500,
|
|
65
|
+
color: '#333',
|
|
66
|
+
padding: '8px 0',
|
|
67
|
+
borderBottom: '1px solid #eee',
|
|
68
|
+
}}>
|
|
69
|
+
Footer Parameters
|
|
70
|
+
</div>
|
|
71
|
+
<input
|
|
72
|
+
id="copyright-input"
|
|
73
|
+
type="text"
|
|
74
|
+
style={{
|
|
75
|
+
width: '100%',
|
|
76
|
+
padding: '8px 12px',
|
|
77
|
+
border: '1px solid #ddd',
|
|
78
|
+
borderRadius: '4px',
|
|
79
|
+
fontSize: '14px',
|
|
80
|
+
transition: 'border-color 0.3s',
|
|
81
|
+
outline: 'none',
|
|
82
|
+
}}
|
|
83
|
+
value={props.copyright || ''}
|
|
84
|
+
onChange={(e) => onChange?.({ copyright: e.target.value })}
|
|
85
|
+
placeholder="Please Input Copyright"
|
|
86
|
+
/>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
@@ -11,7 +11,8 @@ import { Router } from 'express';
|
|
|
11
11
|
import fs from 'fs';
|
|
12
12
|
import { isEqual, keyBy, set } from 'lodash';
|
|
13
13
|
import path from 'path';
|
|
14
|
-
import {
|
|
14
|
+
import { METADATA_FILE_NAME, NEW_BLOCK_TEMPLATE_PATH, NEW_BLOCK_TEMPLATE_METADATA_PATH } from '../constants';
|
|
15
|
+
import { isPathSafe, isDev, downloadAsset, isMetadataFile, getPreviewImageRelativePath, initializeMetadata, findComponentFiles, getBlockStudioInfo, getBlockCode, getBlockEntryFilesPattern, safeParse, } from '../utils/helper';
|
|
15
16
|
export const initBlockStudioRouter = Router();
|
|
16
17
|
const BINARY_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg'];
|
|
17
18
|
initBlockStudioRouter.get('/', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -83,6 +84,47 @@ initBlockStudioRouter.post('/', (req, res) => __awaiter(void 0, void 0, void 0,
|
|
|
83
84
|
return res.status(500).json({ error: 'Failed to write file' });
|
|
84
85
|
}
|
|
85
86
|
}));
|
|
87
|
+
initBlockStudioRouter.post('/create', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
if (!isDev) {
|
|
89
|
+
return res.status(403).json({ error: 'Only available in development mode' });
|
|
90
|
+
}
|
|
91
|
+
const { name, description } = req.body;
|
|
92
|
+
if (!name) {
|
|
93
|
+
return res.status(400).json({ error: 'Name is required' });
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const pattern = getBlockEntryFilesPattern();
|
|
97
|
+
const baseDir = path.dirname(pattern.replace(/\*\*?/g, ''));
|
|
98
|
+
const blockDir = path.join(baseDir, name);
|
|
99
|
+
const metadataPath = path.join(blockDir, METADATA_FILE_NAME);
|
|
100
|
+
const indexPath = path.join(blockDir, 'index.tsx');
|
|
101
|
+
// Check if block already exists
|
|
102
|
+
if (fs.existsSync(blockDir)) {
|
|
103
|
+
return res.status(409).json({ error: 'Block already exists' });
|
|
104
|
+
}
|
|
105
|
+
// Create block directory
|
|
106
|
+
fs.mkdirSync(blockDir, { recursive: true });
|
|
107
|
+
// Initialize metadata
|
|
108
|
+
let metadata = initializeMetadata(metadataPath);
|
|
109
|
+
metadata.name = name;
|
|
110
|
+
metadata.description = description || '';
|
|
111
|
+
metadata.createdAt = new Date().toISOString();
|
|
112
|
+
metadata.updatedAt = new Date().toISOString();
|
|
113
|
+
// get template metadata from @metadata.json
|
|
114
|
+
const metadataContent = fs.readFileSync(NEW_BLOCK_TEMPLATE_METADATA_PATH, 'utf-8');
|
|
115
|
+
metadata = Object.assign(Object.assign({}, metadata), safeParse(metadataContent));
|
|
116
|
+
// Write metadata file
|
|
117
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
118
|
+
// Copy template file to index.tsx
|
|
119
|
+
const templateContent = fs.readFileSync(NEW_BLOCK_TEMPLATE_PATH, 'utf-8');
|
|
120
|
+
fs.writeFileSync(indexPath, templateContent);
|
|
121
|
+
return res.json({ success: true, metadata });
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.error('Failed to create block:', error);
|
|
125
|
+
return res.status(500).json({ error: 'Failed to create block' });
|
|
126
|
+
}
|
|
127
|
+
}));
|
|
86
128
|
initBlockStudioRouter.get('/all', (req, res) => __awaiter(void 0, void 0, void 0, function* () {
|
|
87
129
|
const { withBlockletData = true } = req.query;
|
|
88
130
|
const allBlocks = yield findComponentFiles();
|
|
@@ -164,10 +164,24 @@ ${content.trim()}`;
|
|
|
164
164
|
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
|
165
165
|
<meta http-equiv="Referrer-Policy" content="no-referrer">
|
|
166
166
|
<meta http-equiv="Permissions-Policy" content="accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()">`;
|
|
167
|
+
const autoHeightScript = `<script>
|
|
168
|
+
(function() {
|
|
169
|
+
if ('ResizeObserver' in window) {
|
|
170
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
171
|
+
const height = document.documentElement.scrollHeight;
|
|
172
|
+
window.parent.postMessage({ height }, '*');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
resizeObserver.observe(document.documentElement);
|
|
176
|
+
}
|
|
177
|
+
})();
|
|
178
|
+
</script>`;
|
|
167
179
|
// 将处理后的相对路径引入的 CSS 和 JS 注入到 HTML 中
|
|
168
180
|
const htmlContent = htmlWithoutRelativeImport
|
|
169
181
|
.replace('<head>', `<head>${securityHeaders}`)
|
|
170
182
|
.replace('</head>', `${cssContents.map((css) => `<style>${css.trim()}</style>`).join('\n')}
|
|
183
|
+
|
|
184
|
+
${autoHeightScript}
|
|
171
185
|
</head>`)
|
|
172
186
|
.replace('</body>', `
|
|
173
187
|
${jsContents.map((js) => `<script>${js}</script>`).join('\n')}
|
|
@@ -186,19 +200,40 @@ ${content.trim()}`;
|
|
|
186
200
|
}
|
|
187
201
|
export function generateComponent(content, _isDev = true) {
|
|
188
202
|
const htmlContent = content.html;
|
|
189
|
-
const { name } = content;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return `import { createElement } from 'react';
|
|
203
|
+
// const { name } = content;
|
|
204
|
+
return `import React, { useEffect, useRef } from 'react';
|
|
205
|
+
|
|
206
|
+
const htmlContent = ${htmlContent};
|
|
194
207
|
|
|
195
208
|
export default function HtmlPreview() {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
209
|
+
const iframeRef = useRef(null);
|
|
210
|
+
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
const iframe = iframeRef.current;
|
|
213
|
+
if (!iframe) return;
|
|
214
|
+
|
|
215
|
+
const handleMessage = (event) => {
|
|
216
|
+
if (event.source === iframe.contentWindow) {
|
|
217
|
+
const height = event.data.height;
|
|
218
|
+
if (height) {
|
|
219
|
+
iframe.style.height = height + 'px';
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
window.addEventListener('message', handleMessage);
|
|
225
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
226
|
+
}, []);
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<iframe
|
|
230
|
+
ref={iframeRef}
|
|
231
|
+
style={{ border: 'none', width: '100%', height: '0px', maxHeight: '100vh' }}
|
|
232
|
+
sandbox="allow-scripts"
|
|
233
|
+
title="HtmlPreview"
|
|
234
|
+
srcDoc={htmlContent}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
202
237
|
}`;
|
|
203
238
|
}
|
|
204
239
|
export function initHtmlPreviewTransformPlugin() {
|