├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── app
├── favicon.ico
├── fonts
│ ├── GeistMonoVF.woff
│ └── GeistVF.woff
├── globals.css
├── layout.js
└── page.js
├── components.json
├── components
├── common
│ ├── footer.jsx
│ └── header.jsx
├── theme-provider.jsx
├── theme-switcher.jsx
└── ui
│ ├── accordion.jsx
│ ├── alert-dialog.jsx
│ ├── alert.jsx
│ ├── aspect-ratio.jsx
│ ├── avatar.jsx
│ ├── badge.jsx
│ ├── breadcrumb.jsx
│ ├── button.jsx
│ ├── calendar.jsx
│ ├── card.jsx
│ ├── carousel.jsx
│ ├── chart.jsx
│ ├── checkbox.jsx
│ ├── collapsible.jsx
│ ├── command.jsx
│ ├── context-menu.jsx
│ ├── dialog.jsx
│ ├── drawer.jsx
│ ├── dropdown-menu.jsx
│ ├── form.jsx
│ ├── hover-card.jsx
│ ├── input-otp.jsx
│ ├── input.jsx
│ ├── label.jsx
│ ├── menubar.jsx
│ ├── navigation-menu.jsx
│ ├── pagination.jsx
│ ├── popover.jsx
│ ├── progress.jsx
│ ├── radio-group.jsx
│ ├── resizable.jsx
│ ├── scroll-area.jsx
│ ├── select.jsx
│ ├── separator.jsx
│ ├── sheet.jsx
│ ├── skeleton.jsx
│ ├── slider.jsx
│ ├── sonner.jsx
│ ├── switch.jsx
│ ├── table.jsx
│ ├── tabs.jsx
│ ├── textarea.jsx
│ ├── toast.jsx
│ ├── toaster.jsx
│ ├── toggle-group.jsx
│ ├── toggle.jsx
│ └── tooltip.jsx
├── hooks
└── use-toast.js
├── jsconfig.json
├── lib
└── utils.js
├── next.config.mjs
├── package-lock.json
├── package.json
├── postcss.config.mjs
├── tailwind.config.js
└── yarn.lock
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.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 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Tapas Adhikary
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NextShad
2 |
3 | A template repository that helps you to get started with your Next.js and ShadCN projects with one click!
4 |
5 | 
6 |
7 | ## Usages
8 | This repository contains the Next.js APP Router scaffolding along with all shadcn configurations and components. You can use this repository in a couple of ways:
9 |
10 | 1. Just fork it and use it as your own.
11 | 2. Create a repository by clicking on the `Use this template` button at the top-right of the page.
12 |
13 |
14 | ## Getting Started
15 |
16 | - First install the dependencies using `npm install` or equivalents like yarn, pnpm, or byn.
17 |
18 | - Then, run the development server:
19 |
20 | ```bash
21 | npm run dev
22 | # or
23 | yarn dev
24 | # or
25 | pnpm dev
26 | # or
27 | bun dev
28 | ```
29 |
30 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
31 |
32 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
33 |
34 | ## 🫶 Support
35 | > Liked my work? You can show your support with a STAR(⭐). I am an independent educator who creates meaningful projects to teach programming. You can support me further by [sponsoring me on GitHub](https://github.com/sponsors/atapas).
36 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atapas/nextshad/374f6507887f10ec86dc9e3fdb802327cca8845a/app/favicon.ico
--------------------------------------------------------------------------------
/app/fonts/GeistMonoVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atapas/nextshad/374f6507887f10ec86dc9e3fdb802327cca8845a/app/fonts/GeistMonoVF.woff
--------------------------------------------------------------------------------
/app/fonts/GeistVF.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atapas/nextshad/374f6507887f10ec86dc9e3fdb802327cca8845a/app/fonts/GeistVF.woff
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | :root {
7 | --background: 0 0% 100%;
8 | --foreground: 240 10% 3.9%;
9 | --card: 0 0% 100%;
10 | --card-foreground: 240 10% 3.9%;
11 | --popover: 0 0% 100%;
12 | --popover-foreground: 240 10% 3.9%;
13 | --primary: 240 5.9% 10%;
14 | --primary-foreground: 0 0% 98%;
15 | --secondary: 240 4.8% 95.9%;
16 | --secondary-foreground: 240 5.9% 10%;
17 | --muted: 240 4.8% 95.9%;
18 | --muted-foreground: 240 3.8% 46.1%;
19 | --accent: 240 4.8% 95.9%;
20 | --accent-foreground: 240 5.9% 10%;
21 | --destructive: 0 84.2% 60.2%;
22 | --destructive-foreground: 0 0% 98%;
23 | --border: 240 5.9% 90%;
24 | --input: 240 5.9% 90%;
25 | --ring: 240 10% 3.9%;
26 | --chart-1: 12 76% 61%;
27 | --chart-2: 173 58% 39%;
28 | --chart-3: 197 37% 24%;
29 | --chart-4: 43 74% 66%;
30 | --chart-5: 27 87% 67%;
31 | --radius: 0.5rem;
32 | }
33 | .dark {
34 | --background: 240 10% 3.9%;
35 | --foreground: 0 0% 98%;
36 | --card: 240 10% 3.9%;
37 | --card-foreground: 0 0% 98%;
38 | --popover: 240 10% 3.9%;
39 | --popover-foreground: 0 0% 98%;
40 | --primary: 0 0% 98%;
41 | --primary-foreground: 240 5.9% 10%;
42 | --secondary: 240 3.7% 15.9%;
43 | --secondary-foreground: 0 0% 98%;
44 | --muted: 240 3.7% 15.9%;
45 | --muted-foreground: 240 5% 64.9%;
46 | --accent: 240 3.7% 15.9%;
47 | --accent-foreground: 0 0% 98%;
48 | --destructive: 0 62.8% 30.6%;
49 | --destructive-foreground: 0 0% 98%;
50 | --border: 240 3.7% 15.9%;
51 | --input: 240 3.7% 15.9%;
52 | --ring: 240 4.9% 83.9%;
53 | --chart-1: 220 70% 50%;
54 | --chart-2: 160 60% 45%;
55 | --chart-3: 30 80% 55%;
56 | --chart-4: 280 65% 60%;
57 | --chart-5: 340 75% 55%;
58 | }
59 | }
60 |
61 | body {
62 | overflow: hidden;
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/app/layout.js:
--------------------------------------------------------------------------------
1 | import localFont from "next/font/local";
2 | import "./globals.css";
3 |
4 | import { ThemeProvider } from "@/components/theme-provider";
5 |
6 | import { Header } from "@/components/common/header";
7 | import { Footer } from "@/components/common/footer";
8 |
9 | const geistSans = localFont({
10 | src: "./fonts/GeistVF.woff",
11 | variable: "--font-geist-sans",
12 | weight: "100 900",
13 | });
14 | const geistMono = localFont({
15 | src: "./fonts/GeistMonoVF.woff",
16 | variable: "--font-geist-mono",
17 | weight: "100 900",
18 | });
19 |
20 | export const metadata = {
21 | title: "NextShad",
22 | description: "A template repository with the Next.js + ShandCN Scaffolding created for anyone who doesn't want to go through the instillation repeatedly.",
23 | };
24 |
25 | export default function RootLayout({ children }) {
26 | return (
27 |
28 |
31 |
37 |
38 |
39 | {children}
40 |
41 |
42 |
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/app/page.js:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 | import { Star } from "lucide-react";
3 |
4 | export default async function Home() {
5 | const response = await fetch("https://api.github.com/repos/atapas/nextshad", { cache: 'no-store' });
6 | const data = await response.json();
7 | const starGazzersCount = data?.stargazers_count;
8 |
9 | console.log(starGazzersCount);
10 |
11 | return (
12 |
13 |
14 |
15 |
23 |
24 |
32 |
33 |
34 | -
35 | Find shadcn components under the{" "}
36 |
37 | app/components/ui
38 |
39 | folder.
40 |
41 | -
42 | Get started by editing{" "}
43 |
44 | app/page.js
45 |
46 | .
47 |
48 | - Save and see your changes instantly.
49 |
50 |
51 |
69 |
70 |
71 |
72 | );
73 | }
74 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": true,
5 | "tsx": false,
6 | "tailwind": {
7 | "config": "tailwind.config.js",
8 | "css": "app/globals.css",
9 | "baseColor": "zinc",
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 | }
--------------------------------------------------------------------------------
/components/common/footer.jsx:
--------------------------------------------------------------------------------
1 |
2 | export const Footer = () => {
3 | return (
4 |
9 | )
10 | }
--------------------------------------------------------------------------------
/components/common/header.jsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | import { ThemeSwitcher } from "../theme-switcher"
4 | import { Tablets } from "lucide-react"
5 |
6 | export const Header = () => {
7 |
8 | return (
9 |
10 |
14 |
15 |
18 |
19 | )
20 | }
--------------------------------------------------------------------------------
/components/theme-provider.jsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import { ThemeProvider as NextThemesProvider } from "next-themes"
5 |
6 | export function ThemeProvider({ children, ...props }) {
7 | return {children}
8 | }
9 |
--------------------------------------------------------------------------------
/components/theme-switcher.jsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import { Moon, Sun } from "lucide-react"
5 | import { useTheme } from "next-themes"
6 |
7 | import { Button } from "@/components/ui/button"
8 | import {
9 | DropdownMenu,
10 | DropdownMenuContent,
11 | DropdownMenuItem,
12 | DropdownMenuTrigger,
13 | } from "@/components/ui/dropdown-menu"
14 |
15 | export function ThemeSwitcher() {
16 | const { setTheme } = useTheme()
17 |
18 | return (
19 |
20 |
21 |
26 |
27 |
28 | setTheme("light")}>
29 | Light
30 |
31 | setTheme("dark")}>
32 | Dark
33 |
34 | setTheme("system")}>
35 | System
36 |
37 |
38 |
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/components/ui/accordion.jsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as AccordionPrimitive from "@radix-ui/react-accordion"
5 | import { ChevronDownIcon } from "@radix-ui/react-icons"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Accordion = AccordionPrimitive.Root
10 |
11 | const AccordionItem = React.forwardRef(({ className, ...props }, ref) => (
12 |
13 | ))
14 | AccordionItem.displayName = "AccordionItem"
15 |
16 | const AccordionTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
17 |
18 | svg]:rotate-180",
22 | className
23 | )}
24 | {...props}>
25 | {children}
26 |
28 |
29 |
30 | ))
31 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
32 |
33 | const AccordionContent = React.forwardRef(({ className, children, ...props }, ref) => (
34 |
38 | {children}
39 |
40 | ))
41 | AccordionContent.displayName = AccordionPrimitive.Content.displayName
42 |
43 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
44 |
--------------------------------------------------------------------------------
/components/ui/alert-dialog.jsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
5 |
6 | import { cn } from "@/lib/utils"
7 | import { buttonVariants } from "@/components/ui/button"
8 |
9 | const AlertDialog = AlertDialogPrimitive.Root
10 |
11 | const AlertDialogTrigger = AlertDialogPrimitive.Trigger
12 |
13 | const AlertDialogPortal = AlertDialogPrimitive.Portal
14 |
15 | const AlertDialogOverlay = React.forwardRef(({ className, ...props }, ref) => (
16 |
23 | ))
24 | AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
25 |
26 | const AlertDialogContent = React.forwardRef(({ className, ...props }, ref) => (
27 |
28 |
29 |
36 |
37 | ))
38 | AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
39 |
40 | const AlertDialogHeader = ({
41 | className,
42 | ...props
43 | }) => (
44 |
47 | )
48 | AlertDialogHeader.displayName = "AlertDialogHeader"
49 |
50 | const AlertDialogFooter = ({
51 | className,
52 | ...props
53 | }) => (
54 |
57 | )
58 | AlertDialogFooter.displayName = "AlertDialogFooter"
59 |
60 | const AlertDialogTitle = React.forwardRef(({ className, ...props }, ref) => (
61 |
62 | ))
63 | AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
64 |
65 | const AlertDialogDescription = React.forwardRef(({ className, ...props }, ref) => (
66 |
70 | ))
71 | AlertDialogDescription.displayName =
72 | AlertDialogPrimitive.Description.displayName
73 |
74 | const AlertDialogAction = React.forwardRef(({ className, ...props }, ref) => (
75 |
76 | ))
77 | AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
78 |
79 | const AlertDialogCancel = React.forwardRef(({ className, ...props }, ref) => (
80 |
84 | ))
85 | AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
86 |
87 | export {
88 | AlertDialog,
89 | AlertDialogPortal,
90 | AlertDialogOverlay,
91 | AlertDialogTrigger,
92 | AlertDialogContent,
93 | AlertDialogHeader,
94 | AlertDialogFooter,
95 | AlertDialogTitle,
96 | AlertDialogDescription,
97 | AlertDialogAction,
98 | AlertDialogCancel,
99 | }
100 |
--------------------------------------------------------------------------------
/components/ui/alert.jsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { cva } from "class-variance-authority";
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const alertVariants = cva(
7 | "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
8 | {
9 | variants: {
10 | variant: {
11 | default: "bg-background text-foreground",
12 | destructive:
13 | "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
14 | },
15 | },
16 | defaultVariants: {
17 | variant: "default",
18 | },
19 | }
20 | )
21 |
22 | const Alert = React.forwardRef(({ className, variant, ...props }, ref) => (
23 |
28 | ))
29 | Alert.displayName = "Alert"
30 |
31 | const AlertTitle = React.forwardRef(({ className, ...props }, ref) => (
32 |
36 | ))
37 | AlertTitle.displayName = "AlertTitle"
38 |
39 | const AlertDescription = React.forwardRef(({ className, ...props }, ref) => (
40 |
44 | ))
45 | AlertDescription.displayName = "AlertDescription"
46 |
47 | export { Alert, AlertTitle, AlertDescription }
48 |
--------------------------------------------------------------------------------
/components/ui/aspect-ratio.jsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
4 |
5 | const AspectRatio = AspectRatioPrimitive.Root
6 |
7 | export { AspectRatio }
8 |
--------------------------------------------------------------------------------
/components/ui/avatar.jsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as AvatarPrimitive from "@radix-ui/react-avatar"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | const Avatar = React.forwardRef(({ className, ...props }, ref) => (
9 |
13 | ))
14 | Avatar.displayName = AvatarPrimitive.Root.displayName
15 |
16 | const AvatarImage = React.forwardRef(({ className, ...props }, ref) => (
17 |
21 | ))
22 | AvatarImage.displayName = AvatarPrimitive.Image.displayName
23 |
24 | const AvatarFallback = React.forwardRef(({ className, ...props }, ref) => (
25 |
32 | ))
33 | AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
34 |
35 | export { Avatar, AvatarImage, AvatarFallback }
36 |
--------------------------------------------------------------------------------
/components/ui/badge.jsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { cva } from "class-variance-authority";
3 |
4 | import { cn } from "@/lib/utils"
5 |
6 | const badgeVariants = cva(
7 | "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8 | {
9 | variants: {
10 | variant: {
11 | default:
12 | "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
13 | secondary:
14 | "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15 | destructive:
16 | "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
17 | outline: "text-foreground",
18 | },
19 | },
20 | defaultVariants: {
21 | variant: "default",
22 | },
23 | }
24 | )
25 |
26 | function Badge({
27 | className,
28 | variant,
29 | ...props
30 | }) {
31 | return ();
32 | }
33 |
34 | export { Badge, badgeVariants }
35 |
--------------------------------------------------------------------------------
/components/ui/breadcrumb.jsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons"
3 | import { Slot } from "@radix-ui/react-slot"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const Breadcrumb = React.forwardRef(
8 | ({ ...props }, ref) =>
9 | )
10 | Breadcrumb.displayName = "Breadcrumb"
11 |
12 | const BreadcrumbList = React.forwardRef(({ className, ...props }, ref) => (
13 |
20 | ))
21 | BreadcrumbList.displayName = "BreadcrumbList"
22 |
23 | const BreadcrumbItem = React.forwardRef(({ className, ...props }, ref) => (
24 |
28 | ))
29 | BreadcrumbItem.displayName = "BreadcrumbItem"
30 |
31 | const BreadcrumbLink = React.forwardRef(({ asChild, className, ...props }, ref) => {
32 | const Comp = asChild ? Slot : "a"
33 |
34 | return (
35 | ()
39 | );
40 | })
41 | BreadcrumbLink.displayName = "BreadcrumbLink"
42 |
43 | const BreadcrumbPage = React.forwardRef(({ className, ...props }, ref) => (
44 |
51 | ))
52 | BreadcrumbPage.displayName = "BreadcrumbPage"
53 |
54 | const BreadcrumbSeparator = ({
55 | children,
56 | className,
57 | ...props
58 | }) => (
59 | svg]:size-3.5", className)}
63 | {...props}>
64 | {children ?? }
65 |
66 | )
67 | BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
68 |
69 | const BreadcrumbEllipsis = ({
70 | className,
71 | ...props
72 | }) => (
73 |
78 |
79 | More
80 |
81 | )
82 | BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
83 |
84 | export {
85 | Breadcrumb,
86 | BreadcrumbList,
87 | BreadcrumbItem,
88 | BreadcrumbLink,
89 | BreadcrumbPage,
90 | BreadcrumbSeparator,
91 | BreadcrumbEllipsis,
92 | }
93 |
--------------------------------------------------------------------------------
/components/ui/button.jsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva } from "class-variance-authority";
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
16 | outline:
17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
20 | ghost: "hover:bg-accent hover:text-accent-foreground",
21 | link: "text-primary underline-offset-4 hover:underline",
22 | },
23 | size: {
24 | default: "h-9 px-4 py-2",
25 | sm: "h-8 rounded-md px-3 text-xs",
26 | lg: "h-10 rounded-md px-8",
27 | icon: "h-9 w-9",
28 | },
29 | },
30 | defaultVariants: {
31 | variant: "default",
32 | size: "default",
33 | },
34 | }
35 | )
36 |
37 | const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
38 | const Comp = asChild ? Slot : "button"
39 | return (
40 | ()
44 | );
45 | })
46 | Button.displayName = "Button"
47 |
48 | export { Button, buttonVariants }
49 |
--------------------------------------------------------------------------------
/components/ui/calendar.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import * as React from "react"
3 | import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"
4 | import { DayPicker } from "react-day-picker"
5 |
6 | import { cn } from "@/lib/utils"
7 | import { buttonVariants } from "@/components/ui/button"
8 |
9 | function Calendar({
10 | className,
11 | classNames,
12 | showOutsideDays = true,
13 | ...props
14 | }) {
15 | return (
16 | (.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
40 | : "[&:has([aria-selected])]:rounded-md"
41 | ),
42 | day: cn(
43 | buttonVariants({ variant: "ghost" }),
44 | "h-8 w-8 p-0 font-normal aria-selected:opacity-100"
45 | ),
46 | day_range_start: "day-range-start",
47 | day_range_end: "day-range-end",
48 | day_selected:
49 | "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
50 | day_today: "bg-accent text-accent-foreground",
51 | day_outside:
52 | "day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
53 | day_disabled: "text-muted-foreground opacity-50",
54 | day_range_middle:
55 | "aria-selected:bg-accent aria-selected:text-accent-foreground",
56 | day_hidden: "invisible",
57 | ...classNames,
58 | }}
59 | components={{
60 | IconLeft: ({ ...props }) => ,
61 | IconRight: ({ ...props }) => ,
62 | }}
63 | {...props} />)
64 | );
65 | }
66 | Calendar.displayName = "Calendar"
67 |
68 | export { Calendar }
69 |
--------------------------------------------------------------------------------
/components/ui/card.jsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | const Card = React.forwardRef(({ className, ...props }, ref) => (
6 |
10 | ))
11 | Card.displayName = "Card"
12 |
13 | const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
14 |
18 | ))
19 | CardHeader.displayName = "CardHeader"
20 |
21 | const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
22 |
26 | ))
27 | CardTitle.displayName = "CardTitle"
28 |
29 | const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
30 |
34 | ))
35 | CardDescription.displayName = "CardDescription"
36 |
37 | const CardContent = React.forwardRef(({ className, ...props }, ref) => (
38 |
39 | ))
40 | CardContent.displayName = "CardContent"
41 |
42 | const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
43 |
47 | ))
48 | CardFooter.displayName = "CardFooter"
49 |
50 | export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
51 |
--------------------------------------------------------------------------------
/components/ui/carousel.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import * as React from "react"
3 | import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons"
4 | import useEmblaCarousel from "embla-carousel-react";
5 |
6 | import { cn } from "@/lib/utils"
7 | import { Button } from "@/components/ui/button"
8 |
9 | const CarouselContext = React.createContext(null)
10 |
11 | function useCarousel() {
12 | const context = React.useContext(CarouselContext)
13 |
14 | if (!context) {
15 | throw new Error("useCarousel must be used within a ")
16 | }
17 |
18 | return context
19 | }
20 |
21 | const Carousel = React.forwardRef((
22 | {
23 | orientation = "horizontal",
24 | opts,
25 | setApi,
26 | plugins,
27 | className,
28 | children,
29 | ...props
30 | },
31 | ref
32 | ) => {
33 | const [carouselRef, api] = useEmblaCarousel({
34 | ...opts,
35 | axis: orientation === "horizontal" ? "x" : "y",
36 | }, plugins)
37 | const [canScrollPrev, setCanScrollPrev] = React.useState(false)
38 | const [canScrollNext, setCanScrollNext] = React.useState(false)
39 |
40 | const onSelect = React.useCallback((api) => {
41 | if (!api) {
42 | return
43 | }
44 |
45 | setCanScrollPrev(api.canScrollPrev())
46 | setCanScrollNext(api.canScrollNext())
47 | }, [])
48 |
49 | const scrollPrev = React.useCallback(() => {
50 | api?.scrollPrev()
51 | }, [api])
52 |
53 | const scrollNext = React.useCallback(() => {
54 | api?.scrollNext()
55 | }, [api])
56 |
57 | const handleKeyDown = React.useCallback((event) => {
58 | if (event.key === "ArrowLeft") {
59 | event.preventDefault()
60 | scrollPrev()
61 | } else if (event.key === "ArrowRight") {
62 | event.preventDefault()
63 | scrollNext()
64 | }
65 | }, [scrollPrev, scrollNext])
66 |
67 | React.useEffect(() => {
68 | if (!api || !setApi) {
69 | return
70 | }
71 |
72 | setApi(api)
73 | }, [api, setApi])
74 |
75 | React.useEffect(() => {
76 | if (!api) {
77 | return
78 | }
79 |
80 | onSelect(api)
81 | api.on("reInit", onSelect)
82 | api.on("select", onSelect)
83 |
84 | return () => {
85 | api?.off("select", onSelect)
86 | };
87 | }, [api, onSelect])
88 |
89 | return (
90 | (
102 |
109 | {children}
110 |
111 | )
112 | );
113 | })
114 | Carousel.displayName = "Carousel"
115 |
116 | const CarouselContent = React.forwardRef(({ className, ...props }, ref) => {
117 | const { carouselRef, orientation } = useCarousel()
118 |
119 | return (
120 | ()
130 | );
131 | })
132 | CarouselContent.displayName = "CarouselContent"
133 |
134 | const CarouselItem = React.forwardRef(({ className, ...props }, ref) => {
135 | const { orientation } = useCarousel()
136 |
137 | return (
138 | ()
148 | );
149 | })
150 | CarouselItem.displayName = "CarouselItem"
151 |
152 | const CarouselPrevious = React.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
153 | const { orientation, scrollPrev, canScrollPrev } = useCarousel()
154 |
155 | return (
156 | ()
169 | );
170 | })
171 | CarouselPrevious.displayName = "CarouselPrevious"
172 |
173 | const CarouselNext = React.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
174 | const { orientation, scrollNext, canScrollNext } = useCarousel()
175 |
176 | return (
177 | ()
190 | );
191 | })
192 | CarouselNext.displayName = "CarouselNext"
193 |
194 | export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext };
195 |
--------------------------------------------------------------------------------
/components/ui/chart.jsx:
--------------------------------------------------------------------------------
1 | "use client";
2 | import * as React from "react"
3 | import * as RechartsPrimitive from "recharts"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | // Format: { THEME_NAME: CSS_SELECTOR }
8 | const THEMES = {
9 | light: "",
10 | dark: ".dark"
11 | }
12 |
13 | const ChartContext = React.createContext(null)
14 |
15 | function useChart() {
16 | const context = React.useContext(ChartContext)
17 |
18 | if (!context) {
19 | throw new Error("useChart must be used within a ")
20 | }
21 |
22 | return context
23 | }
24 |
25 | const ChartContainer = React.forwardRef(({ id, className, children, config, ...props }, ref) => {
26 | const uniqueId = React.useId()
27 | const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
28 |
29 | return (
30 | (
31 |
39 |
40 |
41 | {children}
42 |
43 |
44 | )
45 | );
46 | })
47 | ChartContainer.displayName = "Chart"
48 |
49 | const ChartStyle = ({
50 | id,
51 | config
52 | }) => {
53 | const colorConfig = Object.entries(config).filter(([_, config]) => config.theme || config.color)
54 |
55 | if (!colorConfig.length) {
56 | return null
57 | }
58 |
59 | return (
60 | (