├── public
├── favicon-128.png
├── favicon-180.png
├── favicon-192.png
├── favicon-32.png
└── images
│ └── dev-libraries.jpg
├── src
├── shared
│ ├── interfaces
│ │ └── general
│ │ │ └── childrenNode.ts
│ └── contexts
│ │ ├── globalContext.tsx
│ │ └── colorMode.tsx
├── app
│ ├── api
│ │ └── hello
│ │ │ └── route.ts
│ ├── page.e2e.cy.ts
│ ├── page.tsx
│ ├── not-found.tsx
│ ├── not-found.e2e.cy.ts
│ └── layout.tsx
└── components
│ ├── Header
│ ├── index.tsx
│ └── index.component.cy.tsx
│ ├── Footer
│ ├── index.tsx
│ └── index.component.cy.tsx
│ └── ThemeButton
│ ├── index.tsx
│ └── index.component.cy.tsx
├── .prettierignore
├── .vscode
└── settings.json
├── .github
├── dependabot.yml
├── FUNDING.yml
└── workflows
│ ├── npm-publish.yml
│ └── ci.yml
├── .husky
└── pre-commit
├── cypress
├── fixtures
│ └── example.json
└── support
│ ├── component-index.html
│ ├── e2e.ts
│ ├── component.ts
│ └── commands.ts
├── .prettierrc.js
├── next.config.js
├── eslint.config.js
├── lint-staged.config.js
├── cypress.config.ts
├── .gitignore
├── LICENSE.md
├── tsconfig.json
├── bin
└── cli.js
├── webpack.config.js
├── .eslintrc.js
├── package.json
└── README.md
/public/favicon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AstrOOnauta/next-js-boilerplate/HEAD/public/favicon-128.png
--------------------------------------------------------------------------------
/public/favicon-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AstrOOnauta/next-js-boilerplate/HEAD/public/favicon-180.png
--------------------------------------------------------------------------------
/public/favicon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AstrOOnauta/next-js-boilerplate/HEAD/public/favicon-192.png
--------------------------------------------------------------------------------
/public/favicon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AstrOOnauta/next-js-boilerplate/HEAD/public/favicon-32.png
--------------------------------------------------------------------------------
/src/shared/interfaces/general/childrenNode.ts:
--------------------------------------------------------------------------------
1 | export interface ChildrenInterface {
2 | children: React.ReactNode;
3 | }
4 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .next
2 | .cache
3 | package-lock.json
4 | public
5 | node_modules
6 | next-env.d.ts
7 | next.config.ts
8 | yarn.lock
--------------------------------------------------------------------------------
/public/images/dev-libraries.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AstrOOnauta/next-js-boilerplate/HEAD/public/images/dev-libraries.jpg
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules\\typescript\\lib",
3 | "typescript.enablePromptUseWorkspaceTsdk": true
4 | }
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "npm"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | #! npm run cypress:run #! Needs DEV to be running
5 | npm run lint-staged
6 |
--------------------------------------------------------------------------------
/src/app/api/hello/route.ts:
--------------------------------------------------------------------------------
1 | import { NextResponse } from "next/server";
2 |
3 | export async function GET() {
4 | return NextResponse.json({ name: "John Doe" });
5 | }
6 |
--------------------------------------------------------------------------------
/cypress/fixtures/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Using fixtures to represent data",
3 | "email": "hello@cypress.io",
4 | "body": "Fixtures are a great way to mock data for responses to routes"
5 | }
6 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | endOfLine: "auto",
3 | arrowParens: "always",
4 | trailingComma: "es5",
5 | semi: true,
6 | useTabs: false,
7 | singleQuote: false,
8 | bracketSpacing: true,
9 | };
10 |
--------------------------------------------------------------------------------
/src/app/page.e2e.cy.ts:
--------------------------------------------------------------------------------
1 | describe("Home Page", () => {
2 | it("should show the elements on the home", () => {
3 | cy.visit(Cypress.config("baseUrl") as string);
4 |
5 | cy.get('[data-cy="title"]').contains("Boilerplate Next JS");
6 | });
7 | });
8 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | webpackDevMiddleware: (config) => {
5 | config.infrastructureLogging = { level: "error" };
6 | return config;
7 | },
8 | };
9 |
10 | module.exports = nextConfig;
11 |
--------------------------------------------------------------------------------
/cypress/support/component-index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Components App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/app/page.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import { Flex, Text } from "@chakra-ui/react";
5 |
6 | export default function HomePage() {
7 | return (
8 |
9 |
10 |
11 | Boilerplate Next JS
12 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | const pluginSecurity = require("eslint-plugin-security");
2 |
3 | module.exports = [
4 | // Ignore generated/build folders at the config level (flat config supports ignores)
5 | {
6 | ignores: [
7 | "**/.next/**",
8 | "**/node_modules/**",
9 | "**/dist/**",
10 | "**/coverage/**",
11 | "**/.out/**",
12 | "**/.build/**",
13 | "**/public/**",
14 | ],
15 | },
16 | pluginSecurity.configs.recommended,
17 | ];
18 |
--------------------------------------------------------------------------------
/src/components/Header/index.tsx:
--------------------------------------------------------------------------------
1 | import { Flex, Text } from "@chakra-ui/react";
2 |
3 | import ThemeButton from "../ThemeButton";
4 |
5 | interface HeaderProps {
6 | title: string;
7 | }
8 |
9 | export default function Header({ title }: HeaderProps) {
10 | return (
11 |
12 |
13 | {title}
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/lint-staged.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // this will check Typescript files
3 | "**/*.(ts|tsx)": () => "yarn tsc --noEmit",
4 |
5 | // This will lint and format TypeScript and //JavaScript files
6 | "**/*.(ts|tsx|js)": (filenames) => [
7 | `yarn eslint --fix ${filenames.join(" ")}`,
8 | `yarn prettier --write ${filenames.join(" ")}`,
9 | ],
10 |
11 | // this will Format MarkDown and JSON
12 | "**/*.(md|json)": (filenames) =>
13 | `yarn prettier --write ${filenames.join(" ")}`,
14 | };
15 |
--------------------------------------------------------------------------------
/cypress.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "cypress";
2 |
3 | export default defineConfig({
4 | chromeWebSecurity: false,
5 | component: {
6 | specPattern: "src/**/*.component.cy.{js,jsx,ts,tsx}",
7 | devServer: {
8 | framework: "react",
9 | bundler: "webpack",
10 | webpackConfig: require("./webpack.config.js"),
11 | },
12 | },
13 |
14 | e2e: {
15 | baseUrl: "http://localhost:3000",
16 | specPattern: "src/**/*.e2e.cy.{js,jsx,ts,tsx}",
17 | setupNodeEvents(on, config) {
18 | // implement node event listeners here
19 | },
20 | },
21 | });
22 |
--------------------------------------------------------------------------------
/.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 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
38 | #cypress
39 | /cypress/screenshots
40 | /cypress/videos
41 |
--------------------------------------------------------------------------------
/src/components/Header/index.component.cy.tsx:
--------------------------------------------------------------------------------
1 | import { mount } from "cypress/react";
2 | import GlobalContext from "~/shared/contexts/globalContext";
3 | import Header from ".";
4 |
5 | describe("Header", () => {
6 | it("should show the elements on the header", () => {
7 | mount(
8 |
9 |
10 |
11 | );
12 |
13 | cy.get('[data-cy="title-header"]')
14 | .should("be.visible")
15 | .contains("Cypress Test");
16 |
17 | cy.get('[data-cy="theme-button"]').should("be.visible").and("be.enabled");
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/src/components/Footer/index.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import { Flex, Text } from "@chakra-ui/react";
3 |
4 | export default function Footer() {
5 | return (
6 |
7 |
8 | Powered by
9 |
10 |
16 |
17 | AstrOOnauta
18 |
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/ThemeButton/index.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import { IconButton, IconButtonProps } from "@chakra-ui/react";
5 | import { Sun, Moon } from "lucide-react";
6 |
7 | import { useColorMode } from "~/shared/contexts/colorMode";
8 |
9 | export default function ThemeButton(props: IconButtonProps) {
10 | const { colorMode, toggleColorMode } = useColorMode();
11 |
12 | const handleClick: IconButtonProps["onClick"] = (event) => {
13 | toggleColorMode();
14 | props.onClick?.(event as any);
15 | };
16 |
17 | return (
18 |
19 | {colorMode === "light" ? : }
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/cypress/support/e2e.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/e2e.ts is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import "./commands";
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright 2023-present Willian Barbosa Lima do Nascimento & Collaborators
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
8 |
--------------------------------------------------------------------------------
/src/shared/contexts/globalContext.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React from "react";
4 | import { ChakraProvider, defaultSystem, Theme } from "@chakra-ui/react";
5 |
6 | import { ChildrenInterface } from "~/shared/interfaces/general/childrenNode";
7 | import { ColorModeProvider, useColorMode } from "~/shared/contexts/colorMode";
8 |
9 | const ThemeBridge: React.FC<{ children: React.ReactNode }> = ({ children }) => {
10 | const { colorMode } = useColorMode();
11 | return {children} ;
12 | };
13 |
14 | const GlobalContext: React.FC = ({ children }) => {
15 | return (
16 |
17 |
18 | {children}
19 |
20 |
21 | );
22 | };
23 |
24 | export default GlobalContext;
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [AstrOOnauta] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: AstrOOnauta # Replace with a single Patreon username
5 | # open_collective: # Replace with a single Open Collective username
6 | ko_fi: astroonauta # Replace with a single Ko-fi username
7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | # liberapay: # Replace with a single Liberapay username
10 | # issuehunt: # Replace with a single IssueHunt username
11 | # otechie: # Replace with a single Otechie username
12 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: [https://www.buymeacoffee.com/astroonauta] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/src/components/ThemeButton/index.component.cy.tsx:
--------------------------------------------------------------------------------
1 | import { mount } from "cypress/react";
2 | import GlobalContext from "~/shared/contexts/globalContext";
3 | import ThemeButton from ".";
4 |
5 | describe("Theme Button", () => {
6 | it("should fires a onclick event", () => {
7 | const callButtonHandler = {
8 | buttonHandler: () => {},
9 | };
10 |
11 | mount(
12 |
13 |
19 |
20 | );
21 |
22 | cy.get('[data-cy="theme-button"]').should("be.visible").and("be.enabled");
23 |
24 | callButtonHandler.buttonHandler();
25 |
26 | cy.get("@buttonHandler").should("have.been.called");
27 |
28 | cy.get("@buttonHandler").should("have.been.calledOnce");
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "strict": true,
12 | "forceConsistentCasingInFileNames": true,
13 | "noEmit": true,
14 | "esModuleInterop": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "jsx": "react-jsx",
20 | "incremental": true,
21 | "types": [
22 | "cypress",
23 | "node"
24 | ],
25 | "baseUrl": "src",
26 | "paths": {
27 | "~/*": [
28 | "./*"
29 | ]
30 | },
31 | "plugins": [
32 | {
33 | "name": "next"
34 | }
35 | ]
36 | },
37 | "include": [
38 | "next-env.d.ts",
39 | "cypress.d.ts",
40 | "**/*.ts",
41 | "**/*.tsx",
42 | ".next/types/**/*.ts",
43 | ".next/dev/types/**/*.ts"
44 | ],
45 | "exclude": [
46 | "node_modules"
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | const { execSync } = require("child_process");
3 |
4 | const runCommand = (command) => {
5 | try {
6 | execSync(`${command}`, { stdio: "inherit" });
7 | } catch (error) {
8 | console.error(`Failed to execute ${command}`, error);
9 | return false;
10 | }
11 | return true;
12 | };
13 |
14 | const repoName = process.argv[2] || "my-app";
15 | const gitCheckoutCommand = `git clone --depth 1 https://github.com/AstrOOnauta/next-js-boilerplate.git ${repoName}`;
16 | const installDepsCommand = `cd ${repoName} && npm install --legacy-peer-deps`;
17 |
18 | console.log(`Cloning the repository with name ${repoName}`);
19 |
20 | const checkedOut = runCommand(gitCheckoutCommand);
21 |
22 | if (!checkedOut) process.exit(code - 1);
23 |
24 | console.log(`Installing dependencies for ${repoName}`);
25 |
26 | const installDeps = runCommand(installDepsCommand);
27 |
28 | if (!installDeps) process.exit(code - 1);
29 |
30 | console.log("Gratz! You're ready. Follow the following commands to start:");
31 | console.log(`cd ${repoName} && npm run dev`);
32 |
--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2 | # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3 |
4 | name: Publish create-next-js-boilerplate to NPM
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | # build:
12 | # runs-on: ubuntu-latest
13 | # steps:
14 | # - uses: actions/checkout@v3
15 | # - uses: actions/setup-node@v3
16 | # with:
17 | # node-version: 22
18 | # - run: npm ci --legacy-peer-deps
19 | # - run: npm test
20 |
21 | publish-npm:
22 | # needs: build
23 | runs-on: ubuntu-latest
24 | steps:
25 | - uses: actions/checkout@v3
26 | - uses: actions/setup-node@v3
27 | with:
28 | node-version: 22
29 | registry-url: https://registry.npmjs.org/
30 | # - run: npm ci --legacy-peer-deps
31 | - run: npm publish --access public
32 | env:
33 | NODE_AUTH_TOKEN: ${{secrets.npm_token}}
34 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const webpack = require("webpack");
3 |
4 | module.exports = {
5 | ignoreWarnings: [/Serializing big strings/],
6 | resolve: {
7 | extensions: [".ts", ".tsx", ".js", ".jsx"],
8 | alias: {
9 | "~": path.resolve(__dirname, "src"),
10 | },
11 | fallback: {
12 | process: require.resolve("process/browser"),
13 | },
14 | },
15 | module: {
16 | rules: [
17 | {
18 | test: /\.tsx?$/,
19 | exclude: /node_modules/,
20 | use: [
21 | {
22 | loader: "babel-loader",
23 | options: {
24 | presets: [
25 | ["@babel/preset-react", { runtime: "automatic" }],
26 | "@babel/preset-typescript",
27 | ],
28 | },
29 | },
30 | ],
31 | },
32 | ],
33 | },
34 | plugins: [
35 | new webpack.ProvidePlugin({
36 | process: "process/browser",
37 | }),
38 | new webpack.DefinePlugin({
39 | "process.env": JSON.stringify(process.env),
40 | }),
41 | ],
42 | };
43 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | name: ci
3 | on: [pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | strategy:
10 | matrix:
11 | node-version: [22.x]
12 |
13 | steps:
14 | - name: Checkout Repository
15 | uses: actions/checkout@v3
16 |
17 | - name: Setup Node
18 | uses: actions/setup-node@v3
19 | with:
20 | node-version: ${{ matrix.node-version }}
21 |
22 | - uses: actions/cache@v3
23 | id: yarn-cache
24 | with:
25 | path: |
26 | ~/cache
27 | !~/cache/exclude
28 | **/node_modules
29 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
30 | restore-keys: |
31 | ${{ runner.os }}-yarn-
32 |
33 | - name: Install dependencies
34 | run: yarn
35 |
36 | - name: Linting
37 | run: yarn lint
38 |
39 | - name: Build
40 | run: yarn build
41 |
42 | - name: Cypress run
43 | uses: cypress-io/github-action@v6
44 | with:
45 | build: yarn build
46 | start: yarn start
47 |
--------------------------------------------------------------------------------
/cypress/support/component.ts:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/component.ts is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.ts using ES2015 syntax:
17 | import "./commands";
18 |
19 | // Alternatively you can use CommonJS syntax:
20 | // require('./commands')
21 |
22 | import { mount } from "cypress/react";
23 |
24 | // Augment the Cypress namespace to include type definitions for
25 | // your custom command.
26 | // Alternatively, can be defined in cypress/support/component.d.ts
27 | // with a at the top of your spec.
28 | declare global {
29 | namespace Cypress {
30 | interface Chainable {
31 | mount: typeof mount;
32 | }
33 | }
34 | }
35 |
36 | Cypress.Commands.add("mount", mount);
37 |
38 | // Example use:
39 | // cy.mount( )
40 |
--------------------------------------------------------------------------------
/src/app/not-found.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import Link from "next/link";
4 | import { Button, Flex, Text } from "@chakra-ui/react";
5 |
6 | export default function NotFound() {
7 | return (
8 |
9 |
15 |
22 | Oops...
23 |
24 |
30 | 404
31 |
32 |
39 | Page not found
40 |
41 |
42 |
48 | Go to home
49 |
50 |
51 |
52 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/src/app/not-found.e2e.cy.ts:
--------------------------------------------------------------------------------
1 | describe("Not Found", () => {
2 | const notFoundUrl = `${Cypress.config("baseUrl")}/404-page-not-found`;
3 | const goToHomeLink = '[data-cy="go-to-home-link"]';
4 |
5 | it("should show the elements on the 404 page not found", () => {
6 | cy.visit(notFoundUrl, {
7 | failOnStatusCode: false,
8 | });
9 |
10 | cy.get('[data-cy="oops-text"]').contains("Oops...");
11 | cy.get('[data-cy="404-text"]').contains("404");
12 | cy.get('[data-cy="page-not-found-text"]').contains("Page not found");
13 | cy.get(goToHomeLink).should("be.visible").and("not.be.disabled");
14 | cy.get('[data-cy="go-to-home-button"]')
15 | .should("be.visible")
16 | .contains("Go to home");
17 | });
18 |
19 | it("should the button go to home fires a onclick event", () => {
20 | let linkCalled = false;
21 |
22 | cy.visit(notFoundUrl, {
23 | failOnStatusCode: false,
24 | });
25 |
26 | cy.get(goToHomeLink)
27 | .click()
28 | .then(() => {
29 | linkCalled = true;
30 | });
31 |
32 | cy.wait(100).then(() => {
33 | expect(linkCalled).to.eq(true);
34 | });
35 | });
36 |
37 | it("should the link go to home redirect to home page", () => {
38 | cy.visit(notFoundUrl, {
39 | failOnStatusCode: false,
40 | });
41 |
42 | cy.get(goToHomeLink).click();
43 |
44 | cy.location("pathname").should("eq", "/");
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/cypress/support/commands.ts:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************
3 | // This example commands.ts shows you how to
4 | // create various custom commands and overwrite
5 | // existing commands.
6 | //
7 | // For more comprehensive examples of custom
8 | // commands please read more here:
9 | // https://on.cypress.io/custom-commands
10 | // ***********************************************
11 | //
12 | //
13 | // -- This is a parent command --
14 | // Cypress.Commands.add('login', (email, password) => { ... })
15 | //
16 | //
17 | // -- This is a child command --
18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
19 | //
20 | //
21 | // -- This is a dual command --
22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
23 | //
24 | //
25 | // -- This will overwrite an existing command --
26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
27 | //
28 | // declare global {
29 | // namespace Cypress {
30 | // interface Chainable {
31 | // login(email: string, password: string): Chainable
32 | // drag(subject: string, options?: Partial): Chainable
33 | // dismiss(subject: string, options?: Partial): Chainable
34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
35 | // }
36 | // }
37 | // }
38 |
--------------------------------------------------------------------------------
/src/components/Footer/index.component.cy.tsx:
--------------------------------------------------------------------------------
1 | import { mount } from "cypress/react";
2 | import GlobalContext from "~/shared/contexts/globalContext";
3 | import Footer from ".";
4 |
5 | describe("Footer", () => {
6 | const authorLinkElement = '[data-cy="author-link"]';
7 |
8 | it("should show the elements on the footer", () => {
9 | mount(
10 |
11 |
12 |
13 | );
14 |
15 | cy.get('[data-cy="footer-text"]').contains("Powered by");
16 |
17 | cy.get('[data-cy="author-name"]').contains("AstrOOnauta");
18 |
19 | cy.get(authorLinkElement).should("be.visible").and("not.be.disabled");
20 | });
21 |
22 | it("should fires a onclick event ", () => {
23 | mount(
24 |
25 |
26 |
27 | );
28 | let linkCalled = false;
29 |
30 | cy.get(authorLinkElement)
31 | .trigger("click")
32 | .then(() => {
33 | linkCalled = true;
34 | });
35 |
36 | cy.wait(100).then(() => {
37 | expect(linkCalled).to.eq(true);
38 | });
39 | });
40 |
41 | it("should redirect to the author's github", () => {
42 | const urlRedirects: string[] = [];
43 |
44 | mount(
45 |
46 |
47 |
48 | );
49 |
50 | cy.on("url:changed", (newUrl) => {
51 | urlRedirects.push(newUrl);
52 | });
53 |
54 | cy.get(authorLinkElement).should("have.attr", "target", "_blank");
55 |
56 | cy.get(authorLinkElement).invoke("removeAttr", "target").click();
57 |
58 | cy.then(() => {
59 | expect(urlRedirects).to.have.length(1);
60 | expect(urlRedirects[0]).to.eq("https://github.com/AstrOOnauta/");
61 | });
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/src/shared/contexts/colorMode.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import React, {
4 | createContext,
5 | useCallback,
6 | useContext,
7 | useEffect,
8 | useMemo,
9 | useState,
10 | } from "react";
11 |
12 | export type ColorMode = "light" | "dark";
13 |
14 | interface ColorModeContextValue {
15 | colorMode: ColorMode;
16 | toggleColorMode: () => void;
17 | setColorMode: (value: ColorMode) => void;
18 | }
19 |
20 | const ColorModeContext = createContext(
21 | {} as ColorModeContextValue
22 | );
23 |
24 | interface ProviderProps {
25 | children: React.ReactNode;
26 | defaultColorMode?: ColorMode;
27 | storageKey?: string;
28 | }
29 |
30 | export const ColorModeProvider: React.FC = ({
31 | children,
32 | defaultColorMode = "light",
33 | storageKey = "@theme-next-js-boilerplate",
34 | }) => {
35 | const [colorMode, setColorModeState] = useState(defaultColorMode);
36 |
37 | useEffect(() => {
38 | try {
39 | const stored = window.localStorage.getItem(storageKey);
40 | if (stored === "light" || stored === "dark") {
41 | setColorModeState(stored);
42 | }
43 | } catch {
44 | // ignore
45 | }
46 | }, [storageKey]);
47 |
48 | useEffect(() => {
49 | try {
50 | window.localStorage.setItem(storageKey, colorMode);
51 | } catch {
52 | // ignore
53 | }
54 | }, [colorMode, storageKey]);
55 |
56 | const setColorMode = useCallback((value: ColorMode) => {
57 | setColorModeState(value);
58 | }, []);
59 |
60 | const toggleColorMode = useCallback(() => {
61 | setColorModeState((prev) => (prev === "light" ? "dark" : "light"));
62 | }, []);
63 |
64 | const value = useMemo(
65 | () => ({ colorMode, toggleColorMode, setColorMode }),
66 | [colorMode, toggleColorMode, setColorMode]
67 | );
68 |
69 | return (
70 |
71 | {children}
72 |
73 | );
74 | };
75 |
76 | export function useColorMode() {
77 | return useContext(ColorModeContext);
78 | }
79 |
--------------------------------------------------------------------------------
/src/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Poppins } from "next/font/google";
3 |
4 | const poppins = Poppins({
5 | subsets: ["latin"],
6 | weight: ["300", "400", "500", "600", "700"],
7 | display: "swap",
8 | });
9 | import type { Metadata } from "next";
10 |
11 | import GlobalContext from "~/shared/contexts/globalContext";
12 | import { Flex } from "@chakra-ui/react";
13 | import Header from "~/components/Header";
14 | import Footer from "~/components/Footer";
15 |
16 | export const metadata: Metadata = {
17 | title: "Boilerplate Next JS",
18 | description:
19 | "Boilerplate Next JS + Typescript + Chakra UI + Prettier + ESLint + Pre-commit (Husky + Lint-staged) + Cypress (e2e + component)",
20 | openGraph: {
21 | title: "Next JS Boilerplate",
22 | type: "website",
23 | images: [
24 | {
25 | url: "/images/dev-libraries.jpg",
26 | width: 1200,
27 | height: 630,
28 | alt: "Boilerplate Next JS + Typescript + Chakra UI + Prettier + ESLint + Pre-commit (Husky + Lint-staged) + Cypress (e2e + component)",
29 | },
30 | ],
31 | url: "https://github.com/AstrOOnauta/next-js-boilerplate",
32 | },
33 | twitter: {
34 | card: "summary_large_image",
35 | },
36 | icons: {
37 | icon: [
38 | { url: "/favicon-180.png", type: "image/png" },
39 | { url: "/favicon-32.png", type: "image/png", sizes: "32x32" },
40 | { url: "/favicon-128.png", type: "image/png", sizes: "128x128" },
41 | { url: "/favicon-180.png", type: "image/png", sizes: "180x180" },
42 | { url: "/favicon-192.png", type: "image/png", sizes: "192x192" },
43 | ],
44 | apple: [{ url: "/favicon-180.png", type: "image/png" }],
45 | shortcut: [{ url: "/favicon-192.png", type: "image/png" }],
46 | },
47 | metadataBase: new URL("https://github.com/AstrOOnauta/next-js-boilerplate"),
48 | };
49 |
50 | export default function RootLayout({
51 | children,
52 | }: {
53 | children: React.ReactNode;
54 | }) {
55 | return (
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
67 |
68 |
69 |
70 |
71 |
72 | {children}
73 |
74 |
75 |
76 |
77 |
78 | );
79 | }
80 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | ecmaVersion: 2020,
5 | sourceType: "module",
6 | ecmaFeatures: {
7 | jsx: true,
8 | },
9 | },
10 |
11 | env: {
12 | browser: true,
13 | node: true,
14 | es6: true,
15 | },
16 |
17 | settings: {
18 | react: {
19 | version: "detect",
20 | },
21 | "import/resolver": {
22 | node: {
23 | extensions: [".ts", ".tsx"],
24 | },
25 | },
26 | },
27 |
28 | plugins: ["@typescript-eslint", "prettier"],
29 | extends: [
30 | "next/core-web-vitals",
31 | "airbnb",
32 | "prettier",
33 | "plugin:react/recommended",
34 | "plugin:jsx-a11y/recommended",
35 | "plugin:prettier/recommended",
36 | "plugin:sonarjs/recommended",
37 | "plugin:security/recommended-legacy",
38 | "plugin:@typescript-eslint/recommended",
39 | ],
40 |
41 | rules: {
42 | "@typescript-eslint/no-empty-interface": "off",
43 | "@typescript-eslint/explicit-module-boundary-types": "off",
44 | "@typescript-eslint/no-empty-function": "off",
45 | "@typescript-eslint/no-unsafe-assignment": "off",
46 | "@typescript-eslint/ban-types": "off",
47 | "@typescript-eslint/no-unsafe-call": "off",
48 | "@typescript-eslint/no-unsafe-member-access": "off",
49 | "@typescript-eslint/no-unsafe-argument": "off",
50 | "@typescript-eslint/no-misused-promises": "off",
51 | "@typescript-eslint/no-floating-promises": "off",
52 | "react/prop-types": "off",
53 | "react/react-in-jsx-scope": "off",
54 | "react/jsx-props-no-spreading": "off",
55 | "react/jsx-filename-extension": [
56 | 1,
57 | {
58 | extensions: [".ts", ".tsx", ".js", ".jsx"],
59 | },
60 | ],
61 | "react/function-component-definition": [
62 | 2,
63 | {
64 | namedComponents: ["function-declaration", "arrow-function"],
65 | },
66 | ],
67 | "import/prefer-default-export": "off",
68 | "import/no-extraneous-dependencies": "off",
69 | "import/extensions": [
70 | "error",
71 | "ignorePackages",
72 | {
73 | js: "never",
74 | jsx: "never",
75 | ts: "never",
76 | tsx: "never",
77 | },
78 | ],
79 | "no-unused-expressions": "off",
80 | "no-empty-function": "off",
81 | "no-nested-ternary": "off",
82 | "no-shadow": "off",
83 | "no-undef": "off",
84 | "no-console": 0,
85 | "dot-notation": 0,
86 | "jsx-a11y/anchor-is-valid": [
87 | "error",
88 | {
89 | components: ["Link"],
90 | specialLink: ["hrefLeft", "hrefRight"],
91 | aspects: ["invalidHref", "preferButton"],
92 | },
93 | ],
94 | "prettier/prettier": [
95 | "error",
96 | {
97 | endOfLine: "auto",
98 | },
99 | ],
100 | },
101 | };
102 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "create-next-js-boilerplate",
3 | "version": "16.0.7",
4 | "description": "Next.js 16 Boilerplate with TypeScript, Chakra UI, ESLint, Prettier, Husky, and Cypress — a complete starter template to build fast, scalable, and modern web applications.",
5 | "author": {
6 | "name": "AstrOOnauta",
7 | "url": "https://github.com/AstrOOnauta"
8 | },
9 | "license": "ISC",
10 | "homepage": "https://github.com/AstrOOnauta/next-js-boilerplate#readme",
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/AstrOOnauta/next-js-boilerplate.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/AstrOOnauta/next-js-boilerplate/issues"
17 | },
18 | "keywords": [
19 | "nextjs",
20 | "next.js",
21 | "nextjs-boilerplate",
22 | "nextjs-starter",
23 | "next.js-template",
24 | "create-next-app",
25 | "typescript",
26 | "chakra-ui",
27 | "eslint",
28 | "prettier",
29 | "husky",
30 | "lint-staged",
31 | "cypress",
32 | "react",
33 | "react-template",
34 | "react-starter",
35 | "frontend-boilerplate",
36 | "nextjs-typescript",
37 | "nextjs-cypress",
38 | "developer-starter-kit",
39 | "nextjs-16"
40 | ],
41 | "bin": {
42 | "create-next-js-boilerplate": "./bin/cli.js"
43 | },
44 | "scripts": {
45 | "dev": "next dev",
46 | "build": "next build",
47 | "start": "next start",
48 | "prettier": "prettier src --check .",
49 | "lint": "eslint",
50 | "lint-staged": "lint-staged",
51 | "husky-install": "husky install",
52 | "type-check": "tsc --project tsconfig.json --pretty --noEmit && eslint --fix . && prettier --write .",
53 | "cypress:open": "cypress open",
54 | "cypress:run": "cypress run && cypress run --component"
55 | },
56 | "dependencies": {
57 | "@chakra-ui/react": "3.30.0",
58 | "@emotion/react": "11.14.0",
59 | "@emotion/styled": "11.14.1",
60 | "framer-motion": "12.23.26",
61 | "lucide-react": "0.561.0",
62 | "next": "16.0.10",
63 | "react": "19.2.3",
64 | "react-dom": "19.2.3"
65 | },
66 | "devDependencies": {
67 | "@babel/core": "7.28.5",
68 | "@babel/preset-react": "7.28.5",
69 | "@babel/preset-typescript": "7.28.5",
70 | "@types/node": "25.0.0",
71 | "@types/react": "19.2.7",
72 | "@types/react-dom": "19.2.3",
73 | "@typescript-eslint/eslint-plugin": "8.49.0",
74 | "babel-loader": "10.0.0",
75 | "cypress": "15.8.0",
76 | "eslint": "9.39.1",
77 | "eslint-config-airbnb": "19.0.4",
78 | "eslint-config-next": "16.0.10",
79 | "eslint-config-prettier": "10.1.8",
80 | "eslint-plugin-jsx-a11y": "6.10.2",
81 | "eslint-plugin-prettier": "5.5.4",
82 | "eslint-plugin-react": "7.37.5",
83 | "eslint-plugin-react-hooks": "7.0.1",
84 | "eslint-plugin-security": "3.0.1",
85 | "eslint-plugin-simple-import-sort": "12.1.1",
86 | "eslint-plugin-sonarjs": "3.0.5",
87 | "husky": "9.1.7",
88 | "lint-staged": "16.2.7",
89 | "prettier": "3.7.4",
90 | "process": "0.11.10",
91 | "typescript": "5.9.3",
92 | "webpack": "5.104.0"
93 | },
94 | "husky": {
95 | "hooks": {
96 | "pre-commit": "lint-staged"
97 | }
98 | },
99 | "lint-staged": {
100 | "src/**/*.{js,jsx,ts,tsx,json,css,md,html}": [
101 | "eslint --fix",
102 | "prettier --write"
103 | ]
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # 🚀 Next.js 16 Boilerplate – TypeScript, Chakra UI, ESLint, Prettier, Husky & Cypress
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | A complete **Next.js 16 starter template** configured with **TypeScript**, **Chakra UI**, **ESLint**, **Prettier**, **Husky**, and **Cypress**.
29 | Perfect for developers who want to build fast, scalable, and modern web applications using the latest **Next.js** features.
30 |
31 | ---
32 |
33 | ## 🧩 About This Boilerplate
34 |
35 | This project is a **Next.js boilerplate** built with **TypeScript**, **Chakra UI**, **ESLint**, **Prettier**, **Husky**, and **Cypress** — designed to help you start new projects quickly and with the best development experience.
36 |
37 | It includes:
38 |
39 | - ⚙️ A clean, scalable architecture;
40 | - 🎨 Theming support (light/dark) with Chakra UI;
41 | - 🧪 E2E and component testing with Cypress;
42 | - ✅ Automated linting, formatting, and pre-commit checks;
43 | - 🚀 SEO-friendly configuration out of the box.
44 |
45 | **Get this starter project and maximize your experience as a developer!**
46 |
47 | ---
48 |
49 |
54 |
55 | ---
56 |
57 | ## 🕰️ Old Versions
58 |
59 | - [Version 15.x](https://github.com/AstrOOnauta/next-js-boilerplate/tree/v15.x)
60 | - [Version 14.x](https://github.com/AstrOOnauta/next-js-boilerplate/tree/v14.x)
61 | - [Version 13.x](https://github.com/AstrOOnauta/next-js-boilerplate/tree/v13.x)
62 |
63 | ---
64 |
65 | ## 🧠 System Requirements
66 |
67 | - Node.js **22.x or later**
68 | - macOS, Windows (including WSL), and Linux supported
69 |
70 | ---
71 |
72 | ## 💻 Technologies Used
73 |
74 | - [Next.js](https://nextjs.org/)
75 | - [TypeScript](https://www.typescriptlang.org/)
76 | - [Chakra UI](https://chakra-ui.com/)
77 | - [ESLint](https://eslint.org/)
78 | - [Prettier](https://prettier.io/)
79 | - [Husky](https://typicode.github.io/husky/#/)
80 | - [Lint-staged](https://github.com/okonet/lint-staged)
81 | - [Cypress](https://www.cypress.io/)
82 |
83 | ---
84 |
85 | ## 🚀 Features of the Next.js 16 Boilerplate
86 |
87 | - ⚛️ Full **Next.js** setup (SSR, SSG, API routes, and more)
88 | - 🎨 Styling with **Chakra UI**
89 | - 🌓 Dark and light theme configuration
90 | - 🛠 **TypeScript** support
91 | - 📝 Linting and formatting via **ESLint** + **Prettier**
92 | - ✅ Pre-commit hooks with **Husky** + **lint-staged**
93 | - 🧪 E2E and component testing via **Cypress**
94 | - ✨ Absolute imports (`~`)
95 | - 📁 Minimal and organized folder structure
96 | - 🔍 SEO-friendly configuration
97 | - ⚡ Ready for production deployment
98 |
99 | ---
100 |
101 | ## ⚙️ Automatic Installation
102 |
103 | ### 1. Create a new project
104 |
105 | ```bash
106 | yarn create next-js-boilerplate
107 | # OR
108 | npx create-next-js-boilerplate
109 | ```
110 |
111 | ### 2. Initialize Husky
112 |
113 | ```bash
114 | yarn husky-install
115 | # OR
116 | npm run husky-install
117 | ```
118 |
119 | ### 3. Run the development server
120 |
121 | ```bash
122 | yarn dev
123 | # OR
124 | npm run dev
125 | ```
126 |
127 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
128 | Edit `pages/index.tsx` — the page updates automatically as you save.
129 |
130 | ---
131 |
132 | ## 🧰 Manual Installation
133 |
134 | ### 1. Clone the repository
135 |
136 | ```bash
137 | git clone https://github.com/AstrOOnauta/next-js-boilerplate.git
138 | ```
139 |
140 | ### 2. Install dependencies
141 |
142 | ```bash
143 | yarn
144 | # OR
145 | npm install
146 | ```
147 |
148 | ### 3. Initialize Husky
149 |
150 | ```bash
151 | yarn husky-install
152 | # OR
153 | npm run husky-install
154 | ```
155 |
156 | ### 4. Run the development server
157 |
158 | ```bash
159 | yarn dev
160 | # OR
161 | npm run dev
162 | ```
163 |
164 | Open [http://localhost:3000](http://localhost:3000) and start building!
165 |
166 | ---
167 |
168 | ## 🧑💻 Terminal Commands
169 |
170 | | Command | Description |
171 | | --------------- | -------------------------------- |
172 | | `dev` | Runs the app on `localhost:3000` |
173 | | `build` | Creates the production build |
174 | | `start` | Runs a production server |
175 | | `prettier` | Formats all files |
176 | | `lint` | Runs ESLint |
177 | | `lint-staged` | Lints only staged files |
178 | | `husky-install` | Initializes Husky |
179 | | `type-check` | Runs TypeScript checks |
180 | | `cypress:open` | Opens Cypress UI |
181 | | `cypress:run` | Runs Cypress tests in CLI |
182 |
183 | ---
184 |
185 | ## 💡 Why Use This Template?
186 |
187 | - Save hours of setup time — everything is pre-configured
188 | - Enforce code quality and consistency automatically
189 | - Start coding immediately with TypeScript + Chakra UI
190 | - Perfect for MVPs, startups, or production-grade apps
191 | - Compatible with macOS, Windows, and Linux
192 |
193 | ---
194 |
195 | ## 🤝 Contributing
196 |
197 | Contributions are welcome!
198 | Feel free to **open an issue** or **submit a pull request** to improve this Next.js boilerplate.
199 |
200 | ---
201 |
202 | ## 📜 License
203 |
204 | This project is licensed under the [ISC License](./LICENSE.md).
205 |
206 | ---
207 |
208 | ## 📈 Keywords
209 |
210 | `nextjs boilerplate`, `next.js starter template`, `next.js 16`, `typescript`, `chakra-ui`, `eslint`, `prettier`, `husky`, `lint-staged`, `cypress`, `react starter`, `frontend boilerplate`, `create next app`
211 |
212 | ---
213 |
214 |
215 |
216 | Thanks for stopping by! 😁
217 |
218 |
--------------------------------------------------------------------------------