@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,82 @@
1
+ import type { MetadataRoute } from "next";
2
+ import { SITE } from "@/constants";
3
+ import type { SitemapPathConfig } from "./types";
4
+ import { absoluteUrl, normalizeSitePath } from "./urls";
5
+
6
+ export type DynamicSitemapProvider = () => Promise<SitemapPathConfig[]>;
7
+
8
+ let dynamicSitemapProvider: DynamicSitemapProvider | null = null;
9
+
10
+ /**
11
+ * Register template-specific dynamic routes (projects, rooms, blog posts, etc.).
12
+ * Call from your template once, e.g. in app/sitemap.ts after importing this module.
13
+ */
14
+ export function registerDynamicSitemapProvider(provider: DynamicSitemapProvider) {
15
+ dynamicSitemapProvider = provider;
16
+ }
17
+
18
+ function toSitemapEntry(config: SitemapPathConfig): MetadataRoute.Sitemap[number] {
19
+ const path = normalizeSitePath(config.path);
20
+ return {
21
+ url: absoluteUrl(path),
22
+ lastModified: config.lastModified ?? new Date(),
23
+ changeFrequency: config.changeFrequency ?? "weekly",
24
+ priority: config.priority ?? (path === "/" ? 1 : 0.7),
25
+ };
26
+ }
27
+
28
+ function moduleStaticPaths(): SitemapPathConfig[] {
29
+ const paths: SitemapPathConfig[] = [...(SITE.seo.sitemap?.staticRoutes ?? [])];
30
+
31
+ if (SITE.features.gallery) {
32
+ paths.push({ path: "/gallery", changeFrequency: "weekly", priority: 0.75 });
33
+ }
34
+
35
+ if (SITE.features.blogCompose) {
36
+ paths.push({ path: "/blog", changeFrequency: "weekly", priority: 0.8 });
37
+ }
38
+
39
+ if (SITE.features.legalPages) {
40
+ paths.push(
41
+ { path: SITE.legal.privacyPolicyPath, changeFrequency: "yearly", priority: 0.3 },
42
+ { path: SITE.legal.termsPath, changeFrequency: "yearly", priority: 0.3 }
43
+ );
44
+ }
45
+
46
+ return paths;
47
+ }
48
+
49
+ /**
50
+ * Production sitemap builder — home route, module routes, SITE.seo.sitemap.staticRoutes,
51
+ * and optional dynamic provider.
52
+ */
53
+ export async function buildAppSitemap(): Promise<MetadataRoute.Sitemap> {
54
+ const seen = new Set<string>();
55
+ const entries: MetadataRoute.Sitemap = [];
56
+
57
+ const push = (config: SitemapPathConfig) => {
58
+ const path = normalizeSitePath(config.path);
59
+ if (seen.has(path)) return;
60
+ seen.add(path);
61
+ entries.push(toSitemapEntry({ ...config, path }));
62
+ };
63
+
64
+ push({ path: "/", changeFrequency: "daily", priority: 1 });
65
+
66
+ for (const config of moduleStaticPaths()) {
67
+ push(config);
68
+ }
69
+
70
+ if (dynamicSitemapProvider) {
71
+ try {
72
+ const dynamic = await dynamicSitemapProvider();
73
+ for (const config of dynamic) {
74
+ push(config);
75
+ }
76
+ } catch (error) {
77
+ console.error("[sitemap] dynamic provider failed:", error);
78
+ }
79
+ }
80
+
81
+ return entries;
82
+ }
@@ -0,0 +1,30 @@
1
+ /** JSON-LD @type values supported by buildOrganizationJsonLd */
2
+ export type SchemaOrgBusinessType =
3
+ | "Organization"
4
+ | "LocalBusiness"
5
+ | "LodgingBusiness"
6
+ | "Hotel"
7
+ | "RealEstateAgent"
8
+ | "Restaurant"
9
+ | "Store";
10
+
11
+ export interface JsonLdObject {
12
+ "@context": "https://schema.org";
13
+ "@type": string;
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ export interface SitemapPathConfig {
18
+ path: string;
19
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
20
+ priority?: number;
21
+ lastModified?: Date | string;
22
+ }
23
+
24
+ export interface PageMetadataInput {
25
+ title?: string;
26
+ description?: string;
27
+ path?: string;
28
+ image?: string;
29
+ noIndex?: boolean;
30
+ }
@@ -0,0 +1,27 @@
1
+ import { SITE } from "@/constants";
2
+
3
+ /**
4
+ * Absolute site URL with no trailing slash on the origin.
5
+ */
6
+ export function getCanonicalOrigin(): string {
7
+ return SITE.domain.baseUrl.replace(/\/$/, "");
8
+ }
9
+
10
+ /**
11
+ * Build absolute URL for a site path (leading slash optional).
12
+ */
13
+ export function absoluteUrl(path = ""): string {
14
+ const origin = getCanonicalOrigin();
15
+ if (!path) return origin;
16
+ const normalized = path.startsWith("/") ? path : `/${path}`;
17
+ return `${origin}${normalized}`;
18
+ }
19
+
20
+ /**
21
+ * Normalize path for sitemap entries (always leading slash, no trailing slash except root).
22
+ */
23
+ export function normalizeSitePath(path: string): string {
24
+ if (!path || path === "/") return "/";
25
+ const withSlash = path.startsWith("/") ? path : `/${path}`;
26
+ return withSlash.replace(/\/+$/, "") || "/";
27
+ }
@@ -0,0 +1,24 @@
1
+ import Script from "next/script";
2
+
3
+ import { SITE } from "@/constants";
4
+ import {
5
+ getThemeModeInitScript,
6
+ THEME_MODE_INIT_SCRIPT_ID,
7
+ THEME_MODE_STORAGE_KEY,
8
+ type ThemeAppearance,
9
+ } from "@/lib/theme/mode-toggle";
10
+
11
+ /**
12
+ * FOUC-safe theme init — mount once in root layout when theme-modes is installed.
13
+ * Requires suppressHydrationWarning on <html> and <body> (see module installer).
14
+ */
15
+ export default function ThemeModeInit() {
16
+ const siteTheme = SITE.theme as { appearance?: ThemeAppearance };
17
+ const siteDefault = siteTheme.appearance ?? "system";
18
+
19
+ return (
20
+ <Script id={THEME_MODE_INIT_SCRIPT_ID} strategy="beforeInteractive">
21
+ {getThemeModeInitScript(THEME_MODE_STORAGE_KEY, siteDefault)}
22
+ </Script>
23
+ );
24
+ }
@@ -0,0 +1,58 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Moon, Sun } from "lucide-react";
5
+
6
+ import { SITE } from "@/constants";
7
+ import {
8
+ applyThemeModeToDocument,
9
+ readThemeModeFromDocument,
10
+ type ThemeAppearance,
11
+ type ThemeMode,
12
+ } from "@/lib/theme/mode-toggle";
13
+
14
+ function getSiteAppearance(): ThemeAppearance {
15
+ const siteTheme = SITE.theme as { appearance?: ThemeAppearance };
16
+ return siteTheme.appearance ?? "system";
17
+ }
18
+
19
+ /**
20
+ * Hydration-safe toggle — matches docsite ThemeToggle:
21
+ * placeholder until mount, then read data-theme from DOM (set by ThemeModeInit script).
22
+ */
23
+ export default function ThemeModeToggle({ className = "" }: { className?: string }) {
24
+ const [mode, setMode] = useState<ThemeMode>("light");
25
+ const [mounted, setMounted] = useState(false);
26
+
27
+ useEffect(() => {
28
+ setMode(readThemeModeFromDocument(getSiteAppearance()));
29
+ setMounted(true);
30
+ }, []);
31
+
32
+ const toggle = () => {
33
+ const next: ThemeMode = mode === "light" ? "dark" : "light";
34
+ setMode(next);
35
+ applyThemeModeToDocument(next);
36
+ };
37
+
38
+ if (!mounted) {
39
+ return (
40
+ <span
41
+ className={`inline-flex h-9 w-9 rounded-full border border-primary/10 bg-bg-card ${className}`}
42
+ aria-hidden="true"
43
+ />
44
+ );
45
+ }
46
+
47
+ return (
48
+ <button
49
+ type="button"
50
+ onClick={toggle}
51
+ className={`inline-flex h-9 w-9 items-center justify-center rounded-full border border-primary/10 bg-bg-card text-text-main hover:border-primary/30 transition-colors cursor-pointer ${className}`}
52
+ aria-label={`Switch to ${mode === "light" ? "dark" : "light"} mode`}
53
+ title={mode === "light" ? "Dark mode" : "Light mode"}
54
+ >
55
+ {mode === "light" ? <Moon className="w-4 h-4" /> : <Sun className="w-4 h-4" />}
56
+ </button>
57
+ );
58
+ }
@@ -0,0 +1,140 @@
1
+ {
2
+ "modules": {
3
+ "enquiry-modal": {
4
+ "label": "Enquiry modal",
5
+ "description": "Lead capture modal wired to /api/leads. Uses SITE.enquiry.selectionOptions or optional listings API.",
6
+ "paths": ["app/components/EnquiryModal.tsx"],
7
+ "featureFlag": "enquiryModal",
8
+ "default": false
9
+ },
10
+ "footer": {
11
+ "label": "Site footer",
12
+ "description": "Footer with legal disclaimer and optional RERA blocks from SITE.footer and SITE.legal.",
13
+ "paths": ["app/components/Footer.tsx"],
14
+ "featureFlag": "footer",
15
+ "default": false
16
+ },
17
+ "hero-simple": {
18
+ "label": "Simple hero",
19
+ "description": "Carousel hero driven by SITE.hero and SITE.assets.heroDesktop / heroMobile.",
20
+ "paths": ["app/components/Hero.tsx"],
21
+ "featureFlag": "heroSimple",
22
+ "default": false
23
+ },
24
+ "seo": {
25
+ "label": "SEO pack",
26
+ "description": "Production sitemap.xml, robots.txt, JSON-LD (Organization + WebSite), canonical URLs, and Open Graph metadata helpers.",
27
+ "paths": [
28
+ "lib/seo/types.ts",
29
+ "lib/seo/urls.ts",
30
+ "lib/seo/json-ld.ts",
31
+ "lib/seo/metadata.ts",
32
+ "lib/seo/sitemap.ts",
33
+ "lib/seo/index.ts",
34
+ "app/components/SiteJsonLd.tsx",
35
+ "app/sitemap.ts",
36
+ "app/robots.ts"
37
+ ],
38
+ "featureFlag": "seo",
39
+ "default": false
40
+ },
41
+ "gallery": {
42
+ "label": "Gallery CMS",
43
+ "description": "Gallery images with admin CRUD, public /gallery page, and homepage GallerySection.",
44
+ "paths": [
45
+ "lib/features/gallery/gallery.types.ts",
46
+ "lib/features/gallery/gallery.repository.ts",
47
+ "lib/features/gallery/gallery.service.ts",
48
+ "lib/features/gallery/gallery.controller.ts",
49
+ "lib/features/gallery/index.ts",
50
+ "lib/controllers/GalleryController.ts",
51
+ "app/api/gallery/route.ts",
52
+ "app/api/gallery/[id]/route.ts",
53
+ "app/components/GallerySection.tsx",
54
+ "app/gallery/page.tsx",
55
+ "app/gallery/layout.tsx",
56
+ "app/admin/hooks/useGallery.ts",
57
+ "app/admin/components/GalleryList.tsx",
58
+ "app/admin/components/GalleryFormModal.tsx"
59
+ ],
60
+ "featureFlag": "gallery",
61
+ "prismaFragment": "prisma/gallery.prisma",
62
+ "default": false
63
+ },
64
+ "reviews": {
65
+ "label": "Reviews & testimonials",
66
+ "description": "Guest reviews with admin CRUD and homepage ReviewsSection carousel.",
67
+ "paths": [
68
+ "lib/features/reviews/review.repository.ts",
69
+ "lib/features/reviews/review.service.ts",
70
+ "lib/features/reviews/review.controller.ts",
71
+ "lib/features/reviews/index.ts",
72
+ "lib/controllers/ReviewController.ts",
73
+ "app/api/reviews/route.ts",
74
+ "app/api/reviews/[id]/route.ts",
75
+ "app/components/ReviewsSection.tsx",
76
+ "app/admin/hooks/useReviews.ts",
77
+ "app/admin/components/ReviewsList.tsx",
78
+ "app/admin/components/ReviewFormModal.tsx"
79
+ ],
80
+ "featureFlag": "reviews",
81
+ "prismaFragment": "prisma/reviews.prisma",
82
+ "default": false
83
+ },
84
+ "legal-pages": {
85
+ "label": "Legal pages",
86
+ "description": "Privacy policy and terms pages driven by SITE.privacyPage and SITE.termsPage.",
87
+ "paths": [
88
+ "app/components/LegalDocumentPage.tsx",
89
+ "app/privacy-policy/page.tsx",
90
+ "app/terms-and-conditions/page.tsx"
91
+ ],
92
+ "featureFlag": "legalPages",
93
+ "default": false
94
+ },
95
+ "blog-compose": {
96
+ "label": "Compose blog",
97
+ "description": "Declarative Compose Blog Engine — JSON block documents, /blog pages, homepage BlogSection, and admin compose editor.",
98
+ "paths": [
99
+ "lib/blog/compose/types.ts",
100
+ "lib/blog/compose/registry.ts",
101
+ "lib/blog/compose/annotate-text.tsx",
102
+ "lib/blog/compose/blocks/text-blocks.tsx",
103
+ "lib/blog/compose/blocks/media-blocks.tsx",
104
+ "lib/blog/compose/interpreter.tsx",
105
+ "lib/blog/compose/index.ts",
106
+ "lib/blog/register-sitemap.ts",
107
+ "lib/features/blog-compose/blog-compose.types.ts",
108
+ "lib/features/blog-compose/blog-compose.repository.ts",
109
+ "lib/features/blog-compose/blog-compose.service.ts",
110
+ "lib/features/blog-compose/blog-compose.controller.ts",
111
+ "lib/features/blog-compose/index.ts",
112
+ "lib/controllers/BlogComposeController.ts",
113
+ "app/api/blog-posts/route.ts",
114
+ "app/api/blog-posts/[id]/route.ts",
115
+ "app/components/BlogSection.tsx",
116
+ "app/blog/page.tsx",
117
+ "app/blog/[slug]/page.tsx",
118
+ "app/blog/layout.tsx",
119
+ "app/admin/hooks/useBlogPosts.ts",
120
+ "app/admin/components/blog-compose-form.ts",
121
+ "app/admin/panels/BlogComposePanel.tsx",
122
+ "app/components/BlogSidebar.tsx",
123
+ "app/components/BlogShell.tsx"
124
+ ],
125
+ "featureFlag": "blogCompose",
126
+ "prismaFragment": "prisma/blog-compose.prisma",
127
+ "default": false
128
+ },
129
+ "theme-modes": {
130
+ "label": "Light & dark theme modes",
131
+ "description": "Optional visitor light/dark toggle, dual palettes in admin Theme editor, and [data-theme] CSS variables.",
132
+ "paths": [
133
+ "app/components/ThemeModeToggle.tsx",
134
+ "app/components/ThemeModeInit.tsx"
135
+ ],
136
+ "featureFlag": "themeModes",
137
+ "default": false
138
+ }
139
+ }
140
+ }
@@ -0,0 +1,33 @@
1
+ datasource db {
2
+ provider = "mysql"
3
+ }
4
+
5
+ generator client {
6
+ provider = "prisma-client-js"
7
+ engineType = "library"
8
+ }
9
+
10
+ model Lead {
11
+ id String @id @default(uuid())
12
+ projectName String
13
+ name String
14
+ email String
15
+ phone String
16
+ message String?
17
+ createdAt DateTime @default(now())
18
+ }
19
+
20
+ model PromoBanner {
21
+ id String @id @default("global")
22
+ imageUrl String @db.Text
23
+ sec1Title String
24
+ sec1Sub String
25
+ sec2Title String
26
+ sec2Sub String
27
+ sec3Title String
28
+ sec3Sub String
29
+ sec4Title String
30
+ sec4Sub String
31
+ newLaunchLogoUrl String? @db.Text
32
+ updatedAt DateTime @updatedAt
33
+ }