juo 0.0.1-alpha.5 → 0.1.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/README.md +6 -5
- package/dist/{analytics-B2gwRg5Q.js → analytics-CgHTVQWO.js} +7 -7
- package/dist/commands/create.d.ts +4 -3
- package/dist/commands/create.js +158 -264
- package/dist/commands/generate.d.ts +6 -5
- package/dist/commands/generate.js +2 -1
- package/dist/commands/publish/index.d.ts +7 -7
- package/dist/commands/publish/index.js +4 -3
- package/dist/generate-vpUPJZRH.js +118 -0
- package/dist/hooks/postrun.js +39 -11
- package/dist/hooks/prerun.js +1 -1
- package/dist/juoTemplateGenerator-MZ8llr7w.js +130 -0
- package/dist/lib/index.d.ts +69 -0
- package/dist/lib/index.js +4 -0
- package/dist/packageGenerator-Dno-ecHh.js +117 -0
- package/oclif.manifest.json +12 -7
- package/package.json +6 -2
- package/templates/block/preact/index.ts.liquid +4 -5
- package/templates/block/preact/{{block.clsName}}.tsx.liquid +1 -2
- package/templates/block/react/index.ts.liquid +3 -6
- package/templates/block/react/{{block.clsName}}.tsx.liquid +2 -3
- package/templates/tailwind/vite.config.ts.liquid +11 -1
- package/dist/generate-D7J6nPBd.js +0 -252
- package/templates/block/react/state.ts.liquid +0 -105
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { defineBlock
|
|
2
|
-
import {
|
|
1
|
+
import { defineBlock } from "@juo/blocks";
|
|
2
|
+
import { createPreactRenderer } from "@juo/blocks/preact";
|
|
3
3
|
import { {{ block.clsName }} } from "./{{block.clsName}}.tsx";
|
|
4
|
-
import type {
|
|
4
|
+
import type { FromSchema, JSONSchema } from "json-schema-to-ts";
|
|
5
5
|
|
|
6
6
|
const schema = {
|
|
7
7
|
type: "object",
|
|
@@ -35,6 +35,5 @@ export const {{ block.clsName }}Block = defineBlock("{{ block.name }}", {
|
|
|
35
35
|
},
|
|
36
36
|
slots: {},
|
|
37
37
|
}),
|
|
38
|
-
|
|
39
|
-
renderer: createPreactRenderer((el: HTMLElement) => render(HelloWorld, el)),
|
|
38
|
+
renderer: createPreactRenderer({{ block.clsName }}),
|
|
40
39
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { defineBlock
|
|
2
|
-
import {
|
|
3
|
-
import { createRoot } from "react-dom/client";
|
|
1
|
+
import { defineBlock } from "@juo/blocks";
|
|
2
|
+
import { createReactRenderer } from "@juo/blocks/react";
|
|
4
3
|
import { FromSchema, JSONSchema } from "json-schema-to-ts";
|
|
5
4
|
import { {{ block.clsName }} } from "./{{ block.clsName }}.tsx";
|
|
6
5
|
|
|
@@ -35,7 +34,5 @@ export const {{ block.clsName }}Block = defineBlock<Schema>("{{ block.name }}",
|
|
|
35
34
|
},
|
|
36
35
|
slots: {},
|
|
37
36
|
}),
|
|
38
|
-
renderer: createReactRenderer(
|
|
39
|
-
createRoot(el).render(createElement({{ block.clsName }}, block.props));
|
|
40
|
-
}),
|
|
37
|
+
renderer: createReactRenderer({{ block.clsName }}),
|
|
41
38
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { useRef, useState } from "react";
|
|
2
2
|
import { MantineProvider } from "@mantine/core";
|
|
3
3
|
import type { Props } from ".";
|
|
4
|
-
import ReactLogo from "../../assets/react-icon.svg?react";
|
|
5
4
|
|
|
6
|
-
const Counter = ({ className }: { className: string }) => {
|
|
7
|
-
const [count, setCount] = useState(
|
|
5
|
+
const Counter = ({ className, initialCount = 0 }: { className: string; initialCount?: number }) => {
|
|
6
|
+
const [count, setCount] = useState(initialCount);
|
|
8
7
|
return (
|
|
9
8
|
<button
|
|
10
9
|
className={`px-4 py-2 rounded-md cursor-pointer ${className}`}
|
|
@@ -16,8 +16,18 @@ export default defineConfig({
|
|
|
16
16
|
}),
|
|
17
17
|
],
|
|
18
18
|
build: {
|
|
19
|
+
lib: {
|
|
20
|
+
entry: "src/blocks/index.ts",
|
|
21
|
+
formats: ["es"],
|
|
22
|
+
fileName: "index",
|
|
23
|
+
},
|
|
19
24
|
rollupOptions: {
|
|
20
|
-
external: [
|
|
25
|
+
external: [
|
|
26
|
+
"@juo/blocks",
|
|
27
|
+
"react",
|
|
28
|
+
"react-dom",
|
|
29
|
+
"preact",
|
|
30
|
+
],
|
|
21
31
|
},
|
|
22
32
|
},
|
|
23
33
|
});
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { Command, Flags } from "@oclif/core";
|
|
2
|
-
import { isCancel, log, select, spinner, text } from "@clack/prompts";
|
|
3
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import { detectPackageManager } from "nypm";
|
|
6
|
-
import slugify from "slugify";
|
|
7
|
-
import { Liquid } from "liquidjs";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { readPackageJSON } from "pkg-types";
|
|
10
|
-
|
|
11
|
-
//#region src/utils/baseTemplateGenerator.ts
|
|
12
|
-
var BaseTemplateGenerator = class {
|
|
13
|
-
renderTemplate(templateName, destDir, scope, fileFilter) {
|
|
14
|
-
try {
|
|
15
|
-
const templateDir = this.getTemplateDir(templateName);
|
|
16
|
-
const engine = new Liquid();
|
|
17
|
-
const files = this.getTemplateFiles(templateName);
|
|
18
|
-
const filteredFiles = fileFilter ? files.filter(fileFilter) : files;
|
|
19
|
-
for (const file of filteredFiles) {
|
|
20
|
-
const filename = engine.parseAndRenderSync(file, scope).replace(/\.liquid$/, "");
|
|
21
|
-
const tplPath = path.join(templateDir, file);
|
|
22
|
-
const destPath = path.join(destDir, filename);
|
|
23
|
-
mkdirSync(path.dirname(destPath), { recursive: true });
|
|
24
|
-
writeFileSync(destPath, engine.parseAndRenderSync(readFileSync(tplPath, "utf-8"), scope));
|
|
25
|
-
}
|
|
26
|
-
} catch (error) {
|
|
27
|
-
throw new Error(`Error rendering template ${templateName}: ${error}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
getTemplateDir(name) {
|
|
31
|
-
const packageRoot = this.resolvePackageRoot();
|
|
32
|
-
return path.join(packageRoot, "templates", name);
|
|
33
|
-
}
|
|
34
|
-
getTemplateFiles(name) {
|
|
35
|
-
function scan(dirpath, baseDir) {
|
|
36
|
-
return readdirSync(dirpath).flatMap((filename) => {
|
|
37
|
-
const filepath = path.join(dirpath, filename);
|
|
38
|
-
if (statSync(filepath).isDirectory()) return scan(filepath, baseDir);
|
|
39
|
-
else return [path.relative(baseDir, filepath)];
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
const templateDir = this.getTemplateDir(name);
|
|
43
|
-
return scan(templateDir, templateDir);
|
|
44
|
-
}
|
|
45
|
-
resolvePackageRoot() {
|
|
46
|
-
let currentPath = path.dirname(fileURLToPath(import.meta.url));
|
|
47
|
-
while (!existsSync(path.join(currentPath, "package.json"))) {
|
|
48
|
-
const parentDir = path.dirname(currentPath);
|
|
49
|
-
if (parentDir === currentPath) throw new Error("Could not find package root");
|
|
50
|
-
currentPath = parentDir;
|
|
51
|
-
}
|
|
52
|
-
return currentPath;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
//#endregion
|
|
57
|
-
//#region src/utils/storyGenerator.ts
|
|
58
|
-
var StoryGenerator = class extends BaseTemplateGenerator {
|
|
59
|
-
async generate(destDir, options) {
|
|
60
|
-
if (options.type === "block") await this.generateBlockTemplate(destDir, options);
|
|
61
|
-
else await this.generateThemeTemplate(destDir, options);
|
|
62
|
-
}
|
|
63
|
-
async generateBlockTemplate(destDir, options) {
|
|
64
|
-
const scope = { block: {
|
|
65
|
-
slug: slugify(options.name, { lower: true }),
|
|
66
|
-
name: options.name,
|
|
67
|
-
clsName: slugify(options.name, { lower: true }).split("-").map((item) => `${item[0].toUpperCase()}${item.substring(1)}`).join(""),
|
|
68
|
-
framework: options.framework
|
|
69
|
-
} };
|
|
70
|
-
if (["react", "preact"].includes(scope.block.framework)) {
|
|
71
|
-
if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
|
|
72
|
-
this.renderTemplate("stories", destDir, scope);
|
|
73
|
-
} else options.logger?.("Story generation skipped");
|
|
74
|
-
}
|
|
75
|
-
async generateThemeTemplate(destDir, options) {
|
|
76
|
-
const themeScope = { theme: {
|
|
77
|
-
name: options.name,
|
|
78
|
-
slug: slugify(options.name, { lower: true }),
|
|
79
|
-
framework: options.framework,
|
|
80
|
-
clsName: slugify(options.name, { lower: true }).split("-").map((item) => `${item[0].toUpperCase()}${item.substring(1)}`).join("")
|
|
81
|
-
} };
|
|
82
|
-
if (options.framework === "react") this.renderTemplate("theme/react", destDir, themeScope, (filename) => filename.includes(".stories.tsx.liquid"));
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/utils/juoTemplateGenerator.ts
|
|
88
|
-
var JuoTemplateGenerator = class extends BaseTemplateGenerator {
|
|
89
|
-
storyGenerator;
|
|
90
|
-
constructor() {
|
|
91
|
-
super();
|
|
92
|
-
this.storyGenerator = new StoryGenerator();
|
|
93
|
-
}
|
|
94
|
-
async generate(destDir, options) {
|
|
95
|
-
await this.generateBlockTemplate(destDir, options);
|
|
96
|
-
}
|
|
97
|
-
async generateBlockTemplate(destDir, options) {
|
|
98
|
-
const scope = { block: {
|
|
99
|
-
slug: slugify(options.name, { lower: true }),
|
|
100
|
-
name: options.name,
|
|
101
|
-
clsName: slugify(options.name, { lower: true }).split("-").map((item) => `${item[0].toUpperCase()}${item.substring(1)}`).join(""),
|
|
102
|
-
tailwind: options.tailwind,
|
|
103
|
-
framework: options.framework
|
|
104
|
-
} };
|
|
105
|
-
this.renderTemplate(`${options.type}/${options.framework}`, path.join(destDir, scope.block.slug), scope);
|
|
106
|
-
options.logger?.("Adding block to theme");
|
|
107
|
-
try {
|
|
108
|
-
appendFileSync(path.join(destDir, "index.ts"), `export { ${scope.block.clsName}Block } from "./${scope.block.slug}";\n`);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
options.logger?.("Error adding block to theme: " + error);
|
|
111
|
-
throw error;
|
|
112
|
-
}
|
|
113
|
-
if (options.story) {
|
|
114
|
-
const projectRoot = path.dirname(path.dirname(destDir));
|
|
115
|
-
const storiesDir = path.join(projectRoot, "stories");
|
|
116
|
-
try {
|
|
117
|
-
await this.storyGenerator.generate(storiesDir, {
|
|
118
|
-
name: scope.block.name,
|
|
119
|
-
type: "block",
|
|
120
|
-
framework: options.framework,
|
|
121
|
-
tailwind: options.tailwind
|
|
122
|
-
});
|
|
123
|
-
} catch (error) {
|
|
124
|
-
options.logger?.("Error generating story: " + error);
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
} else options.logger?.(`Story generation skipped (options.story = ${options.story})`);
|
|
128
|
-
}
|
|
129
|
-
appendStylesheet(destDir) {
|
|
130
|
-
this.renderTemplate("css", path.join(destDir, "src"), {});
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
//#endregion
|
|
135
|
-
//#region src/utils/resolveFramework.ts
|
|
136
|
-
async function resolveFramework() {
|
|
137
|
-
try {
|
|
138
|
-
const packageJson = await readPackageJSON();
|
|
139
|
-
if (!packageJson) throw new Error("Could not find package.json");
|
|
140
|
-
if (packageJson.dependencies == null) throw new Error("Could not find dependencies in package.json");
|
|
141
|
-
if ("preact" in packageJson.dependencies) return "preact";
|
|
142
|
-
return "react";
|
|
143
|
-
} catch (error) {
|
|
144
|
-
throw new Error(`Error resolving framework: ${error}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
//#endregion
|
|
149
|
-
//#region src/commands/generate.ts
|
|
150
|
-
var Generate = class Generate extends Command {
|
|
151
|
-
static id = "generate";
|
|
152
|
-
static description = "Generate blocks for your project";
|
|
153
|
-
static flags = {
|
|
154
|
-
name: Flags.string({
|
|
155
|
-
char: "n",
|
|
156
|
-
description: "The name of the component"
|
|
157
|
-
}),
|
|
158
|
-
type: Flags.string({
|
|
159
|
-
description: "The type of the component",
|
|
160
|
-
options: ["block"],
|
|
161
|
-
default: "block"
|
|
162
|
-
}),
|
|
163
|
-
tailwind: Flags.boolean({
|
|
164
|
-
char: "t",
|
|
165
|
-
default: void 0,
|
|
166
|
-
allowNo: true
|
|
167
|
-
}),
|
|
168
|
-
verbose: Flags.boolean({
|
|
169
|
-
char: "v",
|
|
170
|
-
default: true,
|
|
171
|
-
allowNo: true
|
|
172
|
-
})
|
|
173
|
-
};
|
|
174
|
-
static examples = ["<%= config.bin %> <%= command.id %>"];
|
|
175
|
-
resolvePackageJsonPath() {
|
|
176
|
-
let currentPath = path.resolve("./");
|
|
177
|
-
while (!existsSync(path.join(currentPath, "package.json"))) {
|
|
178
|
-
const parentDir = path.dirname(currentPath);
|
|
179
|
-
if (parentDir === currentPath) throw new Error("Could not find 'package.json' in the project");
|
|
180
|
-
currentPath = parentDir;
|
|
181
|
-
}
|
|
182
|
-
return currentPath;
|
|
183
|
-
}
|
|
184
|
-
async resolveCSSFramework(dir) {
|
|
185
|
-
try {
|
|
186
|
-
const packageJson = await readPackageJSON(path.join(dir, "package.json"));
|
|
187
|
-
if (packageJson?.dependencies?.tailwindcss || packageJson?.devDependencies?.tailwindcss) return "tailwind";
|
|
188
|
-
return false;
|
|
189
|
-
} catch (error) {
|
|
190
|
-
throw new Error(`Error resolving CSS framework: ${error}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
async run() {
|
|
194
|
-
const { flags } = await this.parse(Generate);
|
|
195
|
-
let rootDir;
|
|
196
|
-
const templateGenerator = new JuoTemplateGenerator();
|
|
197
|
-
try {
|
|
198
|
-
rootDir = this.resolvePackageJsonPath();
|
|
199
|
-
} catch (error) {
|
|
200
|
-
throw new Error(`Error resolving package JSON path: ${error}`);
|
|
201
|
-
}
|
|
202
|
-
const tailwind = flags.tailwind ?? await this.resolveCSSFramework(rootDir);
|
|
203
|
-
if (isCancel(flags.type ?? await select({
|
|
204
|
-
message: "What you want to create?",
|
|
205
|
-
options: [
|
|
206
|
-
{
|
|
207
|
-
value: "block",
|
|
208
|
-
label: "Block"
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
value: "page",
|
|
212
|
-
label: "Page"
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
value: "theme",
|
|
216
|
-
label: "Theme"
|
|
217
|
-
}
|
|
218
|
-
],
|
|
219
|
-
initialValue: "block"
|
|
220
|
-
}))) process.exit(0);
|
|
221
|
-
const generateSpinner = flags.verbose ? spinner() : null;
|
|
222
|
-
const blocksDir = path.join(rootDir, "src/blocks");
|
|
223
|
-
const name = flags.name ?? await text({
|
|
224
|
-
message: "What is the name of the component?",
|
|
225
|
-
initialValue: "Starter Block",
|
|
226
|
-
validate(value) {
|
|
227
|
-
if (value.length === 0) return `Value is required!`;
|
|
228
|
-
}
|
|
229
|
-
});
|
|
230
|
-
if (isCancel(name)) this.exit(0);
|
|
231
|
-
const framework = await resolveFramework();
|
|
232
|
-
generateSpinner?.start();
|
|
233
|
-
generateSpinner?.message("Detecting package manager");
|
|
234
|
-
const packageManager = await detectPackageManager(rootDir);
|
|
235
|
-
if (!packageManager) throw new Error("Could not detect package manager");
|
|
236
|
-
if (flags.verbose) log.info("Package manager detected: " + packageManager.name);
|
|
237
|
-
generateSpinner?.message("Generating block");
|
|
238
|
-
await templateGenerator.generate(blocksDir, {
|
|
239
|
-
type: "block",
|
|
240
|
-
framework,
|
|
241
|
-
name,
|
|
242
|
-
tailwind,
|
|
243
|
-
logger: (msg) => generateSpinner?.message(msg),
|
|
244
|
-
story: true
|
|
245
|
-
});
|
|
246
|
-
templateGenerator.appendStylesheet(rootDir);
|
|
247
|
-
generateSpinner?.stop("Generated block");
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
//#endregion
|
|
252
|
-
export { BaseTemplateGenerator as n, Generate as t };
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ContextType,
|
|
3
|
-
createState,
|
|
4
|
-
effect,
|
|
5
|
-
injectContext,
|
|
6
|
-
provideContext,
|
|
7
|
-
Signal,
|
|
8
|
-
StateContext,
|
|
9
|
-
} from "@juo/orion-core";
|
|
10
|
-
|
|
11
|
-
const product1 = "https://placehold.co/600x400";
|
|
12
|
-
const product2 = "https://placehold.co/600x400";
|
|
13
|
-
const product3 = "https://placehold.co/600x400";
|
|
14
|
-
|
|
15
|
-
type State = ContextType<typeof StateContext>;
|
|
16
|
-
|
|
17
|
-
export function provideState(el: HTMLElement) {
|
|
18
|
-
provideContext(el, StateContext, createState());
|
|
19
|
-
|
|
20
|
-
const state = new Signal<State | null>(null);
|
|
21
|
-
|
|
22
|
-
setTimeout(() => {
|
|
23
|
-
const v = injectContext(el, StateContext);
|
|
24
|
-
state.value = v;
|
|
25
|
-
}, 0);
|
|
26
|
-
|
|
27
|
-
effect(() => {
|
|
28
|
-
if (state.value == null) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (state.value.products.value.length === 0) {
|
|
33
|
-
state.value.addProduct({
|
|
34
|
-
id: "p1",
|
|
35
|
-
name: "Hydrating Gel Cleanser for Face and Eye Area",
|
|
36
|
-
description: "150 ml bottle",
|
|
37
|
-
price: 12.49,
|
|
38
|
-
imageUrl: product1,
|
|
39
|
-
});
|
|
40
|
-
state.value.addProduct({
|
|
41
|
-
id: "p2",
|
|
42
|
-
name: "More COLLAGEN",
|
|
43
|
-
description: "blackcurrant",
|
|
44
|
-
price: 22.6,
|
|
45
|
-
imageUrl: product2,
|
|
46
|
-
});
|
|
47
|
-
state.value.addProduct({
|
|
48
|
-
id: "p3",
|
|
49
|
-
name: "Gentle deodorant for underarms and bust",
|
|
50
|
-
description: "Green tea and jasmine",
|
|
51
|
-
price: 6.7,
|
|
52
|
-
imageUrl: product3,
|
|
53
|
-
});
|
|
54
|
-
state.value.addProduct({
|
|
55
|
-
id: "gift",
|
|
56
|
-
name: "Free summer gift",
|
|
57
|
-
description: "",
|
|
58
|
-
price: 0.0,
|
|
59
|
-
imageUrl: product3,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (state.value.subscriptions.value.length === 0) {
|
|
64
|
-
state.value.addSubscription({
|
|
65
|
-
id: "s1",
|
|
66
|
-
items: [
|
|
67
|
-
{
|
|
68
|
-
id: "i1",
|
|
69
|
-
productId: "p1",
|
|
70
|
-
price: 12.49,
|
|
71
|
-
quantity: 2,
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
id: "i2",
|
|
75
|
-
productId: "p2",
|
|
76
|
-
price: 22.6,
|
|
77
|
-
quantity: 1,
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
status: "active",
|
|
81
|
-
nextDeliveryDate: "2025-08-15",
|
|
82
|
-
frequency: "Every 1 month",
|
|
83
|
-
quantity: 1,
|
|
84
|
-
createdAt: "2025-04-15",
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
state.value.addSubscription({
|
|
88
|
-
id: "s2",
|
|
89
|
-
items: [
|
|
90
|
-
{
|
|
91
|
-
id: "i1",
|
|
92
|
-
productId: "p3",
|
|
93
|
-
price: 12.49,
|
|
94
|
-
quantity: 2,
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
status: "active",
|
|
98
|
-
nextDeliveryDate: "2025-09-12",
|
|
99
|
-
frequency: "Every 3 months",
|
|
100
|
-
quantity: 1,
|
|
101
|
-
createdAt: "2024-04-22",
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
}
|