create-gardener 1.1.13 → 2.0.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 (45) hide show
  1. package/package.json +1 -1
  2. package/starter.js +5 -2
  3. package/template/.env +0 -0
  4. package/template/buildHelper.js +3 -0
  5. package/template/jsconfig.json +27 -0
  6. package/template/package.json +6 -5
  7. package/template/src/backend/controllers/gardener/addComponent.ts +27 -0
  8. package/template/src/backend/controllers/gardener/addPage.ts +60 -0
  9. package/template/src/backend/controllers/gardener/createStatic.ts +84 -0
  10. package/template/src/backend/controllers/gardener/imageOptimiser.ts +67 -0
  11. package/template/src/backend/controllers/gardener/index.ts +4 -0
  12. package/template/src/backend/libs/generateWebp.ts +1 -0
  13. package/template/src/backend/routes/gardener.route.ts +15 -5
  14. package/template/src/backend/server.ts +8 -10
  15. package/template/src/frontend/assets/favicon.png +0 -0
  16. package/template/src/frontend/frontendtemplate.ejs +5 -17
  17. package/template/src/frontend/static/cache/favicon_500x500.webp +0 -0
  18. package/template/src/frontend/static/cache/favicon_50x50.webp +0 -0
  19. package/template/src/frontend/static/cache/gardener_50x50.webp +0 -0
  20. package/template/src/frontend/static/components/copybtn.js +86 -0
  21. package/template/src/frontend/static/components/nonui/api.js +33 -16
  22. package/template/src/frontend/static/components/nonui/navigation.js +59 -0
  23. package/template/src/frontend/static/components/secondtest.js +6 -0
  24. package/template/src/frontend/static/components/{emailsvg.js → testdd.js} +7 -7
  25. package/template/src/frontend/static/gardener.js +0 -388
  26. package/template/src/frontend/static/gardenerConfig.js +1 -0
  27. package/template/src/frontend/static/gardenerDev.js +408 -0
  28. package/template/src/frontend/static/global.js +2 -56
  29. package/template/src/frontend/static/pages/_.js +13 -0
  30. package/template/src/frontend/static/pages/_get-started.js +5 -0
  31. package/template/src/frontend/static/style.css +1039 -1
  32. package/template/src/frontend/static/style2.css +1 -1
  33. package/template/src/frontend/static/zod.js +8 -0
  34. package/template/src/frontend/views/_.ejs +96 -216
  35. package/template/src/frontend/views/_get-started.ejs +25 -0
  36. package/template/src/frontend/views/partials/icons/clipboard.ejs +1 -0
  37. package/template/src/frontend/views/partials/icons/clipboardok.ejs +1 -0
  38. package/template/tsconfig.json +1 -1
  39. package/template/src/backend/controllers/gardener.controller.ts +0 -193
  40. package/template/src/frontend/gardenerST.js +0 -431
  41. package/template/src/frontend/static/components/eyeoff.js +0 -50
  42. package/template/src/frontend/static/components/eyeon.js +0 -43
  43. package/template/src/frontend/static/components/passwordBox.js +0 -105
  44. package/template/src/frontend/views/_login.ejs +0 -75
  45. package/template/src/frontend/views/partials/loader.ejs +0 -3
@@ -1,431 +0,0 @@
1
- //Standalone gardener version for no backend environment
2
-
3
- const config = {
4
- mode: 'dev',
5
- hotreload: false
6
- }
7
-
8
- let hotReloadtimeout;
9
- const body = fetchElement('body');
10
-
11
-
12
- function applyHotReloadState() {
13
- const hrcheck = fetchElement('#hrcheckbox');
14
- const checkbox = fetchElement('.hrcheckbox');
15
-
16
- if (hotReload) {
17
- hrcheck.style.background = '#66e666';
18
- checkbox.checked = true;
19
- hotReloadtimeout = setTimeout(() => window.location.reload(), 1000);
20
- } else {
21
- hrcheck.style.background = 'red';
22
- checkbox.checked = false;
23
- clearTimeout(hotReloadtimeout);
24
- }
25
- }
26
-
27
- let hotReload = localStorage.getItem('hotreload');
28
- if (hotReload === null) hotReload = config.hotreload;
29
- else if (hotReload === 'true') hotReload = true
30
- else if (hotReload === 'false') hotReload = false
31
-
32
-
33
-
34
-
35
- if (config.mode === 'dev') {
36
- appendElement(body, gardener({
37
- t: 'p',
38
- attr: {
39
- style: `
40
- position:fixed;
41
- bottom:0;
42
- right:0;
43
- z-index:100;
44
- background:#e5e7eb;
45
- padding:8px;
46
- border-radius:6px;
47
- font-family:sans-serif;
48
- color:black;
49
- font-size:14px;
50
- `
51
- },
52
- children: [
53
- { t: 'span', txt: 'Press ' },
54
- {
55
- t: 'span',
56
- attr: { style: 'color:#22c55e;font-weight:bold;' },
57
- txt: 'Alt+h'
58
- },
59
- { t: 'span', txt: ' to toggle Hot Reload' },
60
- {
61
- t: 'form',
62
- attr: {
63
- id: 'hrcheckbox',
64
- style: 'margin-top:6px;padding:6px;background:red;border-radius:4px;cursor:pointer;'
65
- },
66
- events: { click: togglehotreload },
67
- children: [
68
- { t: 'label', txt: 'Hot Reload ' },
69
- {
70
- t: 'input',
71
- cn: ['hrcheckbox'],
72
- attr: { type: 'checkbox' }
73
- }
74
- ]
75
- }
76
- ]
77
- }));
78
-
79
- applyHotReloadState();
80
-
81
- document.addEventListener('keydown', function(e) {
82
- if (e.altKey && e.key.toLowerCase() === 'h') {
83
- e.preventDefault(); // Stop browser from opening history
84
- // Your logic here...
85
- togglehotreload();
86
- }
87
- });
88
- }
89
-
90
- //appendElement(body, gardener())
91
-
92
-
93
-
94
-
95
- // togglehotreload();
96
-
97
-
98
-
99
-
100
- //if (config.mode === 'dev') {
101
-
102
-
103
- function togglehotreload() {
104
- hotReload = !hotReload;
105
- localStorage.setItem('hotreload', String(hotReload));
106
-
107
- const hrcheck = fetchElement('#hrcheckbox');
108
- const checkbox = fetchElement('.hrcheckbox');
109
-
110
- if (hotReload) {
111
- hrcheck.style.background = '#66e666';
112
- checkbox.checked = true;
113
- hotReloadtimeout = setTimeout(() => window.location.reload(), 1000);
114
- } else {
115
- hrcheck.style.background = 'red';
116
- checkbox.checked = false;
117
- clearTimeout(hotReloadtimeout);
118
- }
119
- }
120
-
121
- function parserWindow(input) {
122
- if (config.mode !== 'dev') return;
123
-
124
- let text;
125
- try {
126
- text = JSON.stringify(JSON.parse(input), null, 2);
127
- } catch {
128
- text = input;
129
- }
130
-
131
- const result = gardener({
132
- t: 'div',
133
- attr: {
134
- style: `
135
- position:fixed;
136
- top:25%;
137
- left:25%;
138
- width:50%;
139
- height:50%;
140
- background:#6b7280;
141
- color:white;
142
- border:2px solid black;
143
- border-radius:8px;
144
- z-index:90;
145
- display:flex;
146
- flex-direction:column;
147
- justify-content:space-between;
148
- `
149
- },
150
- children: [
151
- {
152
- t: 'div',
153
- attr: {
154
- style: `
155
- background:#e5e7eb;
156
- color:black;
157
- padding:10px;
158
- display:flex;
159
- justify-content:space-between;
160
- align-items:center;
161
- border-top-left-radius:8px;
162
- border-top-right-radius:8px;
163
- `
164
- },
165
- children: [
166
- { t: 'h3', txt: 'Parser Window' },
167
- {
168
- t: 'button',
169
- txt: 'Copy JSON',
170
- attr: {
171
- style: `
172
- padding:6px 10px;
173
- background:#f87171;
174
- border-radius:6px;
175
- cursor:pointer;
176
- `
177
- },
178
- events: {
179
- click: () => copyTextToClipboard(text)
180
- }
181
- }
182
- ]
183
- },
184
- {
185
- t: 'pre',
186
- txt: text,
187
- attr: {
188
- style: `
189
- padding:12px;
190
- overflow:auto;
191
- font-size:12px;
192
- white-space:pre-wrap;
193
- `
194
- }
195
- }
196
- ]
197
- });
198
-
199
- appendElement(body, result);
200
- }
201
-
202
-
203
-
204
- async function copyTextToClipboard(txt) {
205
- try {
206
- await navigator.clipboard.writeText(txt);
207
- alert('Component copied to clipboard');
208
- } catch (err) {
209
- console.error('Clipboard copy failed', err);
210
- }
211
- }
212
-
213
-
214
-
215
-
216
- export function fetchElement(param) {
217
- return document.querySelector(param);
218
- }
219
-
220
- export function appendElement(parent, child) {
221
- if (typeof parent === 'string') parent = fetchElement(parent);
222
- parent.appendChild(child);
223
- }
224
-
225
- export function createElement(type, classname) {
226
- let element = document.createElement(type);
227
- if (classname)
228
- element.classList.add(...classname);
229
- return element;
230
- }
231
-
232
- export function insertText(element, text) {
233
- element.innerText = text;
234
- }
235
-
236
- export function replaceElement(original, New) {
237
- if (typeof original === 'string') original = fetchElement(original);
238
- original.replaceWith(New);
239
- }
240
-
241
- export function gardener(Dom) {
242
-
243
- if (Dom.nodeType === 1) return Dom;
244
- // detect if this is an SVG element
245
- const isSVG = [
246
- 'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'g', 'defs', 'clipPath', 'use'
247
- ].includes(Dom.t);
248
-
249
- // create element accordingly
250
- let element;
251
-
252
- if (isSVG) {
253
- element = document.createElementNS('http://www.w3.org/2000/svg', Dom.t);
254
- if (Dom.cn)
255
- element.classList.add(...Dom.cn);
256
- }
257
- else {
258
- element = createElement(Dom.t, Dom.cn);
259
- }
260
-
261
- // text content (skip for SVG like <path>)
262
- if (Dom.txt) {
263
- insertText(element, Dom.txt);
264
- }
265
-
266
- // apply attributes safely
267
- const propertyNames = new Set([
268
- 'value', 'selected', 'muted', 'disabled',
269
- 'selectedIndex', 'volume', // etc.
270
- ]);
271
-
272
- if (Dom.attr) {
273
- for (const [key, value] of Object.entries(Dom.attr)) {
274
- if (isSVG || key.startsWith('data-') || key.startsWith('aria-')) {
275
- element.setAttribute(key, value);
276
- } else if (key in element && !propertyNames.has(key)) {
277
- // Prefer property for known safe cases
278
- try { element[key] = value === '' ? true : value; } catch (e) { element.setAttribute(key, value); }
279
- } else {
280
- element.setAttribute(key, value);
281
- }
282
- }
283
- }
284
-
285
- if (Dom.events) {
286
- Object.entries(Dom.events).forEach(([eventName, handler]) => {
287
- element.addEventListener(eventName, handler);
288
- });
289
- }
290
-
291
- // recursively handle children
292
- if (Dom.children) {
293
- Dom.children.forEach(child => appendElement(element, gardener(child)));
294
- }
295
-
296
- return element;
297
- }
298
-
299
- function cleanStringAndList(input) {
300
- const pattern = /\?"?(\w+)"?\?/g;
301
- const vars = new Set();
302
- let match;
303
-
304
- while ((match = pattern.exec(input)) !== null) {
305
- vars.add(match[1]);
306
- }
307
-
308
- // Replace ?var? with "+var+" and clean up resulting empty strings or double quotes
309
- const cleanedString = input
310
- .replace(pattern, '"+$1+"')
311
- .replace(/^""\+/, '')
312
- .replace(/\+""$/, '');
313
-
314
- return {
315
- cleanedString,
316
- extractedList: [...vars].join(', ')
317
- };
318
- }
319
-
320
- function generateFile(obj) {
321
-
322
-
323
- const formatted = JSON.stringify(obj, null, 2);
324
- const { cleanedString, extractedList } = cleanStringAndList(formatted);
325
-
326
- if (extractedList.length === 0) return `
327
- import { gardener, fetchElement, replaceElement } from '../gardener.js'
328
-
329
- export default function thisfun() {
330
- return gardener(${cleanedString})
331
- }
332
- `;
333
-
334
- return `
335
- import { gardener, fetchElement, replaceElement } from '../gardener.js'
336
-
337
- export default function thisfun({${extractedList}}) {
338
- return gardener(${cleanedString})
339
- }
340
- `;
341
- }
342
-
343
-
344
-
345
-
346
- export function parser(element, isParent = true) {
347
- if (typeof element === 'string') {
348
- element = fetchElement(element);
349
- }
350
-
351
- console.log(element)
352
- const obj = {
353
- t: element.tagName.toLowerCase(),
354
- };
355
-
356
- // add classes if present
357
- if (element.classList.length) {
358
- obj.cn = Array.from(element.classList);
359
- }
360
-
361
- // add attributes if present
362
- const attrs = {};
363
- for (const attr of element.attributes) {
364
- if (attr.name !== 'class') attrs[attr.name] = attr.value;
365
- }
366
- if (Object.keys(attrs).length) obj.attr = attrs;
367
- // add text content (only if no children)
368
- if (element.childNodes.length === 1 && element.firstChild.nodeType === Node.TEXT_NODE) {
369
- obj.txt = element.textContent.trim();
370
-
371
- if (isParent) {
372
-
373
- parserWindow(generateFile(obj))
374
- }
375
-
376
- return obj;
377
- }
378
-
379
-
380
- // add children recursively
381
- const children = [];
382
- for (const child of element.childNodes) {
383
- if (child.nodeType === Node.COMMENT_NODE) continue;
384
-
385
- if (child.nodeType === Node.TEXT_NODE && child.textContent.trim() === '') continue;
386
-
387
- if (child.nodeType === Node.TEXT_NODE) {
388
- children.push({ t: 'span', txt: child.textContent.trim() });
389
- continue;
390
- }
391
- children.push(parser(child, false));
392
- }
393
- if (children.length) obj.children = children;
394
-
395
-
396
- if (isParent) {
397
-
398
-
399
- parserWindow(generateFile(obj))
400
- }
401
-
402
- return obj
403
-
404
-
405
- }
406
-
407
-
408
- export function addEL(parent, event, fun) {
409
- if (typeof parent === 'string') {
410
- parent = fetchElement(parent);
411
- }
412
- parent.addEventListener(event, fun)
413
- }
414
-
415
-
416
- export class State {
417
- constructor(value) {
418
- this.value = value;
419
- this.cb = [];
420
- }
421
- registerCb(cb) {
422
- cb(this.value);
423
- this.cb.push(cb);
424
- }
425
- setTo(val) {
426
- this.value = val;
427
- this.cb.forEach(cb => { cb(val) });
428
- }
429
- }
430
-
431
-
@@ -1,50 +0,0 @@
1
-
2
- import { gardener } from '/static/gardener.js'
3
-
4
- export default function () {
5
- return gardener({
6
- "t": "svg",
7
- "cn": [
8
- "eye"
9
- ],
10
- "attr": {
11
- "xmlns": "http://www.w3.org/2000/svg",
12
- "width": "24",
13
- "height": "24",
14
- "viewBox": "0 0 24 24",
15
- "fill": "none",
16
- "stroke": "currentColor",
17
- "stroke-width": "2",
18
- "stroke-linecap": "round",
19
- "stroke-linejoin": "round"
20
- },
21
- "children": [
22
- {
23
- "t": "path",
24
- "attr": {
25
- "stroke": "none",
26
- "d": "M0 0h24v24H0z",
27
- "fill": "none"
28
- }
29
- },
30
- {
31
- "t": "path",
32
- "attr": {
33
- "d": "M10.585 10.587a2 2 0 0 0 2.829 2.828"
34
- }
35
- },
36
- {
37
- "t": "path",
38
- "attr": {
39
- "d": "M16.681 16.673a8.717 8.717 0 0 1 -4.681 1.327c-3.6 0 -6.6 -2 -9 -6c1.272 -2.12 2.712 -3.678 4.32 -4.674m2.86 -1.146a9.055 9.055 0 0 1 1.82 -.18c3.6 0 6.6 2 9 6c-.666 1.11 -1.379 2.067 -2.138 2.87"
40
- }
41
- },
42
- {
43
- "t": "path",
44
- "attr": {
45
- "d": "M3 3l18 18"
46
- }
47
- }
48
- ]
49
- })
50
- }
@@ -1,43 +0,0 @@
1
-
2
- import { gardener } from '/static/gardener.js'
3
- export default function() {
4
- return gardener({
5
- "t": "svg",
6
- "cn": [
7
- "eye"
8
- ],
9
- "attr": {
10
- "xmlns": "http://www.w3.org/2000/svg",
11
- "width": "24",
12
- "height": "24",
13
- "viewBox": "0 0 24 24",
14
- "fill": "none",
15
- "stroke": "currentColor",
16
- "stroke-width": "2",
17
- "stroke-linecap": "round",
18
- "stroke-linejoin": "round"
19
- },
20
- "children": [
21
- {
22
- "t": "path",
23
- "attr": {
24
- "stroke": "none",
25
- "d": "M0 0h24v24H0z",
26
- "fill": "none"
27
- }
28
- },
29
- {
30
- "t": "path",
31
- "attr": {
32
- "d": "M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0"
33
- }
34
- },
35
- {
36
- "t": "path",
37
- "attr": {
38
- "d": "M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6"
39
- }
40
- }
41
- ]
42
- })
43
- }
@@ -1,105 +0,0 @@
1
- import { gardener, replaceElement, fetchElement } from '/static/gardener.js'
2
- import eyeoff from '/static/components/eyeoff.js'
3
- import eyeon from '/static/components/eyeon.js'
4
- export default function thisfun(visible) {
5
-
6
- const svg = visible ? eyeoff() : eyeon();
7
-
8
- return gardener({
9
- "t": "div",
10
- "cn": [
11
- "w-full",
12
- "passwordbox"
13
- ],
14
- "children": [
15
- {
16
- "t": "label",
17
- "cn": [
18
- "my-1",
19
- "block"
20
- ],
21
- "txt": "Password"
22
- },
23
- {
24
- "t": "span",
25
- "cn": [
26
- "border",
27
- "border-gray-900",
28
- "flex",
29
- "space-x-1",
30
- "items-center",
31
- "h-8",
32
- "p-1",
33
- "rounded-md"
34
- ],
35
- "children": [
36
- {
37
- "t": "svg",
38
- "cn": [
39
- "icon",
40
- "icon-tabler",
41
- "icons-tabler-outline",
42
- "icon-tabler-key"
43
- ],
44
- "attr": {
45
- "xmlns": "http://www.w3.org/2000/svg",
46
- "width": "24",
47
- "height": "24",
48
- "viewBox": "0 0 24 24",
49
- "fill": "none",
50
- "stroke": "currentColor",
51
- "stroke-width": "2",
52
- "stroke-linecap": "round",
53
- "stroke-linejoin": "round"
54
- },
55
- "children": [
56
- {
57
- "t": "path",
58
- "attr": {
59
- "stroke": "none",
60
- "d": "M0 0h24v24H0z",
61
- "fill": "none"
62
- }
63
- },
64
- {
65
- "t": "path",
66
- "attr": {
67
- "d": "M16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1 -4.069 0l-.301 -.301l-6.558 6.558a2 2 0 0 1 -1.239 .578l-.175 .008h-1.172a1 1 0 0 1 -.993 -.883l-.007 -.117v-1.172a2 2 0 0 1 .467 -1.284l.119 -.13l.414 -.414h2v-2h2v-2l2.144 -2.144l-.301 -.301a2.877 2.877 0 0 1 0 -4.069l2.643 -2.643a2.877 2.877 0 0 1 4.069 0"
68
- }
69
- },
70
- {
71
- "t": "path",
72
- "attr": {
73
- "d": "M15 9h.01"
74
- }
75
- }
76
- ]
77
- },
78
- {
79
- "t": "input",
80
- "cn": [
81
- "outline-none",
82
- "inputbox",
83
- "w-full"
84
- ],
85
- "attr": {
86
- "type": visible ? 'text' : 'password',
87
- "name": "password",
88
- value: fetchElement('.inputbox').value,
89
- "required": "",
90
- }
91
- },
92
- {
93
- t: 'span',
94
- events: {
95
- click: () => replaceElement(fetchElement(".passwordbox"), thisfun(!visible)),
96
- },
97
- children: [
98
- svg
99
- ]
100
- }
101
- ]
102
- },
103
- ]
104
- })
105
- }
@@ -1,75 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <link href="/static/style.css" rel="stylesheet"/>
7
- <link href="/static/style2.css" rel="stylesheet"/>
8
- <title>Redvent:Login</title>
9
- </head>
10
- <body>
11
- <div class='notification'></div>
12
- <div class="bg-gray-200 w-screen h-screen flex justify-center items-center" id='body'>
13
-
14
- <!-- Remove this line when you are using hot reload as it will cause delay -->
15
- <%- include('partials/loader') %>
16
- <!-- Remove this line when you are using hot reload as it will cause delay -->
17
- <div class="bg-white rounded-xl w-90 min-h-100 flex items-center flex-col">
18
-
19
- <h1 class="text-center text-4xl p-5">Login</h1>
20
- <form class="w-3/4 flex flex-col space-y-5 loginform" >
21
-
22
- <div>
23
-
24
- <label class="my-1 block">Email</label>
25
- <span class="border border-gray-900 flex space-x-1 items-center h-8 p-1 rounded-md">
26
- <span class='emailsvg'> </span>
27
- <input type="email" class="outline-none w-full" name="email" required>
28
- </span>
29
- </div>
30
-
31
-
32
- <div class="w-full">
33
- <div class="passwordbox">
34
- <input class='inputbox' value=""/>
35
- </div>
36
- <a href='/forgotpass' class="text-right block text-sm text-blue-800 mt-3">Forgot Password?</a>
37
- </div>
38
-
39
-
40
- <button type="submit" class="w-full bg-green-200 rounded-xl p-2 mt-5 hover:bg-green-300 hover:cursor-pointer transition-all">Submit</button>
41
- </form>
42
-
43
- </div>
44
- </div>
45
- <script src='/static/global.js' type="module"></script>
46
- <script type="module">
47
-
48
- import { parser, fetchElement, replaceElement, appendElement } from "/static/gardener.js";
49
- import addNotification from "/static/components/notification.js";
50
- import emailsvg from '/static/components/emailsvg.js';
51
- import passwordbox from "/static/components/passwordBox.js";
52
- import { userlogin } from "/static/components/nonui/api.js";
53
-
54
- // mount password input
55
- replaceElement(fetchElement(".passwordbox"), passwordbox(false));
56
-
57
-
58
- fetchElement(".loginform").addEventListener("submit", async (e) => {
59
- e.preventDefault();
60
-
61
- const formdata = new FormData(e.target);
62
- const result = Object.fromEntries(formdata);
63
-
64
-
65
- const { email, password } = result;
66
- await userlogin(email, password);
67
-
68
- addNotification({status:'success',message:'Login SuccessFull'})
69
- });
70
-
71
- replaceElement(fetchElement('.emailsvg'),emailsvg());
72
- </script>
73
- </body>
74
- </html>
75
-
@@ -1,3 +0,0 @@
1
- <div class='h-screen w-screen bg-white loader absolute'>
2
-
3
- </div>