├── .prettierignore ├── public ├── leaves.jpg ├── milk.svg ├── fish.svg └── steak.svg ├── robots.txt ├── src ├── app │ ├── favicon.ico │ ├── motion │ │ ├── newexample │ │ │ └── page.tsx │ │ ├── usetransform │ │ │ └── page.tsx │ │ ├── usescroll │ │ │ └── page.tsx │ │ ├── scrollwithtoc │ │ │ └── page.tsx │ │ ├── flexgrowsample │ │ │ └── page.tsx │ │ ├── trackelementwithinviewport │ │ │ └── page.tsx │ │ ├── layout │ │ │ └── page.tsx │ │ └── layoutexamples │ │ │ └── page.tsx │ ├── layout.tsx │ ├── page.tsx │ ├── reactflow │ │ └── page.tsx │ ├── constants │ │ └── menu-home.tsx │ ├── forms │ │ └── page.tsx │ ├── globals.css │ └── elements │ │ └── page.tsx ├── lib │ ├── utils.ts │ └── zodSchemas │ │ └── formSchemas.ts └── components │ ├── icons │ ├── icon-interface.ts │ └── metalogo.tsx │ ├── ui │ ├── index.ts │ ├── ProgressBar.tsx │ ├── sonner.tsx │ ├── textarea.tsx │ ├── checkbox.tsx │ ├── tabs.tsx │ ├── button.tsx │ ├── breadcrumb.tsx │ ├── input.tsx │ └── accordion.tsx │ ├── widgets │ ├── CircularProgressBar.tsx │ └── TableOfContents.tsx │ ├── utility │ └── navbar.tsx │ ├── reactflow │ └── nodes │ │ └── DefaultNode.tsx │ └── themeSwitcher.tsx ├── postcss.config.mjs ├── next.config.ts ├── .prettierrc ├── components.json ├── .gitignore ├── tsconfig.json ├── package.json ├── README.md ├── .vscode ├── extensions.json └── settings.json └── eslint.config.mjs /.prettierignore: -------------------------------------------------------------------------------- 1 | *.svg -------------------------------------------------------------------------------- /public/leaves.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seckinyasar/react19-boilerplate/HEAD/public/leaves.jpg -------------------------------------------------------------------------------- /robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Allow: / 3 | Disallow: /private/ 4 | 5 | Sitemap: https://acme.com/sitemap.xml -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seckinyasar/react19-boilerplate/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | }; 6 | 7 | export default nextConfig; 8 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/zodSchemas/formSchemas.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | const loginSchema = z.object({ 4 | email: z.string().email("Enter valid email"), 5 | password: z 6 | .string() 7 | .min(10, "At least 10 characters") 8 | .max(64, "Maximum 64 characters allowed"), 9 | }); 10 | 11 | export { loginSchema }; 12 | -------------------------------------------------------------------------------- /src/components/icons/icon-interface.ts: -------------------------------------------------------------------------------- 1 | //?✔️ Icon interface 2 | //?✔️ Tailwind text color → currentColor sayesinde ikonu renklendirir. 3 | 4 | interface MyIconProps extends React.SVGProps { 5 | width?: number; 6 | height?: number; 7 | strokeWidth?: number; 8 | fill?: string; 9 | } 10 | 11 | export type { MyIconProps }; 12 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.printWidth": 80, 3 | "prettier.tabWidth": 4, 4 | "prettier.Tabs": false, 5 | "prettier.semi": true, 6 | "prettier.singleQuote": true, 7 | "prettier.trailingComma": "none", 8 | "proseWrap": "preserve", 9 | "htmlWhitespaceSensitivity": "ignore", 10 | "jsxSingleQuote": false, 11 | "bracketSpacing": true, 12 | "bracketSameLine": false, 13 | "jsxBracketSameLine": false, 14 | "arrowParens": "always" 15 | } 16 | -------------------------------------------------------------------------------- /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": "", 8 | "css": "src/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 | "iconLibrary": "lucide" 21 | } -------------------------------------------------------------------------------- /src/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | import { Button } from "./Button"; 2 | import { Input } from "./Input"; 3 | import { Textarea } from "./Textarea"; 4 | import * as Breadcrumb from "./Breadcrumb"; 5 | import * as Accordion from "./Accordion"; 6 | import { Checkbox, CheckboxWithText } from "./Checkbox"; 7 | import { Toaster } from "./Sonner"; 8 | import * as Tabs from "./Tabs"; 9 | export { 10 | Button, 11 | Input, 12 | Textarea, 13 | Breadcrumb, 14 | Accordion, 15 | Checkbox, 16 | CheckboxWithText, 17 | Toaster, 18 | Tabs, 19 | }; 20 | -------------------------------------------------------------------------------- /.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.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | 43 | notes.md -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 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": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./src/*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /src/app/motion/newexample/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { cn } from "@/lib/utils"; 3 | import { motion } from "motion/react"; 4 | 5 | const NewExample = () => { 6 | return ( 7 |
8 | 9 | {Array.from({ length: 3 }).map((item, i) => ( 10 | 20 | ))} 21 | 22 |
23 | ); 24 | }; 25 | 26 | export default NewExample; 27 | -------------------------------------------------------------------------------- /src/components/icons/metalogo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { MyIconProps } from "./icon-interface"; 3 | 4 | const MetaLogo: React.FC = ({ 5 | width = 32, 6 | height = 31, 7 | strokeWidth = 1, 8 | fill = "black", 9 | }) => ( 10 | 18 | 27 | 28 | ); 29 | MetaLogo.displayName = "meta-logo"; 30 | export default MetaLogo; 31 | -------------------------------------------------------------------------------- /src/components/ui/ProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import { MotionValue, motion } from "motion/react"; 3 | import { useEffect } from "react"; 4 | 5 | interface ProgressBarProps { 6 | value: number | MotionValue; // 0 - 100 7 | className?: string | undefined; 8 | } 9 | 10 | const ProgressBar = ({ value, className }: ProgressBarProps) => { 11 | useEffect(() => { 12 | console.log(value); 13 | }, [value]); 14 | 15 | return ( 16 | 19 | 23 | 24 | ); 25 | }; 26 | export default ProgressBar; 27 | 28 | //? used motion.div to use value as it is, without any manipulation. Otherwise, it is not working. 29 | -------------------------------------------------------------------------------- /src/app/motion/usetransform/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { motion, useScroll, useTransform } from "motion/react"; 3 | import { useRef } from "react"; 4 | const UseTransform = () => { 5 | const mainDiv = useRef(null); 6 | const { scrollY } = useScroll(); 7 | const motionValueScroll = scrollY; 8 | const xRange = [-200, -100, 100, 200]; 9 | const opacityRange = ["#ccc", "#000", "#000", "#fff"]; 10 | const y = useTransform(motionValueScroll, xRange, opacityRange); 11 | 12 | return ( 13 | 17 |

18 | useTransform Usage 19 |

20 | 21 | 27 |
28 | ); 29 | }; 30 | 31 | export default UseTransform; 32 | -------------------------------------------------------------------------------- /src/components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | //#region //? References 2 | /** 3 | * @file Toaster Component 4 | * 5 | * @section Colors & places they are used 6 | * - `popover` => toast background (`--normal-bg`) 7 | * - `popover-foreground` => toast text (`--normal-text`) 8 | * - `border` => toast border (`--normal-border`) 9 | * 10 | * @notes 11 | * - Theme is dynamically applied using `next-themes` (`system`, `light`, `dark`). 12 | */ 13 | //#endregion 14 | 15 | "use client"; 16 | import { useTheme } from "next-themes"; 17 | import { Toaster as Sonner, ToasterProps } from "sonner"; 18 | 19 | const Toaster = ({ ...props }: ToasterProps) => { 20 | const { theme = "system" } = useTheme(); 21 | 22 | return ( 23 | 35 | ); 36 | }; 37 | 38 | export { Toaster }; 39 | -------------------------------------------------------------------------------- /src/app/motion/usescroll/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import ProgressBar from "@/components/ui/ProgressBar"; 3 | import { useMotionValueEvent, useScroll } from "motion/react"; 4 | const UseScrollExample = () => { 5 | const { scrollY, scrollYProgress } = useScroll(); 6 | 7 | useMotionValueEvent(scrollYProgress, "change", (latest) => { 8 | console.log("Page scroll", latest); 9 | }); 10 | 11 | return ( 12 |
13 | 14 |
15 |

16 | useScroll Hook Example 17 |

18 |
19 |
20 |
21 |
22 |
23 | ); 24 | }; 25 | export default UseScrollExample; 26 | -------------------------------------------------------------------------------- /src/components/widgets/CircularProgressBar.tsx: -------------------------------------------------------------------------------- 1 | import { MotionValue } from "motion/react"; 2 | import { useState } from "react"; 3 | 4 | type ProgressCircleProps = { 5 | size?: number; 6 | strokeWidth?: number; 7 | progress: number | MotionValue; // 0-100 arası değer 8 | }; 9 | 10 | const ProgressCircle = ({ 11 | size = 100, 12 | strokeWidth = 8, 13 | progress, 14 | }: ProgressCircleProps) => { 15 | const radius = (size - strokeWidth) / 2; 16 | const circumference = 2 * Math.PI * radius; 17 | 18 | const [progressState, setProgress] = useState(0); 19 | 20 | return ( 21 | 22 | 30 | 40 | 41 | ); 42 | }; 43 | export default ProgressCircle; 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "component-repo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --turbopack", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-accordion": "^1.2.4", 13 | "@radix-ui/react-checkbox": "^1.1.5", 14 | "@radix-ui/react-progress": "^1.1.7", 15 | "@radix-ui/react-slot": "^1.2.0", 16 | "@radix-ui/react-tabs": "^1.1.4", 17 | "@xyflow/react": "^12.6.0", 18 | "axios": "^1.9.0", 19 | "class-variance-authority": "^0.7.1", 20 | "clsx": "^2.1.1", 21 | "lucide-react": "^0.487.0", 22 | "motion": "^12.12.1", 23 | "next": "^15.3.5", 24 | "next-themes": "^0.4.6", 25 | "react": "^19.0.0", 26 | "react-dom": "^19.0.0", 27 | "sonner": "^2.0.3", 28 | "tailwind-merge": "^3.1.0", 29 | "tw-animate-css": "^1.2.5", 30 | "zod": "^3.24.2" 31 | }, 32 | "devDependencies": { 33 | "@eslint/eslintrc": "^3", 34 | "@tailwindcss/postcss": "^4", 35 | "@types/node": "^20", 36 | "@types/react": "^19", 37 | "@types/react-dom": "^19", 38 | "eslint": "^9", 39 | "eslint-config-next": "15.2.4", 40 | "tailwindcss": "^4", 41 | "typescript": "^5" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { ThemeProvider } from "next-themes"; 3 | import { Geist, Geist_Mono, Inter } from "next/font/google"; 4 | import "./globals.css"; 5 | import { Toaster } from "@/components/ui/Sonner"; 6 | import Navbar from "@/components/utility/navbar"; 7 | 8 | const geistSans = Geist({ 9 | variable: "--font-geist-sans", 10 | subsets: ["latin"], 11 | }); 12 | 13 | const geistMono = Geist_Mono({ 14 | variable: "--font-geist-mono", 15 | subsets: ["latin"], 16 | }); 17 | 18 | const inter = Inter({ 19 | variable: "--font-inter", 20 | subsets: ["latin"], 21 | weight: ["400", "700"], 22 | }); 23 | 24 | export const metadata: Metadata = { 25 | title: "Create Next App", 26 | description: "Generated by create next app", 27 | }; 28 | 29 | export default function RootLayout({ 30 | children, 31 | }: Readonly<{ 32 | children: React.ReactNode; 33 | }>) { 34 | return ( 35 | 36 | 39 | 44 | {children} 45 | 46 | 47 | 48 | 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /src/app/motion/scrollwithtoc/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import TableOfContents from "@/components/widgets/TableOfContents"; 3 | import { motion } from "motion/react"; 4 | export default function Page() { 5 | const contents = [ 6 | { text: "Scroll Animation", id: "Article 1" }, 7 | { text: "First Example ", id: "Article 2" }, 8 | { text: "With InView prop", id: "Article 3" }, 9 | { text: "And testing table of contents", id: "Article 4" }, 10 | { text: "With intersection observer api", id: "Article 5" }, 11 | ]; 12 | 13 | return ( 14 |
15 | 16 |
17 |
Scroll Animation
18 | {contents.map((item, index) => ( 19 | 27 | {item.text} 28 | 29 | ))} 30 |
31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { buttonVariants } from "@/components/ui/Button"; 4 | import Link from "next/link"; 5 | import HomeMenu from "./constants/menu-home"; 6 | 7 | export default function Home() { 8 | return ( 9 |
10 | {/* //? Container_Inner */} 11 |
12 | {HomeMenu.map((menu, index) => ( 13 |
17 |

18 | {menu.title} 19 | {menu.icon} 20 |

21 |
22 | {menu.links.map((link, i) => ( 23 | 31 | {link.label || ""} 32 | {link.icon && link.icon} 33 | 34 | ))} 35 |
36 |
37 | ))} 38 |
39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React19 Boilerplate 2 | 3 | **Boilerplate for React 19, Next.js 15, Tailwind CSS 4, and Motion** projects. [See versions below](#dependencies). 4 | 5 | It is designed to kickstart my frontend tasks. It will be regularly updated with new components and features. 6 | 7 | ## Installation 8 | 9 | 1. Install dependencies: 10 | 11 | ```bash 12 | npm i 13 | ``` 14 | 15 | 2. Run the development server: 16 | 17 | ```bash 18 | npm run dev 19 | ``` 20 | 21 | ## Dependencies 22 | 23 | The project includes the following dependencies: 24 | 25 | ```json 26 | { 27 | "dependencies": { 28 | "@radix-ui/react-accordion": "^1.2.4", 29 | "@radix-ui/react-checkbox": "^1.1.5", 30 | "@radix-ui/react-progress": "^1.1.7", 31 | "@radix-ui/react-slot": "^1.2.0", 32 | "@radix-ui/react-tabs": "^1.1.4", 33 | "@xyflow/react": "^12.6.0", 34 | "axios": "^1.9.0", 35 | "class-variance-authority": "^0.7.1", 36 | "clsx": "^2.1.1", 37 | "lucide-react": "^0.487.0", 38 | "motion": "^12.12.1", 39 | "next": "^15.3.5", 40 | "next-themes": "^0.4.6", 41 | "react": "^19.0.0", 42 | "react-dom": "^19.0.0", 43 | "sonner": "^2.0.3", 44 | "tailwind-merge": "^3.1.0", 45 | "tw-animate-css": "^1.2.5", 46 | "zod": "^3.24.2" 47 | } 48 | } 49 | ``` 50 | 51 | ## To-Do / Next Steps 52 | 53 | The following tasks are planned for future updates (sourced from `notes.md`): 54 | 55 | ### Style 56 | 57 | - [ ] Sonner hover state can have better morphing. 58 | -------------------------------------------------------------------------------- /src/app/motion/flexgrowsample/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import MetaLogo from "@/components/icons/metalogo"; 3 | import { motion } from "motion/react"; 4 | import { useState } from "react"; 5 | const Page = () => { 6 | const [hovered, setHovered] = useState(0); 7 | 8 | return ( 9 |
10 |
11 | {[0, 1, 2].map((index) => ( 12 | setHovered(index)} 21 | className={`flex h-full border border-border rounded-[8px]`} 22 | initial={{ width: "10%" }} 23 | animate={{ width: hovered === index ? "80%" : "10%" }} 24 | > 25 | {hovered === index ? ( 26 |
27 | Place the contents here 28 |
29 | ) : ( 30 |
31 | 32 |
33 | )} 34 |
35 | ))} 36 |
37 |
38 | ); 39 | }; 40 | 41 | export default Page; 42 | -------------------------------------------------------------------------------- /src/components/utility/navbar.tsx: -------------------------------------------------------------------------------- 1 | //#region //? References 2 | /** 3 | * @file Navbar Component 4 | * 5 | * @section Colors & places they are used 6 | * - `secondary/15` => navbar background 7 | * - `black/40` => page icon container background 8 | * - `black` => page icon container hover background 9 | * - `active-svg` => icon stroke (via ThemeSwitcher) 10 | * 11 | * @notes 12 | * - Integrates `ThemeSwitcher` with `navbar` prop for compact styling. 13 | */ 14 | //#endregion 15 | 16 | import { Home, LucideComponent } from "lucide-react"; 17 | import Link from "next/link"; 18 | import ThemeSwitcher from "../themeSwitcher"; 19 | 20 | const pages = [ 21 | { 22 | page: "Home", 23 | href: "/", 24 | icon: Home, 25 | }, 26 | { 27 | page: "forms", 28 | href: "/reactflow", 29 | icon: LucideComponent, 30 | }, 31 | ]; 32 | 33 | export default function Navbar() { 34 | return ( 35 |
36 |
37 | {pages.map((page, index) => ( 38 | 43 | 44 | 45 | ))} 46 | 47 |
48 |
49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | //#region //? References 2 | /** 3 | * @file Textarea Component 4 | * 5 | * @section Colors & places they are used 6 | * - `border-input` => base border 7 | * - `muted-foreground` => placeholder text 8 | * - `ring` => focus state border and ring 9 | * - `destructive` => `aria-invalid` border/ring 10 | * 11 | * @override => width => default full 12 | * Use wrapper to control size. 13 | * 14 | * 15 | */ 16 | //#endregion 17 | 18 | import * as React from "react"; 19 | import { cn } from "@/lib/utils"; 20 | 21 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { 22 | return ( 23 |