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.
- package/README.md +328 -140
- package/package.json +1 -1
- package/template/build/backend/controllers/gardener/addComponent.d.ts +8 -0
- package/template/build/backend/controllers/gardener/addComponent.d.ts.map +1 -0
- package/template/build/backend/controllers/gardener/addComponent.js +19 -0
- package/template/build/backend/controllers/gardener/addComponent.js.map +1 -0
- package/template/build/backend/controllers/gardener/addPage.d.ts +3 -0
- package/template/build/backend/controllers/gardener/addPage.d.ts.map +1 -0
- package/template/build/backend/controllers/gardener/addPage.js +76 -0
- package/template/build/backend/controllers/gardener/addPage.js.map +1 -0
- package/template/build/backend/controllers/gardener/createStatic.d.ts +3 -0
- package/template/build/backend/controllers/gardener/createStatic.d.ts.map +1 -0
- package/template/build/backend/controllers/gardener/createStatic.js +61 -0
- package/template/build/backend/controllers/gardener/createStatic.js.map +1 -0
- package/template/build/backend/controllers/gardener/imageOptimiser.d.ts +3 -0
- package/template/build/backend/controllers/gardener/imageOptimiser.d.ts.map +1 -0
- package/template/build/backend/controllers/gardener/imageOptimiser.js +54 -0
- package/template/build/backend/controllers/gardener/imageOptimiser.js.map +1 -0
- package/template/build/backend/controllers/gardener/index.d.ts +6 -0
- package/template/build/backend/controllers/gardener/index.d.ts.map +1 -0
- package/template/build/backend/controllers/gardener/index.js +6 -0
- package/template/build/backend/controllers/gardener/index.js.map +1 -0
- package/template/build/backend/controllers/gardener/saveTemplate.d.ts +3 -0
- package/template/build/backend/controllers/gardener/saveTemplate.d.ts.map +1 -0
- package/template/build/backend/controllers/gardener/saveTemplate.js +36 -0
- package/template/build/backend/controllers/gardener/saveTemplate.js.map +1 -0
- package/template/build/backend/libs/generateWebp.d.ts +2 -0
- package/template/build/backend/libs/generateWebp.d.ts.map +1 -0
- package/template/build/backend/libs/generateWebp.js +18 -0
- package/template/build/backend/libs/generateWebp.js.map +1 -0
- package/template/build/backend/routes/gardener.route.d.ts +4 -0
- package/template/build/backend/routes/gardener.route.d.ts.map +1 -0
- package/template/build/backend/routes/gardener.route.js +13 -0
- package/template/build/backend/routes/gardener.route.js.map +1 -0
- package/template/build/backend/server.d.ts +2 -0
- package/template/build/backend/server.d.ts.map +1 -0
- package/template/build/backend/server.js +20 -0
- package/template/build/backend/server.js.map +1 -0
- package/template/build/frontend/assets/favicon.png +0 -0
- package/template/build/frontend/assets/gardener.jpg +0 -0
- package/template/build/frontend/static/cache/favicon_500x500.webp +0 -0
- package/template/build/frontend/static/cache/favicon_50x50.webp +0 -0
- package/template/build/frontend/static/cache/gardener_500x500.webp +0 -0
- package/template/build/frontend/static/cache/gardener_50x50.webp +0 -0
- package/template/build/frontend/static/components/copybtn.js +86 -0
- package/template/build/frontend/static/components/nonui/api.js +39 -0
- package/template/build/frontend/static/components/nonui/navigation.js +59 -0
- package/template/build/frontend/static/components/notification.js +67 -0
- package/template/build/frontend/static/gardener.js +89 -0
- package/template/build/frontend/static/gardener.test.js +364 -0
- package/template/build/frontend/static/gardenerConfig.js +1 -0
- package/template/build/frontend/static/gardenerDev.js +499 -0
- package/template/build/frontend/static/global.js +4 -0
- package/template/build/frontend/static/pages/pages._.js +20 -0
- package/template/build/frontend/static/style.css +2 -0
- package/template/build/frontend/static/style2.css +26 -0
- package/template/build/frontend/static/zod.js +8 -0
- package/template/build/frontend/style.css +1045 -0
- package/template/build/frontend/tailwind.css +1 -0
- package/template/build/frontend/views/_.ejs +121 -0
- package/template/build/frontend/views/partials/icons/clipboard.ejs +1 -0
- package/template/build/frontend/views/partials/icons/clipboardok.ejs +1 -0
- package/template/src/backend/controllers/gardener/addPage.ts +30 -24
- package/template/src/backend/controllers/gardener/createStatic.ts +1 -0
- package/template/src/backend/controllers/gardener/saveTemplate.ts +1 -1
- package/template/src/backend/libs/generateWebp.ts +0 -2
- package/template/src/frontend/static/cache/gardener_100x100.webp +0 -0
- package/template/src/frontend/static/components/copybtn.js +16 -3
- package/template/src/frontend/static/components/footer.js +33 -0
- package/template/src/frontend/static/components/gardener/errorBox.js +47 -0
- package/template/src/frontend/static/components/gardener/hotReloadbtn.js +82 -0
- package/template/src/frontend/static/components/gardener/pageOverlayBtn.js +138 -0
- package/template/src/frontend/static/components/gardener/parserWindow.js +159 -0
- package/template/src/frontend/static/components/nonui/api.js +15 -2
- package/template/src/frontend/static/gardener.js +129 -58
- package/template/src/frontend/static/gardenerDev.js +65 -399
- package/template/src/frontend/static/global.js +1 -1
- package/template/src/frontend/static/pages/pages._.js +5 -0
- package/template/src/frontend/static/style.css +101 -1
- package/template/src/frontend/static/style2.css +2 -2
- package/template/src/frontend/static/pages/pages._al.js +0 -2
- package/template/src/frontend/static/pages/pages._new.js +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import "tailwindcss"
|
|
@@ -0,0 +1,121 @@
|
|
|
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 rel="icon" type="image/svg+xml" href="/static/cache/favicon_50x50.webp" />
|
|
7
|
+
<link href="/static/style.css" rel="stylesheet"/>
|
|
8
|
+
<link href="/static/style2.css" rel="stylesheet"/>
|
|
9
|
+
<title>Gardener: The Mini Web Framework</title>
|
|
10
|
+
</head>
|
|
11
|
+
<body class="bg-slate-50 text-slate-900 font-sans">
|
|
12
|
+
|
|
13
|
+
<div class='hidden' id='fileName'><%=fileName%></div>
|
|
14
|
+
<div class='loader w-screen h-screen bg-white fixed z-2'> </div>
|
|
15
|
+
<div class='notification'></div>
|
|
16
|
+
|
|
17
|
+
<div id='main'>
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
<!-- hero -->
|
|
21
|
+
<div class='hero flex-wrap w-full h-screen bg-green-200 flex justify-center items-center px-10'>
|
|
22
|
+
<div class='w-200'>
|
|
23
|
+
<a href="https://ritish.site">Home</a> > <a href="https://ritish.site/projects">Projects</a> > <a href="/">Gardener</a>
|
|
24
|
+
<h1 class='text-6xl my-10 font-bold text-green-900'>Gardener</h1>
|
|
25
|
+
<h2 class='text-2xl font-bold text-green-800 mb-4'>Develop With No Bloat</h2>
|
|
26
|
+
<p class="text-lg mb-6 max-w-md">Gardener is a lightweight, DOM-first front-end library. No virtual DOM, no JSX, and no compilation step. Just the real DOM.</p>
|
|
27
|
+
<div class='flex gap-2 m-2'>
|
|
28
|
+
<a class="block bg-green-700 text-white px-8 py-3 rounded-lg font-bold hover:bg-green-800 transition" href='/get-started'>Get Started</a>
|
|
29
|
+
<a class="block border border-green-700 text-black px-8 py-3 rounded-lg font-bold hover:text-white hover:bg-green-800 transition" href='/documentation/#introduction'>Documentation</a>
|
|
30
|
+
</div>
|
|
31
|
+
<div class='flex gap-2 m-2'>
|
|
32
|
+
<a class="block border border-green-700 text-black px-8 py-3 rounded-lg font-bold hover:text-white hover:bg-green-800 transition" href='https://github.com/ritishDas/Gardener'>View On Github</a>
|
|
33
|
+
<a class="block border border-green-700 text-black px-8 py-3 rounded-lg font-bold hover:text-white hover:bg-green-800 transition" href='https://www.npmjs.com/package/create-gardener'>View On npm</a>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<img src="/static/cache/gardener_500x500.webp" alt="Gardener Logo" class="w-96 h-96 object-contain ml-10">
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<!-- Copy command -->
|
|
40
|
+
<div class="flex w-1/4 items-center mx-auto my-15 justify-between gap-4 bg-[#1e1e1e] border border-gray-700 rounded-lg px-4 py-3 font-mono shadow-sm group">
|
|
41
|
+
<span class="text-sm md:text-base text-gray-300 select-all">
|
|
42
|
+
<span class="text-emerald-400 mr-2">$</span><span class='initCommand'>pnpm create gardener app</span>
|
|
43
|
+
</span>
|
|
44
|
+
|
|
45
|
+
<button class="copybtn flex items-center justify-center p-2 text-gray-400 hover:text-white hover:bg-white/10 rounded transition-all duration-200 active:scale-95" title="Copy to clipboard">
|
|
46
|
+
<span class="w-5 h-5" >
|
|
47
|
+
<%- include('partials/icons/clipboard') %>
|
|
48
|
+
</span>
|
|
49
|
+
</button>
|
|
50
|
+
</div>
|
|
51
|
+
<!-- Philosophy -->
|
|
52
|
+
<div class="max-w-5xl mx-auto py-20 px-6 grid md:grid-cols-2 gap-12">
|
|
53
|
+
<div>
|
|
54
|
+
<h3 class="text-3xl font-bold mb-4 text-green-900">✨ Philosophy</h3>
|
|
55
|
+
<ul class="space-y-3 text-slate-700">
|
|
56
|
+
<li><strong>DOM-First:</strong> Renders directly to the real DOM.</li>
|
|
57
|
+
<li><strong>Deterministic:</strong> If you can inspect it, you can understand it.</li>
|
|
58
|
+
<li><strong>Native:</strong> Works in the browser via ES modules.</li>
|
|
59
|
+
<li><strong>Zero Build:</strong> No bundlers or magic required.</li>
|
|
60
|
+
</ul>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<!-- Features -->
|
|
64
|
+
<div>
|
|
65
|
+
<h3 class="text-3xl font-bold mb-4 text-green-900">🚀 Features</h3>
|
|
66
|
+
<div class="grid grid-cols-2 gap-4">
|
|
67
|
+
<div class="p-4 bg-white shadow-sm border border-green-100 rounded">Declarative UI</div>
|
|
68
|
+
<div class="p-4 bg-white shadow-sm border border-green-100 rounded">SVG Namespace Support</div>
|
|
69
|
+
<div class="p-4 bg-white shadow-sm border border-green-100 rounded">Hot Reload</div>
|
|
70
|
+
<div class="p-4 bg-white shadow-sm border border-green-100 rounded">Image Optimization</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<!-- Api Example -->
|
|
76
|
+
<div class="bg-slate-900 py-20 text-white">
|
|
77
|
+
<div class="max-w-5xl mx-auto px-6">
|
|
78
|
+
<h3 class="text-3xl font-bold mb-8 text-center text-green-400">The Core API</h3>
|
|
79
|
+
<div class="bg-slate-800 p-6 rounded-xl border border-slate-700 font-mono text-sm overflow-x-auto">
|
|
80
|
+
<pre class="text-blue-300">
|
|
81
|
+
gardener({
|
|
82
|
+
t: <span class="text-green-300">'div'</span>,
|
|
83
|
+
cn: [<span class="text-green-300">'p-6'</span>, <span class="text-green-300">'flex'</span>],
|
|
84
|
+
attr: { id: <span class="text-green-300">'hero'</span> },
|
|
85
|
+
txt: <span class="text-green-300">'Welcome to the Garden'</span>,
|
|
86
|
+
events: {
|
|
87
|
+
click: () => console.log(<span class="text-green-300">'Growth!'</span>)
|
|
88
|
+
},
|
|
89
|
+
children: [
|
|
90
|
+
{ t: <span class="text-green-300">'span'</span>, txt: <span class="text-green-300">'Pure DOM nodes.'</span> }
|
|
91
|
+
]
|
|
92
|
+
})
|
|
93
|
+
</pre>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="max-w-5xl mx-auto py-20 px-6 text-center">
|
|
99
|
+
<h3 class="text-3xl font-bold mb-4 text-green-900">🧠 Simple State</h3>
|
|
100
|
+
<p class="mb-8 text-slate-600">No proxies. No diffing. Just clean, reactive callbacks.</p>
|
|
101
|
+
<div class="inline-block text-left bg-white p-6 rounded shadow-lg border-t-4 border-green-500 font-mono text-sm">
|
|
102
|
+
<p class="text-slate-500">// Initialize</p>
|
|
103
|
+
<p>const count = new State(0);</p>
|
|
104
|
+
<p class="text-slate-500 mt-2">// React</p>
|
|
105
|
+
<p>count.registerCb(val => updateUI(val));</p>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<!-- Footer -->
|
|
110
|
+
<footer class="bg-green-900 text-green-100 py-12 text-center">
|
|
111
|
+
<p class="text-xl italic">"Because sometimes you don't need a forest. Just a garden."</p>
|
|
112
|
+
<div class="mt-6 text-sm opacity-70">
|
|
113
|
+
MIT Licensed | Built on Express & EJS
|
|
114
|
+
</div>
|
|
115
|
+
</footer>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
</body>
|
|
119
|
+
<script type='module' src='/static/global.js'> </script>
|
|
120
|
+
<script type='module' src='/static/pages/pages._.js'> </script>
|
|
121
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-clipboard"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" /><path d="M9 5a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2" /></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-clipboard-check"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2" /><path d="M9 5a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2" /><path d="M9 14l2 2l4 -4" /></svg>
|
|
@@ -13,41 +13,47 @@ const templateDir = path.join(frontendDir, 'template');
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
async function findTemplate(fileName: string) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
console.log(fileName)
|
|
19
|
-
const searchFile = `template.${fileName}.ejs`;
|
|
20
|
-
console.log(searchFile)
|
|
21
|
-
const searchPath = path.join(templateDir, searchFile);
|
|
22
|
-
|
|
23
|
-
console.log(searchPath)
|
|
24
|
-
try {
|
|
25
|
-
await access(searchPath); // ✅ checks if file exists
|
|
26
|
-
return searchPath; // return full path immediately
|
|
27
|
-
} catch {
|
|
28
|
-
// file does not exist → continue
|
|
29
|
-
}
|
|
16
|
+
try {
|
|
17
|
+
while (fileName.length !== 0) {
|
|
30
18
|
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
console.log(fileName)
|
|
20
|
+
const searchFile = `template.${fileName}.ejs`;
|
|
21
|
+
console.log(searchFile)
|
|
22
|
+
const searchPath = path.join(templateDir, searchFile);
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
console.log(searchPath)
|
|
25
|
+
try {
|
|
26
|
+
await access(searchPath); // ✅ checks if file exists
|
|
27
|
+
return searchPath; // return full path immediately
|
|
28
|
+
} catch {
|
|
29
|
+
// file does not exist → continue
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let lastUnderscore = fileName.lastIndexOf('_');
|
|
33
|
+
if (lastUnderscore === -1) break;
|
|
37
34
|
|
|
35
|
+
if (lastUnderscore === 0) lastUnderscore += 1;
|
|
36
|
+
|
|
37
|
+
fileName = fileName.substring(0, lastUnderscore);
|
|
38
|
+
console.log(fileName);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw new Error("Template not found");
|
|
43
|
+
}
|
|
38
44
|
// ❗ explicit failure instead of silent bug
|
|
39
|
-
throw new Error("Template not found");
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
export async function addPage(req: Request, res: Response) {
|
|
43
48
|
try {
|
|
44
|
-
const
|
|
45
|
-
|
|
49
|
+
const pagename: string = req.body.page;
|
|
50
|
+
const name = pagename.replaceAll('/', '_');
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
|
|
49
|
-
const templatePath = await findTemplate(name
|
|
54
|
+
const templatePath = await findTemplate(name);//path.join(frontendDir, findTemplate(name)); //path.join(frontendDir, 'frontendtemplate.ejs');
|
|
50
55
|
|
|
56
|
+
if (!templatePath) throw new Error('no template found');
|
|
51
57
|
|
|
52
58
|
|
|
53
59
|
|
|
@@ -61,7 +67,7 @@ export async function addPage(req: Request, res: Response) {
|
|
|
61
67
|
|
|
62
68
|
await replaceLastOccurrence(viewPath, '<script', `<script src="/static/pages/pages.${name}.js" type='module'></script>`);
|
|
63
69
|
|
|
64
|
-
const routeEntry = `router.route("${pagename}").get((req: Request, res: Response) => res.render("${name}"));\n`;
|
|
70
|
+
const routeEntry = `router.route("${pagename}").get((req: Request, res: Response) => res.render("${name}",{fileName:"${name}"}));\n`;
|
|
65
71
|
await fsp.appendFile(routePath, routeEntry, "utf8");
|
|
66
72
|
|
|
67
73
|
await fsp.mkdir(jsDir, { recursive: true });
|
|
@@ -13,7 +13,7 @@ export async function saveTemplate(req: Request, res: Response) {
|
|
|
13
13
|
try {
|
|
14
14
|
const { path: reqPath } = req.body; // ✅ renamed
|
|
15
15
|
|
|
16
|
-
const name = reqPath
|
|
16
|
+
const name = reqPath;
|
|
17
17
|
|
|
18
18
|
const sourceFile = path.join(frontendDir, 'views', `${name}.ejs`);
|
|
19
19
|
|
|
@@ -11,8 +11,6 @@ export default async function generateWebP(
|
|
|
11
11
|
const cacheDir = path.dirname(outputPath);
|
|
12
12
|
await fsp.mkdir(cacheDir, { recursive: true });
|
|
13
13
|
|
|
14
|
-
console.log(`Processing image: ${inputPath}`);
|
|
15
|
-
console.log(`Output path: ${outputPath}`);
|
|
16
14
|
|
|
17
15
|
await sharp(inputPath)
|
|
18
16
|
.resize(width, height, {
|
|
Binary file
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
|
|
2
2
|
import { gardener, fetchElement, replaceElement } from '../gardener.js'
|
|
3
|
+
import addNotification from './notification.js';
|
|
3
4
|
|
|
4
5
|
export function copybtn() {
|
|
5
6
|
return gardener({
|
|
6
7
|
"t": "button",
|
|
8
|
+
events: {
|
|
9
|
+
click: () => {
|
|
10
|
+
try {
|
|
11
|
+
navigator.clipboard.writeText(fetchElement('.initCommand').innerText)
|
|
12
|
+
replaceElement('.copybtn', copybtn());
|
|
13
|
+
addNotification({ status: 'success', message: 'Copied' })
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
addNotification({
|
|
17
|
+
status: 'failure', message: "Couldn't Copy"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
},
|
|
7
23
|
"cn": [
|
|
8
24
|
"copybtn",
|
|
9
25
|
"flex",
|
|
@@ -18,9 +34,6 @@ export function copybtn() {
|
|
|
18
34
|
"duration-200",
|
|
19
35
|
"active:scale-95"
|
|
20
36
|
],
|
|
21
|
-
"attr": {
|
|
22
|
-
"title": "Copy to clipboard"
|
|
23
|
-
},
|
|
24
37
|
"children": [
|
|
25
38
|
{
|
|
26
39
|
"t": "span",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
import { gardener, fetchElement, replaceElement } from '../gardener.js'
|
|
3
|
+
|
|
4
|
+
export function footer({mystery}) {
|
|
5
|
+
return gardener({
|
|
6
|
+
"t": "footer",
|
|
7
|
+
"cn": [
|
|
8
|
+
"bg-green-900",
|
|
9
|
+
"text-green-100",
|
|
10
|
+
"py-12",
|
|
11
|
+
"text-center"
|
|
12
|
+
],
|
|
13
|
+
"children": [
|
|
14
|
+
{
|
|
15
|
+
"t": "p",
|
|
16
|
+
"cn": [
|
|
17
|
+
"text-xl",
|
|
18
|
+
"italic"
|
|
19
|
+
],
|
|
20
|
+
"txt": "\"Because sometimes you don't need a forest. Just a garden.\""
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"t": "div",
|
|
24
|
+
"cn": [
|
|
25
|
+
"mt-6",
|
|
26
|
+
"text-sm",
|
|
27
|
+
"opacity-70"
|
|
28
|
+
],
|
|
29
|
+
"txt": "MIT Licensed | Built on Express & EJS "+mystery+""
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
})
|
|
33
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { gardener, fetchElement, appendElement } from '../../gardener.js'
|
|
2
|
+
|
|
3
|
+
const body = fetchElement('body');
|
|
4
|
+
|
|
5
|
+
export function gardenerError(error) {
|
|
6
|
+
appendElement(body, gardener({
|
|
7
|
+
t: 'div',
|
|
8
|
+
// Added: centering, shadow, border-left for "alert" feel, and high z-index
|
|
9
|
+
cn: [
|
|
10
|
+
'fixed', 'top-1/2', 'left-1/2', '-translate-x-1/2', '-translate-y-1/2',
|
|
11
|
+
'w-11/12', 'max-w-md', 'bg-white', 'text-gray-800', 'shadow-2xl',
|
|
12
|
+
'border-l-8', 'border-red-600', 'rounded-r-lg', 'z-[100]', 'p-0', 'overflow-hidden'
|
|
13
|
+
],
|
|
14
|
+
children: [
|
|
15
|
+
{
|
|
16
|
+
t: 'div',
|
|
17
|
+
cn: ['bg-red-50', 'p-4', 'flex', 'items-center', 'gap-3'],
|
|
18
|
+
children: [
|
|
19
|
+
{
|
|
20
|
+
t: 'h2',
|
|
21
|
+
cn: ['text-red-700', 'font-bold', 'text-lg', 'uppercase', 'tracking-wider'],
|
|
22
|
+
txt: '⚠️ System Error'
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
t: 'div',
|
|
28
|
+
cn: ['p-6', 'bg-white'],
|
|
29
|
+
children: [
|
|
30
|
+
{
|
|
31
|
+
t: 'p',
|
|
32
|
+
cn: ['font-mono', 'text-sm', 'bg-gray-100', 'p-3', 'rounded', 'border', 'border-gray-200', 'break-words'],
|
|
33
|
+
txt: error
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
t: 'button',
|
|
37
|
+
cn: ['mt-4', 'w-full', 'py-2', 'bg-gray-800', 'text-white', 'rounded', 'hover:bg-black', 'transition-colors', 'cursor-pointer'],
|
|
38
|
+
txt: 'Dismiss',
|
|
39
|
+
events: {
|
|
40
|
+
click: (e) => e.target.closest('.fixed').remove()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}))
|
|
47
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { gardener, fetchElement, appendElement } from '../../gardener.js'
|
|
2
|
+
import { gardenerError } from './errorBox.js';
|
|
3
|
+
|
|
4
|
+
const config = {
|
|
5
|
+
hotreload: false
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let hotReload;
|
|
9
|
+
let hotReloadtimeout;
|
|
10
|
+
const localStore = localStorage.getItem('hotreload');
|
|
11
|
+
|
|
12
|
+
if (localStore === null) hotReload = config.hotreload;
|
|
13
|
+
else if (localStore === 'true') hotReload = true
|
|
14
|
+
else if (localStore === 'false') hotReload = false
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export function togglehotreload() {
|
|
18
|
+
const hr = hotReload;
|
|
19
|
+
const hrcheck = fetchElement('#hrcheckbox');
|
|
20
|
+
|
|
21
|
+
localStorage.setItem('hotreload', hr);
|
|
22
|
+
|
|
23
|
+
hotReload = !hotReload;
|
|
24
|
+
|
|
25
|
+
if (hr) {
|
|
26
|
+
hrcheck.style.background = '#66e666';
|
|
27
|
+
fetchElement('.hrcheckbox').checked = true;
|
|
28
|
+
localStorage.setItem('hotreload', 'true');
|
|
29
|
+
hotReloadtimeout = setTimeout(() => window.location.reload(), 1000);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
hrcheck.style.background = 'red';
|
|
33
|
+
fetchElement('.hrcheckbox').checked = false;
|
|
34
|
+
localStorage.setItem('hotreload', 'false');
|
|
35
|
+
clearTimeout(hotReloadtimeout);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//localStorage.setItem('hotreload', hotReload);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function hotReloadBtn() {
|
|
42
|
+
return gardener({
|
|
43
|
+
t: 'p',
|
|
44
|
+
cn: ['bg-gray-200', 'fixed', 'bottom-0', 'z-100', 'right-0', 'border-b-1', 'p-2', 'rounded-md'],
|
|
45
|
+
children: [
|
|
46
|
+
{
|
|
47
|
+
t: 'span',
|
|
48
|
+
txt: 'Press '
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
t: 'span',
|
|
52
|
+
cn: ['text-green-500', 'font-bold'],
|
|
53
|
+
txt: 'Alt+h'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
t: 'span',
|
|
57
|
+
txt: ' to toggle Hot Reload'
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
t: 'form',
|
|
61
|
+
attr: {
|
|
62
|
+
id: 'hrcheckbox',
|
|
63
|
+
},
|
|
64
|
+
events: {
|
|
65
|
+
click: () => togglehotreload()
|
|
66
|
+
},
|
|
67
|
+
cn: ['p-2', 'bg-red-300'],
|
|
68
|
+
children: [{
|
|
69
|
+
t: 'label',
|
|
70
|
+
txt: 'Hot Reload ',
|
|
71
|
+
}
|
|
72
|
+
, {
|
|
73
|
+
t: 'input',
|
|
74
|
+
cn: ['hrcheckbox'],
|
|
75
|
+
attr: {
|
|
76
|
+
type: 'checkbox'
|
|
77
|
+
}
|
|
78
|
+
}]
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
})
|
|
82
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { gardener, fetchElement, appendElement } from '../../gardener.js'
|
|
2
|
+
|
|
3
|
+
const body = fetchElement('body');
|
|
4
|
+
|
|
5
|
+
function opnPagedialog(btn = true) {
|
|
6
|
+
if (btn) {
|
|
7
|
+
const dialog = gardener({
|
|
8
|
+
t: 'form', cn: ['addpageform', 'fixed', 'left-2/5', 'bg-gray-200', 'rounded-lg', 'block', 'top-2/5', 'p-2', 'flex', 'flex-col', 'p-5', 'gap-2'], events: {
|
|
9
|
+
submit: async (e) => {
|
|
10
|
+
try {
|
|
11
|
+
e.preventDefault()
|
|
12
|
+
const data = new FormData(e.target);
|
|
13
|
+
const input = Object.fromEntries(data.entries());
|
|
14
|
+
|
|
15
|
+
const response = await fetch('/addpage', {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": 'application/json'
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify(input)
|
|
21
|
+
}).then(res => res.json())
|
|
22
|
+
opnPagedialog(false)
|
|
23
|
+
window.location.href = `${input.page}`
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.log(err)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
}, children: [{
|
|
31
|
+
t: 'label',
|
|
32
|
+
txt: 'ENTER PATH FOR NEW PAGE'
|
|
33
|
+
}, { t: 'input', attr: { name: 'page' }, cn: ['pathinput'] }]
|
|
34
|
+
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
appendElement(body, dialog);
|
|
38
|
+
fetchElement('.pathinput').focus();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
fetchElement('.addpageform').remove();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const pagebtns = gardener({
|
|
48
|
+
t: 'div',
|
|
49
|
+
cn: [
|
|
50
|
+
'fixed',
|
|
51
|
+
'bottom-20',
|
|
52
|
+
'right-4',
|
|
53
|
+
'flex',
|
|
54
|
+
'flex-col',
|
|
55
|
+
'gap-2',
|
|
56
|
+
'bg-white',
|
|
57
|
+
'shadow-lg',
|
|
58
|
+
'rounded-xl',
|
|
59
|
+
'p-3',
|
|
60
|
+
'z-50'
|
|
61
|
+
],
|
|
62
|
+
children: [
|
|
63
|
+
{
|
|
64
|
+
t: 'button',
|
|
65
|
+
cn: [
|
|
66
|
+
'px-4',
|
|
67
|
+
'py-2',
|
|
68
|
+
'bg-blue-500',
|
|
69
|
+
'text-white',
|
|
70
|
+
'rounded-lg',
|
|
71
|
+
'hover:bg-blue-600',
|
|
72
|
+
'transition'
|
|
73
|
+
],
|
|
74
|
+
children: [{ t: 'span', txt: 'New Page' }],
|
|
75
|
+
events: {
|
|
76
|
+
click: opnPagedialog
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
t: 'button',
|
|
81
|
+
cn: [
|
|
82
|
+
'px-4',
|
|
83
|
+
'py-2',
|
|
84
|
+
'bg-gray-800',
|
|
85
|
+
'text-white',
|
|
86
|
+
'rounded-lg',
|
|
87
|
+
'hover:bg-gray-900',
|
|
88
|
+
'transition'
|
|
89
|
+
],
|
|
90
|
+
children: [{ t: 'span', txt: 'Save Template' }],
|
|
91
|
+
events: {
|
|
92
|
+
click: async () => {
|
|
93
|
+
const result = await fetch('/savetemplate', {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers: { "Content-Type": 'application/json' },
|
|
96
|
+
body: JSON.stringify({ path: fetchElement('#fileName').innerText })
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const data = await result.json(); // ✅ fix
|
|
100
|
+
alert(data.message);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
export const addPagebtn = gardener({
|
|
109
|
+
t: 'div',
|
|
110
|
+
cn: ['fixed', 'bottom-4', 'right-4', 'z-50'],
|
|
111
|
+
events: {
|
|
112
|
+
mouseenter: () => appendElement(addPagebtn, pagebtns),
|
|
113
|
+
mouseleave: () => pagebtns.remove()
|
|
114
|
+
},
|
|
115
|
+
children: [
|
|
116
|
+
{
|
|
117
|
+
t: 'span',
|
|
118
|
+
// cn: ['pb-1.5', 'flex', 'items-center', 'justify-center', 'h-15', 'w-15', 'bg-black', 'text-white', 'fixed', 'bottom-22', 'right-2'],
|
|
119
|
+
|
|
120
|
+
cn: [
|
|
121
|
+
'flex',
|
|
122
|
+
'items-center',
|
|
123
|
+
'justify-center',
|
|
124
|
+
'h-14',
|
|
125
|
+
'w-14',
|
|
126
|
+
'bg-black',
|
|
127
|
+
'text-white',
|
|
128
|
+
'fixed',
|
|
129
|
+
'bottom-22',
|
|
130
|
+
'right-2',
|
|
131
|
+
'rounded-full',
|
|
132
|
+
'shadow-lg',
|
|
133
|
+
'cursor-pointer',
|
|
134
|
+
],
|
|
135
|
+
txt: 'GR'
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
});
|