@promakeai/cli 0.4.9 → 0.4.10

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 (63) hide show
  1. package/dist/index.js +183 -176
  2. package/dist/registry/blog-core.json +26 -7
  3. package/dist/registry/blog-list-page.json +2 -2
  4. package/dist/registry/blog-section.json +1 -1
  5. package/dist/registry/cart-drawer.json +1 -1
  6. package/dist/registry/cart-page.json +1 -1
  7. package/dist/registry/category-section.json +1 -1
  8. package/dist/registry/checkout-page.json +1 -1
  9. package/dist/registry/contact-page-centered.json +1 -1
  10. package/dist/registry/contact-page-map-overlay.json +1 -1
  11. package/dist/registry/contact-page-map-split.json +1 -1
  12. package/dist/registry/contact-page-split.json +1 -1
  13. package/dist/registry/contact-page.json +1 -1
  14. package/dist/registry/db.json +129 -0
  15. package/dist/registry/docs/blog-core.md +13 -12
  16. package/dist/registry/docs/blog-list-page.md +1 -1
  17. package/dist/registry/docs/ecommerce-core.md +13 -10
  18. package/dist/registry/docs/featured-products.md +1 -1
  19. package/dist/registry/docs/post-detail-page.md +2 -2
  20. package/dist/registry/docs/product-detail-page.md +2 -2
  21. package/dist/registry/docs/products-page.md +1 -1
  22. package/dist/registry/ecommerce-core.json +25 -5
  23. package/dist/registry/featured-products.json +2 -2
  24. package/dist/registry/forgot-password-page-split.json +1 -1
  25. package/dist/registry/forgot-password-page.json +1 -1
  26. package/dist/registry/header-centered-pill.json +1 -1
  27. package/dist/registry/header-ecommerce.json +1 -1
  28. package/dist/registry/index.json +1 -0
  29. package/dist/registry/login-page-split.json +1 -1
  30. package/dist/registry/login-page.json +1 -1
  31. package/dist/registry/newsletter-section.json +1 -1
  32. package/dist/registry/post-card.json +1 -1
  33. package/dist/registry/post-detail-block.json +1 -1
  34. package/dist/registry/post-detail-page.json +3 -3
  35. package/dist/registry/product-card-detailed.json +1 -1
  36. package/dist/registry/product-card.json +1 -1
  37. package/dist/registry/product-detail-block.json +1 -1
  38. package/dist/registry/product-detail-page.json +3 -3
  39. package/dist/registry/product-detail-section.json +1 -1
  40. package/dist/registry/product-quick-view.json +1 -1
  41. package/dist/registry/products-page.json +2 -2
  42. package/dist/registry/register-page-split.json +1 -1
  43. package/dist/registry/register-page.json +1 -1
  44. package/dist/registry/related-products-block.json +1 -1
  45. package/dist/registry/reset-password-page-split.json +1 -1
  46. package/package.json +2 -4
  47. package/template/README.md +58 -39
  48. package/template/eslint.config.js +37 -37
  49. package/template/package.json +3 -4
  50. package/template/public/data/database.db +0 -0
  51. package/template/scripts/init-db.ts +126 -13
  52. package/template/src/App.tsx +5 -8
  53. package/template/src/PasswordInput.tsx +61 -0
  54. package/template/src/components/FormField.tsx +11 -5
  55. package/template/src/lang/index.ts +86 -86
  56. package/README.md +0 -71
  57. package/template/public/data/database.db-shm +0 -0
  58. package/template/public/data/database.db-wal +0 -0
  59. package/template/src/db/index.ts +0 -20
  60. package/template/src/db/provider.tsx +0 -77
  61. package/template/src/db/schema.json +0 -259
  62. package/template/src/db/types.ts +0 -195
  63. package/template/src/hooks/use-debounced-value.ts +0 -12
@@ -1,15 +1,17 @@
1
1
  import { Stack } from "./Stack";
2
2
  import { Label } from "./ui/label";
3
3
 
4
+ // FormField.tsx
4
5
  export interface FormFieldProps {
5
- label: string;
6
+ label: React.ReactNode;
6
7
  htmlFor?: string;
7
8
  error?: string;
8
9
  required?: boolean;
9
10
  description?: string;
10
11
  children: React.ReactNode;
11
- gap?: 0 | 1 | 2 | 3 | 4 | 6 | 8 | 10 | 12; // Stack gap override
12
+ gap?: 0 | 1 | 2 | 3 | 4 | 6 | 8 | 10 | 12;
12
13
  className?: string;
14
+ labelAction?: React.ReactNode; // YENİ
13
15
  }
14
16
 
15
17
  export function FormField({
@@ -21,12 +23,16 @@ export function FormField({
21
23
  description,
22
24
  gap = 2,
23
25
  className,
26
+ labelAction, // YENİ
24
27
  }: FormFieldProps) {
25
28
  return (
26
29
  <Stack gap={gap} className={className}>
27
- <Label htmlFor={htmlFor}>
28
- {label} {required && <span className="text-destructive">*</span>}
29
- </Label>
30
+ <div className="flex items-center justify-between">
31
+ <Label htmlFor={htmlFor}>
32
+ {label} {required && <span className="text-destructive">*</span>}
33
+ </Label>
34
+ {labelAction}
35
+ </div>
30
36
  {children}
31
37
  {description && (
32
38
  <p className="text-sm text-muted-foreground">
@@ -1,86 +1,86 @@
1
- import i18n from "i18next";
2
- import { initReactI18next } from "react-i18next";
3
- import LanguageDetector from "i18next-browser-languagedetector";
4
-
5
- import constants from "@/constants/constants.json";
6
-
7
- // Auto-import translations from two locations:
8
- // 1. Core: @/lang/{lang}/{namespace}.json (e.g., lang/en/header.json)
9
- // 2. Modules: @/modules/{namespace}/lang/{lang}.json (e.g., modules/about-page/lang/en.json)
10
- const coreLangs = import.meta.glob("@/lang/*/*.json", { eager: true });
11
- const moduleLangs = import.meta.glob("@/modules/*/lang/*.json", { eager: true });
12
-
13
- // Get available languages from config
14
- const availableLanguages =
15
- Object.keys(constants?.site?.availableLanguages || {}) || [];
16
-
17
- // Build resources object: { en: { header: {...}, about-page: {...} }, tr: {...} }
18
- const resources: Record<string, Record<string, any>> = {};
19
-
20
- // Process core translations: /lang/{lang}/{namespace}.json
21
- Object.entries(coreLangs).forEach(([path, module]) => {
22
- const match = path.match(/\/lang\/([^/]+)\/([^/]+)\.json$/);
23
- if (match) {
24
- const [, lang, namespace] = match;
25
- if (!availableLanguages.includes(lang)) return;
26
- if (!resources[lang]) resources[lang] = {};
27
- resources[lang][namespace] = (module as any).default || module;
28
- }
29
- });
30
-
31
- // Process module translations: /modules/{namespace}/lang/{lang}.json
32
- Object.entries(moduleLangs).forEach(([path, module]) => {
33
- const match = path.match(/\/modules\/([^/]+)\/lang\/([^/]+)\.json$/);
34
- if (match) {
35
- const [, namespace, lang] = match;
36
- if (!availableLanguages.includes(lang)) return;
37
- if (!resources[lang]) resources[lang] = {};
38
- resources[lang][namespace] = (module as any).default || module;
39
- }
40
- });
41
-
42
- // Custom detector for cached settings
43
- const settingsDetector = {
44
- name: "settingsDetector",
45
- lookup() {
46
- if (constants.site.overrideBrowserLanguage) {
47
- return constants?.site?.defaultLanguage;
48
- }
49
- return undefined;
50
- },
51
- cacheUserLanguage() {
52
- // Don't cache - settings detector is read-only
53
- },
54
- };
55
-
56
- // Create detector instance and add custom detector
57
- const languageDetector = new LanguageDetector();
58
- languageDetector.addDetector(settingsDetector);
59
-
60
- i18n
61
- .use(languageDetector)
62
- .use(initReactI18next)
63
- .init({
64
- resources,
65
- fallbackLng: constants?.site?.defaultLanguage || "en",
66
- supportedLngs: availableLanguages,
67
- detection: {
68
- // Priority: localStorage > settings > browser
69
- order: ["localStorage", "settingsDetector", "navigator"],
70
- lookupLocalStorage: "i18nextLng",
71
- caches: ["localStorage"],
72
- },
73
- interpolation: {
74
- escapeValue: false,
75
- },
76
- });
77
-
78
- // Helper to change language and persist to localStorage
79
- export const changeLanguage = (lang: string) => {
80
- if (availableLanguages.includes(lang)) {
81
- i18n.changeLanguage(lang);
82
- }
83
- };
84
-
85
- export { availableLanguages };
86
- export default i18n;
1
+ import i18n from "i18next";
2
+ import { initReactI18next } from "react-i18next";
3
+ import LanguageDetector from "i18next-browser-languagedetector";
4
+
5
+ import constants from "@/constants/constants.json";
6
+
7
+ // Auto-import translations from two locations:
8
+ // 1. Core: @/lang/{lang}/{namespace}.json (e.g., lang/en/header.json)
9
+ // 2. Modules: @/modules/{namespace}/lang/{lang}.json (e.g., modules/about-page/lang/en.json)
10
+ const coreLangs = import.meta.glob("@/lang/*/*.json", { eager: true });
11
+ const moduleLangs = import.meta.glob("@/modules/*/lang/*.json", { eager: true });
12
+
13
+ // Get available languages from config
14
+ const availableLanguages =
15
+ Object.keys(constants?.site?.availableLanguages || {}) || [];
16
+
17
+ // Build resources object: { en: { header: {...}, about-page: {...} }, tr: {...} }
18
+ const resources: Record<string, Record<string, any>> = {};
19
+
20
+ // Process core translations: /lang/{lang}/{namespace}.json
21
+ Object.entries(coreLangs).forEach(([path, module]) => {
22
+ const match = path.match(/\/lang\/([^/]+)\/([^/]+)\.json$/);
23
+ if (match) {
24
+ const [, lang, namespace] = match;
25
+ if (!availableLanguages.includes(lang)) return;
26
+ if (!resources[lang]) resources[lang] = {};
27
+ resources[lang][namespace] = (module as any).default || module;
28
+ }
29
+ });
30
+
31
+ // Process module translations: /modules/{namespace}/lang/{lang}.json
32
+ Object.entries(moduleLangs).forEach(([path, module]) => {
33
+ const match = path.match(/\/modules\/([^/]+)\/lang\/([^/]+)\.json$/);
34
+ if (match) {
35
+ const [, namespace, lang] = match;
36
+ if (!availableLanguages.includes(lang)) return;
37
+ if (!resources[lang]) resources[lang] = {};
38
+ resources[lang][namespace] = (module as any).default || module;
39
+ }
40
+ });
41
+
42
+ // Custom detector for cached settings
43
+ const settingsDetector = {
44
+ name: "settingsDetector",
45
+ lookup() {
46
+ if (constants.site.overrideBrowserLanguage) {
47
+ return constants?.site?.defaultLanguage;
48
+ }
49
+ return undefined;
50
+ },
51
+ cacheUserLanguage() {
52
+ // Don't cache - settings detector is read-only
53
+ },
54
+ };
55
+
56
+ // Create detector instance and add custom detector
57
+ const languageDetector = new LanguageDetector();
58
+ languageDetector.addDetector(settingsDetector);
59
+
60
+ i18n
61
+ .use(languageDetector)
62
+ .use(initReactI18next)
63
+ .init({
64
+ resources,
65
+ fallbackLng: constants?.site?.defaultLanguage || "en",
66
+ supportedLngs: availableLanguages,
67
+ detection: {
68
+ // Priority: localStorage > settings > browser
69
+ order: ["localStorage", "settingsDetector", "navigator"],
70
+ lookupLocalStorage: "i18nextLng",
71
+ caches: ["localStorage"],
72
+ },
73
+ interpolation: {
74
+ escapeValue: false,
75
+ },
76
+ });
77
+
78
+ // Helper to change language and persist to localStorage
79
+ export const changeLanguage = (lang: string) => {
80
+ if (availableLanguages.includes(lang)) {
81
+ i18n.changeLanguage(lang);
82
+ }
83
+ };
84
+
85
+ export { availableLanguages };
86
+ export default i18n;
package/README.md DELETED
@@ -1,71 +0,0 @@
1
- # @promakeai/cli
2
-
3
- Modular React template CLI (like shadcn/ui). Create React projects and add feature modules incrementally. Copies code directly into projects rather than installing as dependencies.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- # Install globally
9
- npm install -g @promakeai/cli
10
-
11
- # Create a new project
12
- promake create my-app --preset ecommerce --pm bun
13
-
14
- # Add modules to existing project
15
- promake add hero product-card
16
-
17
- # Theme customization
18
- promake theme --preset blue --radius medium
19
-
20
- # Health check
21
- promake doctor
22
- ```
23
-
24
- ## Commands
25
-
26
- | Command | Description |
27
- |---------|-------------|
28
- | `promake create <name>` | Scaffold a new React project |
29
- | `promake add <items...>` | Add modules, components, or pages |
30
- | `promake remove <modules...>` | Remove installed modules |
31
- | `promake sync` | Install missing modules from promake.json |
32
- | `promake theme` | Configure theme (colors, radius, fonts) |
33
- | `promake list` | Browse available modules |
34
- | `promake doctor` | Analyze project for issues |
35
- | `promake init` | Initialize promake.json |
36
- | `promake zip / unzip` | Archive utilities |
37
-
38
- ## Documentation
39
-
40
- - **[Docs Index](./docs/index.md)** - Full documentation hub
41
- - **[Workflow Guide](./docs/workflow.md)** - Branching, versioning & publish workflow
42
- - **[AI Agent Guide](./docs/ai-agent-guide.md)** - Integrating modules with DB + i18n
43
-
44
- ## Data Layer
45
-
46
- Projects generated by Promake include `@promakeai/dbreact` with a JSON schema
47
- (`src/db/schema.json`) and a prebuilt SQLite database (`public/data/database.db`).
48
- Use `@/db` hooks (`useDbList`, `useDbGet`, etc.) for data access.
49
-
50
- ## Development
51
-
52
- ```bash
53
- # Install dependencies
54
- bun install
55
-
56
- # Run from source
57
- bun run dev
58
-
59
- # Build
60
- bun run build
61
-
62
- # Test
63
- bun test
64
-
65
- # Type check
66
- bun run typecheck
67
- ```
68
-
69
- ## License
70
-
71
- MIT
File without changes
@@ -1,20 +0,0 @@
1
- export { AppDbProvider } from "./provider";
2
-
3
- import { parseJSONSchema } from "@promakeai/dbreact";
4
- import schemaJson from "./schema.json";
5
- export const schema = parseJSONSchema(schemaJson as any);
6
-
7
- export {
8
- useDb,
9
- useAdapter,
10
- useDbLang,
11
- useDbList,
12
- useDbGet,
13
- useDbCreate,
14
- useDbUpdate,
15
- useDbDelete,
16
- SqliteAdapter,
17
- parseJSONSchema,
18
- } from "@promakeai/dbreact";
19
-
20
- export * from "./types";
@@ -1,77 +0,0 @@
1
- import { useEffect, useState, type ReactNode } from "react";
2
- import { useTranslation } from "react-i18next";
3
- import { DbProvider, SqliteAdapter, parseJSONSchema } from "@promakeai/dbreact";
4
- import constants from "@/constants/constants.json";
5
- import schemaJson from "./schema.json";
6
-
7
- const schema = parseJSONSchema(schemaJson as any);
8
-
9
- interface AppDbProviderProps {
10
- children: ReactNode;
11
- }
12
-
13
- const DEFAULT_LANG = constants?.site?.defaultLanguage || "en";
14
-
15
- export function AppDbProvider({ children }: AppDbProviderProps) {
16
- const { i18n } = useTranslation();
17
- const [adapter, setAdapter] = useState<SqliteAdapter | null>(null);
18
- const [error, setError] = useState<Error | null>(null);
19
-
20
- useEffect(() => {
21
- let cancelled = false;
22
-
23
- async function loadDb() {
24
- try {
25
- const response = await fetch("/data/database.db");
26
- if (!response.ok) {
27
- throw new Error(
28
- `Failed to load database: ${response.status} ${response.statusText}`
29
- );
30
- }
31
-
32
- const buffer = await response.arrayBuffer();
33
- if (cancelled) return;
34
-
35
- const dbAdapter = new SqliteAdapter({
36
- schema,
37
- defaultLang: DEFAULT_LANG,
38
- });
39
-
40
- await dbAdapter.connect();
41
- await dbAdapter.import(new Uint8Array(buffer));
42
-
43
- if (!cancelled) {
44
- setAdapter(dbAdapter);
45
- }
46
- } catch (err) {
47
- if (!cancelled) {
48
- setError(err instanceof Error ? err : new Error(String(err)));
49
- }
50
- }
51
- }
52
-
53
- loadDb();
54
-
55
- return () => {
56
- cancelled = true;
57
- };
58
- }, []);
59
-
60
- if (error) {
61
- console.error(error);
62
- }
63
-
64
- if (!adapter) {
65
- return null;
66
- }
67
-
68
- return (
69
- <DbProvider
70
- adapter={adapter}
71
- lang={i18n?.language || DEFAULT_LANG}
72
- fallbackLang={DEFAULT_LANG}
73
- >
74
- {children}
75
- </DbProvider>
76
- );
77
- }
@@ -1,259 +0,0 @@
1
- {
2
- "name": "promake",
3
- "languages": [
4
- "en",
5
- "tr"
6
- ],
7
- "defaultLanguage": "en",
8
- "tables": {
9
- "blog_categories": {
10
- "id": {
11
- "type": "id"
12
- },
13
- "name": {
14
- "type": "string",
15
- "nullable": false,
16
- "translatable": true
17
- },
18
- "slug": {
19
- "type": "string",
20
- "nullable": false,
21
- "unique": true
22
- },
23
- "description": {
24
- "type": "text",
25
- "translatable": true
26
- },
27
- "image": {
28
- "type": "text"
29
- },
30
- "created_at": {
31
- "type": "timestamp"
32
- },
33
- "updated_at": {
34
- "type": "timestamp"
35
- }
36
- },
37
- "posts": {
38
- "id": {
39
- "type": "id"
40
- },
41
- "title": {
42
- "type": "string",
43
- "nullable": false,
44
- "translatable": true
45
- },
46
- "slug": {
47
- "type": "string",
48
- "nullable": false,
49
- "unique": true
50
- },
51
- "content": {
52
- "type": "text",
53
- "nullable": false,
54
- "translatable": true
55
- },
56
- "excerpt": {
57
- "type": "text",
58
- "translatable": true
59
- },
60
- "featured_image": {
61
- "type": "text"
62
- },
63
- "images": {
64
- "type": [
65
- "string"
66
- ]
67
- },
68
- "author": {
69
- "type": "string",
70
- "translatable": true
71
- },
72
- "author_avatar": {
73
- "type": "text"
74
- },
75
- "created_at": {
76
- "type": "timestamp"
77
- },
78
- "published_at": {
79
- "type": "timestamp"
80
- },
81
- "updated_at": {
82
- "type": "timestamp"
83
- },
84
- "tags": {
85
- "type": [
86
- "string"
87
- ]
88
- },
89
- "categories": {
90
- "type": [
91
- "number"
92
- ],
93
- "ref": "blog_categories"
94
- },
95
- "read_time": {
96
- "type": "int",
97
- "default": 0
98
- },
99
- "view_count": {
100
- "type": "int",
101
- "default": 0
102
- },
103
- "featured": {
104
- "type": "bool",
105
- "default": false
106
- },
107
- "published": {
108
- "type": "bool",
109
- "default": true
110
- },
111
- "meta_description": {
112
- "type": "text",
113
- "translatable": true
114
- },
115
- "meta_keywords": {
116
- "type": "text",
117
- "translatable": true
118
- }
119
- },
120
- "product_categories": {
121
- "id": {
122
- "type": "id"
123
- },
124
- "name": {
125
- "type": "string",
126
- "nullable": false,
127
- "translatable": true
128
- },
129
- "slug": {
130
- "type": "string",
131
- "nullable": false,
132
- "unique": true
133
- },
134
- "description": {
135
- "type": "text",
136
- "translatable": true
137
- },
138
- "image": {
139
- "type": "text"
140
- },
141
- "parent_id": {
142
- "type": "int",
143
- "ref": "product_categories"
144
- },
145
- "created_at": {
146
- "type": "timestamp"
147
- },
148
- "updated_at": {
149
- "type": "timestamp"
150
- }
151
- },
152
- "products": {
153
- "id": {
154
- "type": "id"
155
- },
156
- "name": {
157
- "type": "string",
158
- "nullable": false,
159
- "translatable": true
160
- },
161
- "slug": {
162
- "type": "string",
163
- "nullable": false,
164
- "unique": true
165
- },
166
- "description": {
167
- "type": "text",
168
- "translatable": true
169
- },
170
- "price": {
171
- "type": "decimal",
172
- "nullable": false
173
- },
174
- "sale_price": {
175
- "type": "decimal"
176
- },
177
- "on_sale": {
178
- "type": "bool",
179
- "default": false
180
- },
181
- "images": {
182
- "type": [
183
- "string"
184
- ]
185
- },
186
- "brand": {
187
- "type": "string",
188
- "translatable": true
189
- },
190
- "sku": {
191
- "type": "string"
192
- },
193
- "stock": {
194
- "type": "int",
195
- "default": 0
196
- },
197
- "tags": {
198
- "type": [
199
- "string"
200
- ]
201
- },
202
- "categories": {
203
- "type": [
204
- "number"
205
- ],
206
- "ref": "product_categories"
207
- },
208
- "rating": {
209
- "type": "decimal",
210
- "default": 0
211
- },
212
- "review_count": {
213
- "type": "int",
214
- "default": 0
215
- },
216
- "featured": {
217
- "type": "bool",
218
- "default": false
219
- },
220
- "is_new": {
221
- "type": "bool",
222
- "default": false
223
- },
224
- "published": {
225
- "type": "bool",
226
- "default": true
227
- },
228
- "specifications": {
229
- "type": "json"
230
- },
231
- "variants": {
232
- "type": [
233
- {
234
- "id": "string",
235
- "name": "string",
236
- "value": "string",
237
- "price?": "number",
238
- "image?": "string",
239
- "stockQuantity": "number"
240
- }
241
- ]
242
- },
243
- "created_at": {
244
- "type": "timestamp"
245
- },
246
- "updated_at": {
247
- "type": "timestamp"
248
- },
249
- "meta_description": {
250
- "type": "text",
251
- "translatable": true
252
- },
253
- "meta_keywords": {
254
- "type": "text",
255
- "translatable": true
256
- }
257
- }
258
- }
259
- }