kofi-stack-template-generator 2.1.20 → 2.1.22
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/index.js +103 -5
- package/package.json +2 -2
- package/src/templates.generated.ts +6 -6
- package/templates/marketing/payload/_env.example.hbs +31 -3
- package/templates/marketing/payload/_env.local.hbs +26 -3
- package/templates/marketing/payload/package.json.hbs +14 -1
- package/templates/marketing/payload/src/app/(payload)/layout.tsx.hbs +8 -2
- package/templates/marketing/payload/src/payload.config.ts.hbs +67 -2
package/dist/index.js
CHANGED
|
@@ -476,10 +476,108 @@ var EMBEDDED_TEMPLATES = {
|
|
|
476
476
|
}
|
|
477
477
|
`,
|
|
478
478
|
"marketing/nextjs/tsconfig.json.hbs": '{\n "compilerOptions": {\n "target": "ES2017",\n "lib": ["dom", "dom.iterable", "esnext"],\n "allowJs": true,\n "skipLibCheck": true,\n "strict": true,\n "noEmit": true,\n "esModuleInterop": true,\n "module": "esnext",\n "moduleResolution": "bundler",\n "resolveJsonModule": true,\n "isolatedModules": true,\n "jsx": "react-jsx",\n "incremental": true,\n "plugins": [{ "name": "next" }],\n "paths": {\n "@/*": ["./src/*"]\n }\n },\n "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],\n "exclude": ["node_modules"]\n}\n',
|
|
479
|
-
"marketing/payload/_env.example.hbs":
|
|
480
|
-
|
|
479
|
+
"marketing/payload/_env.example.hbs": `# Database (Supabase PostgreSQL)
|
|
480
|
+
DATABASE_URL="postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres"
|
|
481
|
+
|
|
482
|
+
# Payload CMS
|
|
483
|
+
PAYLOAD_SECRET="" # Generate with: openssl rand -base64 32
|
|
484
|
+
|
|
485
|
+
# Scheduled Jobs
|
|
486
|
+
CRON_SECRET="" # Generate with: openssl rand -base64 32
|
|
487
|
+
|
|
488
|
+
# Draft Previews
|
|
489
|
+
PREVIEW_SECRET="" # Generate with: openssl rand -base64 32
|
|
490
|
+
|
|
491
|
+
# Email (Resend)
|
|
492
|
+
RESEND_API_KEY=""
|
|
493
|
+
RESEND_FROM_EMAIL="noreply@yourdomain.com"
|
|
494
|
+
|
|
495
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
496
|
+
# S3 Storage
|
|
497
|
+
S3_BUCKET="media"
|
|
498
|
+
S3_ACCESS_KEY_ID=""
|
|
499
|
+
S3_SECRET_ACCESS_KEY=""
|
|
500
|
+
S3_REGION="us-east-1"
|
|
501
|
+
S3_ENDPOINT="" # Optional: For S3-compatible services
|
|
502
|
+
{{/if}}
|
|
503
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
504
|
+
# Cloudflare R2 Storage
|
|
505
|
+
R2_BUCKET=""
|
|
506
|
+
R2_ACCESS_KEY_ID=""
|
|
507
|
+
R2_SECRET_ACCESS_KEY=""
|
|
508
|
+
R2_ENDPOINT="https://[ACCOUNT_ID].r2.cloudflarestorage.com"
|
|
509
|
+
{{/if}}
|
|
510
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
511
|
+
# Vercel Blob Storage
|
|
512
|
+
BLOB_READ_WRITE_TOKEN=""
|
|
513
|
+
{{/if}}
|
|
514
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
515
|
+
# Google Cloud Storage
|
|
516
|
+
GCS_BUCKET=""
|
|
517
|
+
GCS_PROJECT_ID=""
|
|
518
|
+
GCS_CREDENTIALS="{}" # JSON service account key
|
|
519
|
+
{{/if}}
|
|
520
|
+
{{#if (eq integrations.payloadStorage 'local')}}
|
|
521
|
+
# Local Storage
|
|
522
|
+
# Files are stored in the /media directory by default
|
|
523
|
+
# No additional configuration required
|
|
524
|
+
{{/if}}
|
|
525
|
+
`,
|
|
526
|
+
"marketing/payload/_env.local.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\n\n# Payload CMS\nPAYLOAD_SECRET=\n\n# Scheduled Jobs\nCRON_SECRET=\n\n# Draft Previews\nPREVIEW_SECRET=\n\n# Email (Resend)\nRESEND_API_KEY=\nRESEND_FROM_EMAIL=\n\n{{#if (eq integrations.payloadStorage 's3')}}\n# S3 Storage\nS3_BUCKET=media\nS3_ACCESS_KEY_ID=\nS3_SECRET_ACCESS_KEY=\nS3_REGION=us-east-1\nS3_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n# Cloudflare R2 Storage\nR2_BUCKET=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n# Vercel Blob Storage\nBLOB_READ_WRITE_TOKEN=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n# Google Cloud Storage\nGCS_BUCKET=\nGCS_PROJECT_ID=\nGCS_CREDENTIALS=\n{{/if}}\n",
|
|
481
527
|
"marketing/payload/next.config.ts.hbs": "import { withPayload } from '@payloadcms/next/withPayload'\nimport type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['@repo/ui'],\n}\n\nexport default withPayload(nextConfig)\n",
|
|
482
|
-
"marketing/payload/package.json.hbs":
|
|
528
|
+
"marketing/payload/package.json.hbs": `{
|
|
529
|
+
"name": "@repo/marketing",
|
|
530
|
+
"version": "0.1.0",
|
|
531
|
+
"private": true,
|
|
532
|
+
"scripts": {
|
|
533
|
+
"dev": "next dev -p 3001",
|
|
534
|
+
"build": "next build",
|
|
535
|
+
"start": "next start",
|
|
536
|
+
"lint": "biome check .",
|
|
537
|
+
"lint:fix": "biome check --write .",
|
|
538
|
+
"typecheck": "tsc --noEmit",
|
|
539
|
+
"db:push": "payload migrate",
|
|
540
|
+
"db:seed": "tsx src/seed.ts"
|
|
541
|
+
},
|
|
542
|
+
"dependencies": {
|
|
543
|
+
"next": "^15.4.10",
|
|
544
|
+
"react": "^19.0.0",
|
|
545
|
+
"react-dom": "^19.0.0",
|
|
546
|
+
"payload": "^3.70.0",
|
|
547
|
+
"@payloadcms/db-postgres": "^3.0.0",
|
|
548
|
+
"@payloadcms/next": "^3.0.0",
|
|
549
|
+
"@payloadcms/richtext-lexical": "^3.0.0",
|
|
550
|
+
"@payloadcms/email-resend": "^3.0.0",
|
|
551
|
+
"@payloadcms/plugin-seo": "^3.0.0",
|
|
552
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
553
|
+
"@payloadcms/storage-s3": "^3.0.0",
|
|
554
|
+
{{/if}}
|
|
555
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
556
|
+
"@payloadcms/storage-s3": "^3.0.0",
|
|
557
|
+
{{/if}}
|
|
558
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
559
|
+
"@payloadcms/storage-vercel-blob": "^3.0.0",
|
|
560
|
+
{{/if}}
|
|
561
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
562
|
+
"@payloadcms/storage-gcs": "^3.0.0",
|
|
563
|
+
{{/if}}
|
|
564
|
+
"sharp": "^0.33.0",
|
|
565
|
+
"@repo/ui": "workspace:*"
|
|
566
|
+
},
|
|
567
|
+
"devDependencies": {
|
|
568
|
+
"@repo/config-typescript": "workspace:*",
|
|
569
|
+
"@types/node": "^20.0.0",
|
|
570
|
+
"@types/react": "^19.0.0",
|
|
571
|
+
"@types/react-dom": "^19.0.0",
|
|
572
|
+
"tailwindcss": "^4.0.0",
|
|
573
|
+
"@tailwindcss/postcss": "^4.0.0",
|
|
574
|
+
"postcss": "^8.4.0",
|
|
575
|
+
"sass": "^1.86.0",
|
|
576
|
+
"typescript": "^5.0.0",
|
|
577
|
+
"tsx": "^4.0.0"
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
`,
|
|
483
581
|
"marketing/payload/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
|
|
484
582
|
"marketing/payload/src/app/(frontend)/layout.tsx.hbs": "export default function FrontendLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return <>{children}</>\n}\n",
|
|
485
583
|
"marketing/payload/src/app/(frontend)/page.tsx.hbs": `import { getPayload } from 'payload'
|
|
@@ -573,7 +671,7 @@ export default async function HomePage() {
|
|
|
573
671
|
"marketing/payload/src/app/(payload)/api/graphql-playground/route.ts.hbs": "import config from '@/payload.config'\nimport { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'\nimport { importMap } from '../../importMap.js'\n\nexport const GET = GRAPHQL_PLAYGROUND_GET(config, importMap)\n",
|
|
574
672
|
"marketing/payload/src/app/(payload)/custom.scss.hbs": "/* Custom Payload admin styles */\n",
|
|
575
673
|
"marketing/payload/src/app/(payload)/importMap.js.hbs": "export const importMap = {}\n",
|
|
576
|
-
"marketing/payload/src/app/(payload)/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport config from '@/payload.config'\nimport { RootLayout } from '@payloadcms/next/layouts'\nimport { importMap } from './importMap.js'\nimport './custom.scss'\n\nexport const metadata: Metadata = {\n title: 'Admin Panel',\n}\n\ntype LayoutArgs = {\n children: React.ReactNode\n}\n\nconst Layout = ({ children }: LayoutArgs) =>\n RootLayout({ children, config, importMap })\n\nexport default Layout\n",
|
|
674
|
+
"marketing/payload/src/app/(payload)/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport config from '@/payload.config'\nimport { RootLayout, handleServerFunctions } from '@payloadcms/next/layouts'\nimport type { ServerFunctionClient } from 'payload'\nimport { importMap } from './importMap.js'\nimport './custom.scss'\n\nexport const metadata: Metadata = {\n title: 'Admin Panel',\n}\n\ntype LayoutArgs = {\n children: React.ReactNode\n}\n\nconst serverFunction: ServerFunctionClient = async function (args) {\n 'use server'\n return handleServerFunctions({ ...args, config, importMap })\n}\n\nconst Layout = ({ children }: LayoutArgs) =>\n RootLayout({ children, config, importMap, serverFunction })\n\nexport default Layout\n",
|
|
577
675
|
"marketing/payload/src/app/globals.css.hbs": '@import "tailwindcss";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --font-sans: var(--font-geist-sans);\n --font-mono: var(--font-geist-mono);\n --color-ring: var(--ring);\n --color-input: var(--input);\n --color-border: var(--border);\n --color-destructive: var(--destructive);\n --color-accent-foreground: var(--accent-foreground);\n --color-accent: var(--accent);\n --color-muted-foreground: var(--muted-foreground);\n --color-muted: var(--muted);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-secondary: var(--secondary);\n --color-primary-foreground: var(--primary-foreground);\n --color-primary: var(--primary);\n --color-popover-foreground: var(--popover-foreground);\n --color-popover: var(--popover);\n --color-card-foreground: var(--card-foreground);\n --color-card: var(--card);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n}\n\n:root {\n --radius: 0.625rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n --ring: oklch(0.708 0 0);\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n\n body {\n @apply bg-background text-foreground;\n }\n}\n',
|
|
578
676
|
"marketing/payload/src/app/layout.tsx.hbs": `import type { Metadata } from 'next'
|
|
579
677
|
import './globals.css'
|
|
@@ -613,7 +711,7 @@ export default function RootLayout({
|
|
|
613
711
|
"marketing/payload/src/globals/Navigation.ts.hbs": "import type { GlobalConfig } from 'payload'\n\nexport const Navigation: GlobalConfig = {\n slug: 'navigation',\n access: {\n read: () => true,\n },\n fields: [\n {\n name: 'items',\n type: 'array',\n fields: [\n {\n name: 'label',\n type: 'text',\n required: true,\n },\n {\n name: 'link',\n type: 'group',\n fields: [\n {\n name: 'type',\n type: 'radio',\n options: [\n { label: 'Internal', value: 'internal' },\n { label: 'External', value: 'external' },\n ],\n defaultValue: 'internal',\n },\n {\n name: 'page',\n type: 'relationship',\n relationTo: 'pages',\n admin: {\n condition: (_, siblingData) => siblingData?.type === 'internal',\n },\n },\n {\n name: 'url',\n type: 'text',\n admin: {\n condition: (_, siblingData) => siblingData?.type === 'external',\n },\n },\n ],\n },\n ],\n },\n ],\n}\n",
|
|
614
712
|
"marketing/payload/src/globals/SiteSettings.ts.hbs": "import type { GlobalConfig } from 'payload'\n\nexport const SiteSettings: GlobalConfig = {\n slug: 'site-settings',\n access: {\n read: () => true,\n },\n fields: [\n {\n name: 'siteName',\n type: 'text',\n required: true,\n },\n {\n name: 'siteDescription',\n type: 'textarea',\n },\n {\n name: 'logo',\n type: 'upload',\n relationTo: 'media',\n },\n {\n name: 'favicon',\n type: 'upload',\n relationTo: 'media',\n },\n {\n name: 'socialLinks',\n type: 'array',\n fields: [\n {\n name: 'platform',\n type: 'select',\n options: [\n { label: 'Twitter', value: 'twitter' },\n { label: 'GitHub', value: 'github' },\n { label: 'LinkedIn', value: 'linkedin' },\n { label: 'Discord', value: 'discord' },\n ],\n },\n {\n name: 'url',\n type: 'text',\n },\n ],\n },\n ],\n}\n",
|
|
615
713
|
"marketing/payload/src/globals/index.ts.hbs": "export { SiteSettings } from './SiteSettings'\nexport { Navigation } from './Navigation'\n",
|
|
616
|
-
"marketing/payload/src/payload.config.ts.hbs": "import path from 'path'\nimport { fileURLToPath } from 'url'\nimport { buildConfig } from 'payload'\nimport { postgresAdapter } from '@payloadcms/db-postgres'\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { s3Storage } from '@payloadcms/storage-s3'\nimport {
|
|
714
|
+
"marketing/payload/src/payload.config.ts.hbs": "import path from 'path'\nimport { fileURLToPath } from 'url'\nimport { buildConfig } from 'payload'\nimport { postgresAdapter } from '@payloadcms/db-postgres'\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { seoPlugin } from '@payloadcms/plugin-seo'\nimport { resendAdapter } from '@payloadcms/email-resend'\nimport sharp from 'sharp'\n{{#if (eq integrations.payloadStorage 's3')}}\nimport { s3Storage } from '@payloadcms/storage-s3'\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\nimport { s3Storage } from '@payloadcms/storage-s3'\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\nimport { vercelBlobStorage } from '@payloadcms/storage-vercel-blob'\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\nimport { gcsStorage } from '@payloadcms/storage-gcs'\n{{/if}}\n\nimport { Pages } from './collections/Pages'\nimport { Media } from './collections/Media'\nimport { Users } from './collections/Users'\nimport { Posts } from './collections/Posts'\nimport { SiteSettings } from './globals/SiteSettings'\nimport { Navigation } from './globals/Navigation'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nexport default buildConfig({\n admin: {\n user: Users.slug,\n importMap: {\n baseDir: path.resolve(__dirname),\n },\n },\n db: postgresAdapter({\n pool: {\n connectionString: process.env.DATABASE_URL,\n },\n }),\n editor: lexicalEditor(),\n email: resendAdapter({\n defaultFromAddress: process.env.RESEND_FROM_EMAIL || 'noreply@example.com',\n defaultFromName: '{{projectName}}',\n apiKey: process.env.RESEND_API_KEY || '',\n }),\n collections: [Users, Media, Pages, Posts],\n globals: [SiteSettings, Navigation],\n plugins: [\n{{#if (eq integrations.payloadStorage 's3')}}\n s3Storage({\n collections: {\n media: true,\n },\n bucket: process.env.S3_BUCKET!,\n config: {\n credentials: {\n accessKeyId: process.env.S3_ACCESS_KEY_ID!,\n secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,\n },\n region: process.env.S3_REGION!,\n endpoint: process.env.S3_ENDPOINT,\n forcePathStyle: true,\n },\n }),\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n s3Storage({\n collections: {\n media: true,\n },\n bucket: process.env.R2_BUCKET!,\n config: {\n credentials: {\n accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n },\n region: 'auto',\n endpoint: process.env.R2_ENDPOINT!,\n forcePathStyle: true,\n },\n }),\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n vercelBlobStorage({\n collections: {\n media: true,\n },\n token: process.env.BLOB_READ_WRITE_TOKEN!,\n }),\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n gcsStorage({\n collections: {\n media: true,\n },\n bucket: process.env.GCS_BUCKET!,\n options: {\n projectId: process.env.GCS_PROJECT_ID,\n credentials: JSON.parse(process.env.GCS_CREDENTIALS || '{}'),\n },\n }),\n{{/if}}\n seoPlugin({\n collections: ['pages', 'posts'],\n uploadsCollection: 'media',\n generateTitle: ({ doc }) => `${doc?.title ?? ''} | {{projectName}}`,\n generateDescription: ({ doc }) => doc?.excerpt ?? '',\n }),\n ],\n secret: process.env.PAYLOAD_SECRET!,\n sharp,\n typescript: {\n outputFile: path.resolve(__dirname, 'payload-types.ts'),\n },\n{{#if (eq integrations.payloadStorage 'local')}}\n upload: {\n limits: {\n fileSize: 5000000, // 5MB\n },\n },\n{{/if}}\n})\n",
|
|
617
715
|
"marketing/payload/tsconfig.json.hbs": '{\n "compilerOptions": {\n "target": "ES2017",\n "lib": ["dom", "dom.iterable", "esnext"],\n "allowJs": true,\n "skipLibCheck": true,\n "strict": true,\n "noEmit": true,\n "esModuleInterop": true,\n "module": "esnext",\n "moduleResolution": "bundler",\n "resolveJsonModule": true,\n "isolatedModules": true,\n "jsx": "preserve",\n "incremental": true,\n "plugins": [{ "name": "next" }],\n "paths": {\n "@/*": ["./src/*"]\n }\n },\n "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],\n "exclude": ["node_modules"]\n}\n',
|
|
618
716
|
"monorepo/package.json.hbs": '{\n "name": "{{projectName}}",\n "version": "0.1.0",\n "private": true,\n "scripts": {\n "dev": "node scripts/dev.mjs",\n "dev:all": "turbo dev",\n "dev:web": "turbo -F @repo/web dev",\n "dev:backend": "turbo -F @repo/backend dev",\n "dev:setup": "pnpm --filter @repo/backend dev:setup",\n "build": "turbo build",\n "lint": "turbo lint",\n "lint:fix": "turbo lint:fix",\n "format": "turbo format",\n "typecheck": "turbo typecheck",\n "test": "turbo test",\n "test:e2e": "turbo test:e2e",\n "clean": "turbo clean && rm -rf node_modules",\n "prepare": "husky"\n },\n "devDependencies": {\n "turbo": "^2.0.0",\n "husky": "^9.0.0",\n "lint-staged": "^15.0.0"\n },\n "packageManager": "pnpm@9.0.0",\n "lint-staged": {\n "*.{js,ts,jsx,tsx}": ["biome check --apply"],\n "*.{json,md}": ["biome format --write"]\n }\n}\n',
|
|
619
717
|
"monorepo/pnpm-workspace.yaml.hbs": 'packages:\n - "apps/*"\n - "packages/*"\n',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kofi-stack-template-generator",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"typecheck": "tsc --noEmit"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"kofi-stack-types": "^2.
|
|
20
|
+
"kofi-stack-types": "^2.2.0",
|
|
21
21
|
"handlebars": "^4.7.8",
|
|
22
22
|
"memfs": "^4.9.0"
|
|
23
23
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Auto-generated file. Do not edit manually.
|
|
2
2
|
// Run 'pnpm prebuild' to regenerate.
|
|
3
|
-
// Generated: 2026-01-
|
|
3
|
+
// Generated: 2026-01-15T03:03:22.347Z
|
|
4
4
|
// Template count: 90
|
|
5
5
|
|
|
6
6
|
export const EMBEDDED_TEMPLATES: Record<string, string> = {
|
|
@@ -23,10 +23,10 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
|
|
|
23
23
|
"marketing/nextjs/src/app/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport { Geist, Geist_Mono } from 'next/font/google'\nimport './globals.css'\n\nconst geistSans = Geist({\n variable: '--font-geist-sans',\n subsets: ['latin'],\n})\n\nconst geistMono = Geist_Mono({\n variable: '--font-geist-mono',\n subsets: ['latin'],\n})\n\nexport const metadata: Metadata = {\n title: '{{projectName}} - Marketing',\n description: 'Marketing site for {{projectName}}',\n}\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <html lang=\"en\">\n <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>\n {children}\n </body>\n </html>\n )\n}\n",
|
|
24
24
|
"marketing/nextjs/src/app/page.tsx.hbs": "export default function HomePage() {\n return (\n <main className=\"min-h-screen\">\n {/* Navigation */}\n <nav className=\"sticky top-0 z-50 w-full border-b border-gray-200 dark:border-gray-800 bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm\">\n <div className=\"container mx-auto px-4\">\n <div className=\"flex h-16 items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-gray-900 dark:bg-white\">\n <svg className=\"h-4 w-4 text-white dark:text-gray-900\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n </div>\n <span className=\"font-semibold text-gray-900 dark:text-white\">{{projectName}}</span>\n </div>\n <div className=\"hidden md:flex items-center gap-6\">\n <a href=\"#features\" className=\"text-sm text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors\">\n Features\n </a>\n <a href=\"#\" className=\"text-sm text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors\">\n Pricing\n </a>\n <a href=\"#\" className=\"text-sm text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors\">\n Docs\n </a>\n </div>\n <div className=\"flex items-center gap-4\">\n <a\n href=\"/sign-in\"\n className=\"text-sm font-medium text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-white transition-colors\"\n >\n Sign in\n </a>\n <a\n href=\"/sign-up\"\n className=\"rounded-lg bg-gray-900 dark:bg-white px-4 py-2 text-sm font-medium text-white dark:text-gray-900 hover:opacity-90 transition-opacity\"\n >\n Get Started\n </a>\n </div>\n </div>\n </div>\n </nav>\n\n {/* Hero Section */}\n <section className=\"relative overflow-hidden bg-gradient-to-b from-gray-50 to-white dark:from-gray-900 dark:to-gray-800\">\n <div className=\"container mx-auto px-4 py-24 sm:py-32\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-6xl\">\n Welcome to {{projectName}}\n </h1>\n <p className=\"mt-6 text-lg leading-8 text-gray-600 dark:text-gray-300 max-w-2xl mx-auto\">\n A modern full-stack application built with Next.js, Convex, and Better-Auth.\n </p>\n <div className=\"mt-10 flex items-center justify-center gap-x-6\">\n <a\n href=\"/app\"\n className=\"rounded-lg bg-gray-900 dark:bg-white px-6 py-3 text-sm font-semibold text-white dark:text-gray-900 shadow-sm hover:opacity-90 transition-opacity\"\n >\n Get Started\n </a>\n <a\n href=\"#features\"\n className=\"text-sm font-semibold leading-6 text-gray-900 dark:text-white\"\n >\n Learn more <span aria-hidden=\"true\">→</span>\n </a>\n </div>\n </div>\n </div>\n </section>\n\n {/* Features Section */}\n <section id=\"features\" className=\"py-24 sm:py-32\">\n <div className=\"container mx-auto px-4\">\n <div className=\"text-center mb-16\">\n <h2 className=\"text-3xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-4xl\">\n Everything you need\n </h2>\n <p className=\"mt-4 text-lg text-gray-600 dark:text-gray-300\">\n Built with the best tools for modern web development\n </p>\n </div>\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8\">\n <div className=\"p-6 rounded-xl border border-gray-200 dark:border-gray-700\">\n <div className=\"w-12 h-12 bg-gray-100 dark:bg-gray-800 rounded-lg flex items-center justify-center mb-4\">\n <svg className=\"w-6 h-6 text-gray-900 dark:text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-semibold text-gray-900 dark:text-white mb-2\">\n Lightning Fast\n </h3>\n <p className=\"text-gray-600 dark:text-gray-300\">\n Built on Next.js with Turbopack for instant hot reload and optimized production builds.\n </p>\n </div>\n <div className=\"p-6 rounded-xl border border-gray-200 dark:border-gray-700\">\n <div className=\"w-12 h-12 bg-gray-100 dark:bg-gray-800 rounded-lg flex items-center justify-center mb-4\">\n <svg className=\"w-6 h-6 text-gray-900 dark:text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-semibold text-gray-900 dark:text-white mb-2\">\n Real-time Database\n </h3>\n <p className=\"text-gray-600 dark:text-gray-300\">\n Powered by Convex for automatic real-time sync and type-safe queries.\n </p>\n </div>\n <div className=\"p-6 rounded-xl border border-gray-200 dark:border-gray-700\">\n <div className=\"w-12 h-12 bg-gray-100 dark:bg-gray-800 rounded-lg flex items-center justify-center mb-4\">\n <svg className=\"w-6 h-6 text-gray-900 dark:text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-semibold text-gray-900 dark:text-white mb-2\">\n Secure Auth\n </h3>\n <p className=\"text-gray-600 dark:text-gray-300\">\n Better-Auth provides secure, flexible authentication with social login support.\n </p>\n </div>\n </div>\n </div>\n </section>\n\n {/* CTA Section */}\n <section className=\"py-24 sm:py-32 bg-gray-900 dark:bg-gray-800\">\n <div className=\"container mx-auto px-4 text-center\">\n <h2 className=\"text-3xl font-bold tracking-tight text-white sm:text-4xl\">\n Ready to get started?\n </h2>\n <p className=\"mt-4 text-lg text-gray-300 max-w-2xl mx-auto\">\n Start building your next project with our full-stack template.\n </p>\n <div className=\"mt-10\">\n <a\n href=\"/app\"\n className=\"rounded-lg bg-white px-6 py-3 text-sm font-semibold text-gray-900 shadow-sm hover:opacity-90 transition-opacity\"\n >\n Launch App\n </a>\n </div>\n </div>\n </section>\n\n {/* Footer */}\n <footer className=\"border-t border-gray-200 dark:border-gray-700\">\n <div className=\"container mx-auto px-4 py-12\">\n <div className=\"text-center text-gray-600 dark:text-gray-300\">\n <p>\n Built with{' '}\n <a\n href=\"https://github.com/theodenanyoh11/create-kofi-stack\"\n className=\"text-gray-900 dark:text-white hover:underline\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n create-kofi-stack\n </a>\n </p>\n </div>\n </div>\n </footer>\n </main>\n )\n}\n",
|
|
25
25
|
"marketing/nextjs/tsconfig.json.hbs": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"react-jsx\",\n \"incremental\": true,\n \"plugins\": [{ \"name\": \"next\" }],\n \"paths\": {\n \"@/*\": [\"./src/*\"]\n }\n },\n \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\", \".next/dev/types/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n",
|
|
26
|
-
"marketing/payload/_env.example.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\"postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres\"\n\n# Payload CMS\nPAYLOAD_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Scheduled Jobs\nCRON_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Draft Previews\nPREVIEW_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n#
|
|
27
|
-
"marketing/payload/_env.local.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\n\n# Payload CMS\nPAYLOAD_SECRET=\n\n# Scheduled Jobs\nCRON_SECRET=\n\n# Draft Previews\nPREVIEW_SECRET=\n\n#
|
|
26
|
+
"marketing/payload/_env.example.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\"postgresql://postgres:[PASSWORD]@db.[PROJECT].supabase.co:5432/postgres\"\n\n# Payload CMS\nPAYLOAD_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Scheduled Jobs\nCRON_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Draft Previews\nPREVIEW_SECRET=\"\" # Generate with: openssl rand -base64 32\n\n# Email (Resend)\nRESEND_API_KEY=\"\"\nRESEND_FROM_EMAIL=\"noreply@yourdomain.com\"\n\n{{#if (eq integrations.payloadStorage 's3')}}\n# S3 Storage\nS3_BUCKET=\"media\"\nS3_ACCESS_KEY_ID=\"\"\nS3_SECRET_ACCESS_KEY=\"\"\nS3_REGION=\"us-east-1\"\nS3_ENDPOINT=\"\" # Optional: For S3-compatible services\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n# Cloudflare R2 Storage\nR2_BUCKET=\"\"\nR2_ACCESS_KEY_ID=\"\"\nR2_SECRET_ACCESS_KEY=\"\"\nR2_ENDPOINT=\"https://[ACCOUNT_ID].r2.cloudflarestorage.com\"\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n# Vercel Blob Storage\nBLOB_READ_WRITE_TOKEN=\"\"\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n# Google Cloud Storage\nGCS_BUCKET=\"\"\nGCS_PROJECT_ID=\"\"\nGCS_CREDENTIALS=\"{}\" # JSON service account key\n{{/if}}\n{{#if (eq integrations.payloadStorage 'local')}}\n# Local Storage\n# Files are stored in the /media directory by default\n# No additional configuration required\n{{/if}}\n",
|
|
27
|
+
"marketing/payload/_env.local.hbs": "# Database (Supabase PostgreSQL)\nDATABASE_URL=\n\n# Payload CMS\nPAYLOAD_SECRET=\n\n# Scheduled Jobs\nCRON_SECRET=\n\n# Draft Previews\nPREVIEW_SECRET=\n\n# Email (Resend)\nRESEND_API_KEY=\nRESEND_FROM_EMAIL=\n\n{{#if (eq integrations.payloadStorage 's3')}}\n# S3 Storage\nS3_BUCKET=media\nS3_ACCESS_KEY_ID=\nS3_SECRET_ACCESS_KEY=\nS3_REGION=us-east-1\nS3_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n# Cloudflare R2 Storage\nR2_BUCKET=\nR2_ACCESS_KEY_ID=\nR2_SECRET_ACCESS_KEY=\nR2_ENDPOINT=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n# Vercel Blob Storage\nBLOB_READ_WRITE_TOKEN=\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n# Google Cloud Storage\nGCS_BUCKET=\nGCS_PROJECT_ID=\nGCS_CREDENTIALS=\n{{/if}}\n",
|
|
28
28
|
"marketing/payload/next.config.ts.hbs": "import { withPayload } from '@payloadcms/next/withPayload'\nimport type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['@repo/ui'],\n}\n\nexport default withPayload(nextConfig)\n",
|
|
29
|
-
"marketing/payload/package.json.hbs": "{\n \"name\": \"@repo/marketing\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev -p 3001\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"db:push\": \"payload migrate\",\n \"db:seed\": \"tsx src/seed.ts\"\n },\n \"dependencies\": {\n \"next\": \"^15.4.10\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"payload\": \"^3.70.0\",\n \"@payloadcms/db-postgres\": \"^3.0.0\",\n \"@payloadcms/next\": \"^3.0.0\",\n \"@payloadcms/richtext-lexical\": \"^3.0.0\",\n \"@payloadcms/
|
|
29
|
+
"marketing/payload/package.json.hbs": "{\n \"name\": \"@repo/marketing\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"next dev -p 3001\",\n \"build\": \"next build\",\n \"start\": \"next start\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"db:push\": \"payload migrate\",\n \"db:seed\": \"tsx src/seed.ts\"\n },\n \"dependencies\": {\n \"next\": \"^15.4.10\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\",\n \"payload\": \"^3.70.0\",\n \"@payloadcms/db-postgres\": \"^3.0.0\",\n \"@payloadcms/next\": \"^3.0.0\",\n \"@payloadcms/richtext-lexical\": \"^3.0.0\",\n \"@payloadcms/email-resend\": \"^3.0.0\",\n \"@payloadcms/plugin-seo\": \"^3.0.0\",\n{{#if (eq integrations.payloadStorage 's3')}}\n \"@payloadcms/storage-s3\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n \"@payloadcms/storage-s3\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n \"@payloadcms/storage-vercel-blob\": \"^3.0.0\",\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n \"@payloadcms/storage-gcs\": \"^3.0.0\",\n{{/if}}\n \"sharp\": \"^0.33.0\",\n \"@repo/ui\": \"workspace:*\"\n },\n \"devDependencies\": {\n \"@repo/config-typescript\": \"workspace:*\",\n \"@types/node\": \"^20.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"tailwindcss\": \"^4.0.0\",\n \"@tailwindcss/postcss\": \"^4.0.0\",\n \"postcss\": \"^8.4.0\",\n \"sass\": \"^1.86.0\",\n \"typescript\": \"^5.0.0\",\n \"tsx\": \"^4.0.0\"\n }\n}\n",
|
|
30
30
|
"marketing/payload/postcss.config.mjs.hbs": "export default {\n plugins: {\n '@tailwindcss/postcss': {},\n },\n}\n",
|
|
31
31
|
"marketing/payload/src/app/(frontend)/layout.tsx.hbs": "export default function FrontendLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return <>{children}</>\n}\n",
|
|
32
32
|
"marketing/payload/src/app/(frontend)/page.tsx.hbs": "import { getPayload } from 'payload'\nimport config from '@/payload.config'\n\nexport default async function HomePage() {\n // Check if DATABASE_URL is configured\n if (!process.env.DATABASE_URL || process.env.DATABASE_URL.includes('[PASSWORD]')) {\n return (\n <main className=\"min-h-screen bg-gradient-to-b from-gray-50 to-white\">\n <div className=\"container mx-auto px-4 py-16\">\n <div className=\"max-w-2xl mx-auto text-center\">\n <h1 className=\"text-4xl font-bold text-gray-900 mb-4\">\n Welcome to Your Marketing Site\n </h1>\n <p className=\"text-lg text-gray-600 mb-8\">\n Built with Payload CMS and Next.js\n </p>\n <div className=\"bg-amber-50 border border-amber-200 rounded-lg p-6 text-left\">\n <h2 className=\"text-lg font-semibold text-amber-800 mb-2\">\n Database Setup Required\n </h2>\n <p className=\"text-amber-700 mb-4\">\n To get started, configure your PostgreSQL database:\n </p>\n <ol className=\"list-decimal list-inside text-amber-700 space-y-2\">\n <li>Create a Supabase project at <a href=\"https://supabase.com\" className=\"underline\" target=\"_blank\" rel=\"noopener noreferrer\">supabase.com</a></li>\n <li>Copy your database connection string</li>\n <li>Update <code className=\"bg-amber-100 px-1 rounded\">DATABASE_URL</code> in <code className=\"bg-amber-100 px-1 rounded\">apps/marketing/.env.local</code></li>\n <li>Restart the development server</li>\n </ol>\n </div>\n <div className=\"mt-8\">\n <a\n href=\"/admin\"\n className=\"inline-flex items-center px-6 py-3 bg-gray-900 text-white rounded-lg hover:bg-gray-800 transition-colors\"\n >\n Go to Admin Panel\n </a>\n </div>\n </div>\n </div>\n </main>\n )\n }\n\n try {\n const payload = await getPayload({ config })\n\n const settings = await payload.findGlobal({\n slug: 'site-settings',\n })\n\n return (\n <main className=\"min-h-screen\">\n <div className=\"container mx-auto px-4 py-16\">\n <h1 className=\"text-4xl font-bold\">{settings.siteName || 'Marketing Site'}</h1>\n <p className=\"mt-4 text-lg text-gray-600\">{settings.siteDescription || 'Built with Payload CMS'}</p>\n </div>\n </main>\n )\n } catch (error) {\n return (\n <main className=\"min-h-screen bg-gradient-to-b from-red-50 to-white\">\n <div className=\"container mx-auto px-4 py-16\">\n <div className=\"max-w-2xl mx-auto text-center\">\n <h1 className=\"text-4xl font-bold text-gray-900 mb-4\">\n Database Connection Error\n </h1>\n <div className=\"bg-red-50 border border-red-200 rounded-lg p-6 text-left\">\n <p className=\"text-red-700 mb-4\">\n Could not connect to the database. Please check your configuration:\n </p>\n <ul className=\"list-disc list-inside text-red-700 space-y-2\">\n <li>Verify <code className=\"bg-red-100 px-1 rounded\">DATABASE_URL</code> is correct</li>\n <li>Ensure your database is running and accessible</li>\n <li>Check that the database credentials are valid</li>\n </ul>\n </div>\n </div>\n </div>\n </main>\n )\n }\n}\n",
|
|
@@ -37,7 +37,7 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
|
|
|
37
37
|
"marketing/payload/src/app/(payload)/api/graphql-playground/route.ts.hbs": "import config from '@/payload.config'\nimport { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'\nimport { importMap } from '../../importMap.js'\n\nexport const GET = GRAPHQL_PLAYGROUND_GET(config, importMap)\n",
|
|
38
38
|
"marketing/payload/src/app/(payload)/custom.scss.hbs": "/* Custom Payload admin styles */\n",
|
|
39
39
|
"marketing/payload/src/app/(payload)/importMap.js.hbs": "export const importMap = {}\n",
|
|
40
|
-
"marketing/payload/src/app/(payload)/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport config from '@/payload.config'\nimport { RootLayout } from '@payloadcms/next/layouts'\nimport { importMap } from './importMap.js'\nimport './custom.scss'\n\nexport const metadata: Metadata = {\n title: 'Admin Panel',\n}\n\ntype LayoutArgs = {\n children: React.ReactNode\n}\n\nconst Layout = ({ children }: LayoutArgs) =>\n RootLayout({ children, config, importMap })\n\nexport default Layout\n",
|
|
40
|
+
"marketing/payload/src/app/(payload)/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport config from '@/payload.config'\nimport { RootLayout, handleServerFunctions } from '@payloadcms/next/layouts'\nimport type { ServerFunctionClient } from 'payload'\nimport { importMap } from './importMap.js'\nimport './custom.scss'\n\nexport const metadata: Metadata = {\n title: 'Admin Panel',\n}\n\ntype LayoutArgs = {\n children: React.ReactNode\n}\n\nconst serverFunction: ServerFunctionClient = async function (args) {\n 'use server'\n return handleServerFunctions({ ...args, config, importMap })\n}\n\nconst Layout = ({ children }: LayoutArgs) =>\n RootLayout({ children, config, importMap, serverFunction })\n\nexport default Layout\n",
|
|
41
41
|
"marketing/payload/src/app/globals.css.hbs": "@import \"tailwindcss\";\n\n@custom-variant dark (&:is(.dark *));\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --font-sans: var(--font-geist-sans);\n --font-mono: var(--font-geist-mono);\n --color-ring: var(--ring);\n --color-input: var(--input);\n --color-border: var(--border);\n --color-destructive: var(--destructive);\n --color-accent-foreground: var(--accent-foreground);\n --color-accent: var(--accent);\n --color-muted-foreground: var(--muted-foreground);\n --color-muted: var(--muted);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-secondary: var(--secondary);\n --color-primary-foreground: var(--primary-foreground);\n --color-primary: var(--primary);\n --color-popover-foreground: var(--popover-foreground);\n --color-popover: var(--popover);\n --color-card-foreground: var(--card-foreground);\n --color-card: var(--card);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n}\n\n:root {\n --radius: 0.625rem;\n --background: oklch(1 0 0);\n --foreground: oklch(0.145 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.145 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.145 0 0);\n --primary: oklch(0.205 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.97 0 0);\n --secondary-foreground: oklch(0.205 0 0);\n --muted: oklch(0.97 0 0);\n --muted-foreground: oklch(0.556 0 0);\n --accent: oklch(0.97 0 0);\n --accent-foreground: oklch(0.205 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.922 0 0);\n --input: oklch(0.922 0 0);\n --ring: oklch(0.708 0 0);\n}\n\n.dark {\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n}\n\n@layer base {\n * {\n @apply border-border outline-ring/50;\n }\n\n body {\n @apply bg-background text-foreground;\n }\n}\n",
|
|
42
42
|
"marketing/payload/src/app/layout.tsx.hbs": "import type { Metadata } from 'next'\nimport './globals.css'\n\nexport const metadata: Metadata = {\n title: 'Marketing Site',\n description: 'Built with Payload CMS',\n}\n\nexport default function RootLayout({\n children,\n}: {\n children: React.ReactNode\n}) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n )\n}\n",
|
|
43
43
|
"marketing/payload/src/blocks/Benefits.ts.hbs": "import type { Block } from 'payload'\n\nexport const BenefitsBlock: Block = {\n slug: 'benefits',\n labels: { singular: 'Benefits', plural: 'Benefits' },\n fields: [\n { name: 'label', type: 'text' },\n { name: 'heading', type: 'text', required: true },\n { name: 'description', type: 'textarea' },\n { name: 'image', type: 'upload', relationTo: 'media' },\n {\n name: 'imagePosition',\n type: 'select',\n options: [\n { label: 'Left', value: 'left' },\n { label: 'Right', value: 'right' },\n ],\n defaultValue: 'right',\n },\n {\n name: 'benefits',\n type: 'array',\n fields: [{ name: 'text', type: 'text', required: true }],\n },\n {\n name: 'cta',\n type: 'group',\n fields: [\n { name: 'label', type: 'text' },\n { name: 'url', type: 'text' },\n ],\n },\n ],\n}\n",
|
|
@@ -58,7 +58,7 @@ export const EMBEDDED_TEMPLATES: Record<string, string> = {
|
|
|
58
58
|
"marketing/payload/src/globals/Navigation.ts.hbs": "import type { GlobalConfig } from 'payload'\n\nexport const Navigation: GlobalConfig = {\n slug: 'navigation',\n access: {\n read: () => true,\n },\n fields: [\n {\n name: 'items',\n type: 'array',\n fields: [\n {\n name: 'label',\n type: 'text',\n required: true,\n },\n {\n name: 'link',\n type: 'group',\n fields: [\n {\n name: 'type',\n type: 'radio',\n options: [\n { label: 'Internal', value: 'internal' },\n { label: 'External', value: 'external' },\n ],\n defaultValue: 'internal',\n },\n {\n name: 'page',\n type: 'relationship',\n relationTo: 'pages',\n admin: {\n condition: (_, siblingData) => siblingData?.type === 'internal',\n },\n },\n {\n name: 'url',\n type: 'text',\n admin: {\n condition: (_, siblingData) => siblingData?.type === 'external',\n },\n },\n ],\n },\n ],\n },\n ],\n}\n",
|
|
59
59
|
"marketing/payload/src/globals/SiteSettings.ts.hbs": "import type { GlobalConfig } from 'payload'\n\nexport const SiteSettings: GlobalConfig = {\n slug: 'site-settings',\n access: {\n read: () => true,\n },\n fields: [\n {\n name: 'siteName',\n type: 'text',\n required: true,\n },\n {\n name: 'siteDescription',\n type: 'textarea',\n },\n {\n name: 'logo',\n type: 'upload',\n relationTo: 'media',\n },\n {\n name: 'favicon',\n type: 'upload',\n relationTo: 'media',\n },\n {\n name: 'socialLinks',\n type: 'array',\n fields: [\n {\n name: 'platform',\n type: 'select',\n options: [\n { label: 'Twitter', value: 'twitter' },\n { label: 'GitHub', value: 'github' },\n { label: 'LinkedIn', value: 'linkedin' },\n { label: 'Discord', value: 'discord' },\n ],\n },\n {\n name: 'url',\n type: 'text',\n },\n ],\n },\n ],\n}\n",
|
|
60
60
|
"marketing/payload/src/globals/index.ts.hbs": "export { SiteSettings } from './SiteSettings'\nexport { Navigation } from './Navigation'\n",
|
|
61
|
-
"marketing/payload/src/payload.config.ts.hbs": "import path from 'path'\nimport { fileURLToPath } from 'url'\nimport { buildConfig } from 'payload'\nimport { postgresAdapter } from '@payloadcms/db-postgres'\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { s3Storage } from '@payloadcms/storage-s3'\nimport {
|
|
61
|
+
"marketing/payload/src/payload.config.ts.hbs": "import path from 'path'\nimport { fileURLToPath } from 'url'\nimport { buildConfig } from 'payload'\nimport { postgresAdapter } from '@payloadcms/db-postgres'\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { seoPlugin } from '@payloadcms/plugin-seo'\nimport { resendAdapter } from '@payloadcms/email-resend'\nimport sharp from 'sharp'\n{{#if (eq integrations.payloadStorage 's3')}}\nimport { s3Storage } from '@payloadcms/storage-s3'\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\nimport { s3Storage } from '@payloadcms/storage-s3'\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\nimport { vercelBlobStorage } from '@payloadcms/storage-vercel-blob'\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\nimport { gcsStorage } from '@payloadcms/storage-gcs'\n{{/if}}\n\nimport { Pages } from './collections/Pages'\nimport { Media } from './collections/Media'\nimport { Users } from './collections/Users'\nimport { Posts } from './collections/Posts'\nimport { SiteSettings } from './globals/SiteSettings'\nimport { Navigation } from './globals/Navigation'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = path.dirname(__filename)\n\nexport default buildConfig({\n admin: {\n user: Users.slug,\n importMap: {\n baseDir: path.resolve(__dirname),\n },\n },\n db: postgresAdapter({\n pool: {\n connectionString: process.env.DATABASE_URL,\n },\n }),\n editor: lexicalEditor(),\n email: resendAdapter({\n defaultFromAddress: process.env.RESEND_FROM_EMAIL || 'noreply@example.com',\n defaultFromName: '{{projectName}}',\n apiKey: process.env.RESEND_API_KEY || '',\n }),\n collections: [Users, Media, Pages, Posts],\n globals: [SiteSettings, Navigation],\n plugins: [\n{{#if (eq integrations.payloadStorage 's3')}}\n s3Storage({\n collections: {\n media: true,\n },\n bucket: process.env.S3_BUCKET!,\n config: {\n credentials: {\n accessKeyId: process.env.S3_ACCESS_KEY_ID!,\n secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,\n },\n region: process.env.S3_REGION!,\n endpoint: process.env.S3_ENDPOINT,\n forcePathStyle: true,\n },\n }),\n{{/if}}\n{{#if (eq integrations.payloadStorage 'r2')}}\n s3Storage({\n collections: {\n media: true,\n },\n bucket: process.env.R2_BUCKET!,\n config: {\n credentials: {\n accessKeyId: process.env.R2_ACCESS_KEY_ID!,\n secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,\n },\n region: 'auto',\n endpoint: process.env.R2_ENDPOINT!,\n forcePathStyle: true,\n },\n }),\n{{/if}}\n{{#if (eq integrations.payloadStorage 'vercel-blob')}}\n vercelBlobStorage({\n collections: {\n media: true,\n },\n token: process.env.BLOB_READ_WRITE_TOKEN!,\n }),\n{{/if}}\n{{#if (eq integrations.payloadStorage 'gcs')}}\n gcsStorage({\n collections: {\n media: true,\n },\n bucket: process.env.GCS_BUCKET!,\n options: {\n projectId: process.env.GCS_PROJECT_ID,\n credentials: JSON.parse(process.env.GCS_CREDENTIALS || '{}'),\n },\n }),\n{{/if}}\n seoPlugin({\n collections: ['pages', 'posts'],\n uploadsCollection: 'media',\n generateTitle: ({ doc }) => `${doc?.title ?? ''} | {{projectName}}`,\n generateDescription: ({ doc }) => doc?.excerpt ?? '',\n }),\n ],\n secret: process.env.PAYLOAD_SECRET!,\n sharp,\n typescript: {\n outputFile: path.resolve(__dirname, 'payload-types.ts'),\n },\n{{#if (eq integrations.payloadStorage 'local')}}\n upload: {\n limits: {\n fileSize: 5000000, // 5MB\n },\n },\n{{/if}}\n})\n",
|
|
62
62
|
"marketing/payload/tsconfig.json.hbs": "{\n \"compilerOptions\": {\n \"target\": \"ES2017\",\n \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"noEmit\": true,\n \"esModuleInterop\": true,\n \"module\": \"esnext\",\n \"moduleResolution\": \"bundler\",\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"jsx\": \"preserve\",\n \"incremental\": true,\n \"plugins\": [{ \"name\": \"next\" }],\n \"paths\": {\n \"@/*\": [\"./src/*\"]\n }\n },\n \"include\": [\"next-env.d.ts\", \"**/*.ts\", \"**/*.tsx\", \".next/types/**/*.ts\", \".next/dev/types/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n",
|
|
63
63
|
"monorepo/package.json.hbs": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"scripts\": {\n \"dev\": \"node scripts/dev.mjs\",\n \"dev:all\": \"turbo dev\",\n \"dev:web\": \"turbo -F @repo/web dev\",\n \"dev:backend\": \"turbo -F @repo/backend dev\",\n \"dev:setup\": \"pnpm --filter @repo/backend dev:setup\",\n \"build\": \"turbo build\",\n \"lint\": \"turbo lint\",\n \"lint:fix\": \"turbo lint:fix\",\n \"format\": \"turbo format\",\n \"typecheck\": \"turbo typecheck\",\n \"test\": \"turbo test\",\n \"test:e2e\": \"turbo test:e2e\",\n \"clean\": \"turbo clean && rm -rf node_modules\",\n \"prepare\": \"husky\"\n },\n \"devDependencies\": {\n \"turbo\": \"^2.0.0\",\n \"husky\": \"^9.0.0\",\n \"lint-staged\": \"^15.0.0\"\n },\n \"packageManager\": \"pnpm@9.0.0\",\n \"lint-staged\": {\n \"*.{js,ts,jsx,tsx}\": [\"biome check --apply\"],\n \"*.{json,md}\": [\"biome format --write\"]\n }\n}\n",
|
|
64
64
|
"monorepo/pnpm-workspace.yaml.hbs": "packages:\n - \"apps/*\"\n - \"packages/*\"\n",
|
|
@@ -10,9 +10,37 @@ CRON_SECRET="" # Generate with: openssl rand -base64 32
|
|
|
10
10
|
# Draft Previews
|
|
11
11
|
PREVIEW_SECRET="" # Generate with: openssl rand -base64 32
|
|
12
12
|
|
|
13
|
-
#
|
|
13
|
+
# Email (Resend)
|
|
14
|
+
RESEND_API_KEY=""
|
|
15
|
+
RESEND_FROM_EMAIL="noreply@yourdomain.com"
|
|
16
|
+
|
|
17
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
18
|
+
# S3 Storage
|
|
14
19
|
S3_BUCKET="media"
|
|
15
20
|
S3_ACCESS_KEY_ID=""
|
|
16
21
|
S3_SECRET_ACCESS_KEY=""
|
|
17
|
-
S3_REGION="
|
|
18
|
-
S3_ENDPOINT="
|
|
22
|
+
S3_REGION="us-east-1"
|
|
23
|
+
S3_ENDPOINT="" # Optional: For S3-compatible services
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
26
|
+
# Cloudflare R2 Storage
|
|
27
|
+
R2_BUCKET=""
|
|
28
|
+
R2_ACCESS_KEY_ID=""
|
|
29
|
+
R2_SECRET_ACCESS_KEY=""
|
|
30
|
+
R2_ENDPOINT="https://[ACCOUNT_ID].r2.cloudflarestorage.com"
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
33
|
+
# Vercel Blob Storage
|
|
34
|
+
BLOB_READ_WRITE_TOKEN=""
|
|
35
|
+
{{/if}}
|
|
36
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
37
|
+
# Google Cloud Storage
|
|
38
|
+
GCS_BUCKET=""
|
|
39
|
+
GCS_PROJECT_ID=""
|
|
40
|
+
GCS_CREDENTIALS="{}" # JSON service account key
|
|
41
|
+
{{/if}}
|
|
42
|
+
{{#if (eq integrations.payloadStorage 'local')}}
|
|
43
|
+
# Local Storage
|
|
44
|
+
# Files are stored in the /media directory by default
|
|
45
|
+
# No additional configuration required
|
|
46
|
+
{{/if}}
|
|
@@ -10,9 +10,32 @@ CRON_SECRET=
|
|
|
10
10
|
# Draft Previews
|
|
11
11
|
PREVIEW_SECRET=
|
|
12
12
|
|
|
13
|
-
#
|
|
14
|
-
|
|
13
|
+
# Email (Resend)
|
|
14
|
+
RESEND_API_KEY=
|
|
15
|
+
RESEND_FROM_EMAIL=
|
|
16
|
+
|
|
17
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
18
|
+
# S3 Storage
|
|
19
|
+
S3_BUCKET=media
|
|
15
20
|
S3_ACCESS_KEY_ID=
|
|
16
21
|
S3_SECRET_ACCESS_KEY=
|
|
17
|
-
S3_REGION=
|
|
22
|
+
S3_REGION=us-east-1
|
|
18
23
|
S3_ENDPOINT=
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
26
|
+
# Cloudflare R2 Storage
|
|
27
|
+
R2_BUCKET=
|
|
28
|
+
R2_ACCESS_KEY_ID=
|
|
29
|
+
R2_SECRET_ACCESS_KEY=
|
|
30
|
+
R2_ENDPOINT=
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
33
|
+
# Vercel Blob Storage
|
|
34
|
+
BLOB_READ_WRITE_TOKEN=
|
|
35
|
+
{{/if}}
|
|
36
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
37
|
+
# Google Cloud Storage
|
|
38
|
+
GCS_BUCKET=
|
|
39
|
+
GCS_PROJECT_ID=
|
|
40
|
+
GCS_CREDENTIALS=
|
|
41
|
+
{{/if}}
|
|
@@ -20,8 +20,21 @@
|
|
|
20
20
|
"@payloadcms/db-postgres": "^3.0.0",
|
|
21
21
|
"@payloadcms/next": "^3.0.0",
|
|
22
22
|
"@payloadcms/richtext-lexical": "^3.0.0",
|
|
23
|
-
"@payloadcms/
|
|
23
|
+
"@payloadcms/email-resend": "^3.0.0",
|
|
24
24
|
"@payloadcms/plugin-seo": "^3.0.0",
|
|
25
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
26
|
+
"@payloadcms/storage-s3": "^3.0.0",
|
|
27
|
+
{{/if}}
|
|
28
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
29
|
+
"@payloadcms/storage-s3": "^3.0.0",
|
|
30
|
+
{{/if}}
|
|
31
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
32
|
+
"@payloadcms/storage-vercel-blob": "^3.0.0",
|
|
33
|
+
{{/if}}
|
|
34
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
35
|
+
"@payloadcms/storage-gcs": "^3.0.0",
|
|
36
|
+
{{/if}}
|
|
37
|
+
"sharp": "^0.33.0",
|
|
25
38
|
"@repo/ui": "workspace:*"
|
|
26
39
|
},
|
|
27
40
|
"devDependencies": {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Metadata } from 'next'
|
|
2
2
|
import config from '@/payload.config'
|
|
3
|
-
import { RootLayout } from '@payloadcms/next/layouts'
|
|
3
|
+
import { RootLayout, handleServerFunctions } from '@payloadcms/next/layouts'
|
|
4
|
+
import type { ServerFunctionClient } from 'payload'
|
|
4
5
|
import { importMap } from './importMap.js'
|
|
5
6
|
import './custom.scss'
|
|
6
7
|
|
|
@@ -12,7 +13,12 @@ type LayoutArgs = {
|
|
|
12
13
|
children: React.ReactNode
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
const serverFunction: ServerFunctionClient = async function (args) {
|
|
17
|
+
'use server'
|
|
18
|
+
return handleServerFunctions({ ...args, config, importMap })
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
const Layout = ({ children }: LayoutArgs) =>
|
|
16
|
-
RootLayout({ children, config, importMap })
|
|
22
|
+
RootLayout({ children, config, importMap, serverFunction })
|
|
17
23
|
|
|
18
24
|
export default Layout
|
|
@@ -3,8 +3,21 @@ import { fileURLToPath } from 'url'
|
|
|
3
3
|
import { buildConfig } from 'payload'
|
|
4
4
|
import { postgresAdapter } from '@payloadcms/db-postgres'
|
|
5
5
|
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
|
6
|
-
import { s3Storage } from '@payloadcms/storage-s3'
|
|
7
6
|
import { seoPlugin } from '@payloadcms/plugin-seo'
|
|
7
|
+
import { resendAdapter } from '@payloadcms/email-resend'
|
|
8
|
+
import sharp from 'sharp'
|
|
9
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
10
|
+
import { s3Storage } from '@payloadcms/storage-s3'
|
|
11
|
+
{{/if}}
|
|
12
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
13
|
+
import { s3Storage } from '@payloadcms/storage-s3'
|
|
14
|
+
{{/if}}
|
|
15
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
16
|
+
import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob'
|
|
17
|
+
{{/if}}
|
|
18
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
19
|
+
import { gcsStorage } from '@payloadcms/storage-gcs'
|
|
20
|
+
{{/if}}
|
|
8
21
|
|
|
9
22
|
import { Pages } from './collections/Pages'
|
|
10
23
|
import { Media } from './collections/Media'
|
|
@@ -29,9 +42,15 @@ export default buildConfig({
|
|
|
29
42
|
},
|
|
30
43
|
}),
|
|
31
44
|
editor: lexicalEditor(),
|
|
45
|
+
email: resendAdapter({
|
|
46
|
+
defaultFromAddress: process.env.RESEND_FROM_EMAIL || 'noreply@example.com',
|
|
47
|
+
defaultFromName: '{{projectName}}',
|
|
48
|
+
apiKey: process.env.RESEND_API_KEY || '',
|
|
49
|
+
}),
|
|
32
50
|
collections: [Users, Media, Pages, Posts],
|
|
33
51
|
globals: [SiteSettings, Navigation],
|
|
34
52
|
plugins: [
|
|
53
|
+
{{#if (eq integrations.payloadStorage 's3')}}
|
|
35
54
|
s3Storage({
|
|
36
55
|
collections: {
|
|
37
56
|
media: true,
|
|
@@ -43,10 +62,48 @@ export default buildConfig({
|
|
|
43
62
|
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
|
|
44
63
|
},
|
|
45
64
|
region: process.env.S3_REGION!,
|
|
46
|
-
endpoint: process.env.S3_ENDPOINT
|
|
65
|
+
endpoint: process.env.S3_ENDPOINT,
|
|
47
66
|
forcePathStyle: true,
|
|
48
67
|
},
|
|
49
68
|
}),
|
|
69
|
+
{{/if}}
|
|
70
|
+
{{#if (eq integrations.payloadStorage 'r2')}}
|
|
71
|
+
s3Storage({
|
|
72
|
+
collections: {
|
|
73
|
+
media: true,
|
|
74
|
+
},
|
|
75
|
+
bucket: process.env.R2_BUCKET!,
|
|
76
|
+
config: {
|
|
77
|
+
credentials: {
|
|
78
|
+
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
|
|
79
|
+
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
|
|
80
|
+
},
|
|
81
|
+
region: 'auto',
|
|
82
|
+
endpoint: process.env.R2_ENDPOINT!,
|
|
83
|
+
forcePathStyle: true,
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
{{/if}}
|
|
87
|
+
{{#if (eq integrations.payloadStorage 'vercel-blob')}}
|
|
88
|
+
vercelBlobStorage({
|
|
89
|
+
collections: {
|
|
90
|
+
media: true,
|
|
91
|
+
},
|
|
92
|
+
token: process.env.BLOB_READ_WRITE_TOKEN!,
|
|
93
|
+
}),
|
|
94
|
+
{{/if}}
|
|
95
|
+
{{#if (eq integrations.payloadStorage 'gcs')}}
|
|
96
|
+
gcsStorage({
|
|
97
|
+
collections: {
|
|
98
|
+
media: true,
|
|
99
|
+
},
|
|
100
|
+
bucket: process.env.GCS_BUCKET!,
|
|
101
|
+
options: {
|
|
102
|
+
projectId: process.env.GCS_PROJECT_ID,
|
|
103
|
+
credentials: JSON.parse(process.env.GCS_CREDENTIALS || '{}'),
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
{{/if}}
|
|
50
107
|
seoPlugin({
|
|
51
108
|
collections: ['pages', 'posts'],
|
|
52
109
|
uploadsCollection: 'media',
|
|
@@ -55,7 +112,15 @@ export default buildConfig({
|
|
|
55
112
|
}),
|
|
56
113
|
],
|
|
57
114
|
secret: process.env.PAYLOAD_SECRET!,
|
|
115
|
+
sharp,
|
|
58
116
|
typescript: {
|
|
59
117
|
outputFile: path.resolve(__dirname, 'payload-types.ts'),
|
|
60
118
|
},
|
|
119
|
+
{{#if (eq integrations.payloadStorage 'local')}}
|
|
120
|
+
upload: {
|
|
121
|
+
limits: {
|
|
122
|
+
fileSize: 5000000, // 5MB
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{{/if}}
|
|
61
126
|
})
|