├── .eslintrc.json ├── src ├── app │ ├── favicon.ico │ ├── layout.tsx │ ├── hero-demo │ │ └── page.tsx │ ├── globals.css │ ├── [...page] │ │ └── page.tsx │ ├── testimonial │ │ └── page.tsx │ └── page.tsx ├── components │ ├── Counter │ │ ├── styles.module.css │ │ └── Counter.tsx │ ├── Card │ │ └── Card.tsx │ ├── builder-section.tsx │ └── builder.tsx └── builder-registry.ts ├── postcss.config.js ├── .env ├── next.config.js ├── .gitignore ├── tailwind.config.js ├── public ├── vercel.svg └── next.svg ├── tsconfig.json ├── package.json ├── .vscode └── settings.json └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BuilderIO/nextjs-builder-starter/main/src/app/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # https://www.builder.io/c/docs/using-your-api-key 2 | NEXT_PUBLIC_BUILDER_API_KEY=be3bfb8bd6114d26b25a5713d293373a 3 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const withBuilderDevTools = require("@builder.io/dev-tools/next")(); 2 | 3 | /** @type {import('next').NextConfig} */ 4 | const nextConfig = withBuilderDevTools({}); 5 | 6 | module.exports = nextConfig; 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /src/components/Counter/styles.module.css: -------------------------------------------------------------------------------- 1 | .counter { 2 | margin: 32px auto; 3 | display: flex; 4 | width: 100%; 5 | max-width: 190px; 6 | } 7 | 8 | .btn { 9 | width: 42px; 10 | font-size: 32px; 11 | font-weight: bold; 12 | background-color: #1c6bd1; 13 | color: white; 14 | border: none; 15 | border-radius: 4px; 16 | cursor: pointer; 17 | line-height: 1.4; 18 | } 19 | 20 | .btn:hover { 21 | opacity: 0.8; 22 | } 23 | 24 | .count { 25 | flex: 1; 26 | font-size: 42px; 27 | text-align: center; 28 | color: black; 29 | } 30 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import type { Metadata } from 'next' 3 | import { Inter } from 'next/font/google' 4 | 5 | const inter = Inter({ subsets: ['latin'] }) 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Next App', 9 | description: 'Generated by create next app', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | {children} 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [require('daisyui')], 18 | } 19 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/hero-demo/page.tsx: -------------------------------------------------------------------------------- 1 | import { RenderBuilderSection } from "@/components/builder-section"; 2 | import { builder } from "@builder.io/sdk"; 3 | 4 | builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!); 5 | 6 | export default async function Page() { 7 | const content = await builder 8 | .get('hero-section', { 9 | prerender: false, 10 | }) 11 | .toPromise(); 12 | 13 | return ( 14 |
15 |

16 | Hero demo page 17 |

18 | 19 |
20 | ); 21 | } -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Card/Card.tsx: -------------------------------------------------------------------------------- 1 | export interface CardProps { 2 | imgSrc: string; 3 | title: string; 4 | description: string; 5 | buttonText: string; 6 | } 7 | 8 | export const Card = ({ imgSrc, buttonText, description, title }: CardProps) => { 9 | return ( 10 |
11 |
12 | {title} 13 |
14 |
15 |

{title}

16 |

{description}

17 |
18 | 19 |
20 |
21 |
) 22 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "bundler", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test2", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@types/node": "20.4.4", 13 | "@types/react": "18.2.15", 14 | "@types/react-dom": "18.2.7", 15 | "autoprefixer": "10.4.14", 16 | "eslint": "8.45.0", 17 | "eslint-config-next": "13.4.12", 18 | "next": "13.4.12", 19 | "postcss": "8.4.27", 20 | "react": "18.2.0", 21 | "react-dom": "18.2.0", 22 | "tailwindcss": "3.3.3", 23 | "typescript": "5.1.6" 24 | }, 25 | "devDependencies": { 26 | "@builder.io/dev-tools": "^0.0.40", 27 | "@builder.io/react": "^3.0.8", 28 | "@builder.io/sdk": "^2.0.4", 29 | "daisyui": "^3.3.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Counter/Counter.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import styles from "./styles.module.css"; 4 | 5 | interface CounterProps { 6 | initialCount: number; 7 | } 8 | 9 | function Counter({ initialCount = 99 }: CounterProps) { 10 | const [count, setCount] = useState(initialCount); 11 | 12 | const increment = () => { 13 | setCount((prevCount) => prevCount + 1); 14 | }; 15 | 16 | const decrement = () => { 17 | setCount((prevCount) => prevCount - 1); 18 | }; 19 | 20 | return ( 21 |
22 | 25 | {count} 26 | 29 |
30 | ); 31 | } 32 | 33 | export default Counter; 34 | -------------------------------------------------------------------------------- /src/components/builder-section.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { BuilderComponent, useIsPreviewing } from "@builder.io/react"; 4 | import { BuilderContent, builder } from "@builder.io/sdk"; 5 | 6 | import "../builder-registry"; 7 | 8 | interface BuilderSectionProps { 9 | content?: BuilderContent; 10 | } 11 | 12 | // Builder Public API Key set in .env file 13 | builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!); 14 | 15 | export function RenderBuilderSection({ content }: BuilderSectionProps) { 16 | // Call the useIsPreviewing hook to determine if 17 | // the page is being previewed in Builder 18 | const isPreviewing = useIsPreviewing(); 19 | // If "content" has a value or the page is being previewed in Builder, 20 | // render the BuilderComponent with the specified content and model props. 21 | if (content || isPreviewing) { 22 | return ; 23 | } 24 | 25 | return null; 26 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#fbed80", 4 | "activityBar.background": "#fbed80", 5 | "activityBar.foreground": "#15202b", 6 | "activityBar.inactiveForeground": "#15202b99", 7 | "activityBarBadge.background": "#06b9a5", 8 | "activityBarBadge.foreground": "#15202b", 9 | "commandCenter.border": "#15202b99", 10 | "sash.hoverBorder": "#fbed80", 11 | "statusBar.background": "#f7df1e", 12 | "statusBar.border": "#f7df1e", 13 | "statusBar.foreground": "#15202b", 14 | "statusBarItem.hoverBackground": "#dac308", 15 | "statusBarItem.remoteBackground": "#f7df1e", 16 | "statusBarItem.remoteForeground": "#15202b", 17 | "tab.activeBorder": "#fbed80", 18 | "titleBar.activeBackground": "#fbed80", 19 | "titleBar.activeForeground": "#15202b", 20 | "titleBar.border": "#fbed80", 21 | "titleBar.inactiveBackground": "#fbed8099", 22 | "titleBar.inactiveForeground": "#15202b99" 23 | }, 24 | "peacock.color": "#f9e64f" 25 | } -------------------------------------------------------------------------------- /src/app/[...page]/page.tsx: -------------------------------------------------------------------------------- 1 | import { builder } from "@builder.io/sdk"; 2 | import { RenderBuilderContent } from "../../components/builder"; 3 | 4 | // Builder Public API Key set in .env file 5 | builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!); 6 | 7 | interface PageProps { 8 | params: { 9 | page: string[]; 10 | }; 11 | } 12 | 13 | export default async function Page(props: PageProps) { 14 | const content = await builder 15 | // Get the page content from Builder with the specified options 16 | .get("page", { 17 | userAttributes: { 18 | // Use the page path specified in the URL to fetch the content 19 | urlPath: "/" + (props?.params?.page?.join("/") || ""), 20 | }, 21 | // Set prerender to false to return JSON instead of HTML 22 | prerender: false, 23 | }) 24 | // Convert the result to a promise 25 | .toPromise(); 26 | 27 | return ( 28 | <> 29 | {/* Render the Builder page */} 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /src/builder-registry.ts: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { Builder } from "@builder.io/react"; 3 | import dynamic from "next/dynamic"; 4 | 5 | Builder.registerComponent( 6 | dynamic(() => import("./components/Counter/Counter")), 7 | { 8 | name: "Counter", 9 | inputs: [ 10 | { 11 | name: "initialCount", 12 | type: "number", 13 | required: true, 14 | }, 15 | ], 16 | } 17 | ); 18 | 19 | Builder.registerComponent( 20 | dynamic(async () => (await import("./components/Card/Card")).Card), 21 | { 22 | name: "Card", 23 | inputs: [ 24 | { 25 | name: "buttonText", 26 | type: "string", 27 | required: true, 28 | }, 29 | { 30 | name: "description", 31 | type: "string", 32 | required: true, 33 | }, 34 | { 35 | name: "imgSrc", 36 | type: "string", 37 | required: true, 38 | }, 39 | { 40 | name: "title", 41 | type: "string", 42 | required: true, 43 | }, 44 | ], 45 | } 46 | ); 47 | -------------------------------------------------------------------------------- /src/components/builder.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { BuilderComponent, builder, useIsPreviewing } from "@builder.io/react"; 3 | import type { BuilderContent } from "@builder.io/sdk"; 4 | import DefaultErrorPage from "next/error"; 5 | import "../builder-registry"; 6 | 7 | interface BuilderPageProps { 8 | content?: BuilderContent; 9 | } 10 | 11 | // Builder Public API Key set in .env file 12 | builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!); 13 | 14 | export function RenderBuilderContent({ content }: BuilderPageProps) { 15 | // Call the useIsPreviewing hook to determine if 16 | // the page is being previewed in Builder 17 | const isPreviewing = useIsPreviewing(); 18 | // If "content" has a value or the page is being previewed in Builder, 19 | // render the BuilderComponent with the specified content and model props. 20 | if (content || isPreviewing) { 21 | return ; 22 | } 23 | // If the "content" is falsy and the page is 24 | // not being previewed in Builder, render the 25 | // DefaultErrorPage with a 404. 26 | return ; 27 | } -------------------------------------------------------------------------------- /src/app/testimonial/page.tsx: -------------------------------------------------------------------------------- 1 | import { builder, BuilderContent } from "@builder.io/sdk"; 2 | 3 | builder.init(process.env.NEXT_PUBLIC_BUILDER_API_KEY!); 4 | 5 | export default async function Page() { 6 | const testimonials = await builder.getAll("testimonial", { prerender: false }); 7 | return ( 8 |
9 |

10 | Testimonial page 11 |

12 |
    13 | {testimonials?.map(({ data, id }: BuilderContent) => ( 14 |
  • 15 |
    16 |
    17 | {data!.personName} 21 |
    22 |
    23 |

    {data!.personName}

    24 |

    {data!.content}

    25 |
    26 |
    27 |
  • ))} 28 |
29 |
30 | ); 31 | } -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image' 2 | import Link from 'next/link' 3 | 4 | export default function Home() { 5 | return ( 6 |
7 |
8 |

9 | Next.js + Builder Demo 10 |

11 |
12 |
13 |

Have fun!

14 |
15 | 16 |
17 | 21 |

22 | Main demo{' '} 23 | 24 | -> 25 | 26 |

27 |

28 | See a page that was built with Builder.io and Next.js. 29 |

30 | 31 | 32 | 36 |

37 | Section{' '} 38 | 39 | -> 40 | 41 |

42 |

43 | See how a section of a page works with Builder. 44 |

45 | 46 | 47 | 51 |

52 | CMS Data 53 | 54 | -> 55 | 56 |

57 |

58 | See how to get data from Builder.io into your Next.js app 59 |

60 | 61 | 67 |

68 | Blueprints{' '} 69 | 70 | -> 71 | 72 |

73 |

74 | Quick reference for how to integrate common use cases with Builder 75 |

76 |
77 | 78 |
79 |
80 | ) 81 | } 82 | --------------------------------------------------------------------------------