create-gardener 2.0.8 → 2.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.
Files changed (82) hide show
  1. package/README.md +328 -140
  2. package/package.json +1 -1
  3. package/template/build/backend/controllers/gardener/addComponent.d.ts +8 -0
  4. package/template/build/backend/controllers/gardener/addComponent.d.ts.map +1 -0
  5. package/template/build/backend/controllers/gardener/addComponent.js +19 -0
  6. package/template/build/backend/controllers/gardener/addComponent.js.map +1 -0
  7. package/template/build/backend/controllers/gardener/addPage.d.ts +3 -0
  8. package/template/build/backend/controllers/gardener/addPage.d.ts.map +1 -0
  9. package/template/build/backend/controllers/gardener/addPage.js +76 -0
  10. package/template/build/backend/controllers/gardener/addPage.js.map +1 -0
  11. package/template/build/backend/controllers/gardener/createStatic.d.ts +3 -0
  12. package/template/build/backend/controllers/gardener/createStatic.d.ts.map +1 -0
  13. package/template/build/backend/controllers/gardener/createStatic.js +61 -0
  14. package/template/build/backend/controllers/gardener/createStatic.js.map +1 -0
  15. package/template/build/backend/controllers/gardener/imageOptimiser.d.ts +3 -0
  16. package/template/build/backend/controllers/gardener/imageOptimiser.d.ts.map +1 -0
  17. package/template/build/backend/controllers/gardener/imageOptimiser.js +54 -0
  18. package/template/build/backend/controllers/gardener/imageOptimiser.js.map +1 -0
  19. package/template/build/backend/controllers/gardener/index.d.ts +6 -0
  20. package/template/build/backend/controllers/gardener/index.d.ts.map +1 -0
  21. package/template/build/backend/controllers/gardener/index.js +6 -0
  22. package/template/build/backend/controllers/gardener/index.js.map +1 -0
  23. package/template/build/backend/controllers/gardener/saveTemplate.d.ts +3 -0
  24. package/template/build/backend/controllers/gardener/saveTemplate.d.ts.map +1 -0
  25. package/template/build/backend/controllers/gardener/saveTemplate.js +36 -0
  26. package/template/build/backend/controllers/gardener/saveTemplate.js.map +1 -0
  27. package/template/build/backend/libs/generateWebp.d.ts +2 -0
  28. package/template/build/backend/libs/generateWebp.d.ts.map +1 -0
  29. package/template/build/backend/libs/generateWebp.js +18 -0
  30. package/template/build/backend/libs/generateWebp.js.map +1 -0
  31. package/template/build/backend/routes/gardener.route.d.ts +4 -0
  32. package/template/build/backend/routes/gardener.route.d.ts.map +1 -0
  33. package/template/build/backend/routes/gardener.route.js +13 -0
  34. package/template/build/backend/routes/gardener.route.js.map +1 -0
  35. package/template/build/backend/server.d.ts +2 -0
  36. package/template/build/backend/server.d.ts.map +1 -0
  37. package/template/build/backend/server.js +20 -0
  38. package/template/build/backend/server.js.map +1 -0
  39. package/template/build/frontend/assets/favicon.png +0 -0
  40. package/template/build/frontend/assets/gardener.jpg +0 -0
  41. package/template/build/frontend/static/cache/favicon_500x500.webp +0 -0
  42. package/template/build/frontend/static/cache/favicon_50x50.webp +0 -0
  43. package/template/build/frontend/static/cache/gardener_500x500.webp +0 -0
  44. package/template/build/frontend/static/cache/gardener_50x50.webp +0 -0
  45. package/template/build/frontend/static/components/copybtn.js +86 -0
  46. package/template/build/frontend/static/components/nonui/api.js +39 -0
  47. package/template/build/frontend/static/components/nonui/navigation.js +59 -0
  48. package/template/build/frontend/static/components/notification.js +67 -0
  49. package/template/build/frontend/static/gardener.js +89 -0
  50. package/template/build/frontend/static/gardener.test.js +364 -0
  51. package/template/build/frontend/static/gardenerConfig.js +1 -0
  52. package/template/build/frontend/static/gardenerDev.js +499 -0
  53. package/template/build/frontend/static/global.js +4 -0
  54. package/template/build/frontend/static/pages/pages._.js +20 -0
  55. package/template/build/frontend/static/style.css +2 -0
  56. package/template/build/frontend/static/style2.css +26 -0
  57. package/template/build/frontend/static/zod.js +8 -0
  58. package/template/build/frontend/style.css +1045 -0
  59. package/template/build/frontend/tailwind.css +1 -0
  60. package/template/build/frontend/views/_.ejs +121 -0
  61. package/template/build/frontend/views/partials/icons/clipboard.ejs +1 -0
  62. package/template/build/frontend/views/partials/icons/clipboardok.ejs +1 -0
  63. package/template/src/backend/controllers/gardener/addPage.ts +30 -24
  64. package/template/src/backend/controllers/gardener/createStatic.ts +1 -0
  65. package/template/src/backend/controllers/gardener/saveTemplate.ts +1 -1
  66. package/template/src/backend/libs/generateWebp.ts +0 -2
  67. package/template/src/frontend/static/cache/gardener_100x100.webp +0 -0
  68. package/template/src/frontend/static/components/copybtn.js +16 -3
  69. package/template/src/frontend/static/components/footer.js +33 -0
  70. package/template/src/frontend/static/components/gardener/errorBox.js +47 -0
  71. package/template/src/frontend/static/components/gardener/hotReloadbtn.js +82 -0
  72. package/template/src/frontend/static/components/gardener/pageOverlayBtn.js +138 -0
  73. package/template/src/frontend/static/components/gardener/parserWindow.js +159 -0
  74. package/template/src/frontend/static/components/nonui/api.js +15 -2
  75. package/template/src/frontend/static/gardener.js +129 -58
  76. package/template/src/frontend/static/gardenerDev.js +65 -399
  77. package/template/src/frontend/static/global.js +1 -1
  78. package/template/src/frontend/static/pages/pages._.js +5 -0
  79. package/template/src/frontend/static/style.css +101 -1
  80. package/template/src/frontend/static/style2.css +2 -2
  81. package/template/src/frontend/static/pages/pages._al.js +0 -2
  82. package/template/src/frontend/static/pages/pages._new.js +0 -2
package/README.md CHANGED
@@ -1,187 +1,375 @@
1
- # Gardener Web Application Template
1
+ # 🌱 Gardener
2
2
 
3
- A modern full-stack web application template created with **create-gardener**. This project provides a production-ready setup with TypeScript, Express.js backend, EJS templating, and Tailwind CSS for styling.
3
+ A full-stack web framework that combines Express.js backend with EJS templating and a unique DOM-to-JSON component system. Build web apps with a visual-first approach where you can convert any DOM element into reusable components with a single function call.
4
4
 
5
- ## 🚀 Features
5
+ ## 🚀 Quick Start
6
6
 
7
- - **TypeScript Backend** - Type-safe Express.js server with modern ES modules
8
- - **EJS Templating** - Server-side rendering with EJS view engine
9
- - **Tailwind CSS** - Utility-first CSS framework with JIT compilation
10
- - **Hot Reload Development** - Live reload for both backend and frontend during development
11
- - **Production Ready** - Optimized build process with minification
12
- - **Testing Setup** - Jest configuration for unit and integration tests
13
- - **Image Processing** - Sharp integration for image optimization
14
- - **Validation** - Zod schema validation
15
- - **Environment Configuration** - dotenv support for environment variables
7
+ Create a new Gardener app:
16
8
 
17
- ## 📋 Prerequisites
18
-
19
- - Node.js (v18 or higher recommended)
20
- - pnpm (preferred) or npm
9
+ ```bash
10
+ pnpm create gardener app
11
+ ```
21
12
 
22
- ## 🛠️ Installation
13
+ Install dependencies and start development:
23
14
 
24
15
  ```bash
25
- # Install dependencies
26
16
  pnpm install
27
- # or
28
- npm install
17
+ pnpm dev
29
18
  ```
30
19
 
31
- ## 🏃 Getting Started
20
+ Your app will be running with hot reload enabled!
32
21
 
33
- ### Development Mode
22
+ ## 🌟 Core Features
34
23
 
35
- Start the development server with hot reload:
24
+ ### Backend
25
+ - **Express.js**: Familiar Node.js backend with full Express capabilities
26
+ - **TypeScript Ready**: Built-in TypeScript support for type-safe development
27
+ - **Static Site Generation**: Export your dynamic app to static HTML with one API call
36
28
 
37
- ```bash
38
- pnpm dev
39
- # or
40
- npm run dev
29
+ ### Frontend
30
+ - **EJS Templating**: Server-side rendering with EJS views
31
+ - **Tailwind CSS**: Integrated with watch mode for rapid styling
32
+ - **Gardener Component System**: Unique DOM-to-JSON conversion for reusable components
33
+ - **Live Development Tools**: Browser-based route and component creation
34
+
35
+ ### Developer Experience
36
+ - **Hot Reload**: Toggle with `Alt + H` for instant CSS updates
37
+ - **Visual Component Parser**: Convert DOM elements to JSON components in the browser
38
+ - **Browser-Based Routing**: Create new routes without touching your code
39
+ - **Image Optimization**: Automatic WebP conversion with smart sizing
40
+
41
+ ## 📖 Complete Workflow
42
+
43
+ ### 1. Backend Development
44
+
45
+ Write familiar Express.js code in TypeScript:
46
+
47
+ ```typescript
48
+ // src/backend/server.ts
49
+ app.get('/api/posts', (req, res) => {
50
+ res.json({ posts: [] });
51
+ });
41
52
  ```
42
53
 
43
- This will:
44
- - Start the TypeScript backend server with watch mode on port 3000 (or PORT from .env)
45
- - Run Tailwind CSS in watch mode for live style updates
54
+ ### 2. Creating Pages & Routes
46
55
 
47
- ### Production Build
56
+ **Two ways to create routes:**
48
57
 
49
- Build the application for production:
58
+ #### Browser Method (Recommended for Development)
59
+ 1. Click the "**New Page**" button that appears in development mode
60
+ 2. Enter your route path (e.g., `/about`, `/blog/post`)
61
+ 3. Press Enter - the route and EJS file are created automatically!
50
62
 
51
- ```bash
52
- pnpm build
53
- # or
54
- npm run build
63
+ #### Manual Method
64
+ Create an EJS file in `src/frontend/views/` and add the Express route manually.
65
+
66
+ ### 3. Working with Components
67
+
68
+ Gardener has **two component types**:
69
+
70
+ #### A. EJS Partials (Traditional)
71
+ Static components that render once:
72
+ ```ejs
73
+ <%- include('partials/header') %>
55
74
  ```
56
75
 
57
- This will:
58
- 1. Compile and minify Tailwind CSS
59
- 2. Transpile TypeScript to JavaScript
60
- 3. Copy frontend assets to the build directory
61
- 4. Generate production configuration
76
+ #### B. Gardener Components (Dynamic)
77
+ JSON-based components with the Gardener system:
78
+
79
+ **Creating a Component:**
80
+ 1. Write your HTML structure in an EJS file or browser
81
+ 2. In your JavaScript file, call:
82
+ ```javascript
83
+ import { parser } from '/static/gardenerDev.js';
84
+
85
+ parser('.my-component-selector');
86
+ ```
87
+ 3. A window appears in the browser with the JSON representation
88
+ 4. Name and save the component
89
+ 5. The component is now reusable!
90
+
91
+ **Using a Component:**
92
+ ```javascript
93
+ import { myComponent } from '/static/components/myComponent.js';
94
+ import { gardener, appendElement } from '/static/gardener.js';
95
+
96
+ // Render the component
97
+ const element = gardener(myComponent);
98
+ appendElement('#container', element);
99
+ ```
62
100
 
63
- ### Start Production Server
101
+ **Component Structure:**
102
+ ```javascript
103
+ // Gardener components are JSON objects
104
+ export const button = {
105
+ t: 'button', // tag
106
+ cn: ['btn', 'primary'], // classNames
107
+ txt: 'Click me', // text content
108
+ attr: { id: 'submit' }, // attributes
109
+ events: { click: handleClick }, // event handlers
110
+ children: [...] // nested components
111
+ };
112
+ ```
64
113
 
65
- ```bash
66
- pnpm start
67
- # or
68
- npm start
114
+ ### 4. Parameterized Components
115
+
116
+ Create dynamic components with parameters using `??`:
117
+
118
+ ```javascript
119
+ // In your component definition, wrap dynamic parts with ??
120
+ const card = {
121
+ t: 'div',
122
+ cn: ['card'],
123
+ children: [
124
+ { t: 'h2', txt: '??title??' },
125
+ { t: 'p', txt: '??description??' }
126
+ ]
127
+ };
128
+
129
+ // Use with parameters
130
+ const myCard = gardener(card, {
131
+ title: 'Hello',
132
+ description: 'World'
133
+ });
69
134
  ```
70
135
 
71
- Runs the compiled production build from the `build` directory.
136
+ ### 5. Template System
72
137
 
73
- ** Refer to docs.md for full docs **
138
+ **Save Current Page as Template:**
139
+ - Click "**Save Template**" button in the browser
140
+ - This saves the current page structure as a template
141
+ - Used automatically for deeper routes (e.g., `/blog/` template for `/blog/post-1`)
74
142
 
75
- ## 🧪 Testing
143
+ ### 6. Dynamic Routes & Parameters
76
144
 
77
- Run tests with Jest:
145
+ For parameterized routes like `/post/:id`:
78
146
 
79
- ```bash
80
- pnpm test
81
- # or
82
- npm test
147
+ **Backend:**
148
+ ```javascript
149
+ app.get('/post/:id', (req, res) => {
150
+ res.render('post', {
151
+ id: req.params.id,
152
+ title: 'My Post'
153
+ });
154
+ });
155
+ ```
156
+
157
+ **Frontend (EJS):**
158
+ ```ejs
159
+ <h1>Post <%= id %></h1>
160
+ <p><%= title %></p>
161
+ ```
162
+
163
+ **Query Parameters:**
164
+ ```javascript
165
+ // Backend
166
+ app.get('/search', (req, res) => {
167
+ const query = req.query.q;
168
+ res.render('search', { query });
169
+ });
170
+
171
+ // Frontend EJS
172
+ <p>Searching for: <%= query %></p>
173
+ ```
174
+
175
+ ### 7. Hot Reload for Styling
176
+
177
+ Press **`Alt + H`** to toggle hot reload mode:
178
+ - Automatically refreshes CSS changes
179
+ - No page reload needed
180
+ - Perfect for rapid styling iterations
181
+
182
+ ### 8. Image Optimization
183
+
184
+ Use the built-in image optimizer:
185
+
186
+ ```html
187
+ <img src="/static/image_800x600.webp" alt="Optimized">
188
+ ```
189
+
190
+ Format: `/static/image_{width}x{height}.webp`
191
+
192
+ The server automatically:
193
+ - Converts to WebP format
194
+ - Resizes to specified dimensions
195
+ - Caches for performance
196
+
197
+ ### 9. Static Site Generation
198
+
199
+ Generate a static version of your entire app:
200
+
201
+ ```javascript
202
+ // Make a GET request
203
+ fetch('/createStatic')
204
+ ```
205
+
206
+ Or visit `http://localhost:3000/createStatic` in your browser.
207
+
208
+ Your static site is generated in the `/build` directory!
209
+
210
+ ## 🧩 API Reference
211
+
212
+ ### Gardener Core (`/static/gardener.js`)
213
+
214
+ ```javascript
215
+ import {
216
+ gardener, // Convert JSON to DOM elements
217
+ fetchElement, // Query selector wrapper
218
+ appendElement, // Append child with error handling
219
+ createElement, // Create element with classes
220
+ insertText, // Set text content
221
+ replaceElement // Replace element in DOM
222
+ } from '/static/gardener.js';
223
+
224
+ // Create element from JSON
225
+ const el = gardener({
226
+ t: 'div',
227
+ cn: ['container'],
228
+ attr: { id: 'main' },
229
+ children: [...]
230
+ });
231
+ ```
232
+
233
+ ### Gardener Dev Tools (`/static/gardenerDev.js`)
234
+
235
+ ```javascript
236
+ import {
237
+ parser, // Convert DOM to JSON
238
+ parserWindow, // Show parser UI
239
+ State, // Reactive state management
240
+ addEl // Add event listener helper
241
+ } from '/static/gardenerDev.js';
242
+
243
+ // Reactive State
244
+ const count = new State(0);
245
+ count.registerCb((value) => {
246
+ console.log('Count:', value);
247
+ });
248
+ count.setTo(1); // Triggers callback
249
+ ```
250
+
251
+ ### Navigation (`/static/components/nonui/navigation.js`)
252
+
253
+ ```javascript
254
+ import {
255
+ nextPage, // Navigate with animation
256
+ nextPagehandler, // Set up link handlers
257
+ pageloader // Handle page loader
258
+ } from '/static/components/nonui/navigation.js';
259
+ ```
260
+
261
+ ### API Utilities (`/static/components/nonui/api.js`)
262
+
263
+ ```javascript
264
+ import { Fetch } from '/static/components/nonui/api.js';
265
+
266
+ // Make API requests
267
+ const response = await Fetch('/api/data', { key: 'value' }, 'POST');
268
+ const data = await response.json();
83
269
  ```
84
270
 
85
271
  ## 📁 Project Structure
86
272
 
87
273
  ```
88
- .
274
+ your-app/
89
275
  ├── src/
90
- │ ├── backend/ # Backend TypeScript code
91
- │ │ ├── controllers/ # Route controllers
92
- │ │ ├── routes/ # Express routes
93
- │ │ ├── libs/ # Utility libraries
94
- └── server.ts # Main server file
95
- └── frontend/ # Frontend assets
96
- ├── views/ # EJS templates
97
- │ ├── static/ # Static files (CSS, JS, images)
98
- │ ├── assets/ # Source assets
99
- │ ├── template/ # Frontend templates
100
- └── tailwind.css # Tailwind source file
101
- ├── build/ # Production build output
102
- ├── buildHelper.js # Build utility script
103
- ├── jest.config.js # Jest configuration
104
- ├── tsconfig.json # TypeScript configuration
105
- ├── package.json # Project dependencies
106
- └── .env # Environment variables
107
- ```
108
-
109
- ## ⚙️ Configuration
110
-
111
- ### Environment Variables
112
-
113
- Create a `.env` file in the root directory:
114
-
115
- ```env
116
- PORT=3000
117
- NODE_ENV=development
118
- ```
119
-
120
- ### TypeScript
121
-
122
- The project uses strict TypeScript configuration with:
123
- - ES modules (`"module": "nodenext"`)
124
- - Strict type checking
125
- - Source maps for debugging
126
- - Declaration files generation
127
-
128
- ### Tailwind CSS
129
-
130
- Tailwind CSS v4 is configured with:
131
- - JIT (Just-In-Time) compilation
132
- - Minification in production builds
133
- - Custom styles in `src/frontend/tailwind.css`
134
-
135
- ## 📦 Dependencies
136
-
137
- ### Production
138
- - **express** - Fast, minimalist web framework
139
- - **ejs** - Embedded JavaScript templating
140
- - **tailwindcss** - Utility-first CSS framework
141
- - **sharp** - High-performance image processing
142
- - **zod** - TypeScript-first schema validation
143
- - **dotenv** - Environment variable management
144
-
145
- ### Development
146
- - **typescript** - TypeScript compiler
147
- - **tsx** - TypeScript execution and REPL
148
- - **jest** - Testing framework
149
- - **concurrently** - Run multiple commands concurrently
150
- - **cross-env** - Cross-platform environment variables
151
-
152
- ## 🔧 Build Process
153
-
154
- The `buildHelper.js` script handles:
155
- 1. Copying frontend files to the build directory
156
- 2. Generating production configuration (`gardenerConfig.js`)
157
- 3. Cleaning up unnecessary template files
158
-
159
- ## 📝 Scripts
160
-
161
- | Script | Description |
162
- |--------|-------------|
163
- | `pnpm dev` | Start development server with hot reload |
164
- | `pnpm build` | Build for production |
165
- | `pnpm start` | Start production server |
166
- | `pnpm test` | Run Jest tests |
276
+ │ ├── backend/
277
+ │ │ ├── server.ts # Main server file
278
+ │ │ ├── routes/ # Express routes
279
+ │ │ └── controllers/ # Route controllers
280
+ │ └── frontend/
281
+ ├── views/ # EJS templates
282
+ │ └── partials/ # EJS partials
283
+ │ ├── static/ # Client-side JS
284
+ ├── gardener.js # Core framework
285
+ ├── gardenerDev.js # Dev tools
286
+ │ ├── components/ # Gardener components
287
+ │ │ └── pages/ # Page-specific JS
288
+ ├── template/ # Page templates
289
+ ├── style.css # Compiled Tailwind
290
+ │ └── tailwind.css # Tailwind source
291
+ ├── build/ # Static site output
292
+ └── package.json
293
+ ```
294
+
295
+ ## 🎯 Key Concepts
296
+
297
+ ### 1. DOM-to-JSON Parser
298
+ The `parser()` function converts any DOM element into a JSON representation that can be saved as a reusable component. This allows you to:
299
+ - Build UI visually in the browser
300
+ - Extract components without manual coding
301
+ - Create a library of reusable elements
302
+
303
+ ### 2. Component Composition
304
+ Components are composable JSON objects. Build complex UIs by nesting components:
305
+
306
+ ```javascript
307
+ const page = {
308
+ t: 'div',
309
+ children: [
310
+ header,
311
+ mainContent,
312
+ footer
313
+ ]
314
+ };
315
+ ```
316
+
317
+ ### 3. Development vs Production
318
+ - **Development**: Full dev tools, component parser, hot reload
319
+ - **Production**: Minimal runtime, optimized assets, static export option
320
+
321
+ ## 🔧 Configuration
322
+
323
+ Edit `src/frontend/static/gardenerConfig.js`:
324
+
325
+ ```javascript
326
+ export const mode = 'dev'; // or 'production'
327
+ ```
328
+
329
+ ## 📚 Documentation
330
+
331
+ Visit [gardener.ritish.site](https://gardener.ritish.site) for full documentation and examples.
332
+
333
+ ## 💡 Examples
334
+
335
+ ### Creating a Blog Post Component
336
+
337
+ ```javascript
338
+ // 1. Create HTML in your EJS file
339
+ <div class="post">
340
+ <h2 class="title">?title?</h2>
341
+ <p class="content">?content?</p>
342
+ </div>
343
+
344
+ <div class="post2">
345
+ </div>
346
+
347
+ // 2. Parse it by calling
348
+ parser('.post');
349
+
350
+ // 3. accept the component by giving a name in browser
351
+
352
+ // 4. Use it
353
+
354
+ replaceElement('.post2', component({title:'new component', content:'this is the new content'}))
355
+
356
+ ```
167
357
 
168
358
  ## 🤝 Contributing
169
359
 
170
- This is a template project created by create-gardener. Feel free to modify it according to your needs.
360
+ Contributions are welcome! Visit the [GitHub repository](https://github.com/ritishDas/gardener).
171
361
 
172
362
  ## 📄 License
173
363
 
174
- MIT
364
+ MIT License - See LICENSE file for details.
175
365
 
176
366
  ## 👤 Author
177
367
 
178
- ritishDas
179
-
180
- ## 🔗 Links
368
+ **ritishDas**
181
369
 
182
- - [Gardener Homepage](https://gardener.ritish.site)
183
- - [GitHub Repository](https://github.com/ritishDas/gardener)
370
+ - GitHub: [@ritishDas](https://github.com/ritishDas)
371
+ - Website: [gardener.ritish.site](https://gardener.ritish.site)
184
372
 
185
373
  ---
186
374
 
187
- Created with [create-gardener](https://www.npmjs.com/package/create-gardener) 🌱
375
+ Built with ❤️ for developers who want to move fast without breaking things.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/ritishDas/gardener"
7
7
  },
8
- "version": "2.0.8",
8
+ "version": "2.1.0",
9
9
  "description": "A dom gardener converting dom elements into json and vice versa",
10
10
  "main": "index.js",
11
11
  "bin": {
@@ -0,0 +1,8 @@
1
+ import type { Request, Response } from "express";
2
+ interface AddComponentBody {
3
+ path: string;
4
+ component: string;
5
+ }
6
+ export declare function addComponent(req: Request<{}, {}, AddComponentBody>, res: Response): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=addComponent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addComponent.d.ts","sourceRoot":"","sources":["../../../../src/backend/controllers/gardener/addComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjD,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAQD,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,gBAAgB,CAAC,EAAE,GAAG,EAAE,QAAQ,iBAWvF"}
@@ -0,0 +1,19 @@
1
+ import fsp from "fs/promises";
2
+ import path from 'path';
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = path.dirname(__filename);
6
+ const frontendDir = path.resolve(__dirname, '..', '..', '..', 'frontend');
7
+ export async function addComponent(req, res) {
8
+ try {
9
+ const { path: filePath, component } = req.body;
10
+ await fsp.mkdir(path.join(frontendDir, 'static', 'components'), { recursive: true });
11
+ await fsp.writeFile(path.join(frontendDir, `${filePath}`), component, "utf8");
12
+ res.json({ success: true });
13
+ }
14
+ catch (err) {
15
+ const error = err;
16
+ res.json({ success: false, msg: error.message });
17
+ }
18
+ }
19
+ //# sourceMappingURL=addComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addComponent.js","sourceRoot":"","sources":["../../../../src/backend/controllers/gardener/addComponent.ts"],"names":[],"mappings":"AACA,OAAO,GAAG,MAAM,aAAa,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AAOxB,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAE1E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAsC,EAAE,GAAa;IACtF,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;QAC/C,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC9E,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAE9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,GAAY,CAAC;QAC3B,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Request, Response } from "express";
2
+ export declare function addPage(req: Request, res: Response): Promise<void>;
3
+ //# sourceMappingURL=addPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addPage.d.ts","sourceRoot":"","sources":["../../../../src/backend/controllers/gardener/addPage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA2CjD,wBAAsB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAkCxD"}
@@ -0,0 +1,76 @@
1
+ import fsp from "fs/promises";
2
+ import { access } from "fs/promises";
3
+ import path from 'path';
4
+ import { fileURLToPath } from "url";
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const frontendDir = path.resolve(__dirname, '..', '..', '..', 'frontend');
8
+ const templateDir = path.join(frontendDir, 'template');
9
+ async function findTemplate(fileName) {
10
+ while (fileName.length !== 0) {
11
+ console.log(fileName);
12
+ const searchFile = `template.${fileName}.ejs`;
13
+ console.log(searchFile);
14
+ const searchPath = path.join(templateDir, searchFile);
15
+ console.log(searchPath);
16
+ try {
17
+ await access(searchPath); // ✅ checks if file exists
18
+ return searchPath; // return full path immediately
19
+ }
20
+ catch {
21
+ // file does not exist → continue
22
+ }
23
+ let lastUnderscore = fileName.lastIndexOf('_');
24
+ if (lastUnderscore === -1)
25
+ break;
26
+ if (lastUnderscore === 0)
27
+ lastUnderscore += 1;
28
+ fileName = fileName.substring(0, lastUnderscore);
29
+ console.log(fileName);
30
+ }
31
+ // ❗ explicit failure instead of silent bug
32
+ throw new Error("Template not found");
33
+ }
34
+ export async function addPage(req, res) {
35
+ try {
36
+ const pagename = req.body.page;
37
+ const name = pagename.replaceAll('/', '_');
38
+ const templatePath = await findTemplate(name); //path.join(frontendDir, findTemplate(name)); //path.join(frontendDir, 'frontendtemplate.ejs');
39
+ const viewPath = path.join(frontendDir, `views`, `${name}.ejs`);
40
+ const routePath = path.resolve(__dirname, '..', '..', 'routes', 'gardener.route.ts');
41
+ const jsDir = path.join(frontendDir, 'static/pages');
42
+ const jsFilePath = path.join(jsDir, `pages.${name}.js`);
43
+ const templateContent = await fsp.readFile(templatePath, 'utf8');
44
+ await fsp.writeFile(viewPath, templateContent, "utf8");
45
+ await replaceLastOccurrence(viewPath, '<script', `<script src="/static/pages/pages.${name}.js" type='module'></script>`);
46
+ const routeEntry = `router.route("${pagename}").get((req: Request, res: Response) => res.render("${name}",{fileName:"${name}"}));\n`;
47
+ await fsp.appendFile(routePath, routeEntry, "utf8");
48
+ await fsp.mkdir(jsDir, { recursive: true });
49
+ const jsContent = 'import { gardener, fetchElement, replaceElement, appendElement } from "/static/gardener.js";\n import {log, parser, addEl, State} from "/static/gardenerDev.js"';
50
+ await fsp.writeFile(jsFilePath, jsContent, "utf8");
51
+ res.json({ success: true });
52
+ }
53
+ catch (err) {
54
+ const error = err;
55
+ res.json({ success: false, msg: error.message });
56
+ }
57
+ }
58
+ async function replaceLastOccurrence(filePath, searchPattern, replacementLine) {
59
+ const content = await fsp.readFile(filePath, 'utf8');
60
+ const lines = content.split('\n');
61
+ let found = false;
62
+ for (let i = lines.length - 1; i >= 0; i--) {
63
+ if (lines[i].includes(searchPattern)) {
64
+ lines[i] = `${replacementLine}\n${lines[i]}`;
65
+ found = true;
66
+ break;
67
+ }
68
+ }
69
+ if (found) {
70
+ await fsp.writeFile(filePath, lines.join('\n'), 'utf8');
71
+ }
72
+ else {
73
+ console.warn(`Pattern "${searchPattern}" not found in ${filePath}`);
74
+ }
75
+ }
76
+ //# sourceMappingURL=addPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addPage.js","sourceRoot":"","sources":["../../../../src/backend/controllers/gardener/addPage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Request, Response } from "express";
2
+ export declare function createStatic(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
3
+ //# sourceMappingURL=createStatic.d.ts.map