diff --git a/README.md b/README.md
index 0dea40f..c574c56 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,8 @@
- π¨ TailwindCSS - Class sorting, merging and linting
- π οΈ Shadcn/ui - Customizable UI components
- π Next-auth - Easy authentication library for Next.js (GitHub provider)
+- π React-hook-form - Manage your forms easy and efficient
+- π Zod - Schema validation library
- π§ͺ Jest & React Testing Library - Configured for unit testing
- π Playwright - Configured for e2e testing
- π Absolute Import & Path Alias - Import components using `@/` prefix
@@ -17,7 +19,7 @@
- πΊοΈ Sitemap & robots.txt - With next-sitemap
- π Commitlint - Lint your git commits
- π€ Github actions - Lint your code on PR
-- βοΈ T3-env - Menage your environment variables
+- βοΈ T3-env - Manage your environment variables
- π― Perfect Lighthouse score
## π Deployment
diff --git a/package-lock.json b/package-lock.json
index d4f1454..177bcf8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,17 +8,21 @@
"name": "next-starter",
"version": "1.0.0",
"dependencies": {
+ "@hookform/resolvers": "^3.3.4",
"@radix-ui/react-dropdown-menu": "^2.0.6",
+ "@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-toast": "^1.1.5",
"@t3-oss/env-nextjs": "^0.8.0",
"class-variance-authority": "^0.7.0",
- "clsx": "2.1.0",
+ "clsx": "^2.1.0",
"lucide-react": "^0.312.0",
"next": "14.1.0",
"next-auth": "^4.24.5",
"next-themes": "^0.2.1",
"react": "^18",
"react-dom": "^18",
+ "react-hook-form": "^7.50.0",
"tailwind-merge": "^2.2.1",
"zod": "^3.22.4"
},
@@ -46,7 +50,7 @@
"jest-environment-jsdom": "^29.7.0",
"lint-staged": "^15.2.0",
"next-sitemap": "^4.2.3",
- "postcss": "8.4.33",
+ "postcss": "^8",
"prettier": "^3.2.4",
"tailwindcss": "^3.3.0",
"tailwindcss-animate": "^1.0.7",
@@ -1381,6 +1385,14 @@
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz",
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
},
+ "node_modules/@hookform/resolvers": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.4.tgz",
+ "integrity": "sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==",
+ "peerDependencies": {
+ "react-hook-form": "^7.0.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -2450,6 +2462,29 @@
}
}
},
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz",
+ "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-menu": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.6.tgz",
@@ -2641,6 +2676,40 @@
}
}
},
+ "node_modules/@radix-ui/react-toast": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.1.5.tgz",
+ "integrity": "sha512-fRLn227WHIBRSzuRzGJ8W+5YALxofH23y0MlPLddaIpLpCDqdE0NZlS2NRQDRiptfxDeeCjgFIpexB1/zkxDlw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-collection": "1.0.3",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1",
+ "@radix-ui/react-visually-hidden": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
@@ -2747,6 +2816,29 @@
}
}
},
+ "node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz",
+ "integrity": "sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/rect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz",
@@ -9974,6 +10066,21 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-hook-form": {
+ "version": "7.50.0",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.50.0.tgz",
+ "integrity": "sha512-AOhuzM3RdP09ZCnq+Z0yvKGHK25yiOX5phwxjV9L7U6HMla10ezkBnvQ+Pk4GTuDfsC5P2zza3k8mawFwFLVuQ==",
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
diff --git a/package.json b/package.json
index ad08a73..dfc7468 100644
--- a/package.json
+++ b/package.json
@@ -31,8 +31,11 @@
]
},
"dependencies": {
+ "@hookform/resolvers": "^3.3.4",
"@radix-ui/react-dropdown-menu": "^2.0.6",
+ "@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
+ "@radix-ui/react-toast": "^1.1.5",
"@t3-oss/env-nextjs": "^0.8.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
@@ -42,6 +45,7 @@
"next-themes": "^0.2.1",
"react": "^18",
"react-dom": "^18",
+ "react-hook-form": "^7.50.0",
"tailwind-merge": "^2.2.1",
"zod": "^3.22.4"
},
diff --git a/src/actions/hello-action.ts b/src/actions/hello-action.ts
new file mode 100644
index 0000000..6a0310c
--- /dev/null
+++ b/src/actions/hello-action.ts
@@ -0,0 +1,5 @@
+'use server';
+
+export const helloAction = async (name: string) => {
+ return { message: `Hello ${name}, from server!` };
+};
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index a861806..599ce5c 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -6,6 +6,7 @@ import type { Metadata } from 'next';
import { Footer } from '@/components/footer';
import { Navbar } from '@/components/navbar/navbar';
import { ThemeProvider } from '@/components/theme-provider';
+import { Toaster } from '@/components/ui/toaster';
import { siteConfig } from '@/lib/constant';
import { fonts } from '@/lib/fonts';
import { cn } from '@/lib/utils';
@@ -52,6 +53,7 @@ const RootLayout = ({ children }: PropsWithChildren) => {
{children}
+