├── .eslintrc.json ├── .gitignore ├── README.md ├── components.json ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── next.svg └── vercel.svg ├── src ├── app │ ├── favicon.ico │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── components │ ├── AccordionDemo.tsx │ ├── AlertDemo.tsx │ ├── AlertDialogDemo.tsx │ ├── CardDemo.tsx │ ├── CheckboxDemo.tsx │ ├── CollapsibleDemo.tsx │ ├── ComboboxDemo.tsx │ ├── CommandDemo.tsx │ ├── ContextMenuDemo.tsx │ ├── DataTableDemo.tsx │ ├── DatePickerWithPresets.tsx │ ├── DialogDemo.tsx │ ├── DropdownMenuDemo.tsx │ ├── MenubarDemo.tsx │ ├── NavigationmenuDemo.tsx │ ├── PopoverDemo.tsx │ ├── ProgressDemo.tsx │ ├── RadioGroupDemo.tsx │ ├── ScrollAreaDemo.tsx │ ├── SelectDemo.tsx │ ├── SeparatorDemo.tsx │ ├── SheetDemo.tsx │ ├── SkeletonDemo.tsx │ ├── SliderDemo.tsx │ ├── SwitchDemo.tsx │ ├── TabsDemo.tsx │ ├── TextAreaDemo.tsx │ ├── ToastDemo.tsx │ ├── ToggleDemo.tsx │ ├── TooltipDemo.tsx │ ├── theme-provider.tsx │ └── ui │ │ ├── accordion.tsx │ │ ├── alert-dialog.tsx │ │ ├── alert.tsx │ │ ├── button.tsx │ │ ├── calendar.tsx │ │ ├── card.tsx │ │ ├── checkbox.tsx │ │ ├── collapsible.tsx │ │ ├── combobox.tsx │ │ ├── command.tsx │ │ ├── context-menu.tsx │ │ ├── data-range-picker.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── menubar.tsx │ │ ├── navigation-menu.tsx │ │ ├── popover.tsx │ │ ├── progress.tsx │ │ ├── radio-group.tsx │ │ ├── scroll-area.tsx │ │ ├── select.tsx │ │ ├── separator.tsx │ │ ├── sheet.tsx │ │ ├── skeleton.tsx │ │ ├── slider.tsx │ │ ├── switch.tsx │ │ ├── table.tsx │ │ ├── tabs.tsx │ │ ├── textarea.tsx │ │ ├── toast.tsx │ │ ├── toaster.tsx │ │ ├── toggle.tsx │ │ ├── tooltip.tsx │ │ └── use-toast.ts └── lib │ └── utils.ts ├── tailwind.config.ts └── tsconfig.json /.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linear UI Kit 2 | 3 | This is a [Linear](https://www.linear.app) UI Design using [Shadcn](https://https://ui.shadcn.com/). 4 | 5 | thumbnail 6 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/app/global.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linear-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@radix-ui/react-accordion": "^1.1.2", 13 | "@radix-ui/react-alert-dialog": "^1.0.5", 14 | "@radix-ui/react-checkbox": "^1.0.4", 15 | "@radix-ui/react-collapsible": "^1.0.3", 16 | "@radix-ui/react-context-menu": "^2.1.5", 17 | "@radix-ui/react-dialog": "^1.0.5", 18 | "@radix-ui/react-dropdown-menu": "^2.0.6", 19 | "@radix-ui/react-icons": "^1.3.0", 20 | "@radix-ui/react-label": "^2.0.2", 21 | "@radix-ui/react-menubar": "^1.0.4", 22 | "@radix-ui/react-navigation-menu": "^1.1.4", 23 | "@radix-ui/react-popover": "^1.0.7", 24 | "@radix-ui/react-progress": "^1.0.3", 25 | "@radix-ui/react-radio-group": "^1.1.3", 26 | "@radix-ui/react-scroll-area": "^1.0.5", 27 | "@radix-ui/react-select": "^2.0.0", 28 | "@radix-ui/react-separator": "^1.0.3", 29 | "@radix-ui/react-slider": "^1.1.2", 30 | "@radix-ui/react-slot": "^1.0.2", 31 | "@radix-ui/react-switch": "^1.0.3", 32 | "@radix-ui/react-tabs": "^1.0.4", 33 | "@radix-ui/react-toast": "^1.1.5", 34 | "@radix-ui/react-toggle": "^1.0.3", 35 | "@radix-ui/react-tooltip": "^1.0.7", 36 | "@tanstack/react-table": "^8.10.7", 37 | "class-variance-authority": "^0.7.0", 38 | "clsx": "^2.0.0", 39 | "cmdk": "^0.2.0", 40 | "date-fns": "^2.30.0", 41 | "lucide-react": "^0.290.0", 42 | "next": "^14.0.0", 43 | "next-themes": "^0.2.1", 44 | "radix": "^0.0.0", 45 | "react": "^18.2.0", 46 | "react-day-picker": "^8.9.1", 47 | "react-dom": "^18.2.0", 48 | "react-icons": "^4.11.0", 49 | "tailwind-merge": "^1.14.0", 50 | "tailwindcss-animate": "^1.0.7", 51 | "zod": "^3.22.4" 52 | }, 53 | "devDependencies": { 54 | "@faker-js/faker": "^8.2.0", 55 | "@types/node": "20.8.9", 56 | "@types/react": "18.2.33", 57 | "@types/react-dom": "^18", 58 | "autoprefixer": "^10", 59 | "eslint": "^8", 60 | "eslint-config-next": "14.0.0", 61 | "postcss": "^8", 62 | "tailwindcss": "^3", 63 | "typescript": "5.2.2" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marvkr/linear-shadcn/7cb5293410018a70cf79374adfb122b7671c80d4/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --background: 234 17% 12%; 8 | --foreground: 0 0% 100%; 9 | 10 | --card: 236 18% 15%; 11 | --card-foreground: 210 40% 98%; 12 | 13 | --popover: 236 18% 15%; 14 | --popover-foreground: 0 0% 100%; 15 | 16 | --primary: 235 100% 71%; 17 | --primary-foreground: 0 0% 100%; 18 | 19 | --secondary: 231 20% 19%; 20 | --secondary-foreground: 237 8% 56%; 21 | 22 | --muted: 236 18% 15%; 23 | --muted-foreground: 229 9% 64%; 24 | 25 | --accent: 236 13% 22%; 26 | --accent-foreground: 210 40% 98%; 27 | 28 | --destructive: 0 62.8% 30.6%; 29 | --destructive-foreground: 210 40% 98%; 30 | 31 | --border: 237 15% 26%; 32 | --input: 217.2 32.6% 17.5%; 33 | --ring: 235 100% 71%; 34 | --radius: 0.5rem; 35 | } 36 | } 37 | 38 | @layer base { 39 | * { 40 | @apply border-border; 41 | } 42 | body { 43 | @apply bg-background text-foreground; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter } from "next/font/google"; 3 | import "./globals.css"; 4 | import { Toaster } from "@/components/ui/toaster"; 5 | 6 | const inter = Inter({ subsets: ["latin"] }); 7 | 8 | export const metadata: Metadata = { 9 | title: "Create Next App", 10 | description: "Generated by create next app", 11 | }; 12 | 13 | export default function RootLayout({ 14 | children, 15 | }: { 16 | children: React.ReactNode; 17 | }) { 18 | return ( 19 | 20 | 21 | {children} 22 | 23 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { AccordionDemo } from "@/components/AccordionDemo"; 2 | import { AlertDemo } from "@/components/AlertDemo"; 3 | import { AlertDialogDemo } from "@/components/AlertDialogDemo"; 4 | import { CardDemo } from "@/components/CardDemo"; 5 | import { CheckboxDemo } from "@/components/CheckboxDemo"; 6 | import { Calendar } from "@/components/ui/calendar"; 7 | import { CollapsibleDemo } from "@/components/CollapsibleDemo"; 8 | import { ComboboxDemo } from "@/components/ComboboxDemo"; 9 | import { CommandDemo } from "@/components/CommandDemo"; 10 | import { ContextMenuDemo } from "@/components/ContextMenuDemo"; 11 | import { DataTableDemo } from "@/components/DataTableDemo"; 12 | import { DatePickerWithPresets } from "@/components/DatePickerWithPresets"; 13 | import { DialogDemo } from "@/components/DialogDemo"; 14 | import { DropdownMenuDemo } from "@/components/DropdownMenuDemo"; 15 | import { MenubarDemo } from "@/components/MenubarDemo"; 16 | import { NavigationMenuDemo } from "@/components/NavigationmenuDemo"; 17 | import { PopoverDemo } from "@/components/PopoverDemo"; 18 | import { ProgressDemo } from "@/components/ProgressDemo"; 19 | import { ScrollAreaDemo } from "@/components/ScrollAreaDemo"; 20 | import { SelectDemo } from "@/components/SelectDemo"; 21 | import { SeparatorDemo } from "@/components/SeparatorDemo"; 22 | import { SheetDemo } from "@/components/SheetDemo"; 23 | import { SkeletonDemo } from "@/components/SkeletonDemo"; 24 | import { SliderDemo } from "@/components/SliderDemo"; 25 | import { SwitchDemo } from "@/components/SwitchDemo"; 26 | import { TabsDemo } from "@/components/TabsDemo"; 27 | import { TextareaDemo } from "@/components/TextAreaDemo"; 28 | import { ToastDemo } from "@/components/ToastDemo"; 29 | import { ToggleDemo } from "@/components/ToggleDemo"; 30 | import { TooltipDemo } from "@/components/TooltipDemo"; 31 | import { Button } from "@/components/ui/button"; 32 | 33 | export default function Home() { 34 | return ( 35 | <> 36 |
37 | 38 | 39 | 40 |
41 | 42 | 43 | 44 | 45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 |
54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
76 | 77 | ); 78 | } 79 | -------------------------------------------------------------------------------- /src/components/AccordionDemo.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Accordion, 3 | AccordionContent, 4 | AccordionItem, 5 | AccordionTrigger, 6 | } from "@/components/ui/accordion"; 7 | 8 | export function AccordionDemo() { 9 | return ( 10 | 11 | 12 | Is it accessible? 13 | 14 | Yes. It adheres to the WAI-ARIA design pattern. 15 | 16 | 17 | 18 | Is it styled? 19 | 20 | Yes. It comes with default styles that matches the other 21 | components' aesthetic. 22 | 23 | 24 | 25 | Is it animated? 26 | 27 | Yes. It's animated by default, but you can disable it if you 28 | prefer. 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /src/components/AlertDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Terminal } from "lucide-react"; 2 | 3 | import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; 4 | 5 | export function AlertDemo() { 6 | return ( 7 | 8 | 9 | Heads up! 10 | 11 | You can add components to your app using the cli. 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /src/components/AlertDialogDemo.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | AlertDialog, 3 | AlertDialogAction, 4 | AlertDialogCancel, 5 | AlertDialogContent, 6 | AlertDialogDescription, 7 | AlertDialogFooter, 8 | AlertDialogHeader, 9 | AlertDialogTitle, 10 | AlertDialogTrigger, 11 | } from "@/components/ui/alert-dialog"; 12 | import { Button } from "@/components/ui/button"; 13 | 14 | export function AlertDialogDemo() { 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | Are you absolutely sure? 23 | 24 | This action cannot be undone. This will permanently delete your 25 | account and remove your data from our servers. 26 | 27 | 28 | 29 | Cancel 30 | Continue 31 | 32 | 33 | 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/components/CardDemo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { Button } from "@/components/ui/button"; 4 | import { 5 | Card, 6 | CardContent, 7 | CardDescription, 8 | CardFooter, 9 | CardHeader, 10 | CardTitle, 11 | } from "@/components/ui/card"; 12 | import { Input } from "@/components/ui/input"; 13 | import { Label } from "@/components/ui/label"; 14 | import { 15 | Select, 16 | SelectContent, 17 | SelectItem, 18 | SelectTrigger, 19 | SelectValue, 20 | } from "@/components/ui/select"; 21 | 22 | export function CardDemo() { 23 | return ( 24 | 25 | 26 | Create project 27 | Deploy your new project in one-click. 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 | 49 |
50 |
51 |
52 |
53 | 54 | 55 | 56 | 57 |
58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /src/components/CheckboxDemo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Checkbox } from "@/components/ui/checkbox"; 4 | 5 | export function CheckboxDemo() { 6 | return ( 7 |
8 | 9 | 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/CollapsibleDemo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { ChevronsUpDown, Plus, X } from "lucide-react"; 5 | 6 | import { Button } from "@/components/ui/button"; 7 | import { 8 | Collapsible, 9 | CollapsibleContent, 10 | CollapsibleTrigger, 11 | } from "@/components/ui/collapsible"; 12 | 13 | export function CollapsibleDemo() { 14 | const [isOpen, setIsOpen] = React.useState(false); 15 | 16 | return ( 17 | 21 |
22 |

23 | @peduarte starred 3 repositories 24 |

25 | 26 | 30 | 31 |
32 |
33 | @radix-ui/primitives 34 |
35 | 36 |
37 | @radix-ui/colors 38 |
39 |
40 | @stitches/react 41 |
42 |
43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/components/ComboboxDemo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { Check, ChevronsUpDown } from "lucide-react"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | import { Button } from "@/components/ui/button"; 8 | import { 9 | Command, 10 | CommandEmpty, 11 | CommandGroup, 12 | CommandInput, 13 | CommandItem, 14 | } from "@/components/ui/command"; 15 | import { 16 | Popover, 17 | PopoverContent, 18 | PopoverTrigger, 19 | } from "@/components/ui/popover"; 20 | 21 | const frameworks = [ 22 | { 23 | value: "next.js", 24 | label: "Next.js", 25 | }, 26 | { 27 | value: "sveltekit", 28 | label: "SvelteKit", 29 | }, 30 | { 31 | value: "nuxt.js", 32 | label: "Nuxt.js", 33 | }, 34 | { 35 | value: "remix", 36 | label: "Remix", 37 | }, 38 | { 39 | value: "astro", 40 | label: "Astro", 41 | }, 42 | ]; 43 | 44 | export function ComboboxDemo() { 45 | const [open, setOpen] = React.useState(false); 46 | const [value, setValue] = React.useState(""); 47 | 48 | return ( 49 | 50 | 51 | 61 | 62 | 63 | 64 | 65 | No framework found. 66 | 67 | {frameworks.map((framework) => ( 68 | { 72 | setValue(currentValue === value ? "" : currentValue); 73 | setOpen(false); 74 | }}> 75 | 81 | {framework.label} 82 | 83 | ))} 84 | 85 | 86 | 87 | 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /src/components/CommandDemo.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Calculator, 3 | Calendar, 4 | CreditCard, 5 | Settings, 6 | Smile, 7 | User, 8 | } from "lucide-react"; 9 | 10 | import { 11 | Command, 12 | CommandEmpty, 13 | CommandGroup, 14 | CommandInput, 15 | CommandItem, 16 | CommandList, 17 | CommandSeparator, 18 | CommandShortcut, 19 | } from "@/components/ui/command"; 20 | 21 | export function CommandDemo() { 22 | return ( 23 | 24 | 25 | 26 | No results found. 27 | 28 | 29 | 30 | Calendar 31 | 32 | 33 | 34 | Search Emoji 35 | 36 | 37 | 38 | Calculator 39 | 40 | 41 | 42 | 43 | 44 | 45 | Profile 46 | ⌘P 47 | 48 | 49 | 50 | Billing 51 | ⌘B 52 | 53 | 54 | 55 | Settings 56 | ⌘S 57 | 58 | 59 | 60 | 61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /src/components/ContextMenuDemo.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ContextMenu, 3 | ContextMenuCheckboxItem, 4 | ContextMenuContent, 5 | ContextMenuItem, 6 | ContextMenuLabel, 7 | ContextMenuRadioGroup, 8 | ContextMenuRadioItem, 9 | ContextMenuSeparator, 10 | ContextMenuShortcut, 11 | ContextMenuSub, 12 | ContextMenuSubContent, 13 | ContextMenuSubTrigger, 14 | ContextMenuTrigger, 15 | } from "@/components/ui/context-menu"; 16 | 17 | export function ContextMenuDemo() { 18 | return ( 19 | 20 | 21 | Right click here 22 | 23 | 24 | 25 | Back 26 | ⌘[ 27 | 28 | 29 | Forward 30 | ⌘] 31 | 32 | 33 | Reload 34 | ⌘R 35 | 36 | 37 | More Tools 38 | 39 | 40 | Save Page As... 41 | ⇧⌘S 42 | 43 | Create Shortcut... 44 | Name Window... 45 | 46 | Developer Tools 47 | 48 | 49 | 50 | 51 | Show Bookmarks Bar 52 | ⌘⇧B 53 | 54 | Show Full URLs 55 | 56 | 57 | People 58 | 59 | 60 | Pedro Duarte 61 | 62 | Colm Tuite 63 | 64 | 65 | 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /src/components/DataTableDemo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { 5 | ColumnDef, 6 | ColumnFiltersState, 7 | SortingState, 8 | VisibilityState, 9 | flexRender, 10 | getCoreRowModel, 11 | getFilteredRowModel, 12 | getPaginationRowModel, 13 | getSortedRowModel, 14 | useReactTable, 15 | } from "@tanstack/react-table"; 16 | import { ArrowUpDown, ChevronDown, MoreHorizontal } from "lucide-react"; 17 | 18 | import { Button } from "@/components/ui/button"; 19 | import { Checkbox } from "@/components/ui/checkbox"; 20 | import { 21 | DropdownMenu, 22 | DropdownMenuCheckboxItem, 23 | DropdownMenuContent, 24 | DropdownMenuItem, 25 | DropdownMenuLabel, 26 | DropdownMenuSeparator, 27 | DropdownMenuTrigger, 28 | } from "@/components/ui/dropdown-menu"; 29 | import { Input } from "@/components/ui/input"; 30 | import { 31 | Table, 32 | TableBody, 33 | TableCell, 34 | TableHead, 35 | TableHeader, 36 | TableRow, 37 | } from "@/components/ui/table"; 38 | 39 | const data: Payment[] = [ 40 | { 41 | id: "m5gr84i9", 42 | amount: 316, 43 | status: "success", 44 | email: "ken99@yahoo.com", 45 | }, 46 | { 47 | id: "3u1reuv4", 48 | amount: 242, 49 | status: "success", 50 | email: "Abe45@gmail.com", 51 | }, 52 | { 53 | id: "derv1ws0", 54 | amount: 837, 55 | status: "processing", 56 | email: "Monserrat44@gmail.com", 57 | }, 58 | { 59 | id: "5kma53ae", 60 | amount: 874, 61 | status: "success", 62 | email: "Silas22@gmail.com", 63 | }, 64 | { 65 | id: "bhqecj4p", 66 | amount: 721, 67 | status: "failed", 68 | email: "carmella@hotmail.com", 69 | }, 70 | ]; 71 | 72 | export type Payment = { 73 | id: string; 74 | amount: number; 75 | status: "pending" | "processing" | "success" | "failed"; 76 | email: string; 77 | }; 78 | 79 | export const columns: ColumnDef[] = [ 80 | { 81 | id: "select", 82 | header: ({ table }) => ( 83 | table.toggleAllPageRowsSelected(!!value)} 86 | aria-label="Select all" 87 | /> 88 | ), 89 | cell: ({ row }) => ( 90 | row.toggleSelected(!!value)} 93 | aria-label="Select row" 94 | /> 95 | ), 96 | enableSorting: false, 97 | enableHiding: false, 98 | }, 99 | { 100 | accessorKey: "status", 101 | header: "Status", 102 | cell: ({ row }) => ( 103 |
{row.getValue("status")}
104 | ), 105 | }, 106 | { 107 | accessorKey: "email", 108 | header: ({ column }) => { 109 | return ( 110 | 116 | ); 117 | }, 118 | cell: ({ row }) =>
{row.getValue("email")}
, 119 | }, 120 | { 121 | accessorKey: "amount", 122 | header: () =>
Amount
, 123 | cell: ({ row }) => { 124 | const amount = parseFloat(row.getValue("amount")); 125 | 126 | // Format the amount as a dollar amount 127 | const formatted = new Intl.NumberFormat("en-US", { 128 | style: "currency", 129 | currency: "USD", 130 | }).format(amount); 131 | 132 | return
{formatted}
; 133 | }, 134 | }, 135 | { 136 | id: "actions", 137 | enableHiding: false, 138 | cell: ({ row }) => { 139 | const payment = row.original; 140 | 141 | return ( 142 | 143 | 144 | 148 | 149 | 150 | Actions 151 | navigator.clipboard.writeText(payment.id)}> 153 | Copy payment ID 154 | 155 | 156 | View customer 157 | View payment details 158 | 159 | 160 | ); 161 | }, 162 | }, 163 | ]; 164 | 165 | export function DataTableDemo() { 166 | const [sorting, setSorting] = React.useState([]); 167 | const [columnFilters, setColumnFilters] = React.useState( 168 | [] 169 | ); 170 | const [columnVisibility, setColumnVisibility] = 171 | React.useState({}); 172 | const [rowSelection, setRowSelection] = React.useState({}); 173 | 174 | const table = useReactTable({ 175 | data, 176 | columns, 177 | onSortingChange: setSorting, 178 | onColumnFiltersChange: setColumnFilters, 179 | getCoreRowModel: getCoreRowModel(), 180 | getPaginationRowModel: getPaginationRowModel(), 181 | getSortedRowModel: getSortedRowModel(), 182 | getFilteredRowModel: getFilteredRowModel(), 183 | onColumnVisibilityChange: setColumnVisibility, 184 | onRowSelectionChange: setRowSelection, 185 | state: { 186 | sorting, 187 | columnFilters, 188 | columnVisibility, 189 | rowSelection, 190 | }, 191 | }); 192 | 193 | return ( 194 |
195 |
196 | 200 | table.getColumn("email")?.setFilterValue(event.target.value) 201 | } 202 | className="max-w-sm" 203 | /> 204 | 205 | 206 | 209 | 210 | 211 | {table 212 | .getAllColumns() 213 | .filter((column) => column.getCanHide()) 214 | .map((column) => { 215 | return ( 216 | 221 | column.toggleVisibility(!!value) 222 | }> 223 | {column.id} 224 | 225 | ); 226 | })} 227 | 228 | 229 |
230 |
231 | 232 | 233 | {table.getHeaderGroups().map((headerGroup) => ( 234 | 235 | {headerGroup.headers.map((header) => { 236 | return ( 237 | 238 | {header.isPlaceholder 239 | ? null 240 | : flexRender( 241 | header.column.columnDef.header, 242 | header.getContext() 243 | )} 244 | 245 | ); 246 | })} 247 | 248 | ))} 249 | 250 | 251 | {table.getRowModel().rows?.length ? ( 252 | table.getRowModel().rows.map((row) => ( 253 | 256 | {row.getVisibleCells().map((cell) => ( 257 | 258 | {flexRender( 259 | cell.column.columnDef.cell, 260 | cell.getContext() 261 | )} 262 | 263 | ))} 264 | 265 | )) 266 | ) : ( 267 | 268 | 271 | No results. 272 | 273 | 274 | )} 275 | 276 |
277 |
278 |
279 |
280 | {table.getFilteredSelectedRowModel().rows.length} of{" "} 281 | {table.getFilteredRowModel().rows.length} row(s) selected. 282 |
283 |
284 | 291 | 298 |
299 |
300 |
301 | ); 302 | } 303 | -------------------------------------------------------------------------------- /src/components/DatePickerWithPresets.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import { addDays, format } from "date-fns"; 5 | import { Calendar as CalendarIcon } from "lucide-react"; 6 | 7 | import { cn } from "@/lib/utils"; 8 | import { Button } from "@/components/ui/button"; 9 | import { Calendar } from "@/components/ui/calendar"; 10 | import { 11 | Popover, 12 | PopoverContent, 13 | PopoverTrigger, 14 | } from "@/components/ui/popover"; 15 | import { 16 | Select, 17 | SelectContent, 18 | SelectItem, 19 | SelectTrigger, 20 | SelectValue, 21 | } from "@/components/ui/select"; 22 | 23 | export function DatePickerWithPresets() { 24 | const [date, setDate] = React.useState(); 25 | 26 | return ( 27 | 28 | 29 | 38 | 39 | 40 | 54 |
55 | 56 |
57 |
58 |
59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /src/components/DialogDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@/components/ui/button"; 2 | import { 3 | Dialog, 4 | DialogContent, 5 | DialogDescription, 6 | DialogFooter, 7 | DialogHeader, 8 | DialogTitle, 9 | DialogTrigger, 10 | } from "@/components/ui/dialog"; 11 | import { Input } from "@/components/ui/input"; 12 | import { Label } from "@/components/ui/label"; 13 | 14 | export function DialogDemo() { 15 | return ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | Edit profile 23 | 24 | Make changes to your profile here. Click save when you are done. 25 | 26 | 27 |
28 |
29 | 32 | 37 |
38 |
39 | 42 | 47 |
48 |
49 | 50 | 51 | 52 |
53 |
54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /src/components/DropdownMenuDemo.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Cloud, 3 | CreditCard, 4 | Github, 5 | Keyboard, 6 | LifeBuoy, 7 | LogOut, 8 | Mail, 9 | MessageSquare, 10 | Plus, 11 | PlusCircle, 12 | Settings, 13 | User, 14 | UserPlus, 15 | Users, 16 | } from "lucide-react"; 17 | 18 | import { Button } from "@/components/ui/button"; 19 | import { 20 | DropdownMenu, 21 | DropdownMenuContent, 22 | DropdownMenuGroup, 23 | DropdownMenuItem, 24 | DropdownMenuLabel, 25 | DropdownMenuPortal, 26 | DropdownMenuSeparator, 27 | DropdownMenuShortcut, 28 | DropdownMenuSub, 29 | DropdownMenuSubContent, 30 | DropdownMenuSubTrigger, 31 | DropdownMenuTrigger, 32 | } from "@/components/ui/dropdown-menu"; 33 | 34 | export function DropdownMenuDemo() { 35 | return ( 36 | 37 | 38 | 39 | 40 | 41 | My Account 42 | 43 | 44 | 45 | 46 | Profile 47 | ⇧⌘P 48 | 49 | 50 | 51 | Billing 52 | ⌘B 53 | 54 | 55 | 56 | Settings 57 | ⌘S 58 | 59 | 60 | 61 | Keyboard shortcuts 62 | ⌘K 63 | 64 | 65 | 66 | 67 | 68 | 69 | Team 70 | 71 | 72 | 73 | 74 | Invite users 75 | 76 | 77 | 78 | 79 | 80 | Email 81 | 82 | 83 | 84 | Message 85 | 86 | 87 | 88 | 89 | More... 90 | 91 | 92 | 93 | 94 | 95 | 96 | New Team 97 | ⌘+T 98 | 99 | 100 | 101 | 102 | 103 | GitHub 104 | 105 | 106 | 107 | Support 108 | 109 | 110 | 111 | API 112 | 113 | 114 | 115 | 116 | Log out 117 | ⇧⌘Q 118 | 119 | 120 | 121 | ); 122 | } 123 | -------------------------------------------------------------------------------- /src/components/MenubarDemo.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Menubar, 3 | MenubarCheckboxItem, 4 | MenubarContent, 5 | MenubarItem, 6 | MenubarMenu, 7 | MenubarRadioGroup, 8 | MenubarRadioItem, 9 | MenubarSeparator, 10 | MenubarShortcut, 11 | MenubarSub, 12 | MenubarSubContent, 13 | MenubarSubTrigger, 14 | MenubarTrigger, 15 | } from "@/components/ui/menubar"; 16 | 17 | export function MenubarDemo() { 18 | return ( 19 | 20 | 21 | File 22 | 23 | 24 | New Tab ⌘T 25 | 26 | 27 | New Window ⌘N 28 | 29 | New Incognito Window 30 | 31 | 32 | Share 33 | 34 | Email link 35 | Messages 36 | Notes 37 | 38 | 39 | 40 | 41 | Print... ⌘P 42 | 43 | 44 | 45 | 46 | Edit 47 | 48 | 49 | Undo ⌘Z 50 | 51 | 52 | Redo ⇧⌘Z 53 | 54 | 55 | 56 | Find 57 | 58 | Search the web 59 | 60 | Find... 61 | Find Next 62 | Find Previous 63 | 64 | 65 | 66 | Cut 67 | Copy 68 | Paste 69 | 70 | 71 | 72 | View 73 | 74 | Always Show Bookmarks Bar 75 | 76 | Always Show Full URLs 77 | 78 | 79 | 80 | Reload ⌘R 81 | 82 | 83 | Force Reload ⇧⌘R 84 | 85 | 86 | Toggle Fullscreen 87 | 88 | Hide Sidebar 89 | 90 | 91 | 92 | Profiles 93 | 94 | 95 | Andy 96 | Benoit 97 | Luis 98 | 99 | 100 | Edit... 101 | 102 | Add Profile... 103 | 104 | 105 | 106 | ); 107 | } 108 | -------------------------------------------------------------------------------- /src/components/NavigationmenuDemo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | import Link from "next/link"; 5 | 6 | import { cn } from "@/lib/utils"; 7 | import { 8 | NavigationMenu, 9 | NavigationMenuContent, 10 | NavigationMenuItem, 11 | NavigationMenuLink, 12 | NavigationMenuList, 13 | NavigationMenuTrigger, 14 | navigationMenuTriggerStyle, 15 | } from "@/components/ui/navigation-menu"; 16 | 17 | const components: { title: string; href: string; description: string }[] = [ 18 | { 19 | title: "Alert Dialog", 20 | href: "/docs/primitives/alert-dialog", 21 | description: 22 | "A modal dialog that interrupts the user with important content and expects a response.", 23 | }, 24 | { 25 | title: "Hover Card", 26 | href: "/docs/primitives/hover-card", 27 | description: 28 | "For sighted users to preview content available behind a link.", 29 | }, 30 | { 31 | title: "Progress", 32 | href: "/docs/primitives/progress", 33 | description: 34 | "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", 35 | }, 36 | { 37 | title: "Scroll-area", 38 | href: "/docs/primitives/scroll-area", 39 | description: "Visually or semantically separates content.", 40 | }, 41 | { 42 | title: "Tabs", 43 | href: "/docs/primitives/tabs", 44 | description: 45 | "A set of layered sections of content—known as tab panels—that are displayed one at a time.", 46 | }, 47 | { 48 | title: "Tooltip", 49 | href: "/docs/primitives/tooltip", 50 | description: 51 | "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", 52 | }, 53 | ]; 54 | 55 | export function NavigationMenuDemo() { 56 | return ( 57 | 58 | 59 | 60 | Getting started 61 | 62 | 88 | 89 | 90 | 91 | Components 92 | 93 |
    94 | {components.map((component) => ( 95 | 99 | {component.description} 100 | 101 | ))} 102 |
103 |
104 |
105 | 106 | 107 | 108 | Documentation 109 | 110 | 111 | 112 |
113 |
114 | ); 115 | } 116 | 117 | const ListItem = React.forwardRef< 118 | React.ElementRef<"a">, 119 | React.ComponentPropsWithoutRef<"a"> 120 | >(({ className, title, children, ...props }, ref) => { 121 | return ( 122 |
  • 123 | 124 | 131 |
    {title}
    132 |

    133 | {children} 134 |

    135 |
    136 |
    137 |
  • 138 | ); 139 | }); 140 | ListItem.displayName = "ListItem"; 141 | -------------------------------------------------------------------------------- /src/components/PopoverDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@/components/ui/button"; 2 | import { Input } from "@/components/ui/input"; 3 | import { Label } from "@/components/ui/label"; 4 | import { 5 | Popover, 6 | PopoverContent, 7 | PopoverTrigger, 8 | } from "@/components/ui/popover"; 9 | 10 | export function PopoverDemo() { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 |
    18 |
    19 |

    Dimensions

    20 |

    21 | Set the dimensions for the layer. 22 |

    23 |
    24 |
    25 |
    26 | 27 | 32 |
    33 |
    34 | 35 | 40 |
    41 |
    42 | 43 | 48 |
    49 |
    50 | 51 | 56 |
    57 |
    58 |
    59 |
    60 |
    61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /src/components/ProgressDemo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as React from "react"; 4 | 5 | import { Progress } from "@/components/ui/progress"; 6 | 7 | export function ProgressDemo() { 8 | const [progress, setProgress] = React.useState(13); 9 | 10 | React.useEffect(() => { 11 | const timer = setTimeout(() => setProgress(66), 500); 12 | return () => clearTimeout(timer); 13 | }, []); 14 | 15 | return ; 16 | } 17 | -------------------------------------------------------------------------------- /src/components/RadioGroupDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "@/components/ui/label"; 2 | import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; 3 | 4 | export function RadioGroupDemo() { 5 | return ( 6 | 7 |
    8 | 9 | 10 |
    11 |
    12 | 13 | 14 |
    15 |
    16 | 17 | 18 |
    19 |
    20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /src/components/ScrollAreaDemo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { ScrollArea } from "@/components/ui/scroll-area"; 4 | import { Separator } from "@/components/ui/separator"; 5 | 6 | const tags = Array.from({ length: 50 }).map( 7 | (_, i, a) => `v1.2.0-beta.${a.length - i}` 8 | ); 9 | 10 | export function ScrollAreaDemo() { 11 | return ( 12 | 13 |
    14 |

    Tags

    15 | {tags.map((tag) => ( 16 | <> 17 |
    18 | {tag} 19 |
    20 | 21 | 22 | ))} 23 |
    24 |
    25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/components/SelectDemo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { 4 | Select, 5 | SelectContent, 6 | SelectGroup, 7 | SelectItem, 8 | SelectLabel, 9 | SelectTrigger, 10 | SelectValue, 11 | } from "@/components/ui/select"; 12 | 13 | export function SelectDemo() { 14 | return ( 15 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/components/SeparatorDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Separator } from "@/components/ui/separator"; 2 | 3 | export function SeparatorDemo() { 4 | return ( 5 |
    6 |
    7 |

    Radix Primitives

    8 |

    9 | An open-source UI component library. 10 |

    11 |
    12 | 13 |
    14 |
    Blog
    15 | 16 |
    Docs
    17 | 18 |
    Source
    19 |
    20 |
    21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/components/SheetDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@/components/ui/button"; 2 | import { Input } from "@/components/ui/input"; 3 | import { Label } from "@/components/ui/label"; 4 | import { 5 | Sheet, 6 | SheetClose, 7 | SheetContent, 8 | SheetDescription, 9 | SheetFooter, 10 | SheetHeader, 11 | SheetTitle, 12 | SheetTrigger, 13 | } from "@/components/ui/sheet"; 14 | 15 | export function SheetDemo() { 16 | return ( 17 | 18 | 19 | 20 | 21 | 22 | 23 | Edit profile 24 | 25 | Make changes to your profile here. Click save when you are done. 26 | 27 | 28 |
    29 |
    30 | 33 | 34 |
    35 |
    36 | 39 | 40 |
    41 |
    42 | 43 | 44 | 45 | 46 | 47 |
    48 |
    49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/components/SkeletonDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from "@/components/ui/skeleton"; 2 | 3 | export function SkeletonDemo() { 4 | return ( 5 |
    6 | 7 |
    8 | 9 | 10 |
    11 |
    12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/SliderDemo.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import { Slider } from "@/components/ui/slider"; 3 | 4 | type SliderProps = React.ComponentProps; 5 | 6 | export function SliderDemo({ className, ...props }: SliderProps) { 7 | return ( 8 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/SwitchDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "@/components/ui/label"; 2 | import { Switch } from "@/components/ui/switch"; 3 | 4 | export function SwitchDemo() { 5 | return ( 6 |
    7 | 8 | 9 |
    10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/components/TabsDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "@/components/ui/button"; 2 | import { 3 | Card, 4 | CardContent, 5 | CardDescription, 6 | CardFooter, 7 | CardHeader, 8 | CardTitle, 9 | } from "@/components/ui/card"; 10 | import { Input } from "@/components/ui/input"; 11 | import { Label } from "@/components/ui/label"; 12 | import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; 13 | 14 | export function TabsDemo() { 15 | return ( 16 | 17 | 18 | Account 19 | Password 20 | 21 | 22 | 23 | 24 | Account 25 | 26 | Make changes to your account here. Click save when you are done. 27 | 28 | 29 | 30 |
    31 | 32 | 33 |
    34 |
    35 | 36 | 37 |
    38 |
    39 | 40 | 41 | 42 |
    43 |
    44 | 45 | 46 | 47 | Password 48 | 49 | Change your password here. After saving, you will be logged out. 50 | 51 | 52 | 53 |
    54 | 55 | 56 |
    57 |
    58 | 59 | 60 |
    61 |
    62 | 63 | 64 | 65 |
    66 |
    67 |
    68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /src/components/TextAreaDemo.tsx: -------------------------------------------------------------------------------- 1 | import { Textarea } from "@/components/ui/textarea"; 2 | 3 | export function TextareaDemo() { 4 | return