@navneet_25/tempjs 2.0.0 → 3.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 (90) hide show
  1. package/README.md +66 -18
  2. package/cli/brand-manager.js +183 -96
  3. package/cli/config.js +9 -1
  4. package/cli/doctor.js +393 -0
  5. package/cli/fetch-core-modules.js +130 -0
  6. package/cli/index.js +141 -10
  7. package/cli/info.js +28 -1
  8. package/cli/init-options.js +209 -0
  9. package/cli/module-manager.js +168 -0
  10. package/cli/parse-args.js +21 -0
  11. package/cli/update.js +15 -0
  12. package/cli/version-manager.js +518 -0
  13. package/package.json +27 -4
  14. package/packages/core/modules/README.md +72 -0
  15. package/packages/core/modules/blog-compose/app/admin/components/blog-compose-form.ts +44 -0
  16. package/packages/core/modules/blog-compose/app/admin/hooks/useBlogPosts.ts +103 -0
  17. package/packages/core/modules/blog-compose/app/admin/panels/BlogComposePanel.tsx +388 -0
  18. package/packages/core/modules/blog-compose/app/api/blog-posts/[id]/route.ts +29 -0
  19. package/packages/core/modules/blog-compose/app/api/blog-posts/route.ts +21 -0
  20. package/packages/core/modules/blog-compose/app/blog/[slug]/page.tsx +79 -0
  21. package/packages/core/modules/blog-compose/app/blog/layout.tsx +22 -0
  22. package/packages/core/modules/blog-compose/app/blog/page.tsx +102 -0
  23. package/packages/core/modules/blog-compose/app/components/BlogSection.tsx +74 -0
  24. package/packages/core/modules/blog-compose/app/components/BlogShell.tsx +36 -0
  25. package/packages/core/modules/blog-compose/app/components/BlogSidebar.tsx +112 -0
  26. package/packages/core/modules/blog-compose/lib/blog/compose/annotate-text.tsx +103 -0
  27. package/packages/core/modules/blog-compose/lib/blog/compose/blocks/media-blocks.tsx +97 -0
  28. package/packages/core/modules/blog-compose/lib/blog/compose/blocks/text-blocks.tsx +115 -0
  29. package/packages/core/modules/blog-compose/lib/blog/compose/index.ts +21 -0
  30. package/packages/core/modules/blog-compose/lib/blog/compose/interpreter.tsx +55 -0
  31. package/packages/core/modules/blog-compose/lib/blog/compose/registry.ts +276 -0
  32. package/packages/core/modules/blog-compose/lib/blog/compose/types.ts +128 -0
  33. package/packages/core/modules/blog-compose/lib/blog/register-sitemap.ts +18 -0
  34. package/packages/core/modules/blog-compose/lib/controllers/BlogComposeController.ts +2 -0
  35. package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.controller.ts +78 -0
  36. package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.repository.ts +78 -0
  37. package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.service.ts +72 -0
  38. package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.types.ts +20 -0
  39. package/packages/core/modules/blog-compose/lib/features/blog-compose/index.ts +7 -0
  40. package/packages/core/modules/blog-compose/prisma/blog-compose.prisma +13 -0
  41. package/packages/core/modules/enquiry-modal/app/components/EnquiryModal.tsx +308 -0
  42. package/packages/core/modules/footer/app/components/Footer.tsx +127 -0
  43. package/packages/core/modules/gallery/app/admin/components/GalleryFormModal.tsx +132 -0
  44. package/packages/core/modules/gallery/app/admin/components/GalleryList.tsx +142 -0
  45. package/packages/core/modules/gallery/app/admin/hooks/useGallery.ts +72 -0
  46. package/packages/core/modules/gallery/app/api/gallery/[id]/route.ts +29 -0
  47. package/packages/core/modules/gallery/app/api/gallery/route.ts +22 -0
  48. package/packages/core/modules/gallery/app/components/GallerySection.tsx +92 -0
  49. package/packages/core/modules/gallery/app/gallery/layout.tsx +12 -0
  50. package/packages/core/modules/gallery/app/gallery/page.tsx +179 -0
  51. package/packages/core/modules/gallery/lib/controllers/GalleryController.ts +2 -0
  52. package/packages/core/modules/gallery/lib/features/gallery/gallery.controller.ts +78 -0
  53. package/packages/core/modules/gallery/lib/features/gallery/gallery.repository.ts +55 -0
  54. package/packages/core/modules/gallery/lib/features/gallery/gallery.service.ts +43 -0
  55. package/packages/core/modules/gallery/lib/features/gallery/gallery.types.ts +17 -0
  56. package/packages/core/modules/gallery/lib/features/gallery/index.ts +4 -0
  57. package/packages/core/modules/gallery/prisma/gallery.prisma +11 -0
  58. package/packages/core/modules/hero-simple/app/components/Hero.tsx +160 -0
  59. package/packages/core/modules/legal-pages/app/components/LegalDocumentPage.tsx +61 -0
  60. package/packages/core/modules/legal-pages/app/privacy-policy/page.tsx +19 -0
  61. package/packages/core/modules/legal-pages/app/terms-and-conditions/page.tsx +19 -0
  62. package/packages/core/modules/reviews/app/admin/components/ReviewFormModal.tsx +110 -0
  63. package/packages/core/modules/reviews/app/admin/components/ReviewsList.tsx +116 -0
  64. package/packages/core/modules/reviews/app/admin/hooks/useReviews.ts +70 -0
  65. package/packages/core/modules/reviews/app/api/reviews/[id]/route.ts +29 -0
  66. package/packages/core/modules/reviews/app/api/reviews/route.ts +17 -0
  67. package/packages/core/modules/reviews/app/components/ReviewsSection.tsx +100 -0
  68. package/packages/core/modules/reviews/lib/controllers/ReviewController.ts +2 -0
  69. package/packages/core/modules/reviews/lib/features/reviews/index.ts +3 -0
  70. package/packages/core/modules/reviews/lib/features/reviews/review.controller.ts +64 -0
  71. package/packages/core/modules/reviews/lib/features/reviews/review.repository.ts +50 -0
  72. package/packages/core/modules/reviews/lib/features/reviews/review.service.ts +38 -0
  73. package/packages/core/modules/reviews/prisma/reviews.prisma +9 -0
  74. package/packages/core/modules/seo/app/components/SiteJsonLd.tsx +16 -0
  75. package/packages/core/modules/seo/app/robots.ts +30 -0
  76. package/packages/core/modules/seo/app/sitemap.ts +9 -0
  77. package/packages/core/modules/seo/lib/seo/index.ts +5 -0
  78. package/packages/core/modules/seo/lib/seo/json-ld.ts +128 -0
  79. package/packages/core/modules/seo/lib/seo/metadata.ts +65 -0
  80. package/packages/core/modules/seo/lib/seo/sitemap.ts +82 -0
  81. package/packages/core/modules/seo/lib/seo/types.ts +30 -0
  82. package/packages/core/modules/seo/lib/seo/urls.ts +27 -0
  83. package/packages/core/modules/theme-modes/app/components/ThemeModeInit.tsx +24 -0
  84. package/packages/core/modules/theme-modes/app/components/ThemeModeToggle.tsx +58 -0
  85. package/packages/core/modules.json +140 -0
  86. package/packages/core/prisma/schema.prisma +33 -0
  87. package/scripts/module-installer-core.mjs +657 -0
  88. package/scripts/template-modules-admin.mjs +366 -0
  89. package/scripts/template-modules-home.mjs +120 -0
  90. package/templates.json +163 -8
@@ -0,0 +1,366 @@
1
+ import { mkdirSync, readFileSync, writeFileSync, unlinkSync, existsSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+
4
+ /**
5
+ * Shipped templates with vertical admin tabs (room types, projects, facilities).
6
+ * @param {string} content
7
+ */
8
+ export function isVerticalAdminRegistry(content) {
9
+ return (
10
+ content.includes("RoomTypesPanel") ||
11
+ content.includes("ProjectsPanel") ||
12
+ content.includes("FacilitiesList")
13
+ );
14
+ }
15
+
16
+ /**
17
+ * @param {string} content
18
+ * @param {string} iconName
19
+ */
20
+ function addLucideIcon(content, iconName) {
21
+ if (content.includes(iconName)) return content;
22
+
23
+ const blockMatch = content.match(/import\s*\{([^}]+)\}\s*from\s*"lucide-react";/s);
24
+ if (blockMatch) {
25
+ const icons = blockMatch[1]
26
+ .split(",")
27
+ .map((s) => s.trim())
28
+ .filter(Boolean);
29
+ if (!icons.includes(iconName)) {
30
+ icons.push(iconName);
31
+ }
32
+ const formatted = icons.map((i) => ` ${i}`).join(",\n");
33
+ return content.replace(
34
+ blockMatch[0],
35
+ `import {\n${formatted},\n} from "lucide-react";`
36
+ );
37
+ }
38
+
39
+ const singleMatch = content.match(
40
+ /import\s*\{([^}]+)\}\s*from\s*"lucide-react";/
41
+ );
42
+ if (singleMatch && !singleMatch[1].includes("\n")) {
43
+ const icons = singleMatch[1]
44
+ .split(",")
45
+ .map((s) => s.trim())
46
+ .filter(Boolean);
47
+ if (!icons.includes(iconName)) icons.push(iconName);
48
+ return content.replace(
49
+ singleMatch[0],
50
+ `import { ${icons.join(", ")} } from "lucide-react";`
51
+ );
52
+ }
53
+
54
+ return `import { ${iconName} } from "lucide-react";\n${content}`;
55
+ }
56
+
57
+ /**
58
+ * @param {string} content
59
+ * @param {string} importLine
60
+ */
61
+ function ensureComponentImport(content, importLine) {
62
+ if (content.includes(importLine)) return content;
63
+ const anchor = content.match(/import type \{ AdminTabDefinition \}/);
64
+ if (anchor) {
65
+ return content.replace(
66
+ /import type \{ AdminTabDefinition \}[^\n]+\n/,
67
+ `$&${importLine}\n`
68
+ );
69
+ }
70
+ return `${importLine}\n${content}`;
71
+ }
72
+
73
+ /**
74
+ * @param {string} content
75
+ */
76
+ function ensureSiteImport(content) {
77
+ if (content.includes('from "@/constants"')) return content;
78
+ return `import { SITE } from "@/constants";\n${content}`;
79
+ }
80
+
81
+ /**
82
+ * Merge gallery/reviews/blog-compose tab blocks into an existing vertical template registry.
83
+ * @param {string} registryPath
84
+ * @param {string[]} moduleIds
85
+ */
86
+ export function mergeGalleryReviewsIntoRegistry(registryPath, moduleIds) {
87
+ let content = readFileSync(registryPath, "utf8");
88
+ const hasGallery = moduleIds.includes("gallery");
89
+ const hasReviews = moduleIds.includes("reviews");
90
+ const hasBlogCompose = moduleIds.includes("blog-compose");
91
+
92
+ if (hasGallery || hasReviews || hasBlogCompose) {
93
+ content = ensureSiteImport(content);
94
+ }
95
+
96
+ if (hasGallery) {
97
+ content = addLucideIcon(content, "Images");
98
+ content = ensureComponentImport(
99
+ content,
100
+ 'import GalleryList from "./components/GalleryList";'
101
+ );
102
+
103
+ if (!content.includes('id: "gallery"')) {
104
+ const galleryBlock = `
105
+ if (SITE.features.gallery) {
106
+ tabs.push({
107
+ id: "gallery",
108
+ label: "Photo Gallery",
109
+ icon: Images,
110
+ Panel: GalleryList,
111
+ featureFlag: "gallery",
112
+ });
113
+ }`;
114
+
115
+ content = content.replace(/\n return tabs;/, `${galleryBlock}\n\n return tabs;`);
116
+ }
117
+ }
118
+
119
+ if (hasReviews) {
120
+ content = addLucideIcon(content, "MessageSquare");
121
+ content = ensureComponentImport(
122
+ content,
123
+ 'import ReviewsList from "./components/ReviewsList";'
124
+ );
125
+
126
+ if (!content.includes('id: "reviews"')) {
127
+ const reviewsBlock = `
128
+ if (SITE.features.reviews) {
129
+ tabs.push({
130
+ id: "reviews",
131
+ label: "Testimonials",
132
+ icon: MessageSquare,
133
+ Panel: ReviewsList,
134
+ featureFlag: "reviews",
135
+ });
136
+ }`;
137
+
138
+ content = content.replace(/\n return tabs;/, `${reviewsBlock}\n\n return tabs;`);
139
+ }
140
+ }
141
+
142
+ if (hasBlogCompose) {
143
+ content = addLucideIcon(content, "BookOpen");
144
+ content = ensureComponentImport(
145
+ content,
146
+ 'import BlogComposePanel from "./panels/BlogComposePanel";'
147
+ );
148
+
149
+ if (!content.includes('id: "blog-compose"')) {
150
+ const blogBlock = `
151
+ if (SITE.features.blogCompose) {
152
+ tabs.push({
153
+ id: "blog-compose",
154
+ label: "Blog articles",
155
+ icon: BookOpen,
156
+ Panel: BlogComposePanel,
157
+ featureFlag: "blogCompose",
158
+ });
159
+ }`;
160
+
161
+ content = content.replace(/\n return tabs;/, `${blogBlock}\n\n return tabs;`);
162
+ }
163
+ }
164
+
165
+ writeFileSync(registryPath, content, "utf8");
166
+ }
167
+
168
+ /**
169
+ * Generated registry for scaffold / client projects (no vertical tabs).
170
+ * @param {string[]} moduleIds
171
+ * @returns {string}
172
+ */
173
+ export function buildScaffoldAdminRegistrySource(moduleIds) {
174
+ const hasGallery = moduleIds.includes("gallery");
175
+ const hasReviews = moduleIds.includes("reviews");
176
+ const hasBlogCompose = moduleIds.includes("blog-compose");
177
+
178
+ const imports = [
179
+ 'import type { AdminTabDefinition } from "@/lib/admin/types";',
180
+ 'import { Users, Sliders, Award, Palette } from "lucide-react";',
181
+ 'import LeadsPanel from "./panels/LeadsPanel";',
182
+ 'import PromoBannerForm from "./components/PromoBannerForm";',
183
+ 'import LaunchLogoForm from "./components/LaunchLogoForm";',
184
+ 'import ThemeEditor from "./components/ThemeEditor";',
185
+ ];
186
+
187
+ if (hasGallery || hasReviews || hasBlogCompose) {
188
+ imports.unshift('import { SITE } from "@/constants";');
189
+ }
190
+
191
+ if (hasGallery) {
192
+ imports.push('import { Images } from "lucide-react";');
193
+ imports.push('import GalleryList from "./components/GalleryList";');
194
+ }
195
+ if (hasReviews) {
196
+ imports.push('import { MessageSquare } from "lucide-react";');
197
+ imports.push('import ReviewsList from "./components/ReviewsList";');
198
+ }
199
+ if (hasBlogCompose) {
200
+ imports.push('import { BookOpen } from "lucide-react";');
201
+ imports.push('import BlogComposePanel from "./panels/BlogComposePanel";');
202
+ }
203
+
204
+ const lines = [
205
+ ...imports,
206
+ "",
207
+ "/** Scaffold admin tabs — leads, theme, promo, logo; optional modules when installed. */",
208
+ "export function getAdminTabs(): AdminTabDefinition[] {",
209
+ " const tabs: AdminTabDefinition[] = [",
210
+ " { id: \"leads\", label: \"Customer Leads\", icon: Users, Panel: LeadsPanel },",
211
+ " { id: \"theme\", label: \"Theme & Colors\", icon: Palette, Panel: ThemeEditor },",
212
+ " { id: \"banner\", label: \"Promo Settings\", icon: Sliders, Panel: PromoBannerForm },",
213
+ " { id: \"logo\", label: \"Launch Logo\", icon: Award, Panel: LaunchLogoForm },",
214
+ " ];",
215
+ ];
216
+
217
+ if (hasGallery) {
218
+ lines.push(
219
+ "",
220
+ " if (SITE.features.gallery) {",
221
+ " tabs.push({",
222
+ " id: \"gallery\",",
223
+ " label: \"Photo Gallery\",",
224
+ " icon: Images,",
225
+ " Panel: GalleryList,",
226
+ " featureFlag: \"gallery\",",
227
+ " });",
228
+ " }"
229
+ );
230
+ }
231
+
232
+ if (hasReviews) {
233
+ lines.push(
234
+ "",
235
+ " if (SITE.features.reviews) {",
236
+ " tabs.push({",
237
+ " id: \"reviews\",",
238
+ " label: \"Testimonials\",",
239
+ " icon: MessageSquare,",
240
+ " Panel: ReviewsList,",
241
+ " featureFlag: \"reviews\",",
242
+ " });",
243
+ " }"
244
+ );
245
+ }
246
+
247
+ if (hasBlogCompose) {
248
+ lines.push(
249
+ "",
250
+ " if (SITE.features.blogCompose) {",
251
+ " tabs.push({",
252
+ " id: \"blog-compose\",",
253
+ " label: \"Blog articles\",",
254
+ " icon: BookOpen,",
255
+ " Panel: BlogComposePanel,",
256
+ " featureFlag: \"blogCompose\",",
257
+ " });",
258
+ " }"
259
+ );
260
+ }
261
+
262
+ lines.push("", " return tabs;", "}", "");
263
+
264
+ return lines.join("\n");
265
+ }
266
+
267
+ /** @deprecated Use buildScaffoldAdminRegistrySource */
268
+ export function buildAdminRegistrySource(moduleIds) {
269
+ return buildScaffoldAdminRegistrySource(moduleIds);
270
+ }
271
+
272
+ /**
273
+ * @param {string} templateRoot
274
+ */
275
+ export function removeLegacyAdminContentPage(templateRoot) {
276
+ const contentPage = join(templateRoot, "app", "admin", "content", "page.tsx");
277
+ if (existsSync(contentPage)) {
278
+ unlinkSync(contentPage);
279
+ console.log(" ✓ removed legacy app/admin/content/page.tsx");
280
+ }
281
+ }
282
+
283
+ /**
284
+ * @param {string} templateRoot
285
+ */
286
+ export function applyAdminDashboard(templateRoot) {
287
+ const pageSource = [
288
+ '"use client";',
289
+ "",
290
+ "import React, { useMemo, useState } from \"react\";",
291
+ "import AdminShell from \"@/lib/admin/AdminShell\";",
292
+ "import { getAdminTabs } from \"./registry\";",
293
+ "import { useGetLeads } from \"./hooks/useLeads\";",
294
+ "",
295
+ "export default function AdminDashboard() {",
296
+ " const tabs = useMemo(() => getAdminTabs(), []);",
297
+ " const [activeTabId, setActiveTabId] = useState(tabs[0]?.id ?? \"leads\");",
298
+ " const { isLoading: isLoadingLeads } = useGetLeads();",
299
+ "",
300
+ " return (",
301
+ " <AdminShell",
302
+ " tabs={tabs}",
303
+ " activeTabId={activeTabId}",
304
+ " onTabChange={setActiveTabId}",
305
+ " title=\"Management Dashboard\"",
306
+ " subtitle=\"Manage leads, site settings, and optional content modules.\"",
307
+ " loading={activeTabId === \"leads\" && isLoadingLeads}",
308
+ " />",
309
+ " );",
310
+ "}",
311
+ "",
312
+ ].join("\n");
313
+
314
+ const pagePath = join(templateRoot, "app", "admin", "page.tsx");
315
+ mkdirSync(dirname(pagePath), { recursive: true });
316
+ writeFileSync(pagePath, pageSource, "utf8");
317
+ console.log(" ✓ wired unified app/admin/page.tsx dashboard");
318
+ }
319
+
320
+ /**
321
+ * Wire scaffold registry + dashboard (no gallery/reviews modules).
322
+ * @param {string} templateRoot
323
+ */
324
+ export function applyScaffoldAdminRegistry(templateRoot) {
325
+ const registryPath = join(templateRoot, "app", "admin", "registry.ts");
326
+ if (!existsSync(registryPath)) {
327
+ writeFileSync(registryPath, buildScaffoldAdminRegistrySource([]), "utf8");
328
+ console.log(" ✓ created app/admin/registry.ts (scaffold tabs)");
329
+ }
330
+ applyAdminDashboard(templateRoot);
331
+ }
332
+
333
+ /**
334
+ * Regenerate or merge admin tab registry when gallery/reviews modules are installed.
335
+ * @param {string} templateRoot
336
+ * @param {string[]} moduleIds
337
+ */
338
+ export function applyAdminTabRegistry(templateRoot, moduleIds) {
339
+ const hasGallery = moduleIds.includes("gallery");
340
+ const hasReviews = moduleIds.includes("reviews");
341
+ const hasBlogCompose = moduleIds.includes("blog-compose");
342
+
343
+ if (!hasGallery && !hasReviews && !hasBlogCompose) {
344
+ return;
345
+ }
346
+
347
+ const registryPath = join(templateRoot, "app", "admin", "registry.ts");
348
+ const existing = existsSync(registryPath) ? readFileSync(registryPath, "utf8") : "";
349
+
350
+ if (existing && isVerticalAdminRegistry(existing)) {
351
+ mergeGalleryReviewsIntoRegistry(registryPath, moduleIds);
352
+ console.log(" ✓ merged optional module tabs into app/admin/registry.ts");
353
+ } else {
354
+ mkdirSync(dirname(registryPath), { recursive: true });
355
+ writeFileSync(registryPath, buildScaffoldAdminRegistrySource(moduleIds), "utf8");
356
+ console.log(" ✓ updated app/admin/registry.ts with module tabs");
357
+ applyAdminDashboard(templateRoot);
358
+ }
359
+
360
+ removeLegacyAdminContentPage(templateRoot);
361
+ }
362
+
363
+ /** @deprecated Use applyAdminTabRegistry + applyAdminDashboard */
364
+ export function applyAdminContentPage(templateRoot, moduleIds) {
365
+ applyAdminTabRegistry(templateRoot, moduleIds);
366
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @param {string[]} moduleIds
3
+ * @returns {string}
4
+ */
5
+ export function buildModulesHomePageSource(moduleIds) {
6
+ const hasHero = moduleIds.includes("hero-simple");
7
+ const hasFooter = moduleIds.includes("footer");
8
+ const hasEnquiry = moduleIds.includes("enquiry-modal");
9
+ const hasGallery = moduleIds.includes("gallery");
10
+ const hasReviews = moduleIds.includes("reviews");
11
+ const hasBlogCompose = moduleIds.includes("blog-compose");
12
+
13
+ const uiModules = ["enquiry-modal", "footer", "hero-simple", "gallery", "reviews", "blog-compose"];
14
+ const hasAnyUi = moduleIds.some((id) => uiModules.includes(id));
15
+
16
+ const imports = [
17
+ 'import React, { useState } from "react";',
18
+ 'import Navbar from "./components/Navbar";',
19
+ 'import PromoBanner from "./components/PromoBanner";',
20
+ 'import StickyWidgets from "./components/StickyWidgets";',
21
+ 'import { SITE } from "@/constants";',
22
+ ];
23
+
24
+ if (hasHero) imports.push('import Hero from "./components/Hero";');
25
+ if (hasFooter) imports.push('import Footer from "./components/Footer";');
26
+ if (hasEnquiry) imports.push('import EnquiryModal from "./components/EnquiryModal";');
27
+ if (hasGallery) imports.push('import GallerySection from "./components/GallerySection";');
28
+ if (hasReviews) imports.push('import ReviewsSection from "./components/ReviewsSection";');
29
+ if (hasBlogCompose) imports.push('import BlogSection from "./components/BlogSection";');
30
+
31
+ const lines = [
32
+ ...imports,
33
+ "",
34
+ "export default function HomePage() {",
35
+ " const [isModalOpen, setIsModalOpen] = useState(false);",
36
+ " const [modalSelection, setModalSelection] = useState(\"\");",
37
+ "",
38
+ " const handleOpenEnquiry = (label = \"\") => {",
39
+ " setModalSelection(label || SITE.brand.name);",
40
+ " setIsModalOpen(true);",
41
+ " };",
42
+ "",
43
+ " const handleCloseEnquiry = () => {",
44
+ " setIsModalOpen(false);",
45
+ " setModalSelection(\"\");",
46
+ " };",
47
+ "",
48
+ " return (",
49
+ " <div className=\"relative min-h-screen flex flex-col font-sans bg-bg-main\">",
50
+ " <Navbar onOpenEnquiry={handleOpenEnquiry} />",
51
+ "",
52
+ ];
53
+
54
+ if (hasHero) {
55
+ lines.push(" <Hero onOpenEnquiry={handleOpenEnquiry} />");
56
+ }
57
+
58
+ if (!hasHero && !hasGallery && !hasReviews && !hasBlogCompose) {
59
+ lines.push(
60
+ " <main className=\"mx-auto max-w-3xl px-6 py-16 flex-1\">",
61
+ " <h1 className=\"text-3xl font-bold text-primary\">{SITE.brand.name}</h1>",
62
+ " <p className=\"mt-4 text-text-muted\">{SITE.brand.tagline}</p>",
63
+ " <p className=\"mt-6 text-sm text-text-muted\">",
64
+ " Add domain sections in this template folder.",
65
+ " </p>",
66
+ " </main>"
67
+ );
68
+ }
69
+
70
+ if (hasGallery) {
71
+ lines.push(" <GallerySection />");
72
+ }
73
+
74
+ if (hasReviews) {
75
+ lines.push(" <ReviewsSection />");
76
+ }
77
+
78
+ if (hasBlogCompose) {
79
+ lines.push(" <BlogSection />");
80
+ }
81
+
82
+ lines.push("", " <PromoBanner onOpenEnquiry={handleOpenEnquiry} />");
83
+
84
+ if (hasFooter) {
85
+ lines.push("", " <Footer />");
86
+ }
87
+
88
+ lines.push("", " <StickyWidgets onOpenEnquiry={handleOpenEnquiry} />");
89
+
90
+ if (hasEnquiry) {
91
+ lines.push(
92
+ "",
93
+ " <EnquiryModal",
94
+ " isOpen={isModalOpen}",
95
+ " onClose={handleCloseEnquiry}",
96
+ " defaultSelection={modalSelection}",
97
+ " />"
98
+ );
99
+ }
100
+
101
+ lines.push(" </div>", " );", "}", "");
102
+
103
+ if (!hasAnyUi) {
104
+ return [
105
+ 'import { SITE } from "@/constants";',
106
+ "",
107
+ "export default function HomePage() {",
108
+ " return (",
109
+ " <main className=\"mx-auto max-w-3xl px-6 py-16\">",
110
+ " <h1 className=\"text-3xl font-bold\">{SITE.brand.name}</h1>",
111
+ " <p className=\"mt-4 text-text-muted\">{SITE.brand.tagline}</p>",
112
+ " </main>",
113
+ " );",
114
+ "}",
115
+ "",
116
+ ].join("\n");
117
+ }
118
+
119
+ return lines.join("\n");
120
+ }
package/templates.json CHANGED
@@ -10,13 +10,27 @@
10
10
  "directory": "hotel-website-template",
11
11
  "name": "Hotel Website",
12
12
  "description": "Modern hotel and resort website with admin panel, gallery, and booking features",
13
- "version": "1.2.0",
14
- "stack": ["Next.js 16", "React 19", "TypeScript", "Tailwind CSS 4", "Prisma", "MariaDB", "NextAuth"],
13
+ "version": "1.3.0",
14
+ "stack": [
15
+ "Next.js 16",
16
+ "React 19",
17
+ "TypeScript",
18
+ "Tailwind CSS 4",
19
+ "Prisma",
20
+ "MariaDB",
21
+ "NextAuth"
22
+ ],
15
23
  "packageManager": "pnpm",
16
24
  "node": ">=20",
17
25
  "setupTime": "~10 min",
18
26
  "docker": true,
19
- "tags": ["admin", "cms", "gallery", "booking", "leads"],
27
+ "tags": [
28
+ "admin",
29
+ "cms",
30
+ "gallery",
31
+ "booking",
32
+ "leads"
33
+ ],
20
34
  "features": [
21
35
  "Admin dashboard for rooms, facilities, reviews, and leads",
22
36
  "Gallery and promo banner management",
@@ -24,19 +38,65 @@
24
38
  "LeadRat CRM integration",
25
39
  "Docker Compose for local MariaDB"
26
40
  ],
27
- "docs": "DEVELOPER_GUIDE.md"
41
+ "docs": "GETTING_STARTED.md",
42
+ "init": {
43
+ "flagGroups": [
44
+ "generate",
45
+ "theme",
46
+ "brand",
47
+ "database"
48
+ ],
49
+ "brandFields": [
50
+ "name",
51
+ "shortName",
52
+ "baseUrl",
53
+ "phone",
54
+ "phoneDisplay",
55
+ "countryCode",
56
+ "email",
57
+ "address",
58
+ "tagline",
59
+ "developerName",
60
+ "channelPartner",
61
+ "templeDistance"
62
+ ]
63
+ },
64
+ "coreModules": [
65
+ "enquiry-modal",
66
+ "seo",
67
+ "gallery",
68
+ "reviews"
69
+ ],
70
+ "templateModules": [
71
+ "room-types",
72
+ "facilities",
73
+ "slug-pages"
74
+ ]
28
75
  },
29
76
  "real-estate": {
30
77
  "directory": "real-estate-website-template",
31
78
  "name": "Real Estate Website",
32
79
  "description": "Real estate and property listing website with admin panel and property management",
33
- "version": "1.2.0",
34
- "stack": ["Next.js 16", "React 19", "TypeScript", "Tailwind CSS 4", "Prisma", "MariaDB", "NextAuth"],
80
+ "version": "1.3.0",
81
+ "stack": [
82
+ "Next.js 16",
83
+ "React 19",
84
+ "TypeScript",
85
+ "Tailwind CSS 4",
86
+ "Prisma",
87
+ "MariaDB",
88
+ "NextAuth"
89
+ ],
35
90
  "packageManager": "pnpm",
36
91
  "node": ">=20",
37
92
  "setupTime": "~10 min",
38
93
  "docker": true,
39
- "tags": ["admin", "cms", "properties", "leads"],
94
+ "tags": [
95
+ "admin",
96
+ "cms",
97
+ "properties",
98
+ "leads"
99
+ ],
40
100
  "features": [
41
101
  "Admin dashboard for property listings and leads",
42
102
  "Dynamic project pages with slug routing",
@@ -44,7 +104,102 @@
44
104
  "LeadRat CRM integration",
45
105
  "Docker Compose for local MariaDB"
46
106
  ],
47
- "docs": "DEVELOPER_GUIDE.md"
107
+ "docs": "GETTING_STARTED.md",
108
+ "init": {
109
+ "flagGroups": [
110
+ "generate",
111
+ "theme",
112
+ "brand",
113
+ "database"
114
+ ],
115
+ "brandFields": [
116
+ "name",
117
+ "shortName",
118
+ "baseUrl",
119
+ "phone",
120
+ "phoneDisplay",
121
+ "countryCode",
122
+ "email",
123
+ "address",
124
+ "tagline",
125
+ "developerName",
126
+ "channelPartner",
127
+ "agentRera"
128
+ ]
129
+ },
130
+ "coreModules": [
131
+ "enquiry-modal",
132
+ "footer",
133
+ "hero-simple",
134
+ "seo"
135
+ ],
136
+ "templateModules": [
137
+ "projects",
138
+ "slug-pages"
139
+ ]
140
+ },
141
+ "dev-agency": {
142
+ "directory": "dev-agency-website-template",
143
+ "name": "Dev Agency Website",
144
+ "description": "Freelance dev agency landing page — expertise, team, CTA, featured work carousel, leads, and SEO",
145
+ "version": "1.0.0",
146
+ "stack": [
147
+ "Next.js 16",
148
+ "React 19",
149
+ "TypeScript",
150
+ "Tailwind CSS 4",
151
+ "Prisma",
152
+ "MariaDB",
153
+ "NextAuth"
154
+ ],
155
+ "packageManager": "pnpm",
156
+ "node": ">=20",
157
+ "setupTime": "~10 min",
158
+ "docker": true,
159
+ "tags": [
160
+ "admin",
161
+ "agency",
162
+ "portfolio",
163
+ "leads",
164
+ "seo"
165
+ ],
166
+ "features": [
167
+ "Dark agency landing with expertise, team, CTA, and work carousel",
168
+ "Admin CMS for expertise cards, team members, and featured projects",
169
+ "Lead capture via enquiry modal",
170
+ "SEO pack (sitemap, robots, JSON-LD)",
171
+ "Optional core modules via tempjs add-module (theme-modes, blog-compose+sidebar, gallery, reviews, …)"
172
+ ],
173
+ "optionalModuleExamples": [
174
+ "theme-modes",
175
+ "blog-compose+sidebar"
176
+ ],
177
+ "docs": "GETTING_STARTED.md",
178
+ "init": {
179
+ "flagGroups": [
180
+ "generate",
181
+ "theme",
182
+ "brand",
183
+ "database"
184
+ ],
185
+ "brandFields": [
186
+ "name",
187
+ "shortName",
188
+ "baseUrl",
189
+ "phone",
190
+ "phoneDisplay",
191
+ "countryCode",
192
+ "email",
193
+ "address",
194
+ "tagline",
195
+ "developerName",
196
+ "channelPartner"
197
+ ]
198
+ },
199
+ "coreModules": [
200
+ "enquiry-modal",
201
+ "seo"
202
+ ]
48
203
  }
49
204
  }
50
205
  }