├── .env.example ├── .gitignore ├── .npmrc ├── .prettierignore ├── README.md ├── components.json ├── environment.d.ts ├── eslint.config.mjs ├── next-env.d.ts ├── next-sitemap.config.cjs ├── next.config.ts ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.ico └── favicon.svg ├── redirects.js ├── src ├── app │ ├── (frontend) │ │ ├── [slug] │ │ │ ├── page.client.tsx │ │ │ └── page.tsx │ │ ├── contact │ │ │ ├── page.client.tsx │ │ │ └── page.tsx │ │ ├── globals.css │ │ ├── layout.tsx │ │ ├── not-found.tsx │ │ ├── page.tsx │ │ ├── posts │ │ │ ├── [slug] │ │ │ │ ├── PostHero │ │ │ │ │ └── index.tsx │ │ │ │ ├── page.client.tsx │ │ │ │ └── page.tsx │ │ │ ├── page.client.tsx │ │ │ ├── page.tsx │ │ │ └── page │ │ │ │ └── [pageNumber] │ │ │ │ ├── page.client.tsx │ │ │ │ └── page.tsx │ │ └── providers.tsx │ └── (payload) │ │ ├── (sitemaps) │ │ ├── pages-sitemap.xml │ │ │ └── route.ts │ │ └── posts-sitemap.xml │ │ │ └── route.ts │ │ ├── admin │ │ ├── [[...segments]] │ │ │ ├── not-found.tsx │ │ │ └── page.tsx │ │ └── importMap.js │ │ ├── api │ │ ├── [...slug] │ │ │ └── route.ts │ │ ├── graphql-playground │ │ │ └── route.ts │ │ └── graphql │ │ │ └── route.ts │ │ ├── custom.scss │ │ ├── layout.tsx │ │ └── next │ │ ├── exit-preview │ │ ├── GET.ts │ │ └── route.ts │ │ ├── preview │ │ └── route.ts │ │ └── seed │ │ ├── route.ts │ │ └── seedData │ │ ├── home-static.ts │ │ ├── home.ts │ │ ├── image-1.ts │ │ ├── image-2.ts │ │ ├── image-3.ts │ │ ├── image-hero-1.ts │ │ ├── image-hero1.webp │ │ ├── image-post1.webp │ │ ├── image-post2.webp │ │ ├── image-post3.webp │ │ ├── index.ts │ │ ├── post-1.ts │ │ ├── post-2.ts │ │ └── post-3.ts ├── components │ ├── BeforeDashboard │ │ ├── SeedButton │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── index.scss │ │ └── index.tsx │ ├── BeforeLogin │ │ └── index.tsx │ ├── Card │ │ └── index.tsx │ ├── CollectionArchive │ │ └── CollectionArchive.tsx │ ├── LivePreviewListener │ │ └── index.tsx │ ├── Logo │ │ └── Logo.tsx │ ├── Media │ │ ├── ImageMedia │ │ │ └── index.tsx │ │ ├── VideoMedia │ │ │ └── index.tsx │ │ ├── index.tsx │ │ └── types.ts │ ├── PageRange │ │ └── index.tsx │ ├── Pagination │ │ └── index.tsx │ ├── PayloadRedirects │ │ └── index.tsx │ ├── RichText │ │ └── index.tsx │ ├── ThemeProvider │ │ ├── HeaderTheme │ │ │ └── index.tsx │ │ └── Theme │ │ │ ├── InitTheme │ │ │ └── index.tsx │ │ │ ├── ThemeSelector │ │ │ ├── index.tsx │ │ │ └── types.ts │ │ │ ├── index.tsx │ │ │ ├── shared.ts │ │ │ └── types.ts │ └── ui │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── checkbox.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── pagination.tsx │ │ ├── select.tsx │ │ ├── textarea.tsx │ │ ├── toggle-group.tsx │ │ └── toggle.tsx ├── lib │ ├── scripts │ │ └── setup.js │ └── utils │ │ ├── canUseDOM.ts │ │ ├── deepMerge.ts │ │ ├── formatAuthors.ts │ │ ├── formatDateTime.ts │ │ ├── generateMeta.ts │ │ ├── generatePreviewPath.ts │ │ ├── getDocument.ts │ │ ├── getGlobals.ts │ │ ├── getMeUser.ts │ │ ├── getRedirects.ts │ │ ├── getURL.ts │ │ ├── index.ts │ │ ├── mergeOpenGraph.ts │ │ ├── toKebabCase.ts │ │ ├── useClickableCard.ts │ │ └── useDebounce.ts ├── payload-types.ts ├── payload.config.ts └── payload │ ├── auth │ ├── anyone.ts │ ├── authenticated.ts │ └── authenticatedOrPublished.ts │ ├── blocks │ ├── ArchiveBlock │ │ ├── Component.tsx │ │ └── config.ts │ ├── Banner │ │ ├── Component.tsx │ │ └── config.ts │ ├── CallToAction │ │ ├── Component.tsx │ │ └── config.ts │ ├── Code │ │ ├── Component.client.tsx │ │ ├── Component.tsx │ │ ├── CopyButton.tsx │ │ └── config.ts │ ├── Content │ │ ├── Component.tsx │ │ └── config.ts │ ├── HighImpact │ │ ├── Component.tsx │ │ └── config.ts │ ├── LowImpact │ │ ├── Component.tsx │ │ └── config.ts │ ├── MediaBlock │ │ ├── Component.tsx │ │ └── config.ts │ ├── MediumImpact │ │ ├── Component.tsx │ │ └── config.ts │ ├── RelatedPosts │ │ └── Component.tsx │ └── RenderBlocks.tsx │ ├── collections │ ├── Categories.ts │ ├── Media.ts │ ├── Pages │ │ ├── hooks │ │ │ └── revalidatePage.ts │ │ └── index.ts │ ├── Posts │ │ ├── hooks │ │ │ ├── populateAuthors.ts │ │ │ └── revalidatePost.ts │ │ └── index.ts │ └── Users │ │ └── index.ts │ ├── fields │ ├── Link │ │ ├── index.tsx │ │ ├── link.ts │ │ └── linkGroup.ts │ ├── defaultLexical.ts │ └── slug │ │ ├── SlugComponent.tsx │ │ ├── formatSlug.ts │ │ ├── index.scss │ │ └── index.ts │ ├── globals │ ├── Footer │ │ ├── Component.tsx │ │ ├── RowLabel.tsx │ │ ├── config.ts │ │ └── hooks │ │ │ └── revalidateFooter.ts │ └── Header │ │ ├── Component.client.tsx │ │ ├── Component.tsx │ │ ├── Nav │ │ └── index.tsx │ │ ├── RowLabel.tsx │ │ ├── config.ts │ │ └── hooks │ │ └── revalidateHeader.ts │ ├── hooks │ ├── formatSlug.ts │ ├── populatePublishedAt.ts │ └── revalidateRedirects.ts │ └── plugins │ └── index.ts ├── tailwind.config.mjs └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | # Database connection string 2 | DATABASE_URI=mongodb://127.0.0.1/your-database-name 3 | 4 | # Or use a PG connection string 5 | #DATABASE_URI=postgresql://127.0.0.1:5432/your-database-name 6 | 7 | # Used to encrypt JWT tokens 8 | PAYLOAD_SECRET=YOUR_SECRET_HERE 9 | 10 | # Used to configure CORS, format links and more. No trailing slash 11 | NEXT_PUBLIC_SERVER_URL=http://localhost:3000 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist / media 3 | node_modules 4 | .DS_Store 5 | .env 6 | .next 7 | .vercel 8 | 9 | # Payload default media upload directory 10 | public/media/ 11 | 12 | public/robots.txt 13 | public/sitemap*.xml 14 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | enable-pre-post-scripts=true 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/payload-types.ts 2 | .tmp 3 | **/.git 4 | **/.hg 5 | **/.pnp.* 6 | **/.svn 7 | **/.yarn/** 8 | **/build 9 | **/dist/** 10 | **/node_modules 11 | **/temp 12 | **/docs/** 13 | tsconfig.json 14 | 15 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.mjs", 8 | "css": "src/app/(frontend)/globals.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui" 17 | }, 18 | "iconLibrary": "lucide" 19 | } 20 | -------------------------------------------------------------------------------- /environment.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace NodeJS { 3 | interface ProcessEnv { 4 | PAYLOAD_SECRET: string 5 | DATABASE_URI: string 6 | NEXT_PUBLIC_SERVER_URL: string 7 | VERCEL_PROJECT_PRODUCTION_URL: string 8 | } 9 | } 10 | } // Add environment variables here to ensure type safety throughout the application 11 | 12 | // If this file has no import/export statements (i.e. is a script) 13 | // Convert it into a module by adding an empty export statement. 14 | export { } // Do not delete 15 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path" 2 | import { fileURLToPath } from "url" 3 | import { FlatCompat } from "@eslint/eslintrc" 4 | 5 | const __filename = fileURLToPath(import.meta.url) 6 | const __dirname = dirname(__filename) 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }) 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | { 15 | rules: { 16 | "@typescript-eslint/ban-ts-comment": "warn", 17 | "@typescript-eslint/no-empty-object-type": "warn", 18 | "@typescript-eslint/no-explicit-any": "warn", 19 | "@typescript-eslint/no-unused-vars": [ 20 | "warn", 21 | { 22 | vars: "all", 23 | args: "after-used", 24 | ignoreRestSiblings: false, 25 | argsIgnorePattern: "^_", 26 | varsIgnorePattern: "^_", 27 | destructuredArrayIgnorePattern: "^_", 28 | caughtErrorsIgnorePattern: "^(_|ignore)", 29 | }, 30 | ], 31 | }, 32 | }, 33 | ] 34 | 35 | export default eslintConfig 36 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /next-sitemap.config.cjs: -------------------------------------------------------------------------------- 1 | const SITE_URL = process.env.NEXT_PUBLIC_SERVER_URL || process.env.VERCEL_PROJECT_PRODUCTION_URL || "https://example.com" 2 | 3 | /** @type {import('next-sitemap').IConfig} */ 4 | module.exports = { 5 | siteUrl: SITE_URL, 6 | generateRobotsTxt: true, 7 | exclude: ["/posts-sitemap.xml", "/pages-sitemap.xml", "/*", "/posts/*"], 8 | robotsTxtOptions: { 9 | policies: [ 10 | { 11 | userAgent: "*", 12 | disallow: "/admin/*", 13 | }, 14 | ], 15 | additionalSitemaps: [`${SITE_URL}/pages-sitemap.xml`, `${SITE_URL}/posts-sitemap.xml`], 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import { withPayload } from '@payloadcms/next/withPayload' 2 | 3 | import redirects from './redirects.js' 4 | import { NextConfig } from 'next' 5 | 6 | const NEXT_PUBLIC_SERVER_URL = process.env.VERCEL_PROJECT_PRODUCTION_URL 7 | ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` 8 | : process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000' 9 | 10 | /** @type {import('next').NextConfig} */ 11 | const nextConfig: NextConfig = { 12 | images: { 13 | remotePatterns: [ 14 | ...[NEXT_PUBLIC_SERVER_URL /* 'https://example.com' */].map((item) => { 15 | const url = new URL(item) 16 | 17 | return { 18 | hostname: url.hostname, 19 | protocol: url.protocol.replace(':', '') as 'http' | 'https', 20 | } 21 | }), 22 | ], 23 | }, 24 | reactStrictMode: true, 25 | redirects, 26 | } 27 | 28 | export default withPayload(nextConfig) 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "default-website-template", 3 | "version": "1.0.0", 4 | "description": "Website template for Payload", 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "build": "next build", 9 | "dev": "next dev --turbo", 10 | "start": "next start", 11 | "generate:types": "payload generate:types", 12 | "generate:importmap": "payload generate:importmap", 13 | "lint": "next lint", 14 | "payload": "payload", 15 | "setup": "node -e \"process.env.VERCEL_ENV || process.env.CI ? console.log('Skipping setup in CI environment') : require('child_process').execSync('node src/lib/scripts/setup.js', {stdio: 'inherit'})\"" 16 | }, 17 | "dependencies": { 18 | "@payloadcms/db-mongodb": "^3.24.0", 19 | "@payloadcms/live-preview-react": "^3.24.0", 20 | "@payloadcms/next": "^3.24.0", 21 | "@payloadcms/payload-cloud": "^3.24.0", 22 | "@payloadcms/plugin-redirects": "^3.24.0", 23 | "@payloadcms/plugin-seo": "^3.24.0", 24 | "@payloadcms/richtext-lexical": "^3.24.0", 25 | "@payloadcms/ui": "^3.24.0", 26 | "@radix-ui/react-checkbox": "^1.0.4", 27 | "@radix-ui/react-label": "^2.0.2", 28 | "@radix-ui/react-select": "^2.0.0", 29 | "@radix-ui/react-slot": "^1.0.2", 30 | "@radix-ui/react-toggle": "^1.1.2", 31 | "@radix-ui/react-toggle-group": "^1.1.2", 32 | "class-variance-authority": "^0.7.0", 33 | "clsx": "^2.1.1", 34 | "geist": "^1.3.0", 35 | "graphql": "^16.8.2", 36 | "lucide-react": "^0.378.0", 37 | "next": "^15.1.5", 38 | "next-sitemap": "^4.2.3", 39 | "payload": "^3.24.0", 40 | "prism-react-renderer": "^2.3.1", 41 | "react": "^19.0.0", 42 | "react-dom": "^19.0.0", 43 | "react-hook-form": "7.45.4", 44 | "sharp": "0.32.6", 45 | "tailwind-merge": "^2.3.0", 46 | "tailwindcss-animate": "^1.0.7" 47 | }, 48 | "devDependencies": { 49 | "@eslint/eslintrc": "^3.2.0", 50 | "@tailwindcss/typography": "^0.5.13", 51 | "@types/escape-html": "^1.0.2", 52 | "@types/node": "22.5.4", 53 | "@types/react": "19.0.7", 54 | "@types/react-dom": "19.0.3", 55 | "autoprefixer": "^10.4.19", 56 | "copyfiles": "^2.4.1", 57 | "eslint": "^9.16.0", 58 | "eslint-config-next": "15.1.5", 59 | "postcss": "^8.4.38", 60 | "prettier": "^3.4.2", 61 | "tailwindcss": "^3.4.3", 62 | "typescript": "5.7.3" 63 | }, 64 | "engines": { 65 | "node": "^18.20.2 || >=20.9.0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gioruu/simple-payload-starter/37c918cb7a2fcae9f5bf1a93fdf0d8b02cfe34d5/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /redirects.js: -------------------------------------------------------------------------------- 1 | const redirects = async () => { 2 | const internetExplorerRedirect = { 3 | destination: '/ie-incompatible.html', 4 | has: [ 5 | { 6 | type: 'header', 7 | key: 'user-agent', 8 | value: '(.*Trident.*)', // all ie browsers 9 | }, 10 | ], 11 | permanent: false, 12 | source: '/:path((?!ie-incompatible.html$).*)', // all pages except the incompatibility page 13 | } 14 | 15 | const redirects = [internetExplorerRedirect] 16 | 17 | return redirects 18 | } 19 | 20 | export default redirects 21 | -------------------------------------------------------------------------------- /src/app/(frontend)/[slug]/page.client.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { useHeaderTheme } from '@/components/ThemeProvider/HeaderTheme' 3 | import React, { useEffect } from 'react' 4 | 5 | const PageClient: React.FC = () => { 6 | /* Force the header to be dark mode while we have an image behind it */ 7 | const { setHeaderTheme } = useHeaderTheme() 8 | 9 | useEffect(() => { 10 | setHeaderTheme('light') 11 | }, [setHeaderTheme]) 12 | return 13 | } 14 | 15 | export default PageClient 16 | -------------------------------------------------------------------------------- /src/app/(frontend)/[slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | 3 | import { PayloadRedirects } from '@/components/PayloadRedirects' 4 | import configPromise from '@payload-config' 5 | import { draftMode } from 'next/headers' 6 | import { getPayload } from 'payload' 7 | import { cache } from 'react' 8 | 9 | import type { Page as PageType } from '@/payload-types' 10 | 11 | import { homeStatic } from '@/app/(payload)/next/seed/seedData/home-static' 12 | import { LivePreviewListener } from '@/components/LivePreviewListener' 13 | import { generateMeta } from '@/lib/utils/generateMeta' 14 | import { RenderBlocks } from '@/payload/blocks/RenderBlocks' 15 | import PageClient from './page.client' 16 | 17 | export async function generateStaticParams() { 18 | const payload = await getPayload({ config: configPromise }) 19 | const pages = await payload.find({ 20 | collection: 'pages', 21 | draft: false, 22 | limit: 1000, 23 | overrideAccess: false, 24 | pagination: false, 25 | select: { 26 | slug: true, 27 | }, 28 | }) 29 | 30 | const params = pages.docs 31 | ?.filter((doc) => { 32 | return doc.slug !== 'home' 33 | }) 34 | .map(({ slug }) => { 35 | return { slug } 36 | }) 37 | 38 | return params 39 | } 40 | 41 | type Args = { 42 | params: Promise<{ 43 | slug?: string 44 | }> 45 | } 46 | 47 | export default async function Page({ params: paramsPromise }: Args) { 48 | const { isEnabled: draft } = await draftMode() 49 | const { slug = 'home' } = await paramsPromise 50 | const url = '/' + slug 51 | 52 | let page: PageType | null 53 | 54 | page = await queryPageBySlug({ 55 | slug, 56 | }) 57 | 58 | // Remove this code once your website is seeded 59 | if (!page && slug === 'home') { 60 | page = homeStatic as PageType 61 | } 62 | 63 | if (!page) { 64 | return 65 | } 66 | 67 | const { blocks } = page 68 | 69 | return ( 70 |
71 | 72 | {/* Allows redirects for valid pages too */} 73 | 74 | 75 | {draft && } 76 | 77 | 78 |
79 | ) 80 | } 81 | 82 | export async function generateMetadata({ params: paramsPromise }): Promise { 83 | const { slug = 'home' } = await paramsPromise 84 | const page = await queryPageBySlug({ 85 | slug, 86 | }) 87 | 88 | return generateMeta({ doc: page }) 89 | } 90 | 91 | const queryPageBySlug = cache(async ({ slug }: { slug: string }) => { 92 | const { isEnabled: draft } = await draftMode() 93 | 94 | const payload = await getPayload({ config: configPromise }) 95 | 96 | const result = await payload.find({ 97 | collection: 'pages', 98 | draft, 99 | limit: 1, 100 | pagination: false, 101 | overrideAccess: draft, 102 | where: { 103 | slug: { 104 | equals: slug, 105 | }, 106 | }, 107 | }) 108 | 109 | return result.docs?.[0] || null 110 | }) 111 | -------------------------------------------------------------------------------- /src/app/(frontend)/contact/page.client.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import { useHeaderTheme } from '@/components/ThemeProvider/HeaderTheme' 3 | import React, { useEffect } from 'react' 4 | 5 | const PageClient: React.FC = () => { 6 | /* Force the header to be dark mode while we have an image behind it */ 7 | const { setHeaderTheme } = useHeaderTheme() 8 | 9 | useEffect(() => { 10 | setHeaderTheme('light') 11 | }, [setHeaderTheme]) 12 | return 13 | } 14 | 15 | export default PageClient 16 | -------------------------------------------------------------------------------- /src/app/(frontend)/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | h1, 7 | h2, 8 | h3, 9 | h4, 10 | h5, 11 | h6 { 12 | font-size: auto; 13 | font-weight: auto; 14 | } 15 | 16 | :root { 17 | --background: 0 0% 100%; 18 | --foreground: 222.2 84% 4.9%; 19 | 20 | --card: 240 5% 96%; 21 | --card-foreground: 222.2 84% 4.9%; 22 | 23 | --popover: 0 0% 100%; 24 | --popover-foreground: 222.2 84% 4.9%; 25 | 26 | --primary: 222.2 47.4% 11.2%; 27 | --primary-foreground: 210 40% 98%; 28 | 29 | --secondary: 210 40% 96.1%; 30 | --secondary-foreground: 222.2 47.4% 11.2%; 31 | 32 | --muted: 210 40% 96.1%; 33 | --muted-foreground: 215.4 16.3% 46.9%; 34 | 35 | --accent: 210 40% 96.1%; 36 | --accent-foreground: 222.2 47.4% 11.2%; 37 | 38 | --destructive: 0 84.2% 60.2%; 39 | --destructive-foreground: 210 40% 98%; 40 | 41 | --border: 240 6% 90%; 42 | --input: 214.3 31.8% 91.4%; 43 | --ring: 222.2 84% 4.9%; 44 | 45 | --radius: 0.2rem; 46 | 47 | --success: 196 52% 74%; 48 | --warning: 34 89% 85%; 49 | --error: 10 100% 86%; 50 | } 51 | 52 | [data-theme='dark'] { 53 | --background: 0 0% 0%; 54 | --foreground: 210 40% 98%; 55 | 56 | --card: 0 0% 4%; 57 | --card-foreground: 210 40% 98%; 58 | 59 | --popover: 222.2 84% 4.9%; 60 | --popover-foreground: 210 40% 98%; 61 | 62 | --primary: 210 40% 98%; 63 | --primary-foreground: 222.2 47.4% 11.2%; 64 | 65 | --secondary: 217.2 32.6% 17.5%; 66 | --secondary-foreground: 210 40% 98%; 67 | 68 | --muted: 217.2 32.6% 17.5%; 69 | --muted-foreground: 215 20.2% 65.1%; 70 | 71 | --accent: 217.2 32.6% 17.5%; 72 | --accent-foreground: 210 40% 98%; 73 | 74 | --destructive: 0 62.8% 30.6%; 75 | --destructive-foreground: 210 40% 98%; 76 | 77 | --border: 0, 0%, 15%, 0.5; 78 | --input: 217.2 32.6% 17.5%; 79 | --ring: 212.7 26.8% 83.9%; 80 | 81 | --success: 196 100% 14%; 82 | --warning: 34 51% 25%; 83 | --error: 10 39% 43%; 84 | } 85 | } 86 | 87 | @layer base { 88 | * { 89 | @apply border-border; 90 | } 91 | body { 92 | @apply bg-background text-foreground min-h-[100vh] flex flex-col; 93 | } 94 | } 95 | 96 | html { 97 | opacity: 0; 98 | } 99 | 100 | html[data-theme='dark'], 101 | html[data-theme='light'] { 102 | opacity: initial; 103 | } 104 | -------------------------------------------------------------------------------- /src/app/(frontend)/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from 'next' 2 | 3 | import { cn } from '@/lib/utils' 4 | import { GeistMono } from 'geist/font/mono' 5 | import { GeistSans } from 'geist/font/sans' 6 | import React from 'react' 7 | 8 | import { Footer } from '@/payload/globals/Footer/Component' 9 | import { Header } from '@/payload/globals/Header/Component' 10 | import { InitTheme } from '@/components/ThemeProvider/Theme/InitTheme' 11 | import { mergeOpenGraph } from '@/lib/utils/mergeOpenGraph' 12 | 13 | import { getServerSideURL } from '@/lib/utils/getURL' 14 | import './globals.css' 15 | import { Providers } from './providers' 16 | 17 | export default async function RootLayout({ children }: { children: React.ReactNode }) { 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | {children} 29 |