@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.
- package/README.md +66 -18
- package/cli/brand-manager.js +183 -96
- package/cli/config.js +9 -1
- package/cli/doctor.js +393 -0
- package/cli/fetch-core-modules.js +130 -0
- package/cli/index.js +141 -10
- package/cli/info.js +28 -1
- package/cli/init-options.js +209 -0
- package/cli/module-manager.js +168 -0
- package/cli/parse-args.js +21 -0
- package/cli/update.js +15 -0
- package/cli/version-manager.js +518 -0
- package/package.json +27 -4
- package/packages/core/modules/README.md +72 -0
- package/packages/core/modules/blog-compose/app/admin/components/blog-compose-form.ts +44 -0
- package/packages/core/modules/blog-compose/app/admin/hooks/useBlogPosts.ts +103 -0
- package/packages/core/modules/blog-compose/app/admin/panels/BlogComposePanel.tsx +388 -0
- package/packages/core/modules/blog-compose/app/api/blog-posts/[id]/route.ts +29 -0
- package/packages/core/modules/blog-compose/app/api/blog-posts/route.ts +21 -0
- package/packages/core/modules/blog-compose/app/blog/[slug]/page.tsx +79 -0
- package/packages/core/modules/blog-compose/app/blog/layout.tsx +22 -0
- package/packages/core/modules/blog-compose/app/blog/page.tsx +102 -0
- package/packages/core/modules/blog-compose/app/components/BlogSection.tsx +74 -0
- package/packages/core/modules/blog-compose/app/components/BlogShell.tsx +36 -0
- package/packages/core/modules/blog-compose/app/components/BlogSidebar.tsx +112 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/annotate-text.tsx +103 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/blocks/media-blocks.tsx +97 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/blocks/text-blocks.tsx +115 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/index.ts +21 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/interpreter.tsx +55 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/registry.ts +276 -0
- package/packages/core/modules/blog-compose/lib/blog/compose/types.ts +128 -0
- package/packages/core/modules/blog-compose/lib/blog/register-sitemap.ts +18 -0
- package/packages/core/modules/blog-compose/lib/controllers/BlogComposeController.ts +2 -0
- package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.controller.ts +78 -0
- package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.repository.ts +78 -0
- package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.service.ts +72 -0
- package/packages/core/modules/blog-compose/lib/features/blog-compose/blog-compose.types.ts +20 -0
- package/packages/core/modules/blog-compose/lib/features/blog-compose/index.ts +7 -0
- package/packages/core/modules/blog-compose/prisma/blog-compose.prisma +13 -0
- package/packages/core/modules/enquiry-modal/app/components/EnquiryModal.tsx +308 -0
- package/packages/core/modules/footer/app/components/Footer.tsx +127 -0
- package/packages/core/modules/gallery/app/admin/components/GalleryFormModal.tsx +132 -0
- package/packages/core/modules/gallery/app/admin/components/GalleryList.tsx +142 -0
- package/packages/core/modules/gallery/app/admin/hooks/useGallery.ts +72 -0
- package/packages/core/modules/gallery/app/api/gallery/[id]/route.ts +29 -0
- package/packages/core/modules/gallery/app/api/gallery/route.ts +22 -0
- package/packages/core/modules/gallery/app/components/GallerySection.tsx +92 -0
- package/packages/core/modules/gallery/app/gallery/layout.tsx +12 -0
- package/packages/core/modules/gallery/app/gallery/page.tsx +179 -0
- package/packages/core/modules/gallery/lib/controllers/GalleryController.ts +2 -0
- package/packages/core/modules/gallery/lib/features/gallery/gallery.controller.ts +78 -0
- package/packages/core/modules/gallery/lib/features/gallery/gallery.repository.ts +55 -0
- package/packages/core/modules/gallery/lib/features/gallery/gallery.service.ts +43 -0
- package/packages/core/modules/gallery/lib/features/gallery/gallery.types.ts +17 -0
- package/packages/core/modules/gallery/lib/features/gallery/index.ts +4 -0
- package/packages/core/modules/gallery/prisma/gallery.prisma +11 -0
- package/packages/core/modules/hero-simple/app/components/Hero.tsx +160 -0
- package/packages/core/modules/legal-pages/app/components/LegalDocumentPage.tsx +61 -0
- package/packages/core/modules/legal-pages/app/privacy-policy/page.tsx +19 -0
- package/packages/core/modules/legal-pages/app/terms-and-conditions/page.tsx +19 -0
- package/packages/core/modules/reviews/app/admin/components/ReviewFormModal.tsx +110 -0
- package/packages/core/modules/reviews/app/admin/components/ReviewsList.tsx +116 -0
- package/packages/core/modules/reviews/app/admin/hooks/useReviews.ts +70 -0
- package/packages/core/modules/reviews/app/api/reviews/[id]/route.ts +29 -0
- package/packages/core/modules/reviews/app/api/reviews/route.ts +17 -0
- package/packages/core/modules/reviews/app/components/ReviewsSection.tsx +100 -0
- package/packages/core/modules/reviews/lib/controllers/ReviewController.ts +2 -0
- package/packages/core/modules/reviews/lib/features/reviews/index.ts +3 -0
- package/packages/core/modules/reviews/lib/features/reviews/review.controller.ts +64 -0
- package/packages/core/modules/reviews/lib/features/reviews/review.repository.ts +50 -0
- package/packages/core/modules/reviews/lib/features/reviews/review.service.ts +38 -0
- package/packages/core/modules/reviews/prisma/reviews.prisma +9 -0
- package/packages/core/modules/seo/app/components/SiteJsonLd.tsx +16 -0
- package/packages/core/modules/seo/app/robots.ts +30 -0
- package/packages/core/modules/seo/app/sitemap.ts +9 -0
- package/packages/core/modules/seo/lib/seo/index.ts +5 -0
- package/packages/core/modules/seo/lib/seo/json-ld.ts +128 -0
- package/packages/core/modules/seo/lib/seo/metadata.ts +65 -0
- package/packages/core/modules/seo/lib/seo/sitemap.ts +82 -0
- package/packages/core/modules/seo/lib/seo/types.ts +30 -0
- package/packages/core/modules/seo/lib/seo/urls.ts +27 -0
- package/packages/core/modules/theme-modes/app/components/ThemeModeInit.tsx +24 -0
- package/packages/core/modules/theme-modes/app/components/ThemeModeToggle.tsx +58 -0
- package/packages/core/modules.json +140 -0
- package/packages/core/prisma/schema.prisma +33 -0
- package/scripts/module-installer-core.mjs +657 -0
- package/scripts/template-modules-admin.mjs +366 -0
- package/scripts/template-modules-home.mjs +120 -0
- 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
|
+
}
|