create-gardener 2.1.3 → 2.1.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.
Files changed (96) hide show
  1. package/README.md +108 -302
  2. package/package.json +1 -1
  3. package/template/.env +3 -0
  4. package/template/README.md +181 -0
  5. package/template/buildHelper.js +5 -0
  6. package/template/src/backend/controllers/gardener/hotReload.ts +34 -0
  7. package/template/src/backend/controllers/gardener/imageOptimiser.ts +114 -25
  8. package/template/src/backend/controllers/gardener/index.ts +1 -0
  9. package/template/src/backend/routes/gardener.route.ts +2 -1
  10. package/template/src/backend/server.ts +19 -1
  11. package/template/src/frontend/assets/remote/betterway.jpg +0 -0
  12. package/template/src/frontend/static/components/gardener/hotReloadbtn.js +25 -78
  13. package/template/src/frontend/static/gardenerDev.js +2 -18
  14. package/template/src/frontend/static/style.css +0 -77
  15. package/template/src/frontend/views/_.ejs +101 -89
  16. package/template/build/backend/controllers/gardener/addComponent.d.ts +0 -8
  17. package/template/build/backend/controllers/gardener/addComponent.d.ts.map +0 -1
  18. package/template/build/backend/controllers/gardener/addComponent.js +0 -19
  19. package/template/build/backend/controllers/gardener/addComponent.js.map +0 -1
  20. package/template/build/backend/controllers/gardener/addPage.d.ts +0 -3
  21. package/template/build/backend/controllers/gardener/addPage.d.ts.map +0 -1
  22. package/template/build/backend/controllers/gardener/addPage.js +0 -86
  23. package/template/build/backend/controllers/gardener/addPage.js.map +0 -1
  24. package/template/build/backend/controllers/gardener/createStatic.d.ts +0 -3
  25. package/template/build/backend/controllers/gardener/createStatic.d.ts.map +0 -1
  26. package/template/build/backend/controllers/gardener/createStatic.js +0 -63
  27. package/template/build/backend/controllers/gardener/createStatic.js.map +0 -1
  28. package/template/build/backend/controllers/gardener/imageOptimiser.d.ts +0 -3
  29. package/template/build/backend/controllers/gardener/imageOptimiser.d.ts.map +0 -1
  30. package/template/build/backend/controllers/gardener/imageOptimiser.js +0 -54
  31. package/template/build/backend/controllers/gardener/imageOptimiser.js.map +0 -1
  32. package/template/build/backend/controllers/gardener/index.d.ts +0 -6
  33. package/template/build/backend/controllers/gardener/index.d.ts.map +0 -1
  34. package/template/build/backend/controllers/gardener/index.js +0 -6
  35. package/template/build/backend/controllers/gardener/index.js.map +0 -1
  36. package/template/build/backend/controllers/gardener/saveTemplate.d.ts +0 -3
  37. package/template/build/backend/controllers/gardener/saveTemplate.d.ts.map +0 -1
  38. package/template/build/backend/controllers/gardener/saveTemplate.js +0 -36
  39. package/template/build/backend/controllers/gardener/saveTemplate.js.map +0 -1
  40. package/template/build/backend/libs/generateWebp.d.ts +0 -2
  41. package/template/build/backend/libs/generateWebp.d.ts.map +0 -1
  42. package/template/build/backend/libs/generateWebp.js +0 -16
  43. package/template/build/backend/libs/generateWebp.js.map +0 -1
  44. package/template/build/backend/routes/gardener.route.d.ts +0 -4
  45. package/template/build/backend/routes/gardener.route.d.ts.map +0 -1
  46. package/template/build/backend/routes/gardener.route.js +0 -18
  47. package/template/build/backend/routes/gardener.route.js.map +0 -1
  48. package/template/build/backend/server.d.ts +0 -2
  49. package/template/build/backend/server.d.ts.map +0 -1
  50. package/template/build/backend/server.js +0 -20
  51. package/template/build/backend/server.js.map +0 -1
  52. package/template/build/frontend/assets/favicon.png +0 -0
  53. package/template/build/frontend/assets/gardener.jpg +0 -0
  54. package/template/build/frontend/static/bundle/bundle._.js +0 -1
  55. package/template/build/frontend/static/bundle/bundle._about.js +0 -1
  56. package/template/build/frontend/static/bundle/bundle._kartik.js +0 -1
  57. package/template/build/frontend/static/bundle/bundle._new.js +0 -1
  58. package/template/build/frontend/static/bundle/bundle._ritish.js +0 -1
  59. package/template/build/frontend/static/cache/favicon_500x500.webp +0 -0
  60. package/template/build/frontend/static/cache/favicon_50x50.webp +0 -0
  61. package/template/build/frontend/static/cache/gardener_100x100.webp +0 -0
  62. package/template/build/frontend/static/cache/gardener_500x500.webp +0 -0
  63. package/template/build/frontend/static/cache/gardener_50x50.webp +0 -0
  64. package/template/build/frontend/static/components/copybtn.js +0 -99
  65. package/template/build/frontend/static/components/footer.js +0 -33
  66. package/template/build/frontend/static/components/gardener/errorBox.js +0 -47
  67. package/template/build/frontend/static/components/gardener/hotReloadbtn.js +0 -82
  68. package/template/build/frontend/static/components/gardener/pageOverlayBtn.js +0 -138
  69. package/template/build/frontend/static/components/gardener/parserWindow.js +0 -159
  70. package/template/build/frontend/static/components/nonui/api.js +0 -52
  71. package/template/build/frontend/static/components/nonui/navigation.js +0 -59
  72. package/template/build/frontend/static/components/notification.js +0 -67
  73. package/template/build/frontend/static/gardener.js +0 -160
  74. package/template/build/frontend/static/gardenerConfig.js +0 -1
  75. package/template/build/frontend/static/gardenerDev.js +0 -165
  76. package/template/build/frontend/static/global.js +0 -4
  77. package/template/build/frontend/static/pages/pages._.js +0 -25
  78. package/template/build/frontend/static/pages/pages._about.js +0 -2
  79. package/template/build/frontend/static/pages/pages._kartik.js +0 -2
  80. package/template/build/frontend/static/pages/pages._new.js +0 -2
  81. package/template/build/frontend/static/pages/pages._ritish.js +0 -2
  82. package/template/build/frontend/static/style.css +0 -2
  83. package/template/build/frontend/static/style2.css +0 -26
  84. package/template/build/frontend/style.css +0 -1045
  85. package/template/build/frontend/tailwind.css +0 -1
  86. package/template/build/frontend/views/_.ejs +0 -125
  87. package/template/build/frontend/views/_about.ejs +0 -126
  88. package/template/build/frontend/views/_kartik.ejs +0 -126
  89. package/template/build/frontend/views/_new.ejs +0 -126
  90. package/template/build/frontend/views/_ritish.ejs +0 -126
  91. package/template/build/frontend/views/partials/icons/clipboard.ejs +0 -1
  92. package/template/build/frontend/views/partials/icons/clipboardok.ejs +0 -1
  93. package/template/src/frontend/static/cache/favicon_500x500.webp +0 -0
  94. package/template/src/frontend/static/cache/favicon_50x50.webp +0 -0
  95. package/template/src/frontend/static/cache/gardener_100x100.webp +0 -0
  96. package/template/src/frontend/static/cache/gardener_500x500.webp +0 -0
@@ -0,0 +1,34 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import type { Request, Response } from 'express';
4
+
5
+ // ── Version token ─────────────────────────────────────────────
6
+ // Monotonically-increasing timestamp updated whenever a file
7
+ // in src/frontend/ changes. The frontend stores the first value
8
+ // it sees and reloads as soon as it receives a different one.
9
+ let version: number = Date.now();
10
+
11
+ // ── File watcher ──────────────────────────────────────────────
12
+ const watchTarget = path.resolve('src', 'frontend');
13
+
14
+ let debounce: ReturnType<typeof setTimeout> | null = null;
15
+
16
+ fs.watch(watchTarget, { recursive: true }, (_event, filename) => {
17
+ // Ignore hidden files and node_modules
18
+ if (!filename || filename.startsWith('.')) return;
19
+
20
+ if (debounce) clearTimeout(debounce);
21
+ debounce = setTimeout(() => {
22
+ version = Date.now();
23
+ // console.log(`[gardener] file changed: ${filename} → version ${version}`);
24
+ }, 100);
25
+ });
26
+
27
+ console.log(`[gardener] watching ${watchTarget} for changes…`);
28
+
29
+ // ── Route handler ─────────────────────────────────────────────
30
+ // GET /__gardener/hot-reload
31
+ // Returns { version: <number> }
32
+ export function hotReloadHandler(req: Request, res: Response) {
33
+ res.json({ version });
34
+ }
@@ -3,30 +3,87 @@ import fsp from "fs/promises";
3
3
  import path from "path";
4
4
  import generateWebP from "../../libs/generateWebp.js";
5
5
 
6
-
7
6
  import { fileURLToPath } from "url";
8
7
  const __filename = fileURLToPath(import.meta.url);
9
8
  const __dirname = path.dirname(__filename);
10
9
 
10
+ // Whitelist of allowed remote image domains.
11
+ // Set GARDENER_IMAGE_DOMAINS=example.com,cdn.mysite.com in your .env
12
+ function getAllowedDomains(): string[] {
13
+ const raw = process.env.GARDENER_IMAGE_DOMAINS ?? "";
14
+ return raw
15
+ .split(",")
16
+ .map((d) => d.trim().toLowerCase())
17
+ .filter(Boolean);
18
+ }
19
+
20
+ function isAllowedUrl(rawUrl: string): { ok: true } | { ok: false; reason: string } {
21
+ let parsed: URL;
22
+ try {
23
+ parsed = new URL(rawUrl);
24
+ } catch {
25
+ return { ok: false, reason: "Malformed URL." };
26
+ }
27
+
28
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
29
+ return { ok: false, reason: "Only http/https URLs are allowed." };
30
+ }
31
+
32
+ const allowedDomains = getAllowedDomains();
33
+ if (allowedDomains.length === 0) {
34
+ return { ok: false, reason: "No allowed image domains configured. Set GARDENER_IMAGE_DOMAINS in your .env" };
35
+ }
36
+
37
+ const hostname = parsed.hostname.toLowerCase();
38
+ const isAllowed = allowedDomains.some(
39
+ (domain) => hostname === domain || hostname.endsWith(`.${domain}`)
40
+ );
41
+
42
+ if (!isAllowed) {
43
+ return { ok: false, reason: `Domain '${hostname}' is not in the allowed list.` };
44
+ }
45
+
46
+ return { ok: true };
47
+ }
48
+
49
+ async function downloadRemoteImage(
50
+ remoteUrl: string,
51
+ destPath: string
52
+ ): Promise<void> {
53
+ const response = await fetch(remoteUrl);
54
+
55
+ if (!response.ok) {
56
+ throw new Error(`Remote fetch failed: ${response.status} ${response.statusText}`);
57
+ }
58
+
59
+ const contentType = response.headers.get("content-type") ?? "";
60
+ if (!contentType.startsWith("image/")) {
61
+ throw new Error(`Remote URL did not return an image (got: ${contentType})`);
62
+ }
63
+
64
+ const buffer = await response.arrayBuffer();
65
+ await fsp.writeFile(destPath, Buffer.from(buffer));
66
+ }
11
67
 
12
68
  export async function imageOptimiser(req: Request, res: Response) {
13
69
  try {
14
70
  const { name } = req.params;
15
71
 
16
- if (typeof name !== 'string') return res.status(400).json({ success: false, message: "invalid path" });
17
- // name format: test_500x300.webp
18
- const match = name.match(/^(.+?)_(\d+)x(\d+)\.webp$/);
72
+ if (typeof name !== "string") {
73
+ return res.status(400).json({ success: false, message: "invalid path" });
74
+ }
19
75
 
76
+ // name format: baseName_{width}x{height}.webp
77
+ const match = name.match(/^(.+?)_(\d+)x(\d+)\.webp$/);
20
78
  if (!match) {
21
- return res.status(400).json({ error: "Invalid image format" });
79
+ return res.status(400).json({ error: "Invalid image format. Expected: name_{w}x{h}.webp" });
22
80
  }
23
81
 
24
82
  const [, baseName, widthStr, heightStr] = match;
83
+ const width = parseInt(widthStr!, 10);
84
+ const height = parseInt(heightStr!, 10);
25
85
 
26
- if (!widthStr || !heightStr) return;
27
- const width = parseInt(widthStr, 10);
28
- const height = parseInt(heightStr, 10);
29
-
86
+ // ── 1. Serve from cache if already converted ────────────────────────────
30
87
  const cacheDir = path.join(__dirname, "..", "..", "..", "frontend", "static", "cache");
31
88
  await fsp.mkdir(cacheDir, { recursive: true });
32
89
 
@@ -34,34 +91,66 @@ export async function imageOptimiser(req: Request, res: Response) {
34
91
 
35
92
  try {
36
93
  await fsp.access(outputPath);
37
- return res.sendFile(path.basename(outputPath), {
38
- root: path.dirname(outputPath),
39
- });
94
+ return res.sendFile(path.basename(outputPath), { root: path.dirname(outputPath) });
40
95
  } catch {
41
96
  // not cached → continue
42
97
  }
43
98
 
44
- const assetsDir = path.resolve(__dirname, '..', '..', '..', "frontend", "assets");
45
- const files = await fsp.readdir(assetsDir);
99
+ // ── 2. Locate source image in assets/ (local) ───────────────────────────
100
+ const assetsDir = path.resolve(__dirname, "..", "..", "..", "frontend", "assets");
101
+ await fsp.mkdir(assetsDir, { recursive: true });
46
102
 
47
- const sourceFile = files.find((file) => {
48
- const parsed = path.parse(file);
49
- return parsed.name === baseName;
50
- });
103
+ let inputPath: string | null = null;
51
104
 
52
- if (!sourceFile) {
53
- return res.status(404).json({ error: "Source image not found" });
105
+ const localFiles = await fsp.readdir(assetsDir);
106
+ const localMatch = localFiles.find((file) => path.parse(file).name === baseName);
107
+ if (localMatch) {
108
+ inputPath = path.join(assetsDir, localMatch);
54
109
  }
55
110
 
56
- const inputPath = path.join(assetsDir, sourceFile);
111
+ // ── 3. Check assets/remote/ if not found locally ────────────────────────
112
+ const remoteAssetsDir = path.join(assetsDir, "remote");
113
+ await fsp.mkdir(remoteAssetsDir, { recursive: true });
114
+
115
+ if (!inputPath) {
116
+ const remoteFiles = await fsp.readdir(remoteAssetsDir);
117
+ const remoteMatch = remoteFiles.find((file) => path.parse(file).name === baseName);
118
+ if (remoteMatch) {
119
+ inputPath = path.join(remoteAssetsDir, remoteMatch);
120
+ }
121
+ }
122
+
123
+ // ── 4. Download from remote URL if provided and still not found ──────────
124
+ if (!inputPath) {
125
+ const remoteUrl = req.query.url;
126
+
127
+ if (typeof remoteUrl !== "string" || !remoteUrl) {
128
+ return res.status(404).json({
129
+ error: "Source image not found. Provide ?url=<imageUrl> to use a remote source.",
130
+ });
131
+ }
132
+
133
+ const urlCheck = isAllowedUrl(remoteUrl);
134
+ if (!urlCheck.ok) {
135
+ return res.status(400).json({ error: urlCheck.reason });
136
+ }
137
+
138
+ // Infer extension from URL (fallback to .jpg)
139
+ const urlPathname = new URL(remoteUrl).pathname;
140
+ const remoteExt = path.extname(urlPathname) || ".jpg";
141
+ const destFilename = `${baseName}${remoteExt}`;
142
+ const destPath = path.join(remoteAssetsDir, destFilename);
143
+
144
+ await downloadRemoteImage(remoteUrl, destPath);
145
+ inputPath = destPath;
146
+ }
57
147
 
148
+ // ── 5. Convert & cache ───────────────────────────────────────────────────
58
149
  await generateWebP(inputPath, outputPath, width, height);
59
150
 
60
- return res.sendFile(path.basename(outputPath), {
61
- root: path.dirname(outputPath),
62
- });
151
+ return res.sendFile(path.basename(outputPath), { root: path.dirname(outputPath) });
63
152
  } catch (err) {
64
153
  console.error(err);
65
- return res.status(500).json({ error: "Image optimisation failed" });
154
+ return res.status(500).json({ error: "Image optimisation failed", detail: String(err) });
66
155
  }
67
156
  }
@@ -2,3 +2,4 @@ export * from './imageOptimiser.js';
2
2
  export * from './addPage.js';
3
3
  export * from './addComponent.js';
4
4
  export * from './saveTemplate.js';
5
+ export * from './hotReload.js'
@@ -1,6 +1,6 @@
1
1
  import type { Request, Response } from 'express';
2
2
  import { Router } from "express";
3
- import { addComponent, addPage, imageOptimiser, saveTemplate } from "../controllers/gardener/index.js";
3
+ import { addComponent, addPage, imageOptimiser, saveTemplate, hotReloadHandler } 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('/addcomponent').post(addComponent);
15
15
  router.route('/addpage').post(addPage);
16
16
  router.route('/savetemplate').post(saveTemplate);
17
+ router.route('/__gardener/hot-reload').get(hotReloadHandler);
17
18
  }
18
19
 
19
20
 
@@ -1,7 +1,9 @@
1
1
  // server.ts
2
+ import type { Request, Response, NextFunction } from 'express';
2
3
  import 'dotenv/config';
3
4
  import express from 'express';
4
5
  import frontendRoute from './routes/gardener.route.js'
6
+
5
7
  import path from "path";
6
8
 
7
9
  const app = express();
@@ -15,10 +17,26 @@ const staticFiles = path.resolve(__dirname, '..', 'frontend')
15
17
 
16
18
  app.set('views', path.join(staticFiles, 'views'));
17
19
  app.set("view engine", "ejs");
18
- app.use(express.static(staticFiles));
20
+ app.use(express.static(staticFiles,
21
+ {
22
+ maxAge: '1y', // 1 year
23
+ immutable: true
24
+ }
25
+ ));
26
+
19
27
  app.use(express.json());
20
28
  app.use(frontendRoute);
21
29
 
30
+
31
+ app.use((err: Error & { status: number }, req: Request, res: Response, next: NextFunction) => {
32
+ console.error(err.stack);
33
+
34
+ res.status(err.status || 500).json({
35
+ success: false,
36
+ message: err.message || "Internal Server Error",
37
+ });
38
+ });
39
+
22
40
  const PORT = process.env.PORT || 3000;
23
41
 
24
42
  app.listen(PORT, () => {
@@ -1,82 +1,29 @@
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);
1
+ const POLL_INTERVAL = 500; // ms
2
+ const ENDPOINT = '/__gardener/hot-reload';
3
+
4
+ let knownVersion = null;
5
+
6
+ async function poll() {
7
+ try {
8
+ const res = await fetch(ENDPOINT);
9
+ if (!res.ok) return;
10
+ const { version } = await res.json();
11
+
12
+ if (knownVersion === null) {
13
+ knownVersion = version; // capture baseline on first poll
14
+ return;
15
+ }
16
+
17
+ if (version !== knownVersion) {
18
+ window.location.reload();
19
+ }
20
+ } catch {
21
+ // network hiccup — retry next tick
30
22
  }
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
23
  }
40
24
 
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
- })
25
+ export function startHotReload() {
26
+ poll(); // immediate check
27
+ setInterval(poll, POLL_INTERVAL);
82
28
  }
29
+
@@ -2,7 +2,7 @@ import { mode } from './gardenerConfig.js'
2
2
  import { gardener, appendElement, fetchElement } from './gardener.js'
3
3
  import { addPagebtn } from './components/gardener/pageOverlayBtn.js';
4
4
  import { parserWindow as parserWindowComponent } from './components/gardener/parserWindow.js';
5
- import { hotReloadBtn, togglehotreload } from './components/gardener/hotReloadbtn.js';
5
+ import { startHotReload } from './components/gardener/hotReloadbtn.js';
6
6
  import { gardenerError } from './components/gardener/errorBox.js';
7
7
 
8
8
  const body = fetchElement('body');
@@ -20,28 +20,12 @@ const body = fetchElement('body');
20
20
 
21
21
  if (mode === 'dev') {
22
22
  appendElement(body, addPagebtn);
23
-
24
-
25
- appendElement(body, hotReloadBtn())
26
-
27
- togglehotreload();
23
+ startHotReload();
28
24
  }
29
25
 
30
26
 
31
27
 
32
28
 
33
- document.addEventListener('keydown', function(e) {
34
- // Detect Ctrl + H
35
- if (e.altKey && e.key.toLowerCase() === 'h') {
36
- e.preventDefault(); // Stop browser from opening history
37
- // Your logic here...
38
- togglehotreload();
39
- }
40
- });
41
-
42
-
43
-
44
-
45
29
 
46
30
 
47
31
  export function parserWindow(text) {
@@ -250,18 +250,12 @@
250
250
  .top-0 {
251
251
  top: calc(var(--spacing) * 0);
252
252
  }
253
- .top-1 {
254
- top: calc(var(--spacing) * 1);
255
- }
256
253
  .top-1\/2 {
257
254
  top: calc(1 / 2 * 100%);
258
255
  }
259
256
  .top-1\/4 {
260
257
  top: calc(1 / 4 * 100%);
261
258
  }
262
- .top-2 {
263
- top: calc(var(--spacing) * 2);
264
- }
265
259
  .top-2\/5 {
266
260
  top: calc(2 / 5 * 100%);
267
261
  }
@@ -277,9 +271,6 @@
277
271
  .right-4 {
278
272
  right: calc(var(--spacing) * 4);
279
273
  }
280
- .bottom-0 {
281
- bottom: calc(var(--spacing) * 0);
282
- }
283
274
  .bottom-4 {
284
275
  bottom: calc(var(--spacing) * 4);
285
276
  }
@@ -292,18 +283,12 @@
292
283
  .left-0 {
293
284
  left: calc(var(--spacing) * 0);
294
285
  }
295
- .left-1 {
296
- left: calc(var(--spacing) * 1);
297
- }
298
286
  .left-1\/2 {
299
287
  left: calc(1 / 2 * 100%);
300
288
  }
301
289
  .left-1\/4 {
302
290
  left: calc(1 / 4 * 100%);
303
291
  }
304
- .left-2 {
305
- left: calc(var(--spacing) * 2);
306
- }
307
292
  .left-2\/5 {
308
293
  left: calc(2 / 5 * 100%);
309
294
  }
@@ -319,9 +304,6 @@
319
304
  .z-90 {
320
305
  z-index: 90;
321
306
  }
322
- .z-100 {
323
- z-index: 100;
324
- }
325
307
  .z-\[100\] {
326
308
  z-index: 100;
327
309
  }
@@ -379,12 +361,6 @@
379
361
  .inline-block {
380
362
  display: inline-block;
381
363
  }
382
- .table {
383
- display: table;
384
- }
385
- .h-2 {
386
- height: calc(var(--spacing) * 2);
387
- }
388
364
  .h-2\/4 {
389
365
  height: calc(2 / 4 * 100%);
390
366
  }
@@ -403,24 +379,15 @@
403
379
  .h-screen {
404
380
  height: 100vh;
405
381
  }
406
- .w-1 {
407
- width: calc(var(--spacing) * 1);
408
- }
409
382
  .w-1\/4 {
410
383
  width: calc(1 / 4 * 100%);
411
384
  }
412
- .w-2 {
413
- width: calc(var(--spacing) * 2);
414
- }
415
385
  .w-2\/4 {
416
386
  width: calc(2 / 4 * 100%);
417
387
  }
418
388
  .w-5 {
419
389
  width: calc(var(--spacing) * 5);
420
390
  }
421
- .w-11 {
422
- width: calc(var(--spacing) * 11);
423
- }
424
391
  .w-11\/12 {
425
392
  width: calc(11 / 12 * 100%);
426
393
  }
@@ -457,21 +424,10 @@
457
424
  .flex-1 {
458
425
  flex: 1;
459
426
  }
460
- .border-collapse {
461
- border-collapse: collapse;
462
- }
463
- .-translate-x-1 {
464
- --tw-translate-x: calc(var(--spacing) * -1);
465
- translate: var(--tw-translate-x) var(--tw-translate-y);
466
- }
467
427
  .-translate-x-1\/2 {
468
428
  --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
469
429
  translate: var(--tw-translate-x) var(--tw-translate-y);
470
430
  }
471
- .-translate-y-1 {
472
- --tw-translate-y: calc(var(--spacing) * -1);
473
- translate: var(--tw-translate-x) var(--tw-translate-y);
474
- }
475
431
  .-translate-y-1\/2 {
476
432
  --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
477
433
  translate: var(--tw-translate-x) var(--tw-translate-y);
@@ -482,9 +438,6 @@
482
438
  .cursor-pointer {
483
439
  cursor: pointer;
484
440
  }
485
- .resize {
486
- resize: both;
487
- }
488
441
  .grid-cols-2 {
489
442
  grid-template-columns: repeat(2, minmax(0, 1fr));
490
443
  }
@@ -546,9 +499,6 @@
546
499
  .rounded-lg {
547
500
  border-radius: var(--radius-lg);
548
501
  }
549
- .rounded-md {
550
- border-radius: var(--radius-md);
551
- }
552
502
  .rounded-xl {
553
503
  border-radius: var(--radius-xl);
554
504
  }
@@ -572,10 +522,6 @@
572
522
  border-top-style: var(--tw-border-style);
573
523
  border-top-width: 4px;
574
524
  }
575
- .border-b-1 {
576
- border-bottom-style: var(--tw-border-style);
577
- border-bottom-width: 1px;
578
- }
579
525
  .border-l-8 {
580
526
  border-left-style: var(--tw-border-style);
581
527
  border-left-width: 8px;
@@ -709,9 +655,6 @@
709
655
  .py-20 {
710
656
  padding-block: calc(var(--spacing) * 20);
711
657
  }
712
- .pb-1 {
713
- padding-bottom: calc(var(--spacing) * 1);
714
- }
715
658
  .pb-1\.5 {
716
659
  padding-bottom: calc(var(--spacing) * 1.5);
717
660
  }
@@ -797,9 +740,6 @@
797
740
  .text-green-400 {
798
741
  color: var(--color-green-400);
799
742
  }
800
- .text-green-500 {
801
- color: var(--color-green-500);
802
- }
803
743
  .text-green-800 {
804
744
  color: var(--color-green-800);
805
745
  }
@@ -830,9 +770,6 @@
830
770
  .italic {
831
771
  font-style: italic;
832
772
  }
833
- .underline {
834
- text-decoration-line: underline;
835
- }
836
773
  .opacity-70 {
837
774
  opacity: 70%;
838
775
  }
@@ -852,19 +789,11 @@
852
789
  --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
853
790
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
854
791
  }
855
- .outline {
856
- outline-style: var(--tw-outline-style);
857
- outline-width: 1px;
858
- }
859
792
  .backdrop-blur-md {
860
793
  --tw-backdrop-blur: blur(var(--blur-md));
861
794
  -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
862
795
  backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
863
796
  }
864
- .backdrop-filter {
865
- -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
866
- backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
867
- }
868
797
  .transition {
869
798
  transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
870
799
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
@@ -1081,11 +1010,6 @@
1081
1010
  inherits: false;
1082
1011
  initial-value: 0 0 #0000;
1083
1012
  }
1084
- @property --tw-outline-style {
1085
- syntax: "*";
1086
- inherits: false;
1087
- initial-value: solid;
1088
- }
1089
1013
  @property --tw-backdrop-blur {
1090
1014
  syntax: "*";
1091
1015
  inherits: false;
@@ -1170,7 +1094,6 @@
1170
1094
  --tw-ring-offset-width: 0px;
1171
1095
  --tw-ring-offset-color: #fff;
1172
1096
  --tw-ring-offset-shadow: 0 0 #0000;
1173
- --tw-outline-style: solid;
1174
1097
  --tw-backdrop-blur: initial;
1175
1098
  --tw-backdrop-brightness: initial;
1176
1099
  --tw-backdrop-contrast: initial;