Skip to content

Commit

Permalink
feat: CSS variables and CLI (shadcn-ui#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
shadcn authored Apr 17, 2023
1 parent d3cc7a3 commit a703c6f
Show file tree
Hide file tree
Showing 395 changed files with 8,873 additions and 16,057 deletions.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "shadcn/ui" }],
"changelog": ["@changesets/changelog-github", { "repo": "shadcn-ui" }],
"commit": false,
"fixed": [],
"linked": [],
Expand Down
11 changes: 9 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@
},
"settings": {
"tailwindcss": {
"callees": ["cn"]
"callees": ["cn"],
"config": "tailwind.config.cjs"
},
"next": {
"rootDir": ["apps/*/"]
}
}
},
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser"
}
]
}
37 changes: 2 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,9 @@ Accessible and customizable components that you can copy and paste into your app

![hero](apps/www/public/og.jpg)

## Roadmap
## Documentation

> **Warning**
> This is work in progress. I'm building this in public. You can follow the progress on Twitter [@shadcn](https://twitter.com/shadcn).
- [ ] Toggle Group
- [ ] Toolbar
- [x] ~Toast~
- [x] ~Toggle~
- [x] ~Navigation Menu~
- [x] ~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 `tailwind-merge`
- Animation with `tailwindcss-animate`
- Conditional classes with `clsx`
- Variants with `class-variance-authority`
- Automatic class sorting with `eslint-plugin-tailwindcss`
Visit http://ui.shadcn.com/docs to view the documentation.

## License

Expand Down
2 changes: 1 addition & 1 deletion apps/www/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -----------------------------------------------------------------------------
# App
# -----------------------------------------------------------------------------
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_URL=http://localhost:3001
25 changes: 0 additions & 25 deletions apps/www/app/docs/[[...slug]]/head.tsx

This file was deleted.

135 changes: 101 additions & 34 deletions apps/www/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,74 @@ import { notFound } from "next/navigation"
import { allDocs } from "contentlayer/generated"

import "@/styles/mdx.css"
import type { Metadata } from "next"
import Link from "next/link"
import { ChevronRight } from "lucide-react"
import Balancer from "react-wrap-balancer"

import { siteConfig } from "@/config/site"
import { getTableOfContents } from "@/lib/toc"
import { absoluteUrl, cn } from "@/lib/utils"
import { badgeVariants } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Icons } from "@/components/icons"
import { Mdx } from "@/components/mdx"
import { DocsPageHeader } from "@/components/page-header"
import { Mdx } from "@/components/mdx-components"
import { DocsPager } from "@/components/pager"
import { DashboardTableOfContents } from "@/components/toc"
import { Separator } from "@/components/ui/separator"

interface DocPageProps {
params: {
slug: string[]
}
}

async function getDocFromParams({ params }: DocPageProps) {
const slug = params.slug?.join("/") || ""
const doc = allDocs.find((doc) => doc.slugAsParams === slug)

if (!doc) {
null
}

return doc
}

export async function generateMetadata({
params,
}: DocPageProps): Promise<Metadata> {
const doc = await getDocFromParams({ params })

if (!doc) {
return {}
}

return {
title: doc.title,
description: doc.description,
openGraph: {
title: doc.title,
description: doc.description,
type: "article",
url: absoluteUrl(doc.slug),
images: [
{
url: siteConfig.ogImage,
width: 1200,
height: 630,
alt: siteConfig.name,
},
],
},
twitter: {
card: "summary_large_image",
title: doc.title,
description: doc.description,
images: [siteConfig.ogImage],
creator: "@shadcn",
},
}
}

export async function generateStaticParams(): Promise<
DocPageProps["params"][]
> {
Expand All @@ -27,8 +79,7 @@ export async function generateStaticParams(): Promise<
}

export default async function DocPage({ params }: DocPageProps) {
const slug = params?.slug?.join("/") || ""
const doc = allDocs.find((doc) => doc.slugAsParams === slug)
const doc = await getDocFromParams({ params })

if (!doc) {
notFound()
Expand All @@ -37,41 +88,57 @@ export default async function DocPage({ params }: DocPageProps) {
const toc = await getTableOfContents(doc.body.raw)

return (
<main className="relative py-6 lg:gap-10 lg:py-10 xl:grid xl:grid-cols-[1fr_300px]">
<main className="relative py-6 lg:gap-10 lg:py-8 xl:grid xl:grid-cols-[1fr_300px]">
<div className="mx-auto w-full min-w-0">
<DocsPageHeader heading={doc.title} text={doc.description}>
{doc.radix ? (
<div className="flex items-center space-x-2 pt-4">
{doc.radix?.link && (
<Link
href={doc.radix.link}
target="_blank"
rel="noreferrer"
className="inline-flex items-center rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-900 transition-colors hover:bg-slate-700 hover:text-slate-50"
>
<Icons.radix className="mr-1 h-3 w-3" />
Radix UI
</Link>
)}
{doc.radix?.api && (
<Link
href={doc.radix.api}
target="_blank"
rel="noreferrer"
className="inline-flex items-center rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-900 transition-colors hover:bg-slate-700 hover:text-slate-50"
>
API Reference
</Link>
)}
</div>
) : null}
</DocsPageHeader>
<div className="mb-4 flex items-center space-x-1 text-sm text-muted-foreground">
<div className="overflow-hidden text-ellipsis whitespace-nowrap">
Docs
</div>
<ChevronRight className="h-4 w-4" />
<div className="font-medium text-foreground">{doc.title}</div>
</div>
<div className="space-y-2">
<h1 className={cn("scroll-m-20 text-4xl font-bold tracking-tight")}>
{doc.title}
</h1>
{doc.description && (
<p className="text-lg text-muted-foreground">
<Balancer>{doc.description}</Balancer>
</p>
)}
</div>
{doc.radix ? (
<div className="flex items-center space-x-2 pt-4">
{doc.radix?.link && (
<Link
href={doc.radix.link}
target="_blank"
rel="noreferrer"
className={cn(badgeVariants({ variant: "secondary" }))}
>
<Icons.radix className="mr-1 h-3 w-3" />
Radix UI
</Link>
)}
{doc.radix?.api && (
<Link
href={doc.radix.api}
target="_blank"
rel="noreferrer"
className={cn(badgeVariants({ variant: "secondary" }))}
>
API Reference
</Link>
)}
</div>
) : null}
<Separator className="my-4 md:my-6" />
<Mdx code={doc.body.code} />
<Separator className="my-4 md:my-6" />
<DocsPager doc={doc} />
</div>
<div className="hidden text-sm xl:block">
<div className="sticky top-16 -mt-10 max-h-[calc(var(--vh)-4rem)] overflow-y-auto pt-10">
<div className="sticky top-16 -mt-10 max-h-[calc(var(--vh)-4rem)] overflow-y-auto pt-6">
<DashboardTableOfContents toc={toc} />
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions apps/www/app/docs/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ interface DocsLayoutProps {

export default function DocsLayout({ children }: DocsLayoutProps) {
return (
<div className="flex-1 items-start md:grid md:grid-cols-[220px_minmax(0,1fr)] md:gap-6 lg:grid-cols-[240px_minmax(0,1fr)] lg:gap-10">
<aside className="fixed top-14 z-30 hidden h-[calc(100vh-3.5rem)] w-full shrink-0 overflow-y-auto border-r border-r-slate-100 dark:border-r-slate-700 md:sticky md:block">
<ScrollArea className="pr-6 lg:py-10">
<div className="container flex-1 items-start md:grid md:grid-cols-[220px_minmax(0,1fr)] md:gap-6 lg:grid-cols-[240px_minmax(0,1fr)] lg:gap-10">
<aside className="fixed top-14 z-30 -ml-2 hidden h-[calc(100vh-3.5rem)] w-full shrink-0 overflow-y-auto border-r md:sticky md:block">
<ScrollArea className="py-6 pr-6 lg:py-8">
<DocsSidebarNav items={docsConfig.sidebarNav} />
</ScrollArea>
</aside>
Expand Down
71 changes: 71 additions & 0 deletions apps/www/app/examples/authentication/components/user-auth-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Icons } from "@/components/icons"

interface UserAuthFormProps extends React.HTMLAttributes<HTMLDivElement> {}

export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
const [isLoading, setIsLoading] = React.useState<boolean>(false)

async function onSubmit(event: React.SyntheticEvent) {
event.preventDefault()
setIsLoading(true)

setTimeout(() => {
setIsLoading(false)
}, 3000)
}

return (
<div className={cn("grid gap-6", className)} {...props}>
<form onSubmit={onSubmit}>
<div className="grid gap-2">
<div className="grid gap-1">
<Label className="sr-only" htmlFor="email">
Email
</Label>
<Input
id="email"
placeholder="[email protected]"
type="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
disabled={isLoading}
/>
</div>
<Button disabled={isLoading}>
{isLoading && (
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
)}
Sign In with Email
</Button>
</div>
</form>
<div className="relative">
<div className="absolute inset-0 flex items-center">
<span className="w-full border-t" />
</div>
<div className="relative flex justify-center text-xs uppercase">
<span className="bg-white px-2 text-muted-foreground">
Or continue with
</span>
</div>
</div>
<Button variant="outline" type="button" disabled={isLoading}>
{isLoading ? (
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
) : (
<Icons.gitHub className="mr-2 h-4 w-4" />
)}{" "}
Github
</Button>
</div>
)
}
Loading

0 comments on commit a703c6f

Please sign in to comment.