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
@@ -0,0 +1,159 @@
1
+ import { gardener, fetchElement, appendElement } from '../../gardener.js'
2
+ import { gardenerError } from './errorBox.js';
3
+
4
+ const body = fetchElement('body');
5
+
6
+ const config = {
7
+ componentdir: 'static/components',
8
+ }
9
+
10
+ let result;
11
+ export function parserWindow(text) {
12
+ result = gardener({
13
+ t: 'div',
14
+ cn: ['fixed', 'border-2', 'border-black', 'bg-gray-500', 'text-white', 'rounded-lg', 'z-90', 'w-2/4', 'h-2/4', 'left-1/4', 'flex', 'flex-col', 'justify-between', 'top-1/4'],
15
+ children: [
16
+ {
17
+ t: 'div',
18
+ cn: ['bg-gray-200', 'h-15', 'text-black', 'rounded-t-lg', 'flex', 'items-center', 'justify-around'],
19
+ children: [
20
+ {
21
+ t: 'h3',
22
+ cn: ['font-bold', 'p-5'],
23
+ txt: 'Parser Window'
24
+ },
25
+ {
26
+ t: 'div',
27
+ cn: ['flex', 'gap-3'],
28
+ children: [
29
+ {
30
+ t: 'button',
31
+ cn: ['p-2', 'bg-green-300', 'rounded-lg', 'cursor-pointer'],
32
+ txt: 'Copy Component',
33
+ attr: { id: 'copybtn' },
34
+ events: {
35
+ click: () => { navigator.clipboard.writeText(text); fetchElement('#copybtn').innerText = 'copied'; }
36
+ }
37
+ },
38
+ {
39
+ t: 'button',
40
+ cn: ['p-2', 'bg-red-300', 'rounded-lg', 'cursor-pointer'],
41
+ txt: 'Add Component',
42
+ events: {
43
+ click: () => addComponentForm(text)
44
+ }
45
+ }
46
+ ]
47
+ }
48
+ ]
49
+ },
50
+ {
51
+ t: 'p',
52
+ cn: ['p-5', 'overflow-scroll'],
53
+ txt: text
54
+ },
55
+ ]
56
+ })
57
+
58
+
59
+ return result;
60
+ }
61
+
62
+ function addComponentForm(text) {
63
+ result.remove()
64
+
65
+ const compform = gardener({
66
+ t: 'form',
67
+ events: {
68
+ submit: (event) => {
69
+ event.preventDefault()
70
+ addComponent(text, `${fetchElement('.componentInp').value}`)
71
+ compform.remove();
72
+ }
73
+ },
74
+ cn: ['fixed', 'left-2/5', 'bg-gray-500', 'rounded-lg', 'block', 'top-2/5', 'p-2'],
75
+ children: [
76
+ {
77
+ t: 'input',
78
+ cn: ['bg-white', 'componentInp'],
79
+ attr: {
80
+ type: 'text',
81
+ placeholder: 'Component Name'
82
+ }
83
+ }
84
+ ]
85
+ });
86
+ appendElement(body, compform);
87
+
88
+ fetchElement('.componentInp').focus();
89
+ //setTimeout(() => result.remove(), 500);
90
+ }
91
+
92
+ async function addComponent(txt, path) {
93
+ try {
94
+ const res = await fetch('/addcomponent', {
95
+ method: 'POST',
96
+ headers: {
97
+ "Content-Type": 'application/json'
98
+ },
99
+ body: JSON.stringify({ component: generateFile(txt, path), path: `${config.componentdir}/${path}.js` })
100
+ })
101
+
102
+ if (!res.ok) {
103
+ throw new Error(`Failed to add component: ${res.status} ${res.statusText}`);
104
+ }
105
+
106
+ const data = await res.json()
107
+
108
+ }
109
+ catch (err) {
110
+ console.error('Add Component Error:', err);
111
+ gardenerError(err.message || 'Failed to add component');
112
+ }
113
+
114
+ }
115
+
116
+
117
+ function generateFile(obj, name) {
118
+
119
+
120
+ const { cleanedString, extractedList } = cleanStringAndList(obj);
121
+
122
+ if (extractedList.length === 0) return `
123
+ import { gardener, fetchElement, replaceElement } from '../gardener.js'
124
+
125
+ export function ${name}() {
126
+ return gardener(${cleanedString})
127
+ }
128
+ `;
129
+
130
+ return `
131
+ import { gardener, fetchElement, replaceElement } from '../gardener.js'
132
+
133
+ export function ${name}({${extractedList}}) {
134
+ return gardener(${cleanedString})
135
+ }
136
+ `;
137
+ }
138
+
139
+
140
+ function cleanStringAndList(input) {
141
+ const pattern = /\?"?(\w+)"?\?/g;
142
+ const vars = new Set();
143
+ let match;
144
+
145
+ while ((match = pattern.exec(input)) !== null) {
146
+ vars.add(match[1]);
147
+ }
148
+
149
+ // Replace ?var? with "+var+" and clean up resulting empty strings or double quotes
150
+ const cleanedString = input
151
+ .replace(pattern, '"+$1+"')
152
+ .replace(/^""\+/, '')
153
+ .replace(/\+""$/, '');
154
+
155
+ return {
156
+ cleanedString,
157
+ extractedList: [...vars].join(', ')
158
+ };
159
+ }
@@ -29,11 +29,24 @@ export async function Fetch(
29
29
  body: JSON.stringify(body),
30
30
  });
31
31
 
32
-
32
+ if (!res.ok) {
33
+ throw new Error(`HTTP error! status: ${res.status}`);
34
+ }
33
35
 
34
36
  return res
35
37
  }
36
38
  catch (err) {
37
- console.log(err)
39
+ console.error('Fetch Error:', err);
40
+
41
+ // Import and display error using gardenerError
42
+ import('../gardener/errorBox.js')
43
+ .then(({ gardenerError }) => {
44
+ gardenerError(err.message || 'Network request failed');
45
+ })
46
+ .catch(() => {
47
+ console.error('Error component not available:', err.message);
48
+ });
49
+
50
+ throw err;
38
51
  }
39
52
  }
@@ -1,89 +1,160 @@
1
+ import { gardenerError } from "./components/gardener/errorBox.js";
2
+
1
3
 
2
4
  export function fetchElement(param) {
3
- return document.querySelector(param);
5
+ const element = document.querySelector(param);
6
+ if (!element) {
7
+ console.warn(`Element not found: ${param}`);
8
+ }
9
+ return element;
4
10
  }
5
11
 
6
12
  export function appendElement(parent, child) {
7
- if (typeof parent === 'string') {
8
- parent = fetchElement(parent);
13
+ try {
14
+ if (typeof parent === 'string') {
15
+ parent = fetchElement(parent);
16
+ }
17
+ if (!parent) {
18
+ throw new Error('Parent element is null or undefined');
19
+ }
20
+ if (!child) {
21
+ throw new Error('Child element is null or undefined');
22
+ }
23
+ parent.appendChild(child);
24
+ } catch (error) {
25
+ gardenerError(error);
9
26
  }
10
- parent.appendChild(child);
11
27
  }
12
28
 
13
29
  export function createElement(type, classname) {
14
- let element = document.createElement(type);
15
- if (classname)
16
- element.classList.add(...classname);
17
- return element;
30
+ try {
31
+ if (!type) {
32
+ throw new Error('Element type is required');
33
+ }
34
+ let element = document.createElement(type);
35
+ if (classname)
36
+ element.classList.add(...classname);
37
+ return element;
38
+ } catch (error) {
39
+ gardenerError(error);
40
+ return null;
41
+ }
18
42
  }
19
43
 
20
44
  export function insertText(element, text) {
21
- element.innerText = text;
45
+ if (!element) {
46
+ console.warn('insertText: Element is null or undefined');
47
+ return;
48
+ }
49
+ element.textContent = text;
22
50
  }
23
51
 
24
52
  export function replaceElement(original, New) {
25
- if (typeof original === 'string') {
26
- original = fetchElement(original);
53
+ try {
54
+ if (typeof original === 'string') {
55
+ original = fetchElement(original);
56
+ }
57
+ if (!original) {
58
+ throw new Error('Original element is null or undefined');
59
+ }
60
+ if (!New) {
61
+ throw new Error('New element is null or undefined');
62
+ }
63
+ original.replaceWith(New);
64
+ } catch (error) {
65
+ gardenerError(error);
27
66
  }
28
- original.replaceWith(New);
29
67
  }
30
68
 
31
69
  export function gardener(Dom) {
70
+ try {
71
+ if (!Dom) {
72
+ throw new Error('DOM configuration is null or undefined');
73
+ }
32
74
 
33
- if (Dom.nodeType === 1) return Dom;
34
- // detect if this is an SVG element
35
- const isSVG = [
36
- 'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'g', 'defs', 'clipPath', 'use'
37
- ].includes(Dom.t);
75
+ if (Dom.nodeType === 1) return Dom;
38
76
 
39
- // create element accordingly
40
- let element;
77
+ if (!Dom.t) {
78
+ throw new Error('Element type (t) is required in DOM configuration');
79
+ }
41
80
 
42
- if (isSVG) {
43
- element = document.createElementNS('http://www.w3.org/2000/svg', Dom.t);
44
- if (Dom.cn)
45
- element.classList.add(...Dom.cn);
46
- }
47
- else {
48
- element = createElement(Dom.t, Dom.cn);
49
- }
81
+ // detect if this is an SVG element
82
+ const isSVG = [
83
+ 'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline', 'g', 'defs', 'clipPath', 'use'
84
+ ].includes(Dom.t);
50
85
 
51
- // text content (skip for SVG like <path>)
52
- if (Dom.txt) {
53
- insertText(element, Dom.txt);
54
- }
86
+ // create element accordingly
87
+ let element;
88
+
89
+ if (isSVG) {
90
+ element = document.createElementNS('http://www.w3.org/2000/svg', Dom.t);
91
+ if (Dom.cn)
92
+ element.classList.add(...Dom.cn);
93
+ }
94
+ else {
95
+ element = createElement(Dom.t, Dom.cn);
96
+ }
97
+
98
+ if (!element) {
99
+ throw new Error(`Failed to create element: ${Dom.t}`);
100
+ }
101
+
102
+ // text content (skip for SVG like <path>)
103
+ if (Dom.txt) {
104
+ insertText(element, Dom.txt);
105
+ }
55
106
 
56
- // apply attributes safely
57
- const propertyNames = new Set([
58
- 'value', 'selected', 'muted', 'disabled',
59
- 'selectedIndex', 'volume', // etc.
60
- ]);
61
-
62
- if (Dom.attr) {
63
- for (const [key, value] of Object.entries(Dom.attr)) {
64
- if (isSVG || key.startsWith('data-') || key.startsWith('aria-')) {
65
- element.setAttribute(key, value);
66
- } else if (key in element && !propertyNames.has(key)) {
67
- // Prefer property for known safe cases
68
- try { element[key] = value === '' ? true : value; } catch (e) { element.setAttribute(key, value); }
69
- } else {
70
- element.setAttribute(key, value);
107
+ // apply attributes safely
108
+ const propertyNames = new Set([
109
+ 'value', 'selected', 'muted', 'disabled',
110
+ 'selectedIndex', 'volume', // etc.
111
+ ]);
112
+
113
+ if (Dom.attr) {
114
+ for (const [key, value] of Object.entries(Dom.attr)) {
115
+ try {
116
+ if (isSVG || key.startsWith('data-') || key.startsWith('aria-')) {
117
+ element.setAttribute(key, value);
118
+ } else if (key in element && !propertyNames.has(key)) {
119
+ // Prefer property for known safe cases
120
+ try { element[key] = value === '' ? true : value; } catch (e) { element.setAttribute(key, value); }
121
+ } else {
122
+ element.setAttribute(key, value);
123
+ }
124
+ } catch (attrError) {
125
+ console.warn(`Failed to set attribute ${key}:`, attrError);
126
+ }
71
127
  }
72
128
  }
73
- }
74
129
 
75
- if (Dom.events) {
76
- Object.entries(Dom.events).forEach(([eventName, handler]) => {
77
- element.addEventListener(eventName, handler);
78
- });
79
- }
130
+ if (Dom.events) {
131
+ Object.entries(Dom.events).forEach(([eventName, handler]) => {
132
+ try {
133
+ if (typeof handler !== 'function') {
134
+ throw new Error(`Event handler for '${eventName}' must be a function`);
135
+ }
136
+ element.addEventListener(eventName, handler);
137
+ } catch (eventError) {
138
+ console.warn(`Failed to add event listener ${eventName}:`, eventError);
139
+ }
140
+ });
141
+ }
80
142
 
81
- // recursively handle children
82
- if (Dom.children) {
83
- Dom.children.forEach(child => appendElement(element, gardener(child)));
84
- }
143
+ // recursively handle children
144
+ if (Dom.children) {
145
+ Dom.children.forEach(child => {
146
+ try {
147
+ appendElement(element, gardener(child));
148
+ } catch (childError) {
149
+ console.warn('Failed to append child:', childError);
150
+ }
151
+ });
152
+ }
85
153
 
86
- return element;
154
+ return element;
155
+ } catch (error) {
156
+ gardenerError(error);
157
+ return null;
158
+ }
87
159
  }
88
160
 
89
-