bsmnt 0.2.11 → 0.3.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 (115) hide show
  1. package/dist/helpers/create/copy-template.d.ts +1 -1
  2. package/dist/helpers/create/copy-template.d.ts.map +1 -1
  3. package/dist/helpers/create/index.d.ts.map +1 -1
  4. package/dist/helpers/create/index.js +2 -1
  5. package/dist/helpers/create/index.js.map +1 -1
  6. package/dist/helpers/integrate/merge-config.d.ts.map +1 -1
  7. package/dist/helpers/integrate/merge-config.js +0 -2
  8. package/dist/helpers/integrate/merge-config.js.map +1 -1
  9. package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
  10. package/dist/helpers/integrate/sanity/config.js +3 -14
  11. package/dist/helpers/integrate/sanity/config.js.map +1 -1
  12. package/dist/index.js +84 -35
  13. package/dist/index.js.map +1 -1
  14. package/package.json +1 -1
  15. package/src/templates/next-pagebuilder/.env.example +11 -0
  16. package/src/templates/next-pagebuilder/README.md +23 -0
  17. package/src/templates/next-pagebuilder/_gitignore +67 -0
  18. package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +68 -0
  19. package/src/templates/next-pagebuilder/app/(content)/layout.tsx +13 -0
  20. package/src/templates/next-pagebuilder/app/api/[[...slug]]/route.ts +100 -0
  21. package/src/templates/next-pagebuilder/app/api/draft-mode/disable/route.ts +7 -0
  22. package/src/templates/next-pagebuilder/app/api/draft-mode/enable/route.ts +20 -0
  23. package/src/templates/next-pagebuilder/app/api/revalidate/route.ts +121 -0
  24. package/src/templates/next-pagebuilder/app/favicon.ico +0 -0
  25. package/src/templates/next-pagebuilder/app/layout.tsx +80 -0
  26. package/src/templates/next-pagebuilder/app/robots.ts +15 -0
  27. package/src/templates/next-pagebuilder/app/sitemap.md/route.ts +124 -0
  28. package/src/templates/next-pagebuilder/app/sitemap.xml/route.ts +80 -0
  29. package/src/templates/next-pagebuilder/app/studio/[[...tool]]/page.tsx +8 -0
  30. package/src/templates/next-pagebuilder/biome.json +239 -0
  31. package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +95 -0
  32. package/src/templates/next-pagebuilder/components/layout/header/components/cta-button.tsx +28 -0
  33. package/src/templates/next-pagebuilder/components/layout/header/components/mega-menu-panel.tsx +90 -0
  34. package/src/templates/next-pagebuilder/components/layout/header/components/nav-item-renderer.tsx +98 -0
  35. package/src/templates/next-pagebuilder/components/layout/header/components/nav-leaf-item.tsx +33 -0
  36. package/src/templates/next-pagebuilder/components/layout/header/components/types.ts +7 -0
  37. package/src/templates/next-pagebuilder/components/layout/header/header-client.tsx +110 -0
  38. package/src/templates/next-pagebuilder/components/layout/header/index.tsx +8 -0
  39. package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +45 -0
  40. package/src/templates/next-pagebuilder/components/layout/wrapper/index.tsx +30 -0
  41. package/src/templates/next-pagebuilder/components/page-builder/components/article-content/index.tsx +83 -0
  42. package/src/templates/next-pagebuilder/components/page-builder/components/article-content/related-post-item.tsx +27 -0
  43. package/src/templates/next-pagebuilder/components/page-builder/components/description.tsx +17 -0
  44. package/src/templates/next-pagebuilder/components/page-builder/components/hero.tsx +17 -0
  45. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/content-card.tsx +66 -0
  46. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/content-grid.tsx +42 -0
  47. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/index.tsx +28 -0
  48. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/types.ts +16 -0
  49. package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +36 -0
  50. package/src/templates/next-pagebuilder/components/page-builder/types.ts +23 -0
  51. package/src/templates/next-pagebuilder/components/page-document/index.tsx +91 -0
  52. package/src/templates/next-pagebuilder/components/sanity/draft-mode-toggle.tsx +27 -0
  53. package/src/templates/next-pagebuilder/components/sanity/rich-text.tsx +87 -0
  54. package/src/templates/next-pagebuilder/components/sanity/visual-editing.tsx +27 -0
  55. package/src/templates/next-pagebuilder/components/ui/image/index.tsx +216 -0
  56. package/src/templates/next-pagebuilder/components/ui/link/index.tsx +152 -0
  57. package/src/templates/next-pagebuilder/components/ui/sanity-image/index.tsx +41 -0
  58. package/src/templates/next-pagebuilder/lib/integrations/check-integration.ts +5 -0
  59. package/src/templates/next-pagebuilder/lib/integrations/sanity/client.ts +27 -0
  60. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/disable-draft-mode.tsx +23 -0
  61. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/page-builder-input.tsx +36 -0
  62. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/page-category-input.tsx +50 -0
  63. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/rich-text.tsx +84 -0
  64. package/src/templates/next-pagebuilder/lib/integrations/sanity/confirm-publish-action.ts +40 -0
  65. package/src/templates/next-pagebuilder/lib/integrations/sanity/env.ts +34 -0
  66. package/src/templates/next-pagebuilder/lib/integrations/sanity/fetchers/layout.ts +35 -0
  67. package/src/templates/next-pagebuilder/lib/integrations/sanity/icons.ts +58 -0
  68. package/src/templates/next-pagebuilder/lib/integrations/sanity/live/index.tsx +61 -0
  69. package/src/templates/next-pagebuilder/lib/integrations/sanity/markdown-proxy.config.ts +50 -0
  70. package/src/templates/next-pagebuilder/lib/integrations/sanity/page-builder-config.ts +132 -0
  71. package/src/templates/next-pagebuilder/lib/integrations/sanity/page-category.ts +28 -0
  72. package/src/templates/next-pagebuilder/lib/integrations/sanity/queries.ts +281 -0
  73. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.cli.ts +29 -0
  74. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.config.ts +211 -0
  75. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/index.ts +4 -0
  76. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +89 -0
  77. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/description.ts +29 -0
  78. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/hero.ts +28 -0
  79. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +45 -0
  80. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/content/author.ts +70 -0
  81. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/content/blog-category.ts +55 -0
  82. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/index.ts +96 -0
  83. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/company-data.ts +62 -0
  84. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/footer.ts +79 -0
  85. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/navbar.ts +74 -0
  86. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/link.ts +125 -0
  87. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/logo-field.ts +9 -0
  88. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/metadata.ts +68 -0
  89. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/nav-objects.ts +192 -0
  90. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page-builder.ts +39 -0
  91. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page-folder.ts +124 -0
  92. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page.ts +232 -0
  93. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/richText.ts +63 -0
  94. package/src/templates/next-pagebuilder/lib/integrations/sanity/singletons.ts +44 -0
  95. package/src/templates/next-pagebuilder/lib/integrations/sanity/structure.ts +453 -0
  96. package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/image.ts +8 -0
  97. package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/link.ts +137 -0
  98. package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/page-builder-markdown.ts +81 -0
  99. package/src/templates/next-pagebuilder/lib/scripts/sanity-typegen.ts +45 -0
  100. package/src/templates/next-pagebuilder/lib/styles/cn.ts +5 -0
  101. package/src/templates/next-pagebuilder/lib/styles/global.css +70 -0
  102. package/src/templates/next-pagebuilder/lib/utils/base-url.ts +17 -0
  103. package/src/templates/next-pagebuilder/lib/utils/format-date.ts +8 -0
  104. package/src/templates/next-pagebuilder/lib/utils/json-ld.tsx +213 -0
  105. package/src/templates/next-pagebuilder/lib/utils/metadata.ts +167 -0
  106. package/src/templates/next-pagebuilder/lib/utils/sitemap.ts +37 -0
  107. package/src/templates/next-pagebuilder/lib/utils/slug-tag.ts +6 -0
  108. package/src/templates/next-pagebuilder/next.config.ts +134 -0
  109. package/src/templates/next-pagebuilder/package.json +71 -0
  110. package/src/templates/next-pagebuilder/postcss.config.mjs +39 -0
  111. package/src/templates/next-pagebuilder/proxy.ts +81 -0
  112. package/src/templates/next-pagebuilder/svg.d.ts +5 -0
  113. package/src/templates/next-pagebuilder/tsconfig.json +38 -0
  114. package/src/helpers/integrate/sanity/files/lib/scripts/copy-sanity-mcp.ts +0 -23
  115. package/src/helpers/integrate/sanity/files/lib/scripts/generate-page.ts +0 -297
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "next-pagebuilder",
3
+ "description": "Basement Next.js starter template",
4
+ "version": "0.1.0",
5
+ "private": true,
6
+ "scripts": {
7
+ "analyze": "cross-env ANALYZE=true bun run build",
8
+ "analyze:experimental": "next experimental-analyze",
9
+ "build": "next build",
10
+ "dev": "next dev",
11
+ "format": "biome format --write .",
12
+ "generate": "bun ./lib/scripts/generate.ts",
13
+ "lighthouse": "bunx @unlighthouse/cli --site http://localhost:3000",
14
+ "lint": "biome lint --max-diagnostics=200",
15
+ "lint:fix": "biome lint --write --unsafe --max-diagnostics=200",
16
+ "start": "next start",
17
+ "test": "bun test",
18
+ "typecheck": "tsgo --noEmit",
19
+ "typecheck:compare": "bun run typecheck:tsc && bun run typecheck",
20
+ "typecheck:tsc": "tsc --noEmit --incremental false",
21
+ "sanity:extract": "cd lib/integrations/sanity && bun --env-file ../../../.env.local sanity schema extract",
22
+ "sanity:typegen": "bun ./lib/scripts/sanity-typegen.ts",
23
+ "predev": "bun run sanity:typegen",
24
+ "prebuild": "bun run sanity:typegen"
25
+ },
26
+ "dependencies": {
27
+ "@phosphor-icons/react": "^2.1.10",
28
+ "@portabletext/types": "^4.0.2",
29
+ "@sanity/asset-utils": "^2.3.0",
30
+ "@sanity/image-url": "^2.0.3",
31
+ "@sanity/table": "^2.0.1",
32
+ "@sanity/vision": "^5.17.1",
33
+ "@sanity/visual-editing": "^5.3.1",
34
+ "class-variance-authority": "^0.7.1",
35
+ "next": "16.2.3",
36
+ "next-sanity": "^12.1.4",
37
+ "react": "19.2.4",
38
+ "react-dom": "19.2.4",
39
+ "react-use": "^17.6.0",
40
+ "sanity": "^5.17.1",
41
+ "sanity-plugin-media": "^4.1.1",
42
+ "schema-dts": "^2.0.0",
43
+ "tailwind-merge": "^3.5.0",
44
+ "zod": "^4.3.6"
45
+ },
46
+ "devDependencies": {
47
+ "@biomejs/biome": "2.4.8",
48
+ "@clack/prompts": "^1.1.0",
49
+ "@csstools/postcss-global-data": "^4.0.0",
50
+ "@next/bundle-analyzer": "16.2.1",
51
+ "@svgr/webpack": "^8.1.0",
52
+ "@tailwindcss/postcss": "^4.2.2",
53
+ "@types/bun": "^1.3.11",
54
+ "@types/node": "^25.5.0",
55
+ "@types/react": "^19.2.14",
56
+ "@types/react-dom": "^19.2.3",
57
+ "@typescript/native-preview": "^7.0.0-dev.20260323.1",
58
+ "babel-plugin-react-compiler": "1.0.0",
59
+ "cross-env": "^10.1.0",
60
+ "postcss-functions": "^4.0.2",
61
+ "postcss-preset-env": "^11.2.0",
62
+ "tailwindcss": "^4.2.2",
63
+ "typescript": "^5.9.3"
64
+ },
65
+ "trustedDependencies": [
66
+ "@biomejs/biome",
67
+ "@tailwindcss/oxide",
68
+ "esbuild",
69
+ "sharp"
70
+ ]
71
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * PostCSS preset-env config
3
+ * @see Docs {@link https://github.com/csstools/postcss-plugins/blob/main/plugin-packs/postcss-preset-env/README.md#options}
4
+ * @see Features Flags {@link https://github.com/csstools/postcss-plugins/blob/main/plugin-packs/postcss-preset-env/FEATURES.md}
5
+ * @type {import('postcss-preset-env').pluginOptions}
6
+ */
7
+ const presetEnvConfig = {
8
+ autoprefixer: {
9
+ flexbox: "no-2009",
10
+ },
11
+ stage: 3,
12
+ features: {
13
+ "custom-properties": false,
14
+ "custom-media-queries": true,
15
+ "nesting-rules": true,
16
+ },
17
+ }
18
+
19
+ /**
20
+ * PostCSS global data config
21
+ * Makes sure the css module files have access to these context files
22
+ * @see {@link https://github.com/csstools/postcss-global-data?tab=readme-ov-file#options}
23
+ * @type {import('@csstools/postcss-global-data').pluginOptions}
24
+ */
25
+ const globalDataConfig = {
26
+ files: ["./lib/styles/global.css"],
27
+ }
28
+
29
+ const postcssConfig = {
30
+ // NOTE: Order is important
31
+ plugins: {
32
+ "@tailwindcss/postcss": {},
33
+ "@csstools/postcss-global-data": globalDataConfig,
34
+ // NOTE: This has to be last config
35
+ "postcss-preset-env": presetEnvConfig,
36
+ },
37
+ }
38
+
39
+ export default postcssConfig
@@ -0,0 +1,81 @@
1
+ import type { NextRequest } from "next/server"
2
+ import { NextResponse } from "next/server"
3
+ import {
4
+ acceptHeaderRoutes,
5
+ ignoredPaths,
6
+ mdExtensionRoutes,
7
+ } from "@/lib/integrations/sanity/markdown-proxy.config"
8
+
9
+ export function proxy(request: NextRequest) {
10
+ const { pathname } = request.nextUrl
11
+ const acceptHeader = request.headers.get("accept") || ""
12
+
13
+ if (ignoredPaths.some((p) => pathname.startsWith(p))) {
14
+ return NextResponse.next()
15
+ }
16
+
17
+ if (pathname === "/" && acceptHeader.includes("text/markdown")) {
18
+ const url = request.nextUrl.clone()
19
+ url.pathname = "/api/index.md"
20
+ return NextResponse.rewrite(url)
21
+ }
22
+
23
+ // 1. Rewrite .md extension URLs to API routes
24
+ // e.g. /about.md → /api/about.md
25
+ for (const route of mdExtensionRoutes) {
26
+ const match = route.regex.exec(pathname)
27
+ if (match) {
28
+ const slug = match[1]
29
+ const url = request.nextUrl.clone()
30
+ url.pathname = route.apiPath.replace("[slug]", slug!)
31
+ return NextResponse.rewrite(url)
32
+ }
33
+ }
34
+
35
+ // 2. Accept: text/markdown — rewrite to markdown API route
36
+ if (acceptHeader.includes("text/markdown")) {
37
+ for (const route of acceptHeaderRoutes) {
38
+ const match = route.regex.exec(pathname)
39
+ if (match) {
40
+ const slug = match[1]
41
+ const url = request.nextUrl.clone()
42
+ url.pathname = route.apiPath.replace("[slug]", slug!)
43
+ return NextResponse.rewrite(url)
44
+ }
45
+ }
46
+ }
47
+
48
+ // 3. Add Link header for markdown discoverability on HTML page requests
49
+ const response = NextResponse.next()
50
+
51
+ if (pathname === "/") {
52
+ response.headers.set(
53
+ "Link",
54
+ '</index.md>; rel="alternate"; type="text/markdown"'
55
+ )
56
+ response.headers.set("Vary", "Accept")
57
+ return response
58
+ }
59
+
60
+ for (const route of acceptHeaderRoutes) {
61
+ const match = route.regex.exec(pathname)
62
+ if (match) {
63
+ const slug = match[1]
64
+ const mdUrl = route.publicPath.replace("[slug]", slug!)
65
+ response.headers.set(
66
+ "Link",
67
+ `<${mdUrl}>; rel="alternate"; type="text/markdown"`
68
+ )
69
+ response.headers.set("Vary", "Accept")
70
+ break
71
+ }
72
+ }
73
+
74
+ return response
75
+ }
76
+
77
+ export const config = {
78
+ matcher: [
79
+ "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|sitemap.md|robots.txt).*)",
80
+ ],
81
+ }
@@ -0,0 +1,5 @@
1
+ declare module "*.svg" {
2
+ import type { FC, SVGProps } from "react"
3
+ const content: FC<SVGProps<SVGSVGElement>>
4
+ export default content
5
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "noImplicitOverride": true,
17
+ "exactOptionalPropertyTypes": true,
18
+ "useUnknownInCatchVariables": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+ "noImplicitReturns": true,
21
+ "noUncheckedSideEffectImports": true,
22
+ "noUnusedLocals": true,
23
+ "noUnusedParameters": true,
24
+ "noUncheckedIndexedAccess": true,
25
+ "plugins": [{ "name": "next" }],
26
+ "types": ["bun", "node"],
27
+ "paths": { "@/*": ["./*"] }
28
+ },
29
+ "include": [
30
+ "next-env.d.ts",
31
+ "**/*.ts",
32
+ "**/*.tsx",
33
+ ".next/types/**/*.ts",
34
+ ".next/dev/types/**/*.ts",
35
+ "**/*.mts"
36
+ ],
37
+ "exclude": ["node_modules"]
38
+ }
@@ -1,23 +0,0 @@
1
- /**
2
- * Cross-platform Sanity MCP setup helper
3
- * Copies the Cursor deeplink to clipboard on macOS/Linux/Windows
4
- */
5
-
6
- import { copyToClipboard } from "./utils";
7
-
8
- const link =
9
- "cursor://anysphere.cursor-deeplink/mcp/install?name=Sanity&config=eyJ1cmwiOiJodHRwczovL21jcC5zYW5pdHkuaW8iLCJ0eXBlIjoiaHR0cCJ9Cg==";
10
-
11
- const copied = await copyToClipboard(link);
12
-
13
- console.log("\n🔗 Sanity MCP Setup for Cursor\n");
14
-
15
- if (copied) {
16
- console.log("✅ Link copied to clipboard!");
17
- console.log(" Paste it in your browser or Cursor address bar.\n");
18
- } else {
19
- console.log("📋 Copy this link manually:\n");
20
- console.log(` ${link}\n`);
21
- }
22
-
23
- console.log("This will install the Sanity MCP server in Cursor.");
@@ -1,297 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Generate Page Module
4
- *
5
- * Generates new pages with pre-configured templates through interactive prompts.
6
- * Used by the unified generator: `bun run generate`
7
- *
8
- * Cross-platform compatible (Windows, macOS, Linux)
9
- */
10
-
11
- import * as p from "@clack/prompts";
12
- import { createDir } from "./utils";
13
-
14
- interface PageOptions {
15
- webgl?: boolean;
16
- sanity?: boolean;
17
- theme?: string;
18
- css?: boolean;
19
- }
20
-
21
- export interface PageConfig {
22
- name: string;
23
- options: PageOptions;
24
- }
25
-
26
- /**
27
- * Interactive prompts for page configuration
28
- */
29
- export const promptPageConfig = async (): Promise<PageConfig> => {
30
- const name = await p.text({
31
- message: "What should the page be called?",
32
- placeholder: "about, contact, products",
33
- validate: (value) => {
34
- if (!value) return "Page name is required";
35
- if (!/^[a-zA-Z][a-zA-Z0-9-_]*$/.test(value)) {
36
- return "Page name must start with a letter and contain only letters, numbers, hyphens, and underscores";
37
- }
38
- return undefined;
39
- },
40
- });
41
-
42
- if (p.isCancel(name)) {
43
- p.cancel("Page generation cancelled");
44
- process.exit(0);
45
- }
46
-
47
- const theme = await p.select({
48
- message: "Choose a theme for the page",
49
- options: [
50
- { value: "dark", label: "Dark (default)", hint: "Standard dark theme" },
51
- { value: "light", label: "Light", hint: "Light theme" },
52
- { value: "red", label: "Red", hint: "Red accent theme" },
53
- ],
54
- initialValue: "dark",
55
- });
56
-
57
- if (p.isCancel(theme)) {
58
- p.cancel("Page generation cancelled");
59
- process.exit(0);
60
- }
61
-
62
- const integrations = await p.multiselect({
63
- message: "Which integrations should this page use?",
64
- options: [
65
- { value: "webgl", label: "WebGL Canvas", hint: "Enable 3D graphics" },
66
- { value: "sanity", label: "Sanity CMS", hint: "Content management" },
67
- ],
68
- required: false,
69
- });
70
-
71
- if (p.isCancel(integrations)) {
72
- p.cancel("Page generation cancelled");
73
- process.exit(0);
74
- }
75
-
76
- const includeCss = await p.confirm({
77
- message: "Include a CSS module file?",
78
- initialValue: false,
79
- });
80
-
81
- if (p.isCancel(includeCss)) {
82
- p.cancel("Page generation cancelled");
83
- process.exit(0);
84
- }
85
-
86
- return {
87
- name,
88
- options: {
89
- theme,
90
- webgl: integrations.includes("webgl"),
91
- sanity: integrations.includes("sanity"),
92
- css: includeCss,
93
- },
94
- };
95
- };
96
-
97
- /**
98
- * Generate page.tsx content
99
- */
100
- const generatePageContent = (
101
- pageName: string,
102
- options: PageOptions,
103
- ): string => {
104
- const { webgl, sanity, theme = "dark" } = options;
105
-
106
- // Capitalize first letter for title
107
- const title = pageName.charAt(0).toUpperCase() + pageName.slice(1);
108
-
109
- // Build imports
110
- const imports: string[] = [];
111
- imports.push(`import type { Metadata } from 'next'`);
112
- imports.push(`import { Wrapper } from '@/components/layout/wrapper'`);
113
-
114
- // Integration-specific imports
115
- if (sanity) {
116
- imports.push(
117
- `import { NotConfigured } from '@/components/ui/not-configured'`,
118
- );
119
- }
120
-
121
- if (sanity) {
122
- imports.push(
123
- `import { isSanityConfigured } from '@/lib/integrations/check-integration'`,
124
- );
125
- // sanityFetch and generateSanityMetadata are available for use:
126
- // import { sanityFetch } from 'next-sanity/live'
127
- // import { generateSanityMetadata } from '@/lib/utils/metadata'
128
- }
129
-
130
- // Build wrapper props
131
- const wrapperProps: string[] = [`theme="${theme}"`];
132
- if (webgl) {
133
- wrapperProps.push("webgl");
134
- }
135
-
136
- // Build component body based on integrations
137
- let componentBody: string;
138
-
139
- if (sanity) {
140
- // Sanity only
141
- componentBody = ` // Show setup instructions if Sanity is not configured
142
- if (!isSanityConfigured()) {
143
- return (
144
- <Wrapper theme="${theme}">
145
- <NotConfigured integration="Sanity" />
146
- </Wrapper>
147
- )
148
- }
149
-
150
- // TODO: Create a GROQ query for this page's content type
151
- // const { data } = await sanityFetch({
152
- // query: yourQuery,
153
- // params: { slug: '${pageName}' },
154
- // })
155
-
156
- return (
157
- <Wrapper ${wrapperProps.join(" ")}>
158
- <section className="dr-py-100">
159
- <div className="container">
160
- <h1>${title}</h1>
161
- {/* Your content here */}
162
- {/* Fetch data from Sanity using a custom query */}
163
- </div>
164
- </section>
165
- </Wrapper>
166
- )`;
167
- } else {
168
- // No integrations
169
- componentBody = ` return (
170
- <Wrapper ${wrapperProps.join(" ")}>
171
- <section className="dr-py-100">
172
- <div className="container">
173
- <h1>${title}</h1>
174
- {/* Your content here */}
175
- </div>
176
- </section>
177
- </Wrapper>
178
- )`;
179
- }
180
-
181
- // Build metadata export
182
- let metadataExport: string;
183
- if (sanity) {
184
- metadataExport = `
185
- export async function generateMetadata(): Promise<Metadata> {
186
- if (!isSanityConfigured()) {
187
- return {
188
- title: '${title}',
189
- description: '${title} page description',
190
- }
191
- }
192
-
193
- // TODO: Fetch metadata from Sanity using a custom query
194
- // const { data } = await sanityFetch({
195
- // query: yourQuery,
196
- // params: { slug: '${pageName}' },
197
- // })
198
-
199
- return {
200
- title: '${title}',
201
- description: '${title} page description',
202
- }
203
- }`;
204
- } else {
205
- metadataExport = `
206
- export const metadata: Metadata = {
207
- title: '${title}',
208
- description: '${title} page description',
209
- }`;
210
- }
211
-
212
- // Determine if component should be async
213
- const isAsync = sanity;
214
-
215
- return `${imports.join("\n")}
216
- ${metadataExport}
217
-
218
- export default ${isAsync ? "async " : ""}function ${title}Page() {
219
- ${componentBody}
220
- }
221
- `;
222
- };
223
-
224
- /**
225
- * Create page files and directories
226
- */
227
- export const createPage = async (
228
- pageName: string,
229
- options: PageOptions,
230
- ): Promise<void> => {
231
- const s = p.spinner();
232
-
233
- try {
234
- // Create directory structure
235
- const pageDir = `app/${pageName}`;
236
- const componentsDir = `${pageDir}/_components`;
237
-
238
- s.start(`Creating page structure for "${pageName}"`);
239
-
240
- // Create main page directory (cross-platform)
241
- await createDir(pageDir);
242
-
243
- // Create _components subdirectory (cross-platform)
244
- await createDir(componentsDir);
245
-
246
- // Create .gitkeep in _components
247
- await Bun.write(`${componentsDir}/.gitkeep`, "");
248
-
249
- // Generate and write page.tsx
250
- const pageContent = generatePageContent(pageName, options);
251
- await Bun.write(`${pageDir}/page.tsx`, pageContent);
252
-
253
- // Create CSS module if requested
254
- if (options.css) {
255
- const cssContent = `/* ${pageName}.module.css */
256
-
257
- .container {
258
- /* Add your styles here */
259
- }
260
- `;
261
- await Bun.write(`${pageDir}/${pageName}.module.css`, cssContent);
262
- }
263
-
264
- s.stop(`Page "${pageName}" generated successfully!`);
265
-
266
- // Show what was created
267
- p.log.success(`Generated files:`);
268
- p.log.message(` 📄 ${pageDir}/page.tsx`);
269
- p.log.message(` 📁 ${componentsDir}/`);
270
- if (options.css) {
271
- p.log.message(` 🎨 ${pageDir}/${pageName}.module.css`);
272
- }
273
-
274
- // Build next steps message
275
- const nextSteps = [`1. Customize ${pageDir}/page.tsx`];
276
-
277
- if (options.sanity) {
278
- nextSteps.push(
279
- `2. Create a "${pageName}" page in Sanity Studio at /studio`,
280
- );
281
- }
282
-
283
- nextSteps.push(
284
- `${nextSteps.length + 1}. Add components to ${componentsDir}/`,
285
- );
286
- nextSteps.push(
287
- `${nextSteps.length + 1}. Visit /${pageName} to see your page`,
288
- );
289
-
290
- p.note(`Next steps:\n ${nextSteps.join("\n ")}`);
291
- } catch (error) {
292
- s.stop(`Failed to generate page "${pageName}"`);
293
- throw error;
294
- }
295
- };
296
-
297
- // Export functions for use by unified generate script