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.
- package/dist/helpers/create/copy-template.d.ts +1 -1
- package/dist/helpers/create/copy-template.d.ts.map +1 -1
- package/dist/helpers/create/index.d.ts.map +1 -1
- package/dist/helpers/create/index.js +2 -1
- package/dist/helpers/create/index.js.map +1 -1
- package/dist/helpers/integrate/merge-config.d.ts.map +1 -1
- package/dist/helpers/integrate/merge-config.js +0 -2
- package/dist/helpers/integrate/merge-config.js.map +1 -1
- package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
- package/dist/helpers/integrate/sanity/config.js +3 -14
- package/dist/helpers/integrate/sanity/config.js.map +1 -1
- package/dist/index.js +84 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/templates/next-pagebuilder/.env.example +11 -0
- package/src/templates/next-pagebuilder/README.md +23 -0
- package/src/templates/next-pagebuilder/_gitignore +67 -0
- package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +68 -0
- package/src/templates/next-pagebuilder/app/(content)/layout.tsx +13 -0
- package/src/templates/next-pagebuilder/app/api/[[...slug]]/route.ts +100 -0
- package/src/templates/next-pagebuilder/app/api/draft-mode/disable/route.ts +7 -0
- package/src/templates/next-pagebuilder/app/api/draft-mode/enable/route.ts +20 -0
- package/src/templates/next-pagebuilder/app/api/revalidate/route.ts +121 -0
- package/src/templates/next-pagebuilder/app/favicon.ico +0 -0
- package/src/templates/next-pagebuilder/app/layout.tsx +80 -0
- package/src/templates/next-pagebuilder/app/robots.ts +15 -0
- package/src/templates/next-pagebuilder/app/sitemap.md/route.ts +124 -0
- package/src/templates/next-pagebuilder/app/sitemap.xml/route.ts +80 -0
- package/src/templates/next-pagebuilder/app/studio/[[...tool]]/page.tsx +8 -0
- package/src/templates/next-pagebuilder/biome.json +239 -0
- package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +95 -0
- package/src/templates/next-pagebuilder/components/layout/header/components/cta-button.tsx +28 -0
- package/src/templates/next-pagebuilder/components/layout/header/components/mega-menu-panel.tsx +90 -0
- package/src/templates/next-pagebuilder/components/layout/header/components/nav-item-renderer.tsx +98 -0
- package/src/templates/next-pagebuilder/components/layout/header/components/nav-leaf-item.tsx +33 -0
- package/src/templates/next-pagebuilder/components/layout/header/components/types.ts +7 -0
- package/src/templates/next-pagebuilder/components/layout/header/header-client.tsx +110 -0
- package/src/templates/next-pagebuilder/components/layout/header/index.tsx +8 -0
- package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +45 -0
- package/src/templates/next-pagebuilder/components/layout/wrapper/index.tsx +30 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/article-content/index.tsx +83 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/article-content/related-post-item.tsx +27 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/description.tsx +17 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/hero.tsx +17 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/content-card.tsx +66 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/content-grid.tsx +42 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/index.tsx +28 -0
- package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/types.ts +16 -0
- package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +36 -0
- package/src/templates/next-pagebuilder/components/page-builder/types.ts +23 -0
- package/src/templates/next-pagebuilder/components/page-document/index.tsx +91 -0
- package/src/templates/next-pagebuilder/components/sanity/draft-mode-toggle.tsx +27 -0
- package/src/templates/next-pagebuilder/components/sanity/rich-text.tsx +87 -0
- package/src/templates/next-pagebuilder/components/sanity/visual-editing.tsx +27 -0
- package/src/templates/next-pagebuilder/components/ui/image/index.tsx +216 -0
- package/src/templates/next-pagebuilder/components/ui/link/index.tsx +152 -0
- package/src/templates/next-pagebuilder/components/ui/sanity-image/index.tsx +41 -0
- package/src/templates/next-pagebuilder/lib/integrations/check-integration.ts +5 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/client.ts +27 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/components/disable-draft-mode.tsx +23 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/components/page-builder-input.tsx +36 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/components/page-category-input.tsx +50 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/components/rich-text.tsx +84 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/confirm-publish-action.ts +40 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/env.ts +34 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/fetchers/layout.ts +35 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/icons.ts +58 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/live/index.tsx +61 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/markdown-proxy.config.ts +50 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/page-builder-config.ts +132 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/page-category.ts +28 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/queries.ts +281 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.cli.ts +29 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.config.ts +211 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/index.ts +4 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +89 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/description.ts +29 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/hero.ts +28 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +45 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/content/author.ts +70 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/content/blog-category.ts +55 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/index.ts +96 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/company-data.ts +62 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/footer.ts +79 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/navbar.ts +74 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/link.ts +125 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/logo-field.ts +9 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/metadata.ts +68 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/nav-objects.ts +192 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page-builder.ts +39 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page-folder.ts +124 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page.ts +232 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/richText.ts +63 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/singletons.ts +44 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/structure.ts +453 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/image.ts +8 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/link.ts +137 -0
- package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/page-builder-markdown.ts +81 -0
- package/src/templates/next-pagebuilder/lib/scripts/sanity-typegen.ts +45 -0
- package/src/templates/next-pagebuilder/lib/styles/cn.ts +5 -0
- package/src/templates/next-pagebuilder/lib/styles/global.css +70 -0
- package/src/templates/next-pagebuilder/lib/utils/base-url.ts +17 -0
- package/src/templates/next-pagebuilder/lib/utils/format-date.ts +8 -0
- package/src/templates/next-pagebuilder/lib/utils/json-ld.tsx +213 -0
- package/src/templates/next-pagebuilder/lib/utils/metadata.ts +167 -0
- package/src/templates/next-pagebuilder/lib/utils/sitemap.ts +37 -0
- package/src/templates/next-pagebuilder/lib/utils/slug-tag.ts +6 -0
- package/src/templates/next-pagebuilder/next.config.ts +134 -0
- package/src/templates/next-pagebuilder/package.json +71 -0
- package/src/templates/next-pagebuilder/postcss.config.mjs +39 -0
- package/src/templates/next-pagebuilder/proxy.ts +81 -0
- package/src/templates/next-pagebuilder/svg.d.ts +5 -0
- package/src/templates/next-pagebuilder/tsconfig.json +38 -0
- package/src/helpers/integrate/sanity/files/lib/scripts/copy-sanity-mcp.ts +0 -23
- 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,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
|