@codabytez/create-next-template 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +548 -0
  2. package/dist/index.js +407 -0
  3. package/package.json +31 -0
  4. package/templates/animations/components/motion/fade-in.tsx +28 -0
  5. package/templates/appwrite/.env.example +3 -0
  6. package/templates/appwrite/lib/appwrite.ts +11 -0
  7. package/templates/auth/.env.example +6 -0
  8. package/templates/auth/app/(auth)/sign-in/[[...sign-in]]/page.tsx +9 -0
  9. package/templates/auth/app/(auth)/sign-up/[[...sign-up]]/page.tsx +9 -0
  10. package/templates/auth/middleware.ts +17 -0
  11. package/templates/base/.env.example +1 -0
  12. package/templates/base/.husky/pre-commit +19 -0
  13. package/templates/base/.husky/pre-push +11 -0
  14. package/templates/base/.prettierignore +8 -0
  15. package/templates/base/.prettierrc.json +9 -0
  16. package/templates/base/CONTRIBUTING.md +120 -0
  17. package/templates/base/app/globals.css +28 -0
  18. package/templates/base/app/page.tsx +7 -0
  19. package/templates/base/components/ui/button.tsx +40 -0
  20. package/templates/base/eslint.config.mjs +51 -0
  21. package/templates/base/lib/env.ts +7 -0
  22. package/templates/base/lib/utils.ts +6 -0
  23. package/templates/base/next.config.ts +5 -0
  24. package/templates/base/postcss.config.mjs +7 -0
  25. package/templates/base/tsconfig.json +23 -0
  26. package/templates/convex/.env.example +1 -0
  27. package/templates/convex/convex/schema.ts +10 -0
  28. package/templates/convex/convex/users.ts +19 -0
  29. package/templates/convex/providers/convex-provider.tsx +15 -0
  30. package/templates/data-fetching/lib/api.ts +18 -0
  31. package/templates/data-fetching/providers/query-provider.tsx +22 -0
  32. package/templates/forms/components/forms/example-form.tsx +58 -0
  33. package/templates/forms/lib/validations/example.ts +8 -0
  34. package/templates/prisma/.env.example +1 -0
  35. package/templates/prisma/lib/db.ts +11 -0
  36. package/templates/prisma/prisma/schema.prisma +16 -0
  37. package/templates/ui/components.json +20 -0
@@ -0,0 +1,120 @@
1
+ # Contributing Guide
2
+
3
+ ## Branching Strategy
4
+
5
+ ### Main Branches
6
+
7
+ | Branch | Purpose |
8
+ |---|---|
9
+ | `main` | Production — protected, requires 2 approvals |
10
+ | `staging` | Pre-production testing — protected, requires 1 approval |
11
+ | `dev` | Active development — protected, status checks required |
12
+
13
+ ### Working Branches
14
+
15
+ | Prefix | Use for |
16
+ |---|---|
17
+ | `feature/*` | New features |
18
+ | `fix/*` | Bug fixes |
19
+ | `hotfix/*` | Urgent production fixes |
20
+ | `chore/*` | Maintenance / dependency updates |
21
+ | `docs/*` | Documentation only changes |
22
+
23
+ ---
24
+
25
+ ## Workflow
26
+
27
+ ```bash
28
+ # 1. Pull latest from dev
29
+ git checkout dev
30
+ git pull origin dev
31
+
32
+ # 2. Create your branch
33
+ git checkout -b feature/your-feature-name
34
+
35
+ # 3. Work, commit often
36
+ git add .
37
+ git commit -m "feat: add your feature"
38
+ # pre-commit hook will run automatically:
39
+ # ✔ Prettier format check (auto-fixes if needed)
40
+ # ✔ ESLint (via lint-staged)
41
+ # ✔ TypeScript type check
42
+
43
+ # 4. Push and open a PR into dev
44
+ git push origin feature/your-feature-name
45
+ ```
46
+
47
+ **PR flow:** `feature/*` → `dev` → `staging` → `main`
48
+
49
+ ---
50
+
51
+ ## Commit Message Format
52
+
53
+ ```
54
+ <type>: <short description>
55
+ ```
56
+
57
+ | Type | When to use |
58
+ |---|---|
59
+ | `feat` | New feature |
60
+ | `fix` | Bug fix |
61
+ | `refactor` | Code change that is not a feature or fix |
62
+ | `style` | UI / styling changes |
63
+ | `docs` | Documentation only |
64
+ | `chore` | Maintenance, deps, config |
65
+ | `test` | Adding or updating tests |
66
+
67
+ **Examples:**
68
+ ```
69
+ feat: add user profile page
70
+ fix: correct date formatting on dashboard
71
+ chore: upgrade tailwindcss to v4
72
+ docs: update contributing guide
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Git Hooks
78
+
79
+ This project uses [Husky](https://typicode.github.io/husky/) to enforce quality automatically.
80
+
81
+ ### Pre-commit
82
+ Runs on every `git commit`:
83
+ - Prettier format check (auto-stages fixes if found)
84
+ - ESLint + Prettier via lint-staged (only on staged files)
85
+ - TypeScript type check
86
+
87
+ ### Pre-push
88
+ Runs on every `git push`:
89
+ - Full `next build` — push is blocked if the build fails
90
+
91
+ If a hook blocks you, fix the issue it reports and try again. **Do not bypass hooks with `--no-verify`.**
92
+
93
+ ---
94
+
95
+ ## Code Standards
96
+
97
+ - **No `console.log()`** — use `console.warn()` or `console.error()` only
98
+ - **No `var`** — always use `const` or `let`
99
+ - **No `any`** — avoid unless absolutely necessary (triggers a warning)
100
+ - **Self-closing JSX** — `<Component />` not `<Component></Component>`
101
+ - **No unnecessary curly braces in JSX** — `title="Hello"` not `title={"Hello"}`
102
+ - **Unused variables** — prefix with `_` if intentionally unused (e.g. `_unused`)
103
+
104
+ ---
105
+
106
+ ## Code Review Checklist
107
+
108
+ Before requesting a review, make sure:
109
+
110
+ - [ ] All hooks pass (`pnpm lint`, `pnpm check-types`, `pnpm build`)
111
+ - [ ] No `console.log` left in the code
112
+ - [ ] New env variables are added to `.env.example`
113
+ - [ ] UI changes are tested on mobile viewport
114
+ - [ ] No commented-out code committed
115
+
116
+ Reviewers will check:
117
+ - [ ] Logic correctness
118
+ - [ ] TypeScript types are accurate (no sneaky `as any`)
119
+ - [ ] No unnecessary re-renders or missing `useCallback`/`useMemo`
120
+ - [ ] Consistent naming with the rest of the codebase
@@ -0,0 +1,28 @@
1
+ @import "tailwindcss";
2
+
3
+ @theme {
4
+ /* ================================
5
+ * Colors — add your custom palette here
6
+ * ================================ */
7
+
8
+ /* --color-primary: #your-color;
9
+ --color-secondary: #your-color;
10
+ --color-accent: #your-color;
11
+ --color-background: #your-color;
12
+ --color-foreground: #your-color; */
13
+
14
+ /* ================================
15
+ * Typography
16
+ * ================================ */
17
+
18
+ /* --font-sans: "Inter", sans-serif;
19
+ --font-mono: "JetBrains Mono", monospace; */
20
+
21
+ /* ================================
22
+ * Spacing / Sizing overrides
23
+ * ================================ */
24
+
25
+ /* --radius-sm: 4px;
26
+ --radius-md: 8px;
27
+ --radius-lg: 12px; */
28
+ }
@@ -0,0 +1,7 @@
1
+ export default function Home() {
2
+ return (
3
+ <main className="flex min-h-screen flex-col items-center justify-center p-24">
4
+ <h1 className="text-4xl font-bold">Hello World</h1>
5
+ </main>
6
+ );
7
+ }
@@ -0,0 +1,40 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ const buttonVariants = cva(
5
+ "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
6
+ {
7
+ variants: {
8
+ variant: {
9
+ default: "bg-black text-white hover:bg-black/90",
10
+ outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
11
+ ghost: "hover:bg-accent hover:text-accent-foreground",
12
+ link: "text-primary underline-offset-4 hover:underline",
13
+ destructive: "bg-red-500 text-white hover:bg-red-600",
14
+ },
15
+ size: {
16
+ default: "h-10 px-4 py-2",
17
+ sm: "h-9 rounded-md px-3",
18
+ lg: "h-11 rounded-md px-8",
19
+ icon: "h-10 w-10",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ size: "default",
25
+ },
26
+ }
27
+ );
28
+
29
+ export interface ButtonProps
30
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
31
+ VariantProps<typeof buttonVariants> {}
32
+
33
+ export function Button({ className, variant, size, ...props }: ButtonProps) {
34
+ return (
35
+ <button
36
+ className={cn(buttonVariants({ variant, size, className }))}
37
+ {...props}
38
+ />
39
+ );
40
+ }
@@ -0,0 +1,51 @@
1
+ import { dirname } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { FlatCompat } from "@eslint/eslintrc";
4
+ import prettier from "eslint-plugin-prettier/recommended";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ const compat = new FlatCompat({ baseDirectory: __dirname });
10
+
11
+ const eslintConfig = [
12
+ ...compat.extends("next/core-web-vitals", "next/typescript"),
13
+ prettier,
14
+ {
15
+ rules: {
16
+ "prettier/prettier": "error",
17
+ "no-console": ["error", { allow: ["warn", "error"] }],
18
+ "no-debugger": "error",
19
+ "@typescript-eslint/no-unused-vars": [
20
+ "error",
21
+ {
22
+ argsIgnorePattern: "^_",
23
+ varsIgnorePattern: "^_",
24
+ },
25
+ ],
26
+ "@typescript-eslint/no-explicit-any": "warn",
27
+ "no-var": "error",
28
+ "prefer-const": "error",
29
+ "prefer-arrow-callback": "error",
30
+ "no-duplicate-imports": "error",
31
+ "react/self-closing-comp": "error",
32
+ "react/jsx-curly-brace-presence": [
33
+ "error",
34
+ { props: "never", children: "never" },
35
+ ],
36
+ "react-hooks/rules-of-hooks": "error",
37
+ "react-hooks/exhaustive-deps": "warn",
38
+ },
39
+ },
40
+ {
41
+ ignores: [
42
+ ".next/**",
43
+ "out/**",
44
+ "build/**",
45
+ "next-env.d.ts",
46
+ "node_modules/**",
47
+ ],
48
+ },
49
+ ];
50
+
51
+ export default eslintConfig;
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+
3
+ const envSchema = z.object({
4
+ NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
5
+ });
6
+
7
+ export const env = envSchema.parse(process.env);
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {};
4
+
5
+ export default nextConfig;
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [{ "name": "next" }],
17
+ "paths": {
18
+ "@/*": ["./*"]
19
+ }
20
+ },
21
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
22
+ "exclude": ["node_modules"]
23
+ }
@@ -0,0 +1 @@
1
+ NEXT_PUBLIC_CONVEX_URL=https://your-project.convex.cloud
@@ -0,0 +1,10 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+
4
+ export default defineSchema({
5
+ users: defineTable({
6
+ name: v.string(),
7
+ email: v.string(),
8
+ clerkId: v.optional(v.string()),
9
+ }).index("by_email", ["email"]),
10
+ });
@@ -0,0 +1,19 @@
1
+ import { query, mutation } from "./_generated/server";
2
+ import { v } from "convex/values";
3
+
4
+ export const getUsers = query({
5
+ args: {},
6
+ handler: async (ctx) => {
7
+ return await ctx.db.query("users").collect();
8
+ },
9
+ });
10
+
11
+ export const createUser = mutation({
12
+ args: {
13
+ name: v.string(),
14
+ email: v.string(),
15
+ },
16
+ handler: async (ctx, args) => {
17
+ return await ctx.db.insert("users", args);
18
+ },
19
+ });
@@ -0,0 +1,15 @@
1
+ "use client";
2
+
3
+ import { ConvexProvider, ConvexReactClient } from "convex/react";
4
+
5
+ const convex = new ConvexReactClient(
6
+ process.env.NEXT_PUBLIC_CONVEX_URL as string
7
+ );
8
+
9
+ export function ConvexClientProvider({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode;
13
+ }) {
14
+ return <ConvexProvider client={convex}>{children}</ConvexProvider>;
15
+ }
@@ -0,0 +1,18 @@
1
+ import axios from "axios";
2
+
3
+ export const api = axios.create({
4
+ baseURL: process.env.NEXT_PUBLIC_API_URL ?? "/api",
5
+ headers: {
6
+ "Content-Type": "application/json",
7
+ },
8
+ });
9
+
10
+ api.interceptors.response.use(
11
+ (response) => response,
12
+ (error) => {
13
+ if (error.response?.status === 401) {
14
+ // Handle unauthorized — redirect or clear session
15
+ }
16
+ return Promise.reject(error);
17
+ }
18
+ );
@@ -0,0 +1,22 @@
1
+ "use client";
2
+
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import { useState } from "react";
5
+
6
+ export function QueryProvider({ children }: { children: React.ReactNode }) {
7
+ const [queryClient] = useState(
8
+ () =>
9
+ new QueryClient({
10
+ defaultOptions: {
11
+ queries: {
12
+ staleTime: 60 * 1000,
13
+ retry: 1,
14
+ },
15
+ },
16
+ })
17
+ );
18
+
19
+ return (
20
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
21
+ );
22
+ }
@@ -0,0 +1,58 @@
1
+ "use client";
2
+
3
+ import { useForm } from "react-hook-form";
4
+ import { zodResolver } from "@hookform/resolvers/zod";
5
+ import { exampleSchema, type ExampleFormValues } from "@/lib/validations/example";
6
+
7
+ export function ExampleForm() {
8
+ const {
9
+ register,
10
+ handleSubmit,
11
+ formState: { errors, isSubmitting },
12
+ } = useForm<ExampleFormValues>({
13
+ resolver: zodResolver(exampleSchema),
14
+ });
15
+
16
+ async function onSubmit(data: ExampleFormValues) {
17
+ console.log(data);
18
+ }
19
+
20
+ return (
21
+ <form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-4">
22
+ <div className="flex flex-col gap-1">
23
+ <label htmlFor="name" className="text-sm font-medium">Name</label>
24
+ <input
25
+ id="name"
26
+ {...register("name")}
27
+ className="rounded-md border px-3 py-2 text-sm"
28
+ placeholder="Your name"
29
+ />
30
+ {errors.name && (
31
+ <p className="text-xs text-red-500">{errors.name.message}</p>
32
+ )}
33
+ </div>
34
+
35
+ <div className="flex flex-col gap-1">
36
+ <label htmlFor="email" className="text-sm font-medium">Email</label>
37
+ <input
38
+ id="email"
39
+ type="email"
40
+ {...register("email")}
41
+ className="rounded-md border px-3 py-2 text-sm"
42
+ placeholder="you@example.com"
43
+ />
44
+ {errors.email && (
45
+ <p className="text-xs text-red-500">{errors.email.message}</p>
46
+ )}
47
+ </div>
48
+
49
+ <button
50
+ type="submit"
51
+ disabled={isSubmitting}
52
+ className="rounded-md bg-black px-4 py-2 text-sm text-white hover:bg-black/90 disabled:opacity-50"
53
+ >
54
+ {isSubmitting ? "Submitting..." : "Submit"}
55
+ </button>
56
+ </form>
57
+ );
58
+ }
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+
3
+ export const exampleSchema = z.object({
4
+ name: z.string().min(2, "Name must be at least 2 characters"),
5
+ email: z.string().email("Invalid email address"),
6
+ });
7
+
8
+ export type ExampleFormValues = z.infer<typeof exampleSchema>;
@@ -0,0 +1 @@
1
+ DATABASE_URL="postgresql://user:password@localhost:5432/mydb?schema=public"
@@ -0,0 +1,11 @@
1
+ import { PrismaClient } from "@prisma/client";
2
+
3
+ const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
4
+
5
+ export const db =
6
+ globalForPrisma.prisma ??
7
+ new PrismaClient({
8
+ log: process.env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
9
+ });
10
+
11
+ if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = db;
@@ -0,0 +1,16 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ }
4
+
5
+ datasource db {
6
+ provider = "postgresql"
7
+ url = env("DATABASE_URL")
8
+ }
9
+
10
+ model User {
11
+ id String @id @default(cuid())
12
+ email String @unique
13
+ name String?
14
+ createdAt DateTime @default(now())
15
+ updatedAt DateTime @updatedAt
16
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "default",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ }
20
+ }