@emberkit/cli 0.5.2 → 0.6.1-alpha.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.
Files changed (47) hide show
  1. package/dist/cli.js +44 -10
  2. package/dist/commands/create.js +10 -21
  3. package/dist/templates/action/index.js +12 -0
  4. package/dist/templates/action.js +12 -0
  5. package/dist/templates/api/api.js +280 -0
  6. package/dist/templates/apiRoute/index.js +20 -0
  7. package/dist/templates/apiRoute.js +20 -0
  8. package/dist/templates/blog/blog.js +358 -0
  9. package/dist/templates/component/index.js +14 -0
  10. package/dist/templates/component.js +14 -0
  11. package/dist/templates/config/index.js +13 -0
  12. package/dist/templates/config.js +13 -0
  13. package/dist/templates/context/index.js +21 -0
  14. package/dist/templates/context.js +21 -0
  15. package/dist/templates/dashboard/dashboard.js +406 -0
  16. package/dist/templates/entry/index.js +15 -0
  17. package/dist/templates/entry.js +15 -0
  18. package/dist/templates/errorBoundary/index.js +17 -0
  19. package/dist/templates/errorBoundary.js +17 -0
  20. package/dist/templates/form/index.js +59 -0
  21. package/dist/templates/form.js +59 -0
  22. package/dist/templates/index.js +0 -260
  23. package/dist/templates/layout/index.js +16 -0
  24. package/dist/templates/layout.js +16 -0
  25. package/dist/templates/layoutRoutes/index.js +9 -0
  26. package/dist/templates/layoutRoutes.js +9 -0
  27. package/dist/templates/loader/index.js +10 -0
  28. package/dist/templates/loader.js +10 -0
  29. package/dist/templates/minimal/minimal.js +89 -0
  30. package/dist/templates/project-templates/_shared/base.js +139 -0
  31. package/dist/templates/project-templates/api/api.js +209 -0
  32. package/dist/templates/project-templates/blog/blog.js +283 -0
  33. package/dist/templates/project-templates/dashboard/dashboard.js +331 -0
  34. package/dist/templates/project-templates/minimal/minimal.js +21 -0
  35. package/dist/templates/project-templates/saas/saas.js +461 -0
  36. package/dist/templates/project-templates/starter-kit/starter.js +209 -0
  37. package/dist/templates/project-templates/starter-kit/with-ui.js +365 -0
  38. package/dist/templates/projects/starter.js +286 -0
  39. package/dist/templates/projects/with-ui.js +445 -0
  40. package/dist/templates/projects.js +419 -191
  41. package/dist/templates/route/index.js +12 -0
  42. package/dist/templates/route.js +12 -0
  43. package/dist/templates/saas/saas.js +539 -0
  44. package/dist/templates/signal/index.js +25 -0
  45. package/dist/templates/signal.js +25 -0
  46. package/dist/utils/generator.js +30 -2
  47. package/package.json +1 -2
@@ -0,0 +1,358 @@
1
+ export const blogTemplate = {
2
+ "package.json": `{
3
+ "name": "{{name}}",
4
+ "version": "0.1.0",
5
+ "private": true,
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "emberkit dev",
9
+ "build": "emberkit build",
10
+ "preview": "emberkit preview"
11
+ },
12
+ "dependencies": {
13
+ "@emberkit/core": "^0.2.4"
14
+ },
15
+ "devDependencies": {
16
+ "@emberkit/cli": "^0.2.4",
17
+ "typescript": "^5.7.0",
18
+ "vite": "^6.0.0",
19
+ "tailwindcss": "^4.0.0",
20
+ "@tailwindcss/vite": "^4.0.0"
21
+ }
22
+ }`,
23
+ "tsconfig.json": `{
24
+ "compilerOptions": {
25
+ "target": "ES2022",
26
+ "module": "ESNext",
27
+ "moduleResolution": "bundler",
28
+ "jsx": "react-jsx",
29
+ "jsxImportSource": "@emberkit/core",
30
+ "strict": true,
31
+ "esModuleInterop": true,
32
+ "skipLibCheck": true,
33
+ "forceConsistentCasingInFileNames": true,
34
+ "resolveJsonModule": true,
35
+ "isolatedModules": true,
36
+ "noEmit": true,
37
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
38
+ "paths": {
39
+ "@/*": ["./src/*"]
40
+ }
41
+ },
42
+ "include": ["src"],
43
+ "exclude": ["node_modules", "dist"]
44
+ }`,
45
+ "vite.config.ts": `import { defineConfig } from 'vite';
46
+ import { emberkitVitePlugin } from '@emberkit/core/vite-plugin';
47
+ import tailwindcss from '@tailwindcss/vite';
48
+
49
+ export default defineConfig({
50
+ plugins: [emberkitVitePlugin(), tailwindcss()],
51
+ server: {
52
+ port: 3000,
53
+ host: 'localhost',
54
+ },
55
+ esbuild: {
56
+ jsxImportSource: '@emberkit/core',
57
+ },
58
+ });`,
59
+ "index.html": `<!DOCTYPE html>
60
+ <html lang="en">
61
+ <head>
62
+ <meta charset="UTF-8">
63
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
64
+ <title>{{name}}</title>
65
+ <link rel="preconnect" href="https://fonts.googleapis.com">
66
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
67
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Merriweather:wght@400;700&display=swap" rel="stylesheet">
68
+ </head>
69
+ <body id="app">
70
+ <script type="module" src="/src/index.tsx"></script>
71
+ </body>
72
+ </html>`,
73
+ "src/index.tsx": `import { render } from '@emberkit/core';
74
+ import { routes } from 'virtual:emberkit-routes';
75
+ import App from './routes/_layout';
76
+ import './styles.css';
77
+
78
+ const root = document.getElementById('app');
79
+
80
+ if (root) {
81
+ try {
82
+ render(App, root, { routes });
83
+ } catch (error) {
84
+ console.error('[entry] Render error:', error);
85
+ }
86
+ }`,
87
+ "src/styles.css": `@import "tailwindcss";
88
+
89
+ @theme {
90
+ --font-serif: 'Merriweather', Georgia, serif;
91
+ --font-sans: 'Inter', system-ui, sans-serif;
92
+ }
93
+
94
+ body {
95
+ @apply bg-white text-gray-900 font-sans;
96
+ }
97
+
98
+ .prose {
99
+ @apply max-w-none;
100
+ }
101
+
102
+ .prose h1, .prose h2, .prose h3 {
103
+ @apply font-serif font-bold;
104
+ }
105
+
106
+ .prose p {
107
+ @apply leading-relaxed;
108
+ }
109
+
110
+ .prose a {
111
+ @apply text-blue-600 no-underline hover:underline;
112
+ }
113
+
114
+ .prose code {
115
+ @apply bg-gray-100 px-1.5 py-0.5 rounded text-sm font-mono;
116
+ }
117
+
118
+ .prose pre {
119
+ @apply bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto;
120
+ }
121
+
122
+ .prose pre code {
123
+ @apply bg-transparent p-0 text-sm;
124
+ }
125
+
126
+ .prose blockquote {
127
+ @apply border-l-4 border-gray-300 pl-4 italic text-gray-600;
128
+ }
129
+
130
+ .prose img {
131
+ @apply rounded-lg;
132
+ }
133
+
134
+ .prose ul {
135
+ @apply list-disc pl-6;
136
+ }
137
+
138
+ .prose ol {
139
+ @apply list-decimal pl-6;
140
+ }`,
141
+ "src/routes/_layout.tsx": `import type { RouteComponent } from '@emberkit/core';
142
+ import { Head } from '@emberkit/core';
143
+
144
+ const Layout: RouteComponent = ({ children }) => {
145
+ return (
146
+ <>
147
+ <Head>
148
+ <title>{{name}}</title>
149
+ <meta name="description" content="A minimal blog built with EmberKit" />
150
+ </Head>
151
+ <div className="min-h-screen flex flex-col">
152
+ <header className="border-b border-gray-200">
153
+ <div className="max-w-3xl mx-auto px-6 py-6 flex items-center justify-between">
154
+ <a href="/" className="text-xl font-bold font-serif">{{name}}</a>
155
+ <nav className="flex gap-6 text-sm text-gray-600">
156
+ <a href="/" className="hover:text-gray-900">Posts</a>
157
+ <a href="/about" className="hover:text-gray-900">About</a>
158
+ </nav>
159
+ </div>
160
+ </header>
161
+ <main className="flex-1">{children}</main>
162
+ <footer className="border-t border-gray-200 py-8 text-center text-sm text-gray-500">
163
+ <p>Built with <a href="https://emberkit.dev" className="text-gray-700 hover:underline">EmberKit</a></p>
164
+ </footer>
165
+ </div>
166
+ </>
167
+ );
168
+ };
169
+
170
+ export default Layout;`,
171
+ "src/routes/index.tsx": `import type { RouteComponent } from '@emberkit/core';
172
+
173
+ interface Post {
174
+ slug: string;
175
+ title: string;
176
+ excerpt: string;
177
+ date: string;
178
+ readTime: string;
179
+ }
180
+
181
+ const posts: Post[] = [
182
+ {
183
+ slug: 'getting-started',
184
+ title: 'Getting Started with EmberKit',
185
+ excerpt: 'Learn how to build your first project with EmberKit, a minimalist TypeScript-first JSX framework.',
186
+ date: '2026-05-14',
187
+ readTime: '5 min read',
188
+ },
189
+ {
190
+ slug: 'signals-deep-dive',
191
+ title: 'Signals: A Deep Dive',
192
+ excerpt: 'Understanding reactive signals and how they power the EmberKit runtime.',
193
+ date: '2026-05-10',
194
+ readTime: '8 min read',
195
+ },
196
+ {
197
+ slug: 'file-based-routing',
198
+ title: 'File-Based Routing Explained',
199
+ excerpt: 'How EmberKit automatically creates routes from your file structure.',
200
+ date: '2026-05-05',
201
+ readTime: '4 min read',
202
+ },
203
+ ];
204
+
205
+ const HomePage: RouteComponent = () => {
206
+ return (
207
+ <div className="max-w-3xl mx-auto px-6 py-12">
208
+ <div className="mb-12">
209
+ <h1 className="text-4xl font-bold font-serif mb-4">Latest Posts</h1>
210
+ <p className="text-gray-600 text-lg">Thoughts, tutorials, and updates.</p>
211
+ </div>
212
+ <div className="space-y-10">
213
+ {posts.map((post) => (
214
+ <article key={post.slug} className="group">
215
+ <a href={\`/posts/\${post.slug}\`} className="block">
216
+ <h2 className="text-xl font-semibold font-serif mb-2 group-hover:text-blue-600 transition-colors">
217
+ {post.title}
218
+ </h2>
219
+ <p className="text-gray-600 mb-3">{post.excerpt}</p>
220
+ <div className="flex gap-3 text-sm text-gray-500">
221
+ <time>{post.date}</time>
222
+ <span>&middot;</span>
223
+ <span>{post.readTime}</span>
224
+ </div>
225
+ </a>
226
+ </article>
227
+ ))}
228
+ </div>
229
+ </div>
230
+ );
231
+ };
232
+
233
+ export default HomePage;`,
234
+ "src/routes/[slug].tsx": `import type { RouteComponent, RouteParams } from '@emberkit/core';
235
+ import { Head } from '@emberkit/core';
236
+
237
+ interface PostData {
238
+ title: string;
239
+ date: string;
240
+ author: string;
241
+ content: string;
242
+ }
243
+
244
+ const posts: Record<string, PostData> = {
245
+ 'getting-started': {
246
+ title: 'Getting Started with EmberKit',
247
+ date: 'May 14, 2026',
248
+ author: 'Author Name',
249
+ content: \`
250
+ <p>EmberKit is a minimalist TypeScript-first JSX framework built for speed and simplicity.</p>
251
+ <h2>Installation</h2>
252
+ <p>Get started by creating a new project:</p>
253
+ <pre><code>npm create emberkit@latest my-app</code></pre>
254
+ <h2>Project Structure</h2>
255
+ <p>Your routes live in the \`src/routes\` directory. Each file automatically becomes a route.</p>
256
+ <h2>Development</h2>
257
+ <p>Run the dev server with hot module replacement:</p>
258
+ <pre><code>emberkit dev</code></pre>
259
+ \`,
260
+ },
261
+ 'signals-deep-dive': {
262
+ title: 'Signals: A Deep Dive',
263
+ date: 'May 10, 2026',
264
+ author: 'Author Name',
265
+ content: \`
266
+ <p>Signals are the reactive primitive at the core of EmberKit.</p>
267
+ <h2>Creating Signals</h2>
268
+ <pre><code>const count = signal(0);</code></pre>
269
+ <h2>Computed Values</h2>
270
+ <pre><code>const doubled = computed(() => count.value * 2);</code></pre>
271
+ <h2>Side Effects</h2>
272
+ <pre><code>effect(() => console.log(count.value));</code></pre>
273
+ \`,
274
+ },
275
+ 'file-based-routing': {
276
+ title: 'File-Based Routing Explained',
277
+ date: 'May 5, 2026',
278
+ author: 'Author Name',
279
+ content: \`
280
+ <p>EmberKit uses file-based routing, meaning your file structure defines your routes.</p>
281
+ <h2>Basic Routes</h2>
282
+ <p>\`src/routes/index.tsx\` becomes \`/\`</p>
283
+ <p>\`src/routes/about.tsx\` becomes \`/about\`</p>
284
+ <h2>Dynamic Routes</h2>
285
+ <p>\`src/routes/[slug].tsx\` becomes \`/:slug\`</p>
286
+ \`,
287
+ },
288
+ };
289
+
290
+ interface Params {
291
+ slug: string;
292
+ }
293
+
294
+ const PostPage: RouteComponent<Params> = ({ params }) => {
295
+ const post = posts[params.slug];
296
+
297
+ if (!post) {
298
+ return (
299
+ <div className="max-w-3xl mx-auto px-6 py-12 text-center">
300
+ <h1 className="text-2xl font-bold mb-4">Post not found</h1>
301
+ <a href="/" className="text-blue-600 hover:underline">← Back to posts</a>
302
+ </div>
303
+ );
304
+ }
305
+
306
+ return (
307
+ <>
308
+ <Head>
309
+ <title>{post.title} - {{name}}</title>
310
+ <meta name="description" content={post.title} />
311
+ </Head>
312
+ <article className="max-w-3xl mx-auto px-6 py-12">
313
+ <header className="mb-10">
314
+ <h1 className="text-4xl font-bold font-serif mb-4">{post.title}</h1>
315
+ <div className="flex gap-3 text-sm text-gray-500">
316
+ <time>{post.date}</time>
317
+ <span>&middot;</span>
318
+ <span>By {post.author}</span>
319
+ </div>
320
+ </header>
321
+ <div className="prose" dangerouslySetInnerHTML={{ __html: post.content }} />
322
+ <div className="mt-12 pt-8 border-t border-gray-200">
323
+ <a href="/" className="text-blue-600 hover:underline">← Back to posts</a>
324
+ </div>
325
+ </article>
326
+ </>
327
+ );
328
+ };
329
+
330
+ export default PostPage;`,
331
+ "src/routes/about.tsx": `import type { RouteComponent } from '@emberkit/core';
332
+ import { Head } from '@emberkit/core';
333
+
334
+ const AboutPage: RouteComponent = () => {
335
+ return (
336
+ <>
337
+ <Head>
338
+ <title>About - {{name}}</title>
339
+ </Head>
340
+ <div className="max-w-3xl mx-auto px-6 py-12">
341
+ <h1 className="text-4xl font-bold font-serif mb-6">About</h1>
342
+ <div className="prose">
343
+ <p>Hi, I'm the author of this blog. I write about web development, frameworks, and building fast user interfaces.</p>
344
+ <p>This blog is built with <a href="https://emberkit.dev">EmberKit</a>, a minimalist TypeScript-first JSX framework.</p>
345
+ <h2>Tech Stack</h2>
346
+ <ul>
347
+ <li>EmberKit for routing and rendering</li>
348
+ <li>Tailwind CSS for styling</li>
349
+ <li>File-based routing</li>
350
+ </ul>
351
+ </div>
352
+ </div>
353
+ </>
354
+ );
355
+ };
356
+
357
+ export default AboutPage;`,
358
+ };
@@ -0,0 +1,14 @@
1
+ export const componentTemplate = `interface {{name}}Props {
2
+ className?: string;
3
+ }
4
+
5
+ const {{name}} = ({ className = '' }: {{name}}Props) => {
6
+ return (
7
+ <div className={className}>
8
+ {{name}} component
9
+ </div>
10
+ );
11
+ };
12
+
13
+ export default {{name}};
14
+ `;
@@ -0,0 +1,14 @@
1
+ export const componentTemplate = `interface {{name}}Props {
2
+ className?: string;
3
+ }
4
+
5
+ const {{name}} = ({ className = '' }: {{name}}Props) => {
6
+ return (
7
+ <div className={className}>
8
+ {{name}} component
9
+ </div>
10
+ );
11
+ };
12
+
13
+ export default {{name}};
14
+ `;
@@ -0,0 +1,13 @@
1
+ export const configTemplate = `import { defineConfig } from '@emberkit/core';
2
+
3
+ export default defineConfig({
4
+ mode: 'hybrid',
5
+ server: {
6
+ port: 3000,
7
+ },
8
+ build: {
9
+ outDir: 'dist',
10
+ target: 'esnext',
11
+ },
12
+ });
13
+ `;
@@ -0,0 +1,13 @@
1
+ export const configTemplate = `import { defineConfig } from '@emberkit/core';
2
+
3
+ export default defineConfig({
4
+ mode: 'hybrid',
5
+ server: {
6
+ port: 3000,
7
+ },
8
+ build: {
9
+ outDir: 'dist',
10
+ target: 'esnext',
11
+ },
12
+ });
13
+ `;
@@ -0,0 +1,21 @@
1
+ export const contextTemplate = `import { createContext, useContext } from '@emberkit/core';
2
+
3
+ interface {{name}}Context {
4
+ // Define your context shape
5
+ value: string;
6
+ }
7
+
8
+ const {{name}}Context = createContext<{{name}}Context>({
9
+ value: 'default',
10
+ });
11
+
12
+ // Provider usage:
13
+ // <{{name}}Context.Provider value={{ value: 'hello' }}>
14
+ // {children}
15
+ // </{{name}}Context.Provider>
16
+
17
+ // Consumer usage:
18
+ // const ctx = useContext({{name}}Context);
19
+
20
+ export { {{name}}Context };
21
+ `;
@@ -0,0 +1,21 @@
1
+ export const contextTemplate = `import { createContext, useContext } from '@emberkit/core';
2
+
3
+ interface {{name}}Context {
4
+ // Define your context shape
5
+ value: string;
6
+ }
7
+
8
+ const {{name}}Context = createContext<{{name}}Context>({
9
+ value: 'default',
10
+ });
11
+
12
+ // Provider usage:
13
+ // <{{name}}Context.Provider value={{ value: 'hello' }}>
14
+ // {children}
15
+ // </{{name}}Context.Provider>
16
+
17
+ // Consumer usage:
18
+ // const ctx = useContext({{name}}Context);
19
+
20
+ export { {{name}}Context };
21
+ `;