create-gardener 2.0.3 → 2.0.5

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/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "create-gardener",
3
- "homepage": "https://ritish.site/Gardener",
3
+ "homepage": "https://gardener.ritish.site",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/ritishDas/gardener"
7
7
  },
8
- "version": "2.0.3",
8
+ "version": "2.0.5",
9
9
  "description": "A dom gardener converting dom elements into json and vice versa",
10
10
  "main": "index.js",
11
11
  "bin": {
@@ -7,8 +7,12 @@ async function buildHelper() {
7
7
 
8
8
  await fs.cp(src, dest, { recursive: true });
9
9
 
10
- await fs.writeFile(path.join(dest, 'static', 'gardenerConfig.js'), "export const mode = 'prod';", 'utf8');
10
+ await fs.writeFile(path.join(dest, 'static', 'gardenerConfig.js'), "export const
11
+ mode = 'prod'; ", 'utf8');
12
+
13
+ await fs.rm(path.join(dest, 'template'), { recursive: true });
11
14
 
12
15
  }
13
16
 
14
- buildHelper();// const path = require('path');
17
+ buildHelper();
18
+
@@ -1,25 +1,19 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "esnext",
4
- "module": "nodenext",
3
+ "target": "ESNext",
4
+ "module": "NodeNext",
5
5
  "moduleResolution": "Bundler",
6
+
6
7
  "checkJs": true,
8
+
7
9
  "baseUrl": ".",
8
10
  "paths": {
9
- "/static/*.js": ["src/frontend/static/*.js"]
11
+ "/static/*": ["src/frontend/static/*"]
10
12
  },
11
13
 
12
-
13
14
  "sourceMap": true,
14
- "declaration": true,
15
- "declarationMap": true,
16
-
17
-
18
- "verbatimModuleSyntax": true,
19
- "isolatedModules": true,
20
- "noUncheckedSideEffectImports": true,
21
- "moduleDetection": "force",
22
15
  "skipLibCheck": true
23
16
  },
24
17
  "include": ["src/frontend/static/**/*.js"]
25
18
  }
19
+
@@ -1,7 +1,7 @@
1
1
  {
2
- "name": "create-gardener",
3
- "version": "2.0.3",
4
- "description": "A dom gardener converting dom elements into json and vice versa",
2
+ "name": "app",
3
+ "version": "1.0.0",
4
+ "description": "a web app build with create gardener",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cross-env NODE_ENV=production node build/backend/server.js",
@@ -1,5 +1,6 @@
1
1
  import type { Request, Response } from "express";
2
2
  import fsp from "fs/promises";
3
+ import { access } from "fs/promises";
3
4
  import path from 'path';
4
5
 
5
6
  import { fileURLToPath } from "url";
@@ -7,22 +8,58 @@ const __filename = fileURLToPath(import.meta.url);
7
8
  const __dirname = path.dirname(__filename);
8
9
 
9
10
  const frontendDir = path.resolve(__dirname, '..', '..', '..', 'frontend');
11
+ const templateDir = path.join(frontendDir, 'template');
12
+
13
+
14
+
15
+ async function findTemplate(fileName: string) {
16
+ while (fileName.length !== 0) {
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
+ }
30
+
31
+ const lastUnderscore = fileName.lastIndexOf('_');
32
+ if (lastUnderscore === -1) break;
33
+
34
+ fileName = fileName.substring(0, lastUnderscore + 1);
35
+ console.log(fileName);
36
+ }
37
+
38
+ // ❗ explicit failure instead of silent bug
39
+ throw new Error("Template not found");
40
+ }
10
41
 
11
42
  export async function addPage(req: Request, res: Response) {
12
43
  try {
13
44
  const pagename: string = req.body.page;
14
45
  const name = pagename.replaceAll('/', '_');
15
46
 
16
- const templatePath = path.join(frontendDir, 'frontendtemplate.ejs');
47
+
48
+
49
+ const templatePath = await findTemplate(name);//path.join(frontendDir, findTemplate(name)); //path.join(frontendDir, 'frontendtemplate.ejs');
50
+
51
+
52
+
53
+
17
54
  const viewPath = path.join(frontendDir, `views`, `${name}.ejs`);
18
55
  const routePath = path.resolve(__dirname, '..', '..', 'routes', 'gardener.route.ts');
19
56
  const jsDir = path.join(frontendDir, 'static/pages');
20
- const jsFilePath = path.join(jsDir, `${name}.js`);
57
+ const jsFilePath = path.join(jsDir, `pages.${name}.js`);
21
58
 
22
59
  const templateContent = await fsp.readFile(templatePath, 'utf8');
23
60
  await fsp.writeFile(viewPath, templateContent, "utf8");
24
61
 
25
- await replaceLastOccurrence(viewPath, '<script', `<script src="/static/pages/${name}.js" type='module'></script>`);
62
+ await replaceLastOccurrence(viewPath, '<script', `<script src="/static/pages/pages.${name}.js" type='module'></script>`);
26
63
 
27
64
  const routeEntry = `router.route("${pagename}").get((req: Request, res: Response) => res.render("${name}"));\n`;
28
65
  await fsp.appendFile(routePath, routeEntry, "utf8");
@@ -2,3 +2,4 @@ export * from './imageOptimiser.js';
2
2
  export * from './addPage.js';
3
3
  export * from './createStatic.js';
4
4
  export * from './addComponent.js';
5
+ export * from './saveTemplate.js';
@@ -0,0 +1,60 @@
1
+ import type { Request, Response } from "express";
2
+ import fsp from "fs/promises";
3
+ import path from "path";
4
+ import { fileURLToPath } from "url";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const frontendDir = path.resolve(__dirname, "..", "..", "..", "frontend");
10
+ const templateDir = path.join(frontendDir, "template");
11
+
12
+ export async function saveTemplate(req: Request, res: Response) {
13
+ try {
14
+ const { path: reqPath } = req.body; // ✅ renamed
15
+
16
+ const name = reqPath.replaceAll("/", "_");
17
+
18
+ const sourceFile = path.join(frontendDir, 'views', `${name}.ejs`);
19
+
20
+ const sourceFileContent = await fsp.readFile(sourceFile, "utf-8");
21
+
22
+ const targetFileContent = replaceLastOccurrence(
23
+ sourceFileContent,
24
+ `/static/pages/pages.${name}.js`,
25
+ ""
26
+ );
27
+
28
+ // ✅ ensure directory exists
29
+ await fsp.mkdir(templateDir, { recursive: true });
30
+
31
+ await fsp.writeFile(
32
+ path.join(templateDir, `template.${name}.ejs`),
33
+ targetFileContent,
34
+ "utf-8"
35
+ );
36
+
37
+ return res.json({ message: "Template Saved Successfully" });
38
+ } catch (err) {
39
+ console.error(err);
40
+ return res.status(500).json({ message: "Something went wrong" });
41
+ }
42
+ }
43
+
44
+ function replaceLastOccurrence(
45
+ content: string,
46
+ searchPattern: string,
47
+ replacementLine: string
48
+ ) {
49
+ const lines = content.split("\n");
50
+
51
+ for (let i = lines.length - 1; i >= 0; i--) {
52
+ if (lines[i]!.includes(searchPattern)) {
53
+ lines[i] = replacementLine; // ✅ replace cleanly
54
+ return lines.join("\n"); // ✅ return result
55
+ }
56
+ }
57
+
58
+ console.warn(`Pattern not found: ${searchPattern}`);
59
+ return content; // fallback
60
+ }
@@ -1,6 +1,6 @@
1
1
  import type { Request, Response } from 'express';
2
2
  import { Router } from "express";
3
- import { addComponent, addPage, createStatic, imageOptimiser } from "../controllers/gardener/index.js";
3
+ import { addComponent, addPage, createStatic, imageOptimiser, saveTemplate } from "../controllers/gardener/index.js";
4
4
 
5
5
  const router: Router = Router();
6
6
  export default router;
@@ -14,6 +14,7 @@ if (process.env.NODE_ENV !== 'production') {
14
14
  router.route("/createstatic").get(createStatic);
15
15
  router.route('/addcomponent').post(addComponent);
16
16
  router.route('/addpage').post(addPage);
17
+ router.route('/savetemplate').post(saveTemplate);
17
18
  }
18
19
 
19
20
 
@@ -21,12 +22,3 @@ if (process.env.NODE_ENV !== 'production') {
21
22
 
22
23
 
23
24
  router.route('/').get((req: Request, res: Response) => res.render('_'));
24
- router.route('/login').get((req: Request, res: Response) => res.render('_login'));
25
- router.route("/test").get((req: Request, res: Response) => res.render("_test"))
26
- router.route("/rd").get((req: Request, res: Response) => res.render("_rd"));
27
- router.route("/car").get((req: Request, res: Response) => res.render("_car"));
28
- router.route("/onemore").get((req: Request, res: Response) => res.render("_onemore"));
29
-
30
- router.route("/re").get((req: Request, res: Response) => res.render("_re"));
31
- router.route("/playground").get((req: Request, res: Response) => res.render("_playground"));
32
- router.route("/get-started").get((req: Request, res: Response) => res.render("_get-started"));
@@ -20,15 +20,108 @@ else if (localStore === 'false') hotReload = false
20
20
 
21
21
 
22
22
 
23
+ // const addPagebtn = gardener({
24
+ // t: 'button',
25
+ // cn: ['pb-1.5', 'flex', 'items-center', 'justify-center', 'h-15', 'w-15', 'bg-green-300', 'fixed', 'bottom-22', 'right-2', 'rounded-full', 'text-5xl'],
26
+ // children: [{ t: 'span', txt: '+' }],
27
+ // events: {
28
+ // click: opnPagedialog
29
+ // }
30
+ // });
31
+
32
+ const pagebtns = gardener({
33
+ t: 'div',
34
+ cn: [
35
+ 'fixed',
36
+ 'bottom-20',
37
+ 'right-4',
38
+ 'flex',
39
+ 'flex-col',
40
+ 'gap-2',
41
+ 'bg-white',
42
+ 'shadow-lg',
43
+ 'rounded-xl',
44
+ 'p-3',
45
+ 'z-50'
46
+ ],
47
+ children: [
48
+ {
49
+ t: 'button',
50
+ cn: [
51
+ 'px-4',
52
+ 'py-2',
53
+ 'bg-blue-500',
54
+ 'text-white',
55
+ 'rounded-lg',
56
+ 'hover:bg-blue-600',
57
+ 'transition'
58
+ ],
59
+ children: [{ t: 'span', txt: 'New Page' }],
60
+ events: {
61
+ click: opnPagedialog
62
+ }
63
+ },
64
+ {
65
+ t: 'button',
66
+ cn: [
67
+ 'px-4',
68
+ 'py-2',
69
+ 'bg-gray-800',
70
+ 'text-white',
71
+ 'rounded-lg',
72
+ 'hover:bg-gray-900',
73
+ 'transition'
74
+ ],
75
+ children: [{ t: 'span', txt: 'Save Template' }],
76
+ events: {
77
+ click: async () => {
78
+ const result = await fetch('/savetemplate', {
79
+ method: 'POST',
80
+ headers: { "Content-Type": 'application/json' },
81
+ body: JSON.stringify({ path: window.location.pathname })
82
+ });
83
+
84
+ const data = await result.json(); // ✅ fix
85
+ alert(data.message);
86
+ }
87
+ }
88
+ }
89
+ ]
90
+ });
23
91
  const addPagebtn = gardener({
24
- t: 'button',
25
- cn: ['pb-1.5', 'flex', 'items-center', 'justify-center', 'h-15', 'w-15', 'bg-green-300', 'fixed', 'bottom-22', 'right-2', 'rounded-full', 'text-5xl'],
26
- children: [{ t: 'span', txt: '+' }],
92
+ t: 'div',
93
+ cn: ['fixed', 'bottom-4', 'right-4', 'z-50'],
27
94
  events: {
28
- click: opnPagedialog
29
- }
95
+ mouseenter: () => appendElement(addPagebtn, pagebtns),
96
+ mouseleave: () => pagebtns.remove()
97
+ },
98
+ children: [
99
+ {
100
+ t: 'span',
101
+ // cn: ['pb-1.5', 'flex', 'items-center', 'justify-center', 'h-15', 'w-15', 'bg-black', 'text-white', 'fixed', 'bottom-22', 'right-2'],
102
+
103
+ cn: [
104
+ 'flex',
105
+ 'items-center',
106
+ 'justify-center',
107
+ 'h-14',
108
+ 'w-14',
109
+ 'bg-black',
110
+ 'text-white',
111
+ 'fixed',
112
+ 'bottom-22',
113
+ 'right-2',
114
+ 'rounded-full',
115
+ 'shadow-lg',
116
+ 'cursor-pointer',
117
+ ],
118
+ txt: 'GR'
119
+ }
120
+ ]
30
121
  });
31
122
 
123
+
124
+
32
125
  if (mode === 'dev') {
33
126
  appendElement(body, addPagebtn);
34
127
 
@@ -1,5 +1,2 @@
1
1
  import { gardener, fetchElement, replaceElement, appendElement } from "/static/gardener.js";
2
- import { log, parser, addEl, State } from "/static/gardenerDev.js"
3
-
4
-
5
-
2
+ import {log, parser, addEl, State} from "/static/gardenerDev.js"
@@ -0,0 +1,2 @@
1
+ import { gardener, fetchElement, replaceElement, appendElement } from "/static/gardener.js";
2
+ import {log, parser, addEl, State} from "/static/gardenerDev.js"