diff --git a/.commitlintrc.json b/.commitlintrc.json new file mode 100644 index 00000000000..c30e5a970ba --- /dev/null +++ b/.commitlintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["@commitlint/config-conventional"] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..ae10a5cce3b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,10 @@ +# editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000000..7612cf7791e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json.schemastore.org/eslintrc", + "root": true, + "extends": [ + "next/core-web-vitals", + "turbo", + "prettier", + "plugin:tailwindcss/recommended" + ], + "plugins": ["tailwindcss"], + "rules": { + "@next/next/no-html-link-for-pages": "off", + "react/jsx-key": "off", + "tailwindcss/no-custom-classname": "off" + }, + "settings": { + "tailwindcss": { + "callees": ["cn"] + }, + "next": { + "rootDir": ["apps/*/"] + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..d1d13f07567 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js + +# testing +coverage + +# next.js +.next/ +out/ +build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# turbo +.turbo + +.contentlayer \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 00000000000..4974c35b430 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000000..0da96d6baa5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx pretty-quick --staged diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..3e775efb0f4 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +auto-install-peers=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..50e4b92aeb8 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v16.18.0 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..304879dc230 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "eslint.workingDirectories": [ + { "pattern": "apps/*/" }, + { "pattern": "packages/*/" } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 00000000000..2bf7d8917f2 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# shadcn/ui + +Beautifully designed components built with Radix UI and Tailwind CSS. + +![hero](apps/www/public/og.jpg) + +## Roadmap + +> **Warning** +> This is work in progress. I'm building this in public. You can follow the progress on Twitter [@shadcn](https://twitter.com/shadcn). + +- [ ] Toast +- [ ] Toggle +- [ ] Toggle Group +- [ ] Toolbar +- [ ] Navigation Menu +- [ ] Figma? + +## Get Started + +Starting a new project? Check out the Next.js template. + +```bash +npx create-next-app -e https://github.com/shadcn/next-template +``` + +### Features + +- Radix UI Primitives +- Tailwind CSS +- Fonts with `@next/font` +- Icons from [Lucide](https://lucide.dev) +- Dark mode with `next-themes` +- Automatic import sorting with `@ianvs/prettier-plugin-sort-imports` + +### Tailwind CSS Features + +- Class merging with `taiwind-merge` +- Animation with `tailwindcss-animate` +- Conditional classes with `clsx` +- Variants with `class-variance-authority` +- Automatic class sorting with `eslint-plugin-tailwindcss` + +## License + +Licensed under the [MIT license](https://github.com/shadcn/ui/blob/main/LICENSE.md). diff --git a/apps/www/.env.example b/apps/www/.env.example new file mode 100644 index 00000000000..66fa3666970 --- /dev/null +++ b/apps/www/.env.example @@ -0,0 +1,4 @@ +# ----------------------------------------------------------------------------- +# App +# ----------------------------------------------------------------------------- +NEXT_PUBLIC_APP_URL=http://localhost:3000 \ No newline at end of file diff --git a/apps/www/.gitignore b/apps/www/.gitignore new file mode 100644 index 00000000000..a5c89361da8 --- /dev/null +++ b/apps/www/.gitignore @@ -0,0 +1,2 @@ +.vscode +.env \ No newline at end of file diff --git a/apps/www/app/docs/[[...slug]]/head.tsx b/apps/www/app/docs/[[...slug]]/head.tsx new file mode 100644 index 00000000000..1516c7f9d02 --- /dev/null +++ b/apps/www/app/docs/[[...slug]]/head.tsx @@ -0,0 +1,25 @@ +import { allDocs } from "contentlayer/generated" + +import MdxHead from "@/components/mdx-head" + +interface HeadProps { + params: { + slug: string[] + } +} + +export default function Head({ params }: HeadProps) { + const slug = params?.slug?.join("/") || "" + const doc = allDocs.find((doc) => doc.slugAsParams === slug) + + if (!doc) { + return null + } + + return ( + + ) +} diff --git a/apps/www/app/docs/[[...slug]]/page.tsx b/apps/www/app/docs/[[...slug]]/page.tsx new file mode 100644 index 00000000000..c08aa2f2561 --- /dev/null +++ b/apps/www/app/docs/[[...slug]]/page.tsx @@ -0,0 +1,80 @@ +import { notFound } from "next/navigation" +import { allDocs } from "contentlayer/generated" + +import "@/styles/mdx.css" +import Link from "next/link" + +import { getTableOfContents } from "@/lib/toc" +import { Icons } from "@/components/icons" +import { Mdx } from "@/components/mdx" +import { DocsPageHeader } from "@/components/page-header" +import { DocsPager } from "@/components/pager" +import { DashboardTableOfContents } from "@/components/toc" +import { Separator } from "@/components/ui/separator" + +interface DocPageProps { + params: { + slug: string[] + } +} + +export async function generateStaticParams(): Promise< + DocPageProps["params"][] +> { + return allDocs.map((doc) => ({ + slug: doc.slugAsParams.split("/"), + })) +} + +export default async function DocPage({ params }: DocPageProps) { + const slug = params?.slug?.join("/") || "" + const doc = allDocs.find((doc) => doc.slugAsParams === slug) + + if (!doc) { + notFound() + } + + const toc = await getTableOfContents(doc.body.raw) + + return ( +
+
+ + {doc.radix ? ( +
+ {doc.radix?.link && ( + + + Radix UI + + )} + {doc.radix?.api && ( + + API Reference + + )} +
+ ) : null} +
+ + + +
+
+
+ +
+
+
+ ) +} diff --git a/apps/www/app/docs/layout.tsx b/apps/www/app/docs/layout.tsx new file mode 100644 index 00000000000..b6269c6bd2a --- /dev/null +++ b/apps/www/app/docs/layout.tsx @@ -0,0 +1,20 @@ +import { docsConfig } from "@/config/docs" +import { DocsSidebarNav } from "@/components/sidebar-nav" +import { ScrollArea } from "@/components/ui/scroll-area" + +interface DocsLayoutProps { + children: React.ReactNode +} + +export default function DocsLayout({ children }: DocsLayoutProps) { + return ( +
+ + {children} +
+ ) +} diff --git a/apps/www/app/head.tsx b/apps/www/app/head.tsx new file mode 100644 index 00000000000..44ccc7dec76 --- /dev/null +++ b/apps/www/app/head.tsx @@ -0,0 +1,43 @@ +import { siteConfig } from "@/config/site" + +export default function Head() { + const url = process.env.NEXT_PUBLIC_APP_URL + const ogUrl = new URL(`${url}/og.jpg`) + + return ( + <> + {`${siteConfig.name} - ${siteConfig.description}`} + + + + + + + + + + + + + + + + + + + ) +} diff --git a/apps/www/app/layout.tsx b/apps/www/app/layout.tsx new file mode 100644 index 00000000000..2e4e2b274c1 --- /dev/null +++ b/apps/www/app/layout.tsx @@ -0,0 +1,44 @@ +import { Inter as FontSans } from "@next/font/google" + +import "@/styles/globals.css" +import { cn } from "@/lib/utils" +import { Analytics } from "@/components/analytics" +import { SiteFooter } from "@/components/site-footer" +import { SiteHeader } from "@/components/site-header" +import { TailwindIndicator } from "@/components/tailwind-indicator" +import { ThemeProvider } from "@/components/theme-provider" + +const fontSans = FontSans({ + subsets: ["latin"], + variable: "--font-sans", +}) + +interface RootLayoutProps { + children: React.ReactNode +} + +export default function RootLayout({ children }: RootLayoutProps) { + return ( + <> + + + + +
+ +
{children}
+ +
+ +
+ + + + + ) +} diff --git a/apps/www/app/page.tsx b/apps/www/app/page.tsx new file mode 100644 index 00000000000..b255fafc095 --- /dev/null +++ b/apps/www/app/page.tsx @@ -0,0 +1,71 @@ +import Link from "next/link" + +import { siteConfig } from "@/config/site" +import { cn } from "@/lib/utils" +import { AppleMusicDemo } from "@/components/apple-music-demo" +import { CopyButton } from "@/components/copy-button" +import { PromoVideo } from "@/components/promo-video" +import { AspectRatio } from "@/components/ui/aspect-ratio" +import { buttonVariants } from "@/components/ui/button" + +export default function IndexPage() { + return ( + <> +
+
+

+ Beautifully designed components
+ built with Radix UI and Tailwind CSS. +

+

+ Accessible and customizable components that you can copy and paste + into your apps. Free. Open Source. And Next.js 13 Ready. +

+
+
+ +
+
+ + Documentation + + + GitHub + +
+            
+              npx create-next-app -e https://github.com/shadcn/next-template
+            
+            
+          
+
+
+

+ You are looking at an early preview. You can follow the progress on{" "} + + Twitter + + . +

+
+
+
+ +
+ + ) +} diff --git a/apps/www/assets/fonts/Inter-Bold.ttf b/apps/www/assets/fonts/Inter-Bold.ttf new file mode 100644 index 00000000000..8e82c70d108 Binary files /dev/null and b/apps/www/assets/fonts/Inter-Bold.ttf differ diff --git a/apps/www/assets/fonts/Inter-Regular.ttf b/apps/www/assets/fonts/Inter-Regular.ttf new file mode 100644 index 00000000000..8d4eebf2066 Binary files /dev/null and b/apps/www/assets/fonts/Inter-Regular.ttf differ diff --git a/apps/www/components/analytics.tsx b/apps/www/components/analytics.tsx new file mode 100644 index 00000000000..164e9b79043 --- /dev/null +++ b/apps/www/components/analytics.tsx @@ -0,0 +1,7 @@ +"use client" + +import { Analytics as VercelAnalytics } from "@vercel/analytics/react" + +export function Analytics() { + return +} diff --git a/apps/www/components/apple-music-demo.tsx b/apps/www/components/apple-music-demo.tsx new file mode 100644 index 00000000000..92e11729ed2 --- /dev/null +++ b/apps/www/components/apple-music-demo.tsx @@ -0,0 +1,745 @@ +import * as React from "react" +import Image from "next/image" +import { + Album, + CreditCard, + Globe, + Keyboard, + LayoutGrid, + Library, + ListMusic, + LogOut, + Mail, + MessageSquare, + Mic, + Mic2, + Music, + Music2, + PlayCircle, + Plus, + PlusCircle, + Podcast, + Radio, + Settings, + User, + UserPlus, + Users, +} from "lucide-react" + +import { cn } from "@/lib/utils" +import { AspectRatio } from "@/components/ui/aspect-ratio" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from "@/components/ui/context-menu" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + Menubar, + MenubarCheckboxItem, + MenubarContent, + MenubarItem, + MenubarLabel, + MenubarMenu, + MenubarRadioGroup, + MenubarRadioItem, + MenubarSeparator, + MenubarShortcut, + MenubarSub, + MenubarSubContent, + MenubarSubTrigger, + MenubarTrigger, +} from "@/components/ui/menubar" +import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area" +import { Separator } from "@/components/ui/separator" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" + +const playlists = [ + "Recently Added", + "Recently Played", + "Top Songs", + "Top Albums", + "Top Artists", + "Logic Discography", + "Bedtime Beats", + "Feeling Happy", + "I miss Y2K Pop", + "Runtober", + "Mellow Days", + "Eminem Essentials", +] + +interface Album { + name: string + artist: string + cover: string +} + +const listenNowAlbums: Album[] = [ + { + name: "Async Awakenings", + artist: "Nina Netcode", + cover: + "https://images.unsplash.com/photo-1547355253-ff0740f6e8c1?w=300&dpr=2&q=80", + }, + { + name: "The Art of Reusability", + artist: "Lena Logic", + cover: + "https://images.unsplash.com/photo-1576075796033-848c2a5f3696?w=300&dpr=2&q=80", + }, + { + name: "Stateful Symphony", + artist: "Beth Binary", + cover: + "https://images.unsplash.com/photo-1606542758304-820b04394ac2?w=300&dpr=2&q=80", + }, + { + name: "React Rendezvous", + artist: "Ethan Byte", + cover: + "https://images.unsplash.com/photo-1598295893369-1918ffaf89a2?w=300&dpr=2&q=80", + }, +] + +const madeForYouAlbums: Album[] = [ + { + name: "Async Awakenings", + artist: "Nina Netcode", + cover: + "https://images.unsplash.com/photo-1580428180098-24b353d7e9d9?w=300&dpr=2&q=80", + }, + { + name: "Stateful Symphony", + artist: "Beth Binary", + cover: + "https://images.unsplash.com/photo-1606542758304-820b04394ac2?w=300&dpr=2&q=80", + }, + { + name: "Stateful Symphony", + artist: "Beth Binary", + cover: + "https://images.unsplash.com/photo-1598062548091-a6fb6a052562?w=300&dpr=2&q=80", + }, + { + name: "The Art of Reusability", + artist: "Lena Logic", + cover: + "https://images.unsplash.com/photo-1626759486966-c067e3f79982?w=300&dpr=2&q=80", + }, + { + name: "Thinking Components", + artist: "Lena Logic", + cover: + "https://images.unsplash.com/photo-1576075796033-848c2a5f3696?w=300&dpr=2&q=80", + }, + { + name: "Functional Fury", + artist: "Beth Binary", + cover: + "https://images.unsplash.com/photo-1606542758304-820b04394ac2?w=300&dpr=2&q=80", + }, + { + name: "React Rendezvous", + artist: "Ethan Byte", + cover: + "https://images.unsplash.com/photo-1598295893369-1918ffaf89a2?w=300&dpr=2&q=80", + }, +] + +export function AppleMusicDemo() { + return ( +
+ + + Music + + About Music + + + Preferences... ⌘, + + + + Hide Music... ⌘H + + + Hide Others... ⇧⌘H + + + + Quit Music ⌘Q + + + + + + File + + + + + New + + + Playlist ⌘N + + + Playlist from Selection ⇧⌘N + + + Smart Playlist... ⌥⌘N + + Playlist Folder + Genius Playlist + + + + Open Stream URL... ⌘U + + + Close Window ⌘W + + + + Library + + Update Cloud Library + Update Genius + + Organize Library... + Export Library... + + Import Playlist... + Export Playlist... + Show Duplicate Items + + Get Album Artwork + Get Track Names + + + + Import... ⌘O + + Burn Playlist to Disc... + + + Show in Finder ⇧⌘R{" "} + + Convert + + Page Setup... + + Print... ⌘P + + + + + Edit + + + Undo ⌘Z + + + Redo ⇧⌘Z + + + + Cut ⌘X + + + Copy ⌘C + + + Paste ⌘V + + + + Select All ⌘A + + + Deselect All ⇧⌘A + + + + Smart Dictation...{" "} + + + + + + Emoji & Symbols{" "} + + + + + + + + View + + Show Playing Next + Show Lyrics + + + Show Status Bar + + + Hide Sidebar + + Enter Full Screen + + + + + Account + + Switch Account + + + Andy + Benoit + Luis + + + Manage Famliy... + + Add Account... + + + +
+
+
+ +
+
+ +
+ + + Music + + Podcasts + + Live + + +
+

Welcome back

+
+ + + + + + My Account + + + + + Profile + ⇧⌘P + + + + Billing + ⌘B + + + + Settings + ⌘S + + + + Keyboard shortcuts + ⌘K + + + + + + + Team + + + + + Invite users + + + + + + Email + + + + Message + + + + + More... + + + + + + + + + Log out + ⇧⌘Q + + + +
+ +
+
+

+ Listen Now +

+

+ Top picks for you. Updated daily. +

+
+
+ +
+ +
+ {listenNowAlbums.map((album) => ( + + ))} +
+
+
+

+ Made for You +

+

+ Your personal playlists. Updated daily. +

+
+ +
+ + +
+ {madeForYouAlbums.map((album) => ( + + ))} +
+ +
+
+
+ +
+
+

+ New Episodes +

+

+ Your favorite podcasts. Updated daily. +

+
+
+ +
+
+ +

+ No episodes added +

+

+ You have not added any podcasts. Add one below. +

+ + + + + + + Add Podcast + + Copy and paste the podcast feed URL to import. + + +
+
+ + +
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+ ) +} + +interface AlbumArtworkProps extends React.HTMLAttributes { + album: Album + aspectRatio?: number +} + +function AlbumArtwork({ + album, + aspectRatio = 3 / 4, + className, + ...props +}: AlbumArtworkProps) { + return ( +
+ + + + {album.name} + + + + Add to Library + + Add to Playlist + + + + New Playlist + + + {playlists.map((playlist) => ( + + {playlist} + + ))} + + + + Play Next + Play Later + Create Station + + Like + Share + + +
+

{album.name}

+

+ {album.artist} +

+
+
+ ) +} + +interface DemoIndicatorProps extends React.HTMLAttributes {} + +export function DemoIndicator({ className }: DemoIndicatorProps) { + return ( + + + + + ) +} diff --git a/apps/www/components/callout.tsx b/apps/www/components/callout.tsx new file mode 100644 index 00000000000..328f1805d7d --- /dev/null +++ b/apps/www/components/callout.tsx @@ -0,0 +1,31 @@ +import { cn } from "@/lib/utils" + +interface CalloutProps { + icon?: string + children?: React.ReactNode + type?: "default" | "warning" | "danger" +} + +export function Callout({ + children, + icon, + type = "default", + ...props +}: CalloutProps) { + return ( +
+ {icon && {icon}} +
{children}
+
+ ) +} diff --git a/apps/www/components/card.tsx b/apps/www/components/card.tsx new file mode 100644 index 00000000000..b1db16bae3a --- /dev/null +++ b/apps/www/components/card.tsx @@ -0,0 +1,38 @@ +import Link from "next/link" + +import { cn } from "@/lib/utils" + +interface CardProps extends React.HTMLAttributes { + href?: string + disabled?: boolean +} + +export function Card({ + href, + className, + children, + disabled, + ...props +}: CardProps) { + return ( +
+
+
+ {children} +
+
+ {href && ( + + View + + )} +
+ ) +} diff --git a/apps/www/components/code-block-wrapper.tsx b/apps/www/components/code-block-wrapper.tsx new file mode 100644 index 00000000000..62689a6c3f3 --- /dev/null +++ b/apps/www/components/code-block-wrapper.tsx @@ -0,0 +1,56 @@ +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible" + +interface CodeBlockProps extends React.HTMLAttributes { + expandButtonTitle?: string +} + +export function CodeBlockWrapper({ + expandButtonTitle = "View Code", + className, + children, + ...props +}: CodeBlockProps) { + const [isOpened, setIsOpened] = React.useState(false) + + return ( + +
+ +
+ {children} +
+
+
+ + + +
+
+
+ ) +} diff --git a/apps/www/components/component-card.tsx b/apps/www/components/component-card.tsx new file mode 100644 index 00000000000..f2d00c7e814 --- /dev/null +++ b/apps/www/components/component-card.tsx @@ -0,0 +1,21 @@ +import React from "react" + +import { cn } from "@/lib/utils" +import { AspectRatio } from "@/components/ui/aspect-ratio" + +export function ComponentCard({ + className, + ...props +}: React.HTMLAttributes) { + return ( + +
+ + ) +} diff --git a/apps/www/components/component-example.tsx b/apps/www/components/component-example.tsx new file mode 100644 index 00000000000..9e2a867ff5e --- /dev/null +++ b/apps/www/components/component-example.tsx @@ -0,0 +1,77 @@ +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" +import { CopyButton, CopyWithClassNames } from "@/components/copy-button" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" + +interface ComponentExampleProps extends React.HTMLAttributes { + extractClassname?: boolean + extractedClassNames?: string +} + +export function ComponentExample({ + children, + className, + extractClassname, + extractedClassNames, + ...props +}: ComponentExampleProps) { + const [Example, Code, ...Children] = React.Children.toArray( + children + ) as React.ReactElement[] + + const codeString = React.useMemo(() => { + if ( + typeof Code?.props["data-rehype-pretty-code-fragment"] !== "undefined" + ) { + const [, Button] = React.Children.toArray( + Code.props.children + ) as React.ReactElement[] + return Button?.props?.value || null + } + }, [Code]) + + return ( +
+ +
+ + Preview + Code + + {extractedClassNames ? ( + + ) : ( + codeString && + )} +
+ +
+ {Example} +
+
+ +
+
+ {Code} +
+ {Children && ( +
+ {Children} +
+ )} +
+
+
+
+ ) +} diff --git a/apps/www/components/component-source.tsx b/apps/www/components/component-source.tsx new file mode 100644 index 00000000000..d940d2aa465 --- /dev/null +++ b/apps/www/components/component-source.tsx @@ -0,0 +1,21 @@ +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" +import { CodeBlockWrapper } from "@/components/code-block-wrapper" + +interface ComponentSourceProps extends React.HTMLAttributes { + src: string +} + +export function ComponentSource({ children, className }: ComponentSourceProps) { + return ( + + {children} + + ) +} diff --git a/apps/www/components/copy-button.tsx b/apps/www/components/copy-button.tsx new file mode 100644 index 00000000000..e1ddffa7abe --- /dev/null +++ b/apps/www/components/copy-button.tsx @@ -0,0 +1,190 @@ +"use client" + +import * as React from "react" +import { DropdownMenuTriggerProps } from "@radix-ui/react-dropdown-menu" +import { NpmCommands } from "types/unist" + +import { cn } from "@/lib/utils" +import { Icons } from "@/components/icons" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +interface CopyButtonProps extends React.HTMLAttributes { + value: string + src?: string +} + +async function copyToClipboardWithMeta( + value: string, + meta?: Record +) { + navigator.clipboard.writeText(value) + + if (meta) { + await fetch("/api/log", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + event: "copy_primitive", + data: { + primitive: meta?.component, + }, + }), + }) + } +} + +export function CopyButton({ + value, + className, + src, + ...props +}: CopyButtonProps) { + const [hasCopied, setHasCopied] = React.useState(false) + + React.useEffect(() => { + setTimeout(() => { + setHasCopied(false) + }, 2000) + }, [hasCopied]) + + return ( + + ) +} + +interface CopyWithClassNamesProps extends DropdownMenuTriggerProps { + value: string + classNames: string + className: string +} + +export function CopyWithClassNames({ + value, + classNames, + className, + ...props +}: CopyWithClassNamesProps) { + const [hasCopied, setHasCopied] = React.useState(false) + + React.useEffect(() => { + setTimeout(() => { + setHasCopied(false) + }, 2000) + }, [hasCopied]) + + const copyToClipboard = React.useCallback((value: string) => { + copyToClipboardWithMeta(value) + setHasCopied(true) + }, []) + + return ( + + + {hasCopied ? ( + + ) : ( + + )} + Copy + + + copyToClipboard(value)}> + + Component + + copyToClipboard(classNames)}> + + Classname + + + + ) +} + +interface CopyNpmCommandButtonProps extends DropdownMenuTriggerProps { + commands: Required +} + +export function CopyNpmCommandButton({ + commands, + className, + ...props +}: CopyNpmCommandButtonProps) { + const [hasCopied, setHasCopied] = React.useState(false) + + React.useEffect(() => { + setTimeout(() => { + setHasCopied(false) + }, 2000) + }, [hasCopied]) + + const copyCommand = React.useCallback((value: string) => { + copyToClipboardWithMeta(value) + setHasCopied(true) + }, []) + + return ( + + + {hasCopied ? ( + + ) : ( + + )} + Copy + + + copyCommand(commands.__npmCommand__)}> + + npm + + copyCommand(commands.__yarnCommand__)}> + + yarn + + copyCommand(commands.__pnpmCommand__)}> + + pnpm + + + + ) +} diff --git a/apps/www/components/examples/.eslintrc.json b/apps/www/components/examples/.eslintrc.json new file mode 100644 index 00000000000..6579e1b264d --- /dev/null +++ b/apps/www/components/examples/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/eslintrc", + "rules": { + "react/no-unescaped-entities": "off" + } +} diff --git a/apps/www/components/examples/accordion/demo.tsx b/apps/www/components/examples/accordion/demo.tsx new file mode 100644 index 00000000000..680c6042322 --- /dev/null +++ b/apps/www/components/examples/accordion/demo.tsx @@ -0,0 +1,32 @@ +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion" + +export function AccordionDemo() { + return ( + + + Is it accessible? + + Yes. It adheres to the WAI-ARIA design pattern. + + + + Is it styled? + + Yes. It comes with default styles that matches the other components' + aesthetic. + + + + Is it animated? + + Yes. It's animated by default, but you can disable it if you prefer. + + + + ) +} diff --git a/apps/www/components/examples/alert-dialog/demo.tsx b/apps/www/components/examples/alert-dialog/demo.tsx new file mode 100644 index 00000000000..a50a2e9e8d7 --- /dev/null +++ b/apps/www/components/examples/alert-dialog/demo.tsx @@ -0,0 +1,37 @@ +"use client" + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog" +import { Button } from "@/components/ui/button" + +export function AlertDialogDemo() { + return ( + + + + + + + Are you sure absolutely sure? + + This action cannot be undone. This will permanently delete your + account and remove your data from our servers. + + + + Cancel + Continue + + + + ) +} diff --git a/apps/www/components/examples/aspect-ratio/demo.tsx b/apps/www/components/examples/aspect-ratio/demo.tsx new file mode 100644 index 00000000000..939733ab3aa --- /dev/null +++ b/apps/www/components/examples/aspect-ratio/demo.tsx @@ -0,0 +1,18 @@ +"use client" + +import Image from "next/image" + +import { AspectRatio } from "@/components/ui/aspect-ratio" + +export function AspectRatioDemo() { + return ( + + Photo by Alvaro Pinot + + ) +} diff --git a/apps/www/components/examples/avatar/demo.tsx b/apps/www/components/examples/avatar/demo.tsx new file mode 100644 index 00000000000..1f5a138b22a --- /dev/null +++ b/apps/www/components/examples/avatar/demo.tsx @@ -0,0 +1,12 @@ +"use client" + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" + +export function AvatarDemo() { + return ( + + + CN + + ) +} diff --git a/apps/www/components/examples/button/demo.tsx b/apps/www/components/examples/button/demo.tsx new file mode 100644 index 00000000000..3c564b6aabe --- /dev/null +++ b/apps/www/components/examples/button/demo.tsx @@ -0,0 +1,5 @@ +import { Button } from "@/components/ui/button" + +export function ButtonDemo() { + return +} diff --git a/apps/www/components/examples/button/ghost.tsx b/apps/www/components/examples/button/ghost.tsx new file mode 100644 index 00000000000..eda0a3315c5 --- /dev/null +++ b/apps/www/components/examples/button/ghost.tsx @@ -0,0 +1,5 @@ +import { Button } from "@/components/ui/button" + +export function ButtonGhost() { + return +} diff --git a/apps/www/components/examples/button/link.tsx b/apps/www/components/examples/button/link.tsx new file mode 100644 index 00000000000..e0f0138a892 --- /dev/null +++ b/apps/www/components/examples/button/link.tsx @@ -0,0 +1,5 @@ +import { Button } from "@/components/ui/button" + +export function ButtonLink() { + return +} diff --git a/apps/www/components/examples/button/loading.tsx b/apps/www/components/examples/button/loading.tsx new file mode 100644 index 00000000000..6d9d240431d --- /dev/null +++ b/apps/www/components/examples/button/loading.tsx @@ -0,0 +1,12 @@ +import { Loader2 } from "lucide-react" + +import { Button } from "@/components/ui/button" + +export function ButtonLoading() { + return ( + + ) +} diff --git a/apps/www/components/examples/button/outline.tsx b/apps/www/components/examples/button/outline.tsx new file mode 100644 index 00000000000..a392ee77c2d --- /dev/null +++ b/apps/www/components/examples/button/outline.tsx @@ -0,0 +1,5 @@ +import { Button } from "@/components/ui/button" + +export function ButtonOutline() { + return +} diff --git a/apps/www/components/examples/button/subtle.tsx b/apps/www/components/examples/button/subtle.tsx new file mode 100644 index 00000000000..d499fac0e2c --- /dev/null +++ b/apps/www/components/examples/button/subtle.tsx @@ -0,0 +1,5 @@ +import { Button } from "@/components/ui/button" + +export function ButtonSubtle() { + return +} diff --git a/apps/www/components/examples/button/with-icon.tsx b/apps/www/components/examples/button/with-icon.tsx new file mode 100644 index 00000000000..1e7ddce1433 --- /dev/null +++ b/apps/www/components/examples/button/with-icon.tsx @@ -0,0 +1,11 @@ +import { Mail } from "lucide-react" + +import { Button } from "@/components/ui/button" + +export function ButtonWithIcon() { + return ( + + ) +} diff --git a/apps/www/components/examples/checkbox/demo.tsx b/apps/www/components/examples/checkbox/demo.tsx new file mode 100644 index 00000000000..f3406096003 --- /dev/null +++ b/apps/www/components/examples/checkbox/demo.tsx @@ -0,0 +1,17 @@ +"use client" + +import { Checkbox } from "@/components/ui/checkbox" + +export function CheckboxDemo() { + return ( +
+ + +
+ ) +} diff --git a/apps/www/components/examples/checkbox/disabled.tsx b/apps/www/components/examples/checkbox/disabled.tsx new file mode 100644 index 00000000000..9ad610ef5c1 --- /dev/null +++ b/apps/www/components/examples/checkbox/disabled.tsx @@ -0,0 +1,17 @@ +"use client" + +import { Checkbox } from "@/components/ui/checkbox" + +export function CheckboxDisabled() { + return ( +
+ + +
+ ) +} diff --git a/apps/www/components/examples/checkbox/with-text.tsx b/apps/www/components/examples/checkbox/with-text.tsx new file mode 100644 index 00000000000..8a8cc6eb73f --- /dev/null +++ b/apps/www/components/examples/checkbox/with-text.tsx @@ -0,0 +1,22 @@ +"use client" + +import { Checkbox } from "@/components/ui/checkbox" + +export function CheckboxWithText() { + return ( +
+ +
+ +

+ You agree to our Terms of Service and Privacy Policy. +

+
+
+ ) +} diff --git a/apps/www/components/examples/collapsible/demo.tsx b/apps/www/components/examples/collapsible/demo.tsx new file mode 100644 index 00000000000..6166ed5d7d6 --- /dev/null +++ b/apps/www/components/examples/collapsible/demo.tsx @@ -0,0 +1,46 @@ +"use client" + +import * as React from "react" +import { ChevronsUpDown, Plus, X } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible" + +export function CollapsibleDemo() { + const [isOpen, setIsOpen] = React.useState(false) + + return ( + +
+

+ @peduarte starred 3 repositories +

+ + + +
+
+ @radix-ui/primitives +
+ +
+ @radix-ui/colors +
+
+ @stitches/react +
+
+
+ ) +} diff --git a/apps/www/components/examples/context-menu/demo.tsx b/apps/www/components/examples/context-menu/demo.tsx new file mode 100644 index 00000000000..92a976ece5d --- /dev/null +++ b/apps/www/components/examples/context-menu/demo.tsx @@ -0,0 +1,89 @@ +"use client" + +import { + Cloud, + CreditCard, + Github, + Keyboard, + LifeBuoy, + LogOut, + Mail, + MessageSquare, + Plus, + PlusCircle, + Settings, + User, + UserPlus, + Users, +} from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + ContextMenu, + ContextMenuCheckboxItem, + ContextMenuContent, + ContextMenuGroup, + ContextMenuItem, + ContextMenuLabel, + ContextMenuPortal, + ContextMenuRadioGroup, + ContextMenuRadioItem, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuTrigger, +} from "@/components/ui/context-menu" + +export function ContextMenuDemo() { + return ( + + + Right click here + + + + Back + ⌘[ + + + Forward + ⌘] + + + Reload + ⌘R + + + More Tools + + + Save Page As... + ⇧⌘S + + Create Shortcut... + Name Window... + + Developer Tools + + + + + Show Bookmarks Bar + ⌘⇧B + + Show Full URLs + + + People + + + Pedro Duarte + + Colm Tuite + + + + ) +} diff --git a/apps/www/components/examples/dialog/demo.tsx b/apps/www/components/examples/dialog/demo.tsx new file mode 100644 index 00000000000..e04d2412058 --- /dev/null +++ b/apps/www/components/examples/dialog/demo.tsx @@ -0,0 +1,49 @@ +"use client" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" + +export function DialogDemo() { + return ( + + + + + + + Edit profile + + Make changes to your profile here. Click save when you're done. + + +
+
+ + +
+
+ + +
+
+ + + +
+
+ ) +} diff --git a/apps/www/components/examples/dropdown-menu/checkboxes.tsx b/apps/www/components/examples/dropdown-menu/checkboxes.tsx new file mode 100644 index 00000000000..2afa795b406 --- /dev/null +++ b/apps/www/components/examples/dropdown-menu/checkboxes.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import { DropdownMenuCheckboxItemProps } from "@radix-ui/react-dropdown-menu" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +type Checked = DropdownMenuCheckboxItemProps["checked"] + +export function DropdownMenuCheckboxes() { + const [showStatusBar, setShowStatusBar] = React.useState(true) + const [showActivityBar, setShowActivityBar] = React.useState(false) + const [showPanel, setShowPanel] = React.useState(false) + + return ( + + + + + + Appearance + + + Status Bar + + + Activity Bar + + + Panel + + + + ) +} diff --git a/apps/www/components/examples/dropdown-menu/demo.tsx b/apps/www/components/examples/dropdown-menu/demo.tsx new file mode 100644 index 00000000000..a01307978b3 --- /dev/null +++ b/apps/www/components/examples/dropdown-menu/demo.tsx @@ -0,0 +1,124 @@ +"use client" + +import { + Cloud, + CreditCard, + Github, + Keyboard, + LifeBuoy, + LogOut, + Mail, + MessageSquare, + Plus, + PlusCircle, + Settings, + User, + UserPlus, + Users, +} from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +export function DropdownMenuDemo() { + return ( + + + + + + My Account + + + + + Profile + ⇧⌘P + + + + Billing + ⌘B + + + + Settings + ⌘S + + + + Keyboard shortcuts + ⌘K + + + + + + + Team + + + + + Invite users + + + + + + Email + + + + Message + + + + + More... + + + + + + + New Team + ⌘+T + + + + + + GitHub + + + + Support + + + + API + + + + + Log out + ⇧⌘Q + + + + ) +} diff --git a/apps/www/components/examples/dropdown-menu/radio-group.tsx b/apps/www/components/examples/dropdown-menu/radio-group.tsx new file mode 100644 index 00000000000..33c73747c13 --- /dev/null +++ b/apps/www/components/examples/dropdown-menu/radio-group.tsx @@ -0,0 +1,37 @@ +"use client" + +import * as React from "react" +import { DropdownMenuCheckboxItemProps } from "@radix-ui/react-dropdown-menu" + +import { Button } from "@/components/ui/button" +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" + +export function DropdownMenuRadioGroupDemo() { + const [position, setPosition] = React.useState("bottom") + + return ( + + + + + + Panel Position + + + Top + Bottom + Right + + + + ) +} diff --git a/apps/www/components/examples/hover-card/demo.tsx b/apps/www/components/examples/hover-card/demo.tsx new file mode 100644 index 00000000000..ec01d36d2ee --- /dev/null +++ b/apps/www/components/examples/hover-card/demo.tsx @@ -0,0 +1,39 @@ +import { CalendarDays } from "lucide-react" + +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Button } from "@/components/ui/button" +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from "@/components/ui/hover-card" + +export function HoverCardDemo() { + return ( + + + + + +
+ + + VC + +
+

@nextjs

+

+ The React Framework – created and maintained by @vercel. +

+
+ {" "} + + Joined December 2021 + +
+
+
+
+
+ ) +} diff --git a/apps/www/components/examples/index.tsx b/apps/www/components/examples/index.tsx new file mode 100644 index 00000000000..a406751085a --- /dev/null +++ b/apps/www/components/examples/index.tsx @@ -0,0 +1,117 @@ +import { AccordionDemo } from "@/components/examples/accordion/demo" +import { AlertDialogDemo } from "@/components/examples/alert-dialog/demo" +import { AspectRatioDemo } from "@/components/examples/aspect-ratio/demo" +import { AvatarDemo } from "@/components/examples/avatar/demo" +import { ButtonDemo } from "@/components/examples/button/demo" +import { ButtonGhost } from "@/components/examples/button/ghost" +import { ButtonLink } from "@/components/examples/button/link" +import { ButtonLoading } from "@/components/examples/button/loading" +import { ButtonOutline } from "@/components/examples/button/outline" +import { ButtonSubtle } from "@/components/examples/button/subtle" +import { ButtonWithIcon } from "@/components/examples/button/with-icon" +import { CheckboxDemo } from "@/components/examples/checkbox/demo" +import { CheckboxDisabled } from "@/components/examples/checkbox/disabled" +import { CheckboxWithText } from "@/components/examples/checkbox/with-text" +import { CollapsibleDemo } from "@/components/examples/collapsible/demo" +import { ContextMenuDemo } from "@/components/examples/context-menu/demo" +import { DialogDemo } from "@/components/examples/dialog/demo" +import { DropdownMenuCheckboxes } from "@/components/examples/dropdown-menu/checkboxes" +import { DropdownMenuDemo } from "@/components/examples/dropdown-menu/demo" +import { DropdownMenuRadioGroupDemo } from "@/components/examples/dropdown-menu/radio-group" +import { HoverCardDemo } from "@/components/examples/hover-card/demo" +import { InputDemo } from "@/components/examples/input/demo" +import { InputDisabled } from "@/components/examples/input/disabled" +import { InputWithButton } from "@/components/examples/input/with-button" +import { InputWithLabel } from "@/components/examples/input/with-label" +import { InputWithText } from "@/components/examples/input/with-text" +import { LabelDemo } from "@/components/examples/label/demo" +import { MenubarDemo } from "@/components/examples/menubar/demo" +import { PopoverDemo } from "@/components/examples/popover/demo" +import { ProgressDemo } from "@/components/examples/progress/demo" +import { RadioGroupDemo } from "@/components/examples/radio-group/demo" +import { ScrollAreaDemo } from "@/components/examples/scroll-area/demo" +import { SelectDemo } from "@/components/examples/select/demo" +import { SeparatorDemo } from "@/components/examples/separator/demo" +import { SliderDemo } from "@/components/examples/slider/demo" +import { SwitchDemo } from "@/components/examples/switch/demo" +import { TabsDemo } from "@/components/examples/tabs/demo" +import { TextareaDemo } from "@/components/examples/textarea/demo" +import { TextareaDisabled } from "@/components/examples/textarea/disabled" +import { TextareaWithButton } from "@/components/examples/textarea/with-button" +import { TextareaWithLabel } from "@/components/examples/textarea/with-label" +import { TextareaWithText } from "@/components/examples/textarea/with-text" +import { TooltipDemo } from "@/components/examples/tooltip/demo" +import { TypographyBlockquote } from "@/components/examples/typography/blockquote" +import { TypographyDemo } from "@/components/examples/typography/demo" +import { TypographyH1 } from "@/components/examples/typography/h1" +import { TypographyH2 } from "@/components/examples/typography/h2" +import { TypographyH3 } from "@/components/examples/typography/h3" +import { TypographyH4 } from "@/components/examples/typography/h4" +import { TypographyInlineCode } from "@/components/examples/typography/inline-code" +import { TypographyLarge } from "@/components/examples/typography/large" +import { TypographyLead } from "@/components/examples/typography/lead" +import { TypographyList } from "@/components/examples/typography/list" +import { TypographyP } from "@/components/examples/typography/p" +import { TypographySmall } from "@/components/examples/typography/small" +import { TypographySubtle } from "@/components/examples/typography/subtle" +import { TypographyTable } from "@/components/examples/typography/table" + +export const examples = { + AccordionDemo, + AlertDialogDemo, + AspectRatioDemo, + AvatarDemo, + ButtonDemo, + ButtonGhost, + ButtonLink, + ButtonLoading, + ButtonOutline, + ButtonSubtle, + ButtonWithIcon, + CheckboxDemo, + CheckboxDisabled, + CheckboxWithText, + CollapsibleDemo, + ContextMenuDemo, + DialogDemo, + DropdownMenuCheckboxes, + DropdownMenuDemo, + DropdownMenuRadioGroupDemo, + HoverCardDemo, + InputDemo, + InputDisabled, + InputWithButton, + InputWithLabel, + InputWithText, + LabelDemo, + MenubarDemo, + PopoverDemo, + ProgressDemo, + RadioGroupDemo, + ScrollAreaDemo, + SelectDemo, + SeparatorDemo, + SliderDemo, + SwitchDemo, + TabsDemo, + TextareaDemo, + TextareaDisabled, + TextareaWithButton, + TextareaWithLabel, + TextareaWithText, + TooltipDemo, + TypographyBlockquote, + TypographyDemo, + TypographyH1, + TypographyH2, + TypographyH3, + TypographyH4, + TypographyInlineCode, + TypographyLarge, + TypographyLead, + TypographyList, + TypographyP, + TypographySmall, + TypographySubtle, + TypographyTable, +} diff --git a/apps/www/components/examples/input/demo.tsx b/apps/www/components/examples/input/demo.tsx new file mode 100644 index 00000000000..8cbad785465 --- /dev/null +++ b/apps/www/components/examples/input/demo.tsx @@ -0,0 +1,5 @@ +import { Input } from "@/components/ui/input" + +export function InputDemo() { + return +} diff --git a/apps/www/components/examples/input/disabled.tsx b/apps/www/components/examples/input/disabled.tsx new file mode 100644 index 00000000000..8c5861aaebe --- /dev/null +++ b/apps/www/components/examples/input/disabled.tsx @@ -0,0 +1,5 @@ +import { Input } from "@/components/ui/input" + +export function InputDisabled() { + return +} diff --git a/apps/www/components/examples/input/with-button.tsx b/apps/www/components/examples/input/with-button.tsx new file mode 100644 index 00000000000..cc16f3aedb5 --- /dev/null +++ b/apps/www/components/examples/input/with-button.tsx @@ -0,0 +1,11 @@ +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" + +export function InputWithButton() { + return ( +
+ + +
+ ) +} diff --git a/apps/www/components/examples/input/with-label.tsx b/apps/www/components/examples/input/with-label.tsx new file mode 100644 index 00000000000..807bc691dda --- /dev/null +++ b/apps/www/components/examples/input/with-label.tsx @@ -0,0 +1,11 @@ +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" + +export function InputWithLabel() { + return ( +
+ + +
+ ) +} diff --git a/apps/www/components/examples/input/with-text.tsx b/apps/www/components/examples/input/with-text.tsx new file mode 100644 index 00000000000..6c870a96e1e --- /dev/null +++ b/apps/www/components/examples/input/with-text.tsx @@ -0,0 +1,12 @@ +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" + +export function InputWithText() { + return ( +
+ + +

Enter your email address.

+
+ ) +} diff --git a/apps/www/components/examples/label/demo.tsx b/apps/www/components/examples/label/demo.tsx new file mode 100644 index 00000000000..67b106330a3 --- /dev/null +++ b/apps/www/components/examples/label/demo.tsx @@ -0,0 +1,13 @@ +import { Checkbox } from "@/components/ui/checkbox" +import { Label } from "@/components/ui/label" + +export function LabelDemo() { + return ( +
+
+ + +
+
+ ) +} diff --git a/apps/www/components/examples/menubar/demo.tsx b/apps/www/components/examples/menubar/demo.tsx new file mode 100644 index 00000000000..eaaf1ddc4ce --- /dev/null +++ b/apps/www/components/examples/menubar/demo.tsx @@ -0,0 +1,109 @@ +"use client" + +import { + Menubar, + MenubarCheckboxItem, + MenubarContent, + MenubarItem, + MenubarMenu, + MenubarRadioGroup, + MenubarRadioItem, + MenubarSeparator, + MenubarShortcut, + MenubarSub, + MenubarSubContent, + MenubarSubTrigger, + MenubarTrigger, +} from "@/components/ui/menubar" + +export function MenubarDemo() { + return ( + + + File + + + New Tab ⌘T + + + New Window ⌘N + + New Incognito Window + + + Share + + Email link + Messages + Notes + + + + + Print... ⌘P + + + + + Edit + + + Undo ⌘Z + + + Redo ⇧⌘Z + + + + Find + + Search the web + + Find... + Find Next + Find Previous + + + + Cut + Copy + Paste + + + + View + + Always Show Bookmarks Bar + + Always Show Full URLs + + + + Reload ⌘R + + + Force Reload ⇧⌘R + + + Toggle Fullscreen + + Hide Sidebar + + + + Profiles + + + Andy + Benoit + Luis + + + Edit... + + Add Profile... + + + + ) +} diff --git a/apps/www/components/examples/popover/demo.tsx b/apps/www/components/examples/popover/demo.tsx new file mode 100644 index 00000000000..1672e56ab0a --- /dev/null +++ b/apps/www/components/examples/popover/demo.tsx @@ -0,0 +1,69 @@ +"use client" + +import { Settings2 } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover" + +export function PopoverDemo() { + return ( + + + + + +
+
+

Dimensions

+

+ Set the dimensions for the layer. +

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ ) +} diff --git a/apps/www/components/examples/progress/demo.tsx b/apps/www/components/examples/progress/demo.tsx new file mode 100644 index 00000000000..3dda0445cc7 --- /dev/null +++ b/apps/www/components/examples/progress/demo.tsx @@ -0,0 +1,16 @@ +"use client" + +import * as React from "react" + +import { Progress } from "@/components/ui/progress" + +export function ProgressDemo() { + const [progress, setProgress] = React.useState(13) + + React.useEffect(() => { + const timer = setTimeout(() => setProgress(66), 500) + return () => clearTimeout(timer) + }, []) + + return +} diff --git a/apps/www/components/examples/radio-group/demo.tsx b/apps/www/components/examples/radio-group/demo.tsx new file mode 100644 index 00000000000..eb2b448ec59 --- /dev/null +++ b/apps/www/components/examples/radio-group/demo.tsx @@ -0,0 +1,23 @@ +"use client" + +import { Label } from "@/components/ui/label" +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" + +export function RadioGroupDemo() { + return ( + +
+ + +
+
+ + +
+
+ + +
+
+ ) +} diff --git a/apps/www/components/examples/scroll-area/demo.tsx b/apps/www/components/examples/scroll-area/demo.tsx new file mode 100644 index 00000000000..636c79e7217 --- /dev/null +++ b/apps/www/components/examples/scroll-area/demo.tsx @@ -0,0 +1,26 @@ +import * as React from "react" + +import { ScrollArea } from "@/components/ui/scroll-area" +import { Separator } from "@/components/ui/separator" + +const tags = Array.from({ length: 50 }).map( + (_, i, a) => `v1.2.0-beta.${a.length - i}` +) + +export function ScrollAreaDemo() { + return ( + +
+

Tags

+ {tags.map((tag) => ( + +
+ {tag} +
+ +
+ ))} +
+
+ ) +} diff --git a/apps/www/components/examples/select/demo.tsx b/apps/www/components/examples/select/demo.tsx new file mode 100644 index 00000000000..46a8fe4e462 --- /dev/null +++ b/apps/www/components/examples/select/demo.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" + +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectSeparator, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" + +export function SelectDemo() { + return ( + + ) +} diff --git a/apps/www/components/examples/separator/demo.tsx b/apps/www/components/examples/separator/demo.tsx new file mode 100644 index 00000000000..bc31794aafa --- /dev/null +++ b/apps/www/components/examples/separator/demo.tsx @@ -0,0 +1,22 @@ +import { Separator } from "@/components/ui/separator" + +export function SeparatorDemo() { + return ( +
+
+

Radix Primitives

+

+ An open-source UI component library. +

+
+ +
+
Blog
+ +
Docs
+ +
Source
+
+
+ ) +} diff --git a/apps/www/components/examples/slider/demo.tsx b/apps/www/components/examples/slider/demo.tsx new file mode 100644 index 00000000000..5ad3612729e --- /dev/null +++ b/apps/www/components/examples/slider/demo.tsx @@ -0,0 +1,5 @@ +import { Slider } from "@/components/ui/slider" + +export function SliderDemo() { + return +} diff --git a/apps/www/components/examples/switch/demo.tsx b/apps/www/components/examples/switch/demo.tsx new file mode 100644 index 00000000000..f336a69dba6 --- /dev/null +++ b/apps/www/components/examples/switch/demo.tsx @@ -0,0 +1,11 @@ +import { Label } from "@/components/ui/label" +import { Switch } from "@/components/ui/switch" + +export function SwitchDemo() { + return ( +
+ + +
+ ) +} diff --git a/apps/www/components/examples/tabs/demo.tsx b/apps/www/components/examples/tabs/demo.tsx new file mode 100644 index 00000000000..ea4d2a5df6a --- /dev/null +++ b/apps/www/components/examples/tabs/demo.tsx @@ -0,0 +1,51 @@ +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" + +export function TabsDemo() { + return ( + + + Account + Password + + +

+ Make changes to your account here. Click save when you're done. +

+
+
+ + +
+
+ + +
+
+
+ +
+
+ +

+ Change your password here. After saving, you'll be logged out. +

+
+
+ + +
+
+ + +
+
+
+ +
+
+
+ ) +} diff --git a/apps/www/components/examples/textarea/demo.tsx b/apps/www/components/examples/textarea/demo.tsx new file mode 100644 index 00000000000..6ddc09ef464 --- /dev/null +++ b/apps/www/components/examples/textarea/demo.tsx @@ -0,0 +1,5 @@ +import { Textarea } from "@/components/ui/textarea" + +export function TextareaDemo() { + return