Compare commits

..

154 Commits

Author SHA1 Message Date
github-actions[bot]
59b2cc8142 chore(release): version packages (#2420)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-14 16:06:43 +04:00
Vulcan-Coder
0e721be8dd Update models.ts (#2374)
Fixed the space at the start of the UUID
2024-01-14 11:27:26 +00:00
shadcn
7640ef7bbc feat: add support for adding devDependencies in the cli (#2419)
* feat(cli): add support for install devDependencies

* chore: add changeset
2024-01-14 15:21:57 +04:00
김태강
8f3b28f50f feat(components): add "use client" directive to carousel, resizable component (#2319)
[Reopen a PR that was accidentally closed.](https://github.com/shadcn-ui/ui/pull/2233)
carousel, resizable components to be used by the app router, a "use client" directive is required.
2024-01-07 09:24:23 +00:00
vinay
73be841162 [Docs] Update CLI options while configuring components.json (#2283)
New Line added to the docs.
Just for the consistency.

![image](https://github.com/shadcn-ui/ui/assets/94120295/e0da71c1-72d1-4e5d-bba9-54634a9d0e31)
2024-01-07 09:23:35 +00:00
Nuriman Quddus
ad32fdeb7d fix: typo on carousel import (#2216)
# What's changed

- [x] Fixed the typo on carousel component

before fix: "@/registry/new-york/ui/carousel"
after fix: "@/components/ui/carousel"

this is ease the user to copy paste without error
2024-01-07 08:04:54 +00:00
Clarence
2dd7864007 fix: Github case correction (#2268) 2024-01-07 07:59:20 +00:00
Andrew Qiao
5d37bae1b8 fix(www): incorrect toggle aria labels and values (#2163)
- some `Toggle` and `ToggleGroup` demos had incorrect `aria-label` or `value` props
2024-01-07 07:49:26 +00:00
Chase
4b59cb812e fix(docs): Resizable panel direction should be horizontal (#2295)
In the [resizable documentation](https://ui.shadcn.com/docs/components/resizable) the handle example shows a horizontal handle but the code example has `direction="vertical"` when it should be `direction="horizontal"`

<img width="745" alt="Screenshot 2024-01-05 at 9 34 43 AM" src="https://github.com/shadcn-ui/ui/assets/7241069/68c21241-e0c7-41b1-81d7-579306149520">
2024-01-07 07:43:51 +00:00
Anshul Kanwar
4b200ebf59 docs: typo in drawer, dialog and sheet (#2306) 2024-01-07 07:26:21 +00:00
Tilak Thapa
33795426dd Fix: Add e.preventDefault() to prevent page reload (#2278)
Fixes #2277

Add `e.preventDefault()` to prevent page reload in mail component

![image](https://github.com/shadcn-ui/ui/assets/106688422/d1373e8f-0c46-4f2e-8caf-2fcd2076b2fb)
2024-01-07 07:17:47 +00:00
github-actions[bot]
fb614ac292 chore(release): version packages (#2269)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-01-02 22:42:42 +04:00
shadcn
be580dbf76 feat(cli): add support for custom ui dir (#2266)
* feat(cli): add support for custom ui dir

* docs(www): update docs for aliases.ui

* chore: add changeset
2024-01-02 22:32:15 +04:00
shadcn
98859e7b1c feat(www): update keyboard handling for command menu (#2264) 2024-01-02 11:48:27 +04:00
kal07
6b523b60db Update pagination.mdx (#2191)
fix the Nextjs import example
2023-12-26 14:23:04 +00:00
Ghribi Ouassim
e3d5377a3e Added new label for mobile navigation (#2182)
- Update the `mobile-nav` component and added `new` label if `item.label` is present in the `docsConfig.sidebarNav`.

![image](https://github.com/shadcn-ui/ui/assets/70029024/e19eddf4-22bb-4afe-8158-ea795ea0c5c0)
2023-12-26 14:17:40 +00:00
shadcn
f60945c252 fix: add tailwind.prefix to schema (#2200)
* fix: add tailwind.prefix to schema

* fix(www): format
2023-12-26 18:00:26 +04:00
Rishabh
5eb33f7830 docs(pagination): wrong import path of components in pagination usage (#2180)
This PR:

Fixes: #2150
2023-12-26 13:35:19 +00:00
Rishabh
f6fef4a2ed docs(drawer): missing drawer footer import in drawer usage example (#2169)
This PR:

- Fixes:  #2168
2023-12-24 05:47:02 +00:00
arshad
f6f64ce773 Update: Rename 'ResizableGroup' to 'ResizablePanelGroup' in Documentation (#2166)
### Overview
This pull request updates the documentation to reflect the correct component name, changing `ResizableGroup` to `ResizablePanelGroup`. This change ensures consistency and correctness in the documentation, aiding developers in correctly implementing the component.

### Changes Made
- In the code examples within the documentation, `ResizableGroup` has been renamed to `ResizablePanelGroup`.
- This change is applied to both horizontal and vertical orientation examples.

### Additional Information
- These changes are confined to documentation and do not alter the actual implementation or functionality of the components in question.

Please review the changes for accuracy and merge if appropriate. Thanks!
2023-12-24 05:40:05 +00:00
Nader Ferjani
7ce4414445 docs: typo in drawer (#2164)
Co-authored-by: shadcn <m@shadcn.com>
2023-12-24 09:35:26 +04:00
shadcn
319c7c55cc fix(www): mail icon size (#2173) 2023-12-24 09:32:46 +04:00
shadcn
57d404b5d3 feat: new components (#2144) 2023-12-22 23:36:59 +04:00
github-actions[bot]
6145dd8118 chore(release): version packages (#1756)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-12-22 21:05:24 +04:00
Bereket Engida
4fb98d520f feat(cli): add support for custom Tailwind prefix transformer (#770)
* feat(cli): add support for custom Tailwind prefix

* fix(cli): add tw prefix on classes applied in the css file

* feat(cli): add support for custom tailwind prefix

* chore: add changeset

* style(shadcn-ui): code format

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-12-22 01:42:40 +04:00
ocavue
1cf5fad881 fix(toast): replace MAX_VALUE with MAX_SAFE_INTEGER (#1982)
This PR replaces the maximum id from `Number.MAX_VALUE` to `Number.MAX_SAFE_INTEGER` in `use-toast.ts`. Considering how JS stores numbers, it's unsafe to plus one if the number is larger than `Number.MAX_SAFE_INTEGER`. Here is an example:

```js 
> let num

> num = Number.MAX_VALUE - 1
> num + 1 === num
true

> num = Number.MAX_SAFE_INTEGER - 1
> num + 1 === num
false
```
2023-11-21 12:13:44 +00:00
Js Park
6f3050248c docs(www): update installation of Astro (#1958)
- The latest version of Astro generates `tailwind.config.mjs` file instead of `tailwind.config.cjs`.
- The `index.astro` file is located in `/src/pages`.
2023-11-19 07:24:12 +00:00
Gravy59
1903eb94a8 fix(www): typo in metric cards (#1975) 2023-11-19 11:16:27 +04:00
Danilo Britto
9f3ae7746f docs(www): add indeterminate state checkboxes on all data table demos and code examples (#1959)
Co-authored-by: shadcn <m@shadcn.com>
2023-11-19 11:15:44 +04:00
Dimitri POSTOLOV
c579e9232c add missing return Update page.tsx (#1952) 2023-11-17 00:20:36 +04:00
兰天游
08018ed623 feat: fix for column grouping (#945) 2023-11-12 19:12:40 +00:00
Max Wiseman
1db90baaf2 feat(toggle-group): add toggle-group component (#1547)
* feat: added toggle-group component

* fix(components): ran build:registry script

* fix(components): fixed colors in toggle-group
- Dark mode border color is now consistent with the toggle component

* fix(components): fixed component.json toggle-group
- Added the content field to `components.json` for toggle-group
- Ran build:registry again

* feat(toggle-group): simplify implementation

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-11-12 23:03:14 +04:00
shadcn
3dc6207e97 chore: build registry 2023-11-12 22:13:40 +04:00
Yahor Barkouski
5d2373fb7a fix(www): update faker version, reduce int() deprecation (#1832)
* fix: update faker version, reduce int() deprecation

* chore: pnpm format:write

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-11-12 22:12:58 +04:00
Peeranat Danaidusadeekul
e67c0d4507 style(command): add import type for Command component (#1490)
* style: add import type for Command component

* style(code): format code

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-11-12 22:12:16 +04:00
Mubin Ansari
147206c168 Remove Redundant md:w-full class in DialogPrimitive.Content in dialog and alert-dialog (#1640)
closes #1639
2023-11-12 11:09:14 +00:00
Thomas Alberola
e6e9a6772b Move className overwrite of AccordionContent to the children component (#1670)
In order to have a smooth opening of the accordion, moving the `AccordionContent` `className` overwrite to the children wrapper component allow Radix to calculate correctly the animation and execute a smooth animation in case of `className` on the `AccordionContent` component.

Possibly related to https://github.com/shadcn-ui/ui/issues/944
2023-11-12 10:56:52 +00:00
Chongyi Zheng
1ae9ffcf58 chore: upgrade @radix-ui/react-select to 2.0.0 (#1688) 2023-11-12 10:32:03 +00:00
shadcn
8fad64a854 feat(select): add scroll up and down button 2023-11-12 14:25:35 +04:00
shadcn
7527ff490a Merge branch 'main' into main 2023-11-12 13:49:12 +04:00
Tanish Baansal
3a279a2766 refactor(calendar): updated css so date doesn't show up selected twice in DatePickerComponent (#1852)
React Day Picker also has a unique styling distinction that designates the `day_outside` dates as unselected, and the selection of `day_outside` only highlights the dates in the next month. This PR will fix this issue - https://github.com/shadcn-ui/ui/issues/1762 and help with a cleaner UX 

  
<br/>

| Old Date Range Picker  | New Date Range Picker           |
| ---------------------- | ---------------------- |
| ![old](https://github.com/shadcn-ui/ui/assets/7449806/42e9448f-9e38-486c-b65c-cf00ec1ec7c7) | ![new](https://github.com/shadcn-ui/ui/assets/7449806/804f83d7-1b74-474c-8992-2d6d844dfb35) |

<br/>

#### React Day Picker
<img width="444" alt="image" src="https://github.com/shadcn-ui/ui/assets/7449806/aaeae160-b38c-4c16-bb2d-66898cf290d3">
2023-11-12 09:36:12 +00:00
Gravy59
51c8c3d798 fix(#1686): remove redundant children prop (#1717)
This pull request resolves #1686.

## Rationale for this PR

This PR affects the code for `RadioGroupItem` in both styles by removing the `children` prop from the component. The children prop is automatically passed in by the use of the spread operator (`...props`) and is redundant because it is never used in the component.

This PR shouldn't affect tests, representation, etc. and is merely a cosmetic change. There is no urgent need to merge this.
2023-11-12 09:28:07 +00:00
William Frank Monroy Mamani
53f211b043 docs: updated contributing guidelines to easily contribute (#1830)
## Explanation
Added detailed info to clone and setup the project to contribute.

Following the PR #1650 and suggestion of @shadcn.  Thanks!
2023-11-12 07:57:25 +00:00
Shubhdeep Chhabra
a2ed2883ac fix(alert-dialog): removed unused children prop (#1828) 2023-11-12 11:46:21 +04:00
Greg
66c7f6d73b fix(scroll-area): horizontal scroll bar not visible (#1829)
PRs #1515 and #1296 interfere with each other and cause the horizontal scroll bar to not be visible. This removes the conditional `flex-1`, however you could also remove `flex-col` to achieve the same result.

before:

https://github.com/shadcn-ui/ui/assets/9381099/6514de2e-e353-4d0b-bd24-aff79e0d5161

after:


https://github.com/shadcn-ui/ui/assets/9381099/3205baad-569b-4096-8dcd-9beb794de536
2023-11-12 07:36:35 +00:00
shadcn
fc3d8288f7 ci: update tasks name to make debug easier (#1932) 2023-11-12 11:30:00 +04:00
shadcn
6e399abdb4 fix(table): update style for table footer (#1931)
* fix(table): update table footer style

* chore: run registry

* style: fix docs
2023-11-12 11:20:18 +04:00
Martini
3c22784a98 docs(www): Fix typo (#1853) 2023-11-12 10:18:34 +04:00
Cole Cline
c82a6fab5f docs(www): Missing import statement (#1877)
Added missing import statement in fonts example in Next.js installation docs
2023-11-12 10:17:56 +04:00
Innei
3fccfeb301 fix(switch): change width unit to rem (#1891)
Signed-off-by: Innei <i@innei.in>
Co-authored-by: shadcn <m@shadcn.com>
2023-11-12 10:17:07 +04:00
Kevin Mok
42e8eaf7cb docs(www): add remix dark mode docs (#1920)
* docs(www): add remix dark mode docs

* docs(www): add modification to tailwindcss file
2023-11-12 10:16:22 +04:00
Michael Stramel
d250109cc4 fix(www): destructive contrast increase (#1899) 2023-11-06 18:30:44 +04:00
iaingymware
ef73e591c8 Merge branch 'main' into main 2023-10-24 19:50:21 +01:00
miquelvir
c6917799ce docs(card): remove unused line #1652 (#1798)
Fixes #1652
2023-10-24 12:27:21 +00:00
iaingymware
b4efc8aa4d Merge branch 'main' into main 2023-10-24 12:15:43 +01:00
miquelvir
35f776d38c Fix combobox examples using labels as value (#1788)
Fix #1785
2023-10-21 14:09:57 +00:00
Akshay Sharma
5cadc5e983 fix(www): update twitter icon to X (#1551)
* refactor(icon.tsx): twitter icon updated to latest version X icon

* refactor(icon.tsx): twitter icon updated to latest version X icon

* refactor(icons.tsx): added the same changes to the icon for X twitter icon

* refactor(icons.tsx): change the formating of the code

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-10-21 18:03:31 +04:00
Greg
e0782b328b docs(scroll-area): add example for horizontal scroll area (#1515)
Adds documentation to the `<ScrollArea>` component for creating a scroll area with a horizontal scrollbar. There is also a commit to fix the improper sizing of a horizontal scroll bars.

Before:
https://github.com/shadcn-ui/ui/assets/9381099/a8b512f1-37f7-4107-a9fa-42a26e124696

After:
https://github.com/shadcn-ui/ui/assets/9381099/480f881c-b0fe-4b1b-9472-c533135e6769
2023-10-21 13:54:16 +00:00
Bumsik Kim
cf0dadafce fix(example): Prevent hydration error in music example (#1569)
<DisalogTrigger> should have asChild when a button used.
2023-10-21 12:58:30 +00:00
/raj
5877dcd21a docs(www): bunx scripts run using bun instead of node (#1590)
* fix: using bun to initialize project works now

* style(www): format write

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-10-21 16:47:21 +04:00
Stefan Schulz
95be4835b1 fix(calendar): showOutsideDays=false (#1731)
showOutsideDays=false will shift the missing days of a month to the start of the row (cause of 'flex' in classnames: row), to fix it, we can use the same height and width in a cell as in a day

Co-authored-by: shadcn <m@shadcn.com>
2023-10-21 16:47:00 +04:00
Karan Janthe
5a13def46d fix: updated error msg for jsconfig in cli (#1696)
* fix: updated error msg for jsconfig in cli

* chore: add changeset

* style(cli): format

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-10-21 16:35:55 +04:00
kevinmitch14
b8810caac7 fix: remove invalid collapsible prop (#496)
only available when type="single"

Co-authored-by: shadcn <m@shadcn.com>
2023-10-21 16:28:00 +04:00
Peeranat Danaidusadeekul
24ec36ee7b docs: add missing tailwind config in Astro install (#1264)
* docs: add missing tailwind config in Astro install

* style: prettier format

---------

Co-authored-by: Peeranat Danaidusadeekul <ppeeranat.d@skooldio.com>
Co-authored-by: shadcn <m@shadcn.com>
2023-10-21 16:26:28 +04:00
onurhan
dd94aa936f fix(docs): present useForm when copy form (#1486)
When I tried it after the attached issue, I realized;
For someone who's absolutely copying and pasting form the guide, this would give an error, as useForm is not imported in the guide. So I fixed that.

Related issue: https://github.com/shadcn-ui/ui/issues/1482

Fix #1482
2023-10-21 12:16:22 +00:00
IDRISSI HAMZA
44f35d55b0 fix(components): fix text wrapping issue in buttons (#1548)
## What does this PR do?

This pull request resolves an issue where the button text wraps onto the next line in specific screen sizes when the text contains two or more words. By applying the whitespace-nowrap utility class to the button element, the text now remains on a single line, even on screens with limited space. This enhancement ensures a consistent and visually pleasing user experience across various devices :

### Before (Get Started Button)
![before](https://github.com/shadcn-ui/ui/assets/97639117/50c8211d-2ed7-46d0-8ab2-d4c565d0d6f3)


### After  (Get Started Button)
![after](https://github.com/shadcn-ui/ui/assets/97639117/0f9f7e68-31e8-4011-a2ca-d7e59b3690ee)





This problem arises in other projects utilizing Shadcn, and this pull request addresses and resolves the issue, as demonstrated in the Cal.com project example:

### Before (Set Up Button)
![button-before](https://github.com/calcom/cal.com/assets/97639117/8f588a53-411a-4e9d-95df-76bd42d480d7)

### After  (Set Up Button)
![button-fixed](https://github.com/calcom/cal.com/assets/97639117/4c74e77a-a2cd-4b0c-87ee-a82dbefc23eb)
2023-10-21 12:09:10 +00:00
N8
958a0fdb18 docs: ✏️ Add defaultValues to input in form examples (#1610)
Fixes: https://github.com/shadcn-ui/ui/issues/1609
2023-10-21 11:57:26 +00:00
Lachlan Heywood
6b660033fb fix(components): remove className from dialog portals (#1606)
Fixes #1595, #1644

This PR changes the components that use the `DialogPortal` element to be aliases rather than components that pass a className prop.

The `DialogPortalProps` type from `@radix/react-dialog` recently had a patch update that probably should have been a minor or maybe a major update which is causing a few people to see the error `Property 'className' does not exist on type 'DialogPortalProps'`.

Since the `DialogPortal` component doesn't actually output any DOM elements, it never technically supported the `className` prop and the fact that it surfaced that prop was really a bug.

The `AlertDialog` and `Dialog` components were updated in #1603, but the `Sheet` component still references `className` which is resolved in this PR.
2023-10-21 11:56:31 +00:00
iaingymware
dac5a0bd2c Merge branch 'main' into main 2023-10-20 19:46:52 +01:00
Olle Månsson
648ddde3a2 Fix support rule in site-header.tsx (#1628)
Fixes https://github.com/shadcn-ui/ui/issues/1627 if that is desired.
2023-10-19 18:10:45 +00:00
Luka Hartwig
4ec8a67dab Support tailwind.config.ts (#1247)
Fixes #659
Fixes #633

Create Next App is using `tailwind.config.ts` in the TypeScript template. Since this is a very common use case it would be nice to preserve the type safety of the file.

I added new templates for TypeScript files. I see there is an issue #1073 which asks for ESM support as well. This is not included in this PR.

I also fixed the type error in the keyframes that is also handled in #636
2023-10-19 17:44:11 +00:00
CamTheGoblin
9091dcdc1b docs(install): Clarify & Match tsconfig Edits (#1642)
This is a small update to the installation instructions for some of the frameworks to make the instructions on editing the tsconfig file consistant across the frameworks, and remove some potentially confusing wording (if people read too fast...like me). 

Mainly applying the gatsby tsconfig instructions to vite and astro, as it is the most clear. 
Additionally changed the wording from:
```
 Add the code below to the compilerOptions...
```
to:
```
Add the following code to the compilerOptions...
```
to avoid people easily misreading it as "add the code **below the** compilerOptions".
2023-10-19 17:27:01 +00:00
Josiah Hawkins
33f89e9654 docs: remove unused imports (#1661)
- Remove unused import from Alert Default example
- Remove unused imports from Alert Destructive example
- Remove unused imports from Dropdown Menu Radio Group example
2023-10-19 17:20:34 +00:00
shadcn
545423c93b chore: add kodiak 2023-10-19 21:12:17 +04:00
shadcn
82528a62a0 Merge branch 'main' into main 2023-10-18 21:37:12 +04:00
Deveesh Shetty
14abbd94b5 fix(www): removes redundant class-name from H2 component (#1703)
* chore: removes redundant class from typography-h2

* chore: remove class from new york style

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-10-18 21:33:24 +04:00
iaingymware
cf54b6fa71 Merge branch 'main' into main 2023-10-16 10:20:47 +01:00
Caíque de Castro Soares da Silva
46f247c47f style(shadcn-ui): use space instead of tab on config fixture (#1707)
* style: use space instead of tab on config fixture

* style: fix identation on template script

* chore(shadcn-ui): add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-10-16 13:16:55 +04:00
iaingymware
beb0281ca2 Merge branch 'main' into main 2023-10-16 10:15:44 +01:00
Iain Wandless
a54ade1b98 Merge branch 'main' of https://github.com/iaingymware/ui 2023-10-16 10:09:31 +01:00
Iain Wandless
11c1bc2cb9 feat(select): update newyork to use radix icons 2023-10-16 10:09:24 +01:00
Robert Soriano
4083876e80 docs: update Remix config to use ESM (#1710)
* docs(remix): replace postcss config sample to use export default

* docs(remix): replace tailwind config sample to use export default

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-10-16 12:56:08 +04:00
alex
0176754ff2 docs(www): add astro dark mode implementation (#1755)
* docs(www): add astro dark mode implementation

* docs(www): reduce redundancy in mode toggle
2023-10-16 12:37:25 +04:00
iaingymware
1be434bc64 Merge branch 'main' into main 2023-10-15 21:12:50 +01:00
shadcn
2a346ede51 feat(www): add custom close button example (#1753) 2023-10-15 16:28:57 +04:00
shadcn
82c56f9503 docs(www): add fonts docs (#1752) 2023-10-15 15:37:25 +04:00
Iain Wandless
f68798e50b Revert "feat(select): update registry"
This reverts commit b37fc17f04.
2023-10-10 14:15:08 +01:00
Iain Wandless
b37fc17f04 feat(select): update registry 2023-10-10 14:11:32 +01:00
Iain Wandless
d6063c5769 feat(select): scrollable with large datasets
newyork ui
2023-10-10 14:09:32 +01:00
Iain Wandless
ef9fa600a5 feat(select): scrollable with large datasets
update to default ui
2023-10-10 14:01:43 +01:00
shadcn
43c4023ed8 chore: rebuild registry 2023-10-03 18:47:47 +04:00
github-actions[bot]
c765635e13 chore(release): version packages (#1663)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-10-03 18:39:32 +04:00
shadcn
95a9673b1e minify cli (#1662)
* chore(shadcn-ui): minify build

* chore: add changeset
2023-10-03 18:20:58 +04:00
Oguz Kazkayasi
617cdd0e77 docs(www): framework is changed to language at language search example (#1646)
Co-authored-by: shadcn <m@shadcn.com>
2023-10-03 17:38:10 +04:00
shadcn
1536b7824e feat: export portal and overlay for alert-dialog, dialog and sheet (#1660) 2023-10-03 17:12:40 +04:00
Rohid
524e4b8b95 fix(alert-dialog): update portal component (#1603) 2023-10-03 17:02:31 +04:00
Diego Franchina
1f16cf4728 fix(scroll-area): added conditional flex-1 (#1296) 2023-09-25 15:29:05 +04:00
Rohan Godha
4f8d768e59 docs(www): add bun support for installation commands (#1445)
* feat(www): add bun support for commands

* chore: remove changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-09-21 17:30:29 +04:00
Shoaib Ahmed
c0deeac0d0 fix(table): add relative class to handle overflow issue (#1370) 2023-09-19 19:17:38 +04:00
github-actions[bot]
897376329b chore(release): version packages (#1556)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-19 17:14:39 +04:00
shadcn
d3d52fc687 docs(cli): update link to documentation (#1555)
* docs(cli): update link to documentation

* chore: add changeset
2023-09-19 16:52:45 +04:00
shadcn
4d0864a5c2 Merge branch 'main' of github.com:shadcn/ui 2023-09-19 16:36:06 +04:00
shadcn
e8f58932bd chore: update repo for changeset 2023-09-19 16:35:50 +04:00
shadcn
2f0dbca221 feat(cli): do not ask for confirmation (#1554)
* feat(cli): do not confirm

* chore: add changeset
2023-09-19 16:25:57 +04:00
Paul Ebose
58d012e342 feat(cli): add overwrite confirmation for existing components (#973)
* feat(cli):  add overwrite confirmation for existing components

* fix(cli): handle overwrite for multiple items

* chore: add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-09-19 15:57:19 +04:00
Shishir
963114e118 feat(cli): support adding all components via CLI (#1033)
* feat: support adding all components via CLI

`shadcn-ui add --all`

This was manually tested to work as expected.

* chore: run prettier

* fix(cli): rename to all

* chore: add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-09-19 07:37:35 +04:00
Ayhan
0a4286500e fix(cli): handle ts file extension (#1466)
Co-authored-by: shadcn <m@shadcn.com>
2023-09-19 07:23:07 +04:00
Santi Dalmasso
ae845788f6 fix(cli): deduplicate classNames in applyColorMapping (#1089)
* fix(cli): deduplicate classNames in applyColorMapping

* refactor: simplify applyColorMapping return

* chore: add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-09-19 07:04:57 +04:00
oasisy
ccb2d695a7 fix(www): enable input editing in the dialog demo (#1428)
Co-authored-by: shadcn <m@shadcn.com>
2023-09-18 17:35:27 +04:00
Abderrahim Guerfi
b838ffe8cc docs(www): add missing prop to ThemeProvider (#1447)
Co-authored-by: shadcn <m@shadcn.com>
2023-09-18 16:47:58 +04:00
Robert Soriano
7ce6c495bd fix(www): rename DataTableFacetedFilter interface (#1438)
Co-authored-by: shadcn <m@shadcn.com>
2023-09-18 16:31:21 +04:00
MD
c9ca64d2b9 docs(www): update manual.mdx (#1471)
Fix file name

Co-authored-by: shadcn <m@shadcn.com>
2023-09-18 16:25:26 +04:00
Arjun Raj
4bb9e9de53 docs(www): update cli add options (#1484) 2023-09-18 16:23:47 +04:00
Nikhar Pandya
c21ecfb665 docs(www): update contrubuting.md and next.mdx (#1343)
* docs: Update CONTRIBUTING.md

added commit convention section to the contribution docs.

* docs: Update next.mdx for dark mode

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-08-31 17:01:36 +04:00
sanka
613ec3583f docs(www): update dark-mode for vite (#1118)
Co-authored-by: sanka <sanka.s@fidenz.com>
Co-authored-by: shadcn <m@shadcn.com>
2023-08-26 14:45:34 +04:00
Diego Franchina
170d3c087c fix(scroll-area): missing key prop error (#1295)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-25 07:24:04 +04:00
kevinmitch14
4b0fbe27fa fix(www): don't allow empty chat messages (#1137)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-25 06:51:19 +04:00
rcrosbourne
c34193cd34 docs(www): add Laravel install docs (#1279)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-24 20:01:29 +04:00
Deveesh Shetty
88fdc989e9 chore(www): remove unneccesary imports (#1311)
* chore: remove uneccesary imports

* chore: remove from new-york style

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-08-24 09:26:12 +04:00
K-Sato
4506822389 chore: remove a duplicate call in init.test (#1319)
* chore: remove duplicate call in init.test

* chore: add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-08-24 09:14:20 +04:00
jspark
33a5fc7966 docs(www): fix typo (#1270) 2023-08-17 21:39:49 +04:00
Dani
33b77e2f31 fix(toast): toast add missing text color class (#1162)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-17 15:27:23 +04:00
shadcn
e3769277d8 docs: update CONTRIBUTING.md 2023-08-17 15:00:08 +04:00
shadcn
3992a7b19c docs: add contributing guide (#1266) 2023-08-17 14:59:22 +04:00
shadcn
52c23746bc fix(www): issue with border radius in component preview (#1265) 2023-08-17 14:14:48 +04:00
vinay
f68976b667 docs(www): remove unused Link import in form docs. (#1251)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-17 13:50:34 +04:00
Edgaras Benediktavicius
7a1f80af2c docs(www): @hookform/resolvers installation missing (#1257)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-17 13:43:32 +04:00
我不是张硕
646f715388 fix(www): error in color values for slaet (#1224)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-17 13:35:06 +04:00
Alonso Ureña
9441130f05 fix(www): payment method :has selector not working on Firefox (#1209)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-16 21:11:49 +04:00
Daniele Luisetto
48e3a4a326 fix(docs): add missing files in toast manual installation (#1243)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-16 07:32:09 +04:00
Daniele Luisetto
98078fbe01 fix(docs): missing form manual installation and aspect-ratio typo (#1242)
* fix(docs): add form manual installation

* fix(docs): typo in aspect-ratio

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-08-16 07:26:49 +04:00
shadcn
8be9e5d966 fix(www): extra semi 2023-08-15 19:25:11 +04:00
Nguyen Long Nhat
a8b1ea7e55 fix: remove semicolon duplicated in theme.css (#1146) 2023-08-15 19:24:37 +04:00
shadcn
3c9f7ca0e2 feat: themes (#1135) 2023-08-07 22:39:16 +04:00
shadcn
c598f19845 docs(www): fix typo 2023-08-04 20:54:46 +04:00
Paul Ebose
7962cee384 docs(www): add api reference for components.json (#982)
* docs: add api reference for component.json file

* docs: use Link for internal links in component.json

* docs(www): update docs for components.json

---------

Co-authored-by: shadcn <m@shadcn.com>
2023-08-04 17:03:41 +04:00
Guten Ye
de3c34845b docs(www): update import in remix installation (#974)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-03 22:27:39 +04:00
vinay
6a1354e52d fix(examples): update keyboard shortcut for opening dialog on Windows (#1004) 2023-08-03 22:22:38 +04:00
Rudy Orre
1532a15894 docs(www): add missing "command" component to imports (#550)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-03 21:57:39 +04:00
Alan Daniel
8e5d080900 docs(www): add dark mode for Vite. (#814)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-03 19:41:33 +04:00
GrungeElFz
cf95943446 docs(www): update import path for button (#839)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-03 19:03:44 +04:00
vinay
3210bed755 fix(next-template): remove experimental appdir (#979)
Co-authored-by: shadcn <m@shadcn.com>
2023-08-01 19:21:18 +04:00
Bernardo Ferrari
eaa91d43df style(card): remove extra spacing (#1082) 2023-08-01 19:07:03 +04:00
Antsiferov Maxim
8cf0c7f3ba fix(alert): padding on Firefox (#1059)
Co-authored-by: shadcn <m@shadcn.com>
2023-07-30 15:50:11 +04:00
Abdulelah
da7729644c fix(combobox): search language by label in examples (#989)
Co-authored-by: shadcn <m@shadcn.com>
2023-07-30 15:33:18 +04:00
shadcn
aca3ef97e3 fix(www): responsive cards (#1066) 2023-07-28 23:14:38 +04:00
Deveesh Shetty
c9fecd4cdf fix(www): overflow issue in documentation (#1055)
Co-authored-by: shadcn <m@shadcn.com>
2023-07-28 16:03:43 +04:00
munan56
6cf598d47f docs(www): update import path next.mdx (#1062) 2023-07-28 15:56:19 +04:00
shadcn
91727ec460 ci: rename repo owner (#1056) 2023-07-27 13:12:13 +04:00
Pedro Vítor Ribeiro Martins
5e172fc34f docs(www): add typescript configuration question to cli docs (#898)
Co-authored-by: shadcn <m@shadcn.com>
2023-07-12 20:34:05 +04:00
Drew Greene
f461ab0910 docs(www): update label in card demo (#799)
Co-authored-by: shadcn <m@shadcn.com>
2023-07-12 20:22:35 +04:00
Lennart Gastler
26c8d0f662 docs(www): improve astro guide (#858) 2023-07-12 20:17:25 +04:00
vinay
ac5c727fc9 docs(www): add links to frameworks (#744)
Co-authored-by: shadcn <m@shadcn.com>
2023-07-05 23:29:14 +04:00
shadcn
54b1f5b661 feat: update next-template 2023-07-05 23:00:03 +04:00
395 changed files with 16494 additions and 1380 deletions

View File

@@ -1,6 +1,6 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "shadcn/ui" }],
"changelog": ["@changesets/changelog-github", { "repo": "shadcn-ui/ui" }],
"commit": false,
"fixed": [],
"linked": [],

View File

@@ -7,7 +7,7 @@ on:
jobs:
lint:
runs-on: ubuntu-latest
name: Lint
name: pnpm lint
steps:
- uses: actions/checkout@v3
with:
@@ -16,7 +16,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm
@@ -43,7 +43,7 @@ jobs:
format:
runs-on: ubuntu-latest
name: Format
name: pnpm format:check
steps:
- uses: actions/checkout@v3
with:
@@ -52,7 +52,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm
@@ -81,7 +81,7 @@ jobs:
tsc:
runs-on: ubuntu-latest
name: TypeScript
name: pnpm typecheck
steps:
- uses: actions/checkout@v3
with:
@@ -90,7 +90,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm

View File

@@ -10,7 +10,7 @@ on:
jobs:
comment:
if: |
github.repository_owner == 'shadcn' &&
github.repository_owner == 'shadcn-ui' &&
${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
name: Write comment to the PR

View File

@@ -10,7 +10,7 @@ on:
jobs:
prerelease:
if: |
github.repository_owner == 'shadcn' &&
github.repository_owner == 'shadcn-ui' &&
contains(github.event.pull_request.labels.*.name, '🚀 autorelease')
name: Build & Publish a beta release to NPM
runs-on: ubuntu-latest

View File

@@ -9,7 +9,7 @@ on:
jobs:
release:
if: ${{ github.repository_owner == 'shadcn' }}
if: ${{ github.repository_owner == 'shadcn-ui' }}
name: Create a PR for release workflow
runs-on: ubuntu-latest
steps:

View File

@@ -7,7 +7,7 @@ on:
jobs:
test:
runs-on: ubuntu-latest
name: Test
name: pnpm test
steps:
- uses: actions/checkout@v3
with:
@@ -16,7 +16,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- uses: pnpm/action-setup@v2.2.4
name: Install pnpm

18
.kodiak.toml Normal file
View File

@@ -0,0 +1,18 @@
# .kodiak.toml
version = 1
[merge]
automerge_label = "automerge"
require_automerge_label = true
method = "squash"
delete_branch_on_merge = true
optimistic_updates = false
prioritize_ready_to_merge = true
notify_on_conflict = true
[merge.message]
title = "pull_request_title"
body = "pull_request_body"
include_pr_number = true
body_type = "markdown"
strip_html_comments = true

2
.nvmrc
View File

@@ -1 +1 @@
v16.18.0
v18.17.0

175
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,175 @@
# Contributing
Thanks for your interest in contributing to ui.shadcn.com. We're happy to have you here.
Please take a moment to review this document before submitting your first pull request. We also strongly recommend that you check for open issues and pull requests to see if someone else is working on something similar.
If you need any help, feel free to reach out to [@shadcn](https://twitter.com/shadcn).
## About this repository
This repository is a monorepo.
- We use [pnpm](https://pnpm.io) and [`workspaces`](https://pnpm.io/workspaces) for development.
- We use [Turborepo](https://turbo.build/repo) as our build system.
- We use [changesets](https://github.com/changesets/changesets) for managing releases.
## Structure
This repository is structured as follows:
```
apps
└── www
├── app
├── components
├── content
└── registry
├── default
│ ├── example
│ └── ui
└── new-york
├── example
└── ui
packages
└── cli
```
| Path | Description |
| --------------------- | ---------------------------------------- |
| `apps/www/app` | The Next.js application for the website. |
| `apps/www/components` | The React components for the website. |
| `apps/www/content` | The content for the website. |
| `apps/www/registry` | The registry for the components. |
| `packages/cli` | The `shadcn-ui` package. |
## Development
### Fork this repo
You can fork this repo by clicking the fork button in the top right corner of this page.
### Clone on your local machine
```bash
git clone https://github.com/your-username/ui.git
```
### Navigate to project directory
```bash
cd ui
```
### Create a new Branch
```bash
git checkout -b my-new-branch
```
### Install dependencies
```bash
pnpm install
```
### Run a workspace
You can use the `pnpm --filter=[WORKSPACE]` command to start the development process for a workspace.
#### Examples
1. To run the `ui.shadcn.com` website:
```bash
pnpm --filter=www dev
```
2. To run the `shadcn-ui` package:
```bash
pnpm --filter=shadcn-ui dev
```
## Documentation
The documentation for this project is located in the `www` workspace. You can run the documentation locally by running the following command:
```bash
pnpm --filter=www dev
```
Documentation is written using [MDX](https://mdxjs.com). You can find the documentation files in the `apps/www/content/docs` directory.
## Components
We use a registry system for developing components. You can find the source code for the components under `apps/www/registry`. The components are organized by styles.
```bash
apps
└── www
└── registry
├── default
│ ├── example
│ └── ui
└── new-york
├── example
└── ui
```
When adding or modifying components, please ensure that:
1. You make the changes for every style.
2. You update the documentation.
3. You run `pnpm build:registry` to update the registry.
## Commit Convention
Before you create a Pull Request, please check whether your commits comply with
the commit conventions used in this repository.
When you create a commit we kindly ask you to follow the convention
`category(scope or module): message` in your commit message while using one of
the following categories:
- `feat / feature`: all changes that introduce completely new code or new
features
- `fix`: changes that fix a bug (ideally you will additionally reference an
issue if present)
- `refactor`: any code related change that is not a fix nor a feature
- `docs`: changing existing or creating new documentation (i.e. README, docs for
usage of a lib or cli usage)
- `build`: all changes regarding the build of the software, changes to
dependencies or the addition of new dependencies
- `test`: all changes regarding tests (adding new tests or changing existing
ones)
- `ci`: all changes regarding the configuration of continuous integration (i.e.
github actions, ci system)
- `chore`: all changes to the repository that do not fit into any of the above
categories
e.g. `feat(components): add new prop to the avatar component`
If you are interested in the detailed specification you can visit
https://www.conventionalcommits.org/ or check out the
[Angular Commit Message Guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines).
## Requests for new components
If you have a request for a new component, please open a discussion on GitHub. We'll be happy to help you out.
## CLI
The `shadcn-ui` package is a CLI for adding components to your project. You can find the documentation for the CLI [here](https://ui.shadcn.com/docs/cli).
Any changes to the CLI should be made in the `packages/cli` directory. If you can, it would be great if you could add tests for your changes.
## Testing
Tests are written using [Vitest](https://vitest.dev). You can run all the tests from the root of the repository.
```bash
pnpm test
```
Please ensure that the tests are passing when submitting a pull request. If you're adding new features, please include tests.

View File

@@ -8,6 +8,10 @@ Accessible and customizable components that you can copy and paste into your app
Visit http://ui.shadcn.com/docs to view the documentation.
## Contributing
Please read the [contributing guide](/CONTRIBUTING.md).
## License
Licensed under the [MIT license](https://github.com/shadcn/ui/blob/main/LICENSE.md).

View File

@@ -3,4 +3,5 @@ node_modules
.next
build
.contentlayer
__registry__/index.tsx
__registry__/index.tsx
app/examples/mail/components/mail.tsx

View File

@@ -68,6 +68,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/ui/card")),
files: ["registry/default/ui/card.tsx"],
},
"carousel": {
name: "carousel",
type: "components:ui",
registryDependencies: ["button"],
component: React.lazy(() => import("@/registry/default/ui/carousel")),
files: ["registry/default/ui/carousel.tsx"],
},
"checkbox": {
name: "checkbox",
type: "components:ui",
@@ -103,6 +110,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/ui/dialog")),
files: ["registry/default/ui/dialog.tsx"],
},
"drawer": {
name: "drawer",
type: "components:ui",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/ui/drawer")),
files: ["registry/default/ui/drawer.tsx"],
},
"dropdown-menu": {
name: "dropdown-menu",
type: "components:ui",
@@ -152,6 +166,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/ui/navigation-menu")),
files: ["registry/default/ui/navigation-menu.tsx"],
},
"pagination": {
name: "pagination",
type: "components:ui",
registryDependencies: ["button"],
component: React.lazy(() => import("@/registry/default/ui/pagination")),
files: ["registry/default/ui/pagination.tsx"],
},
"popover": {
name: "popover",
type: "components:ui",
@@ -173,6 +194,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/ui/radio-group")),
files: ["registry/default/ui/radio-group.tsx"],
},
"resizable": {
name: "resizable",
type: "components:ui",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/ui/resizable")),
files: ["registry/default/ui/resizable.tsx"],
},
"scroll-area": {
name: "scroll-area",
type: "components:ui",
@@ -215,6 +243,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/ui/slider")),
files: ["registry/default/ui/slider.tsx"],
},
"sonner": {
name: "sonner",
type: "components:ui",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/ui/sonner")),
files: ["registry/default/ui/sonner.tsx"],
},
"switch": {
name: "switch",
type: "components:ui",
@@ -257,6 +292,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/ui/toggle")),
files: ["registry/default/ui/toggle.tsx"],
},
"toggle-group": {
name: "toggle-group",
type: "components:ui",
registryDependencies: ["toggle"],
component: React.lazy(() => import("@/registry/default/ui/toggle-group")),
files: ["registry/default/ui/toggle-group.tsx"],
},
"tooltip": {
name: "tooltip",
type: "components:ui",
@@ -432,6 +474,48 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/card-with-form")),
files: ["registry/default/example/card-with-form.tsx"],
},
"carousel-demo": {
name: "carousel-demo",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/default/example/carousel-demo")),
files: ["registry/default/example/carousel-demo.tsx"],
},
"carousel-size": {
name: "carousel-size",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/default/example/carousel-size")),
files: ["registry/default/example/carousel-size.tsx"],
},
"carousel-spacing": {
name: "carousel-spacing",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/default/example/carousel-spacing")),
files: ["registry/default/example/carousel-spacing.tsx"],
},
"carousel-orientation": {
name: "carousel-orientation",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/default/example/carousel-orientation")),
files: ["registry/default/example/carousel-orientation.tsx"],
},
"carousel-api": {
name: "carousel-api",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/default/example/carousel-api")),
files: ["registry/default/example/carousel-api.tsx"],
},
"carousel-plugin": {
name: "carousel-plugin",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/default/example/carousel-plugin")),
files: ["registry/default/example/carousel-plugin.tsx"],
},
"checkbox-demo": {
name: "checkbox-demo",
type: "components:example",
@@ -502,6 +586,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/combobox-popover")),
files: ["registry/default/example/combobox-popover.tsx"],
},
"combobox-responsive": {
name: "combobox-responsive",
type: "components:example",
registryDependencies: ["combobox","popover","drawer"],
component: React.lazy(() => import("@/registry/default/example/combobox-responsive")),
files: ["registry/default/example/combobox-responsive.tsx"],
},
"command-demo": {
name: "command-demo",
type: "components:example",
@@ -565,6 +656,27 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/dialog-demo")),
files: ["registry/default/example/dialog-demo.tsx"],
},
"dialog-close-button": {
name: "dialog-close-button",
type: "components:example",
registryDependencies: ["dialog","button"],
component: React.lazy(() => import("@/registry/default/example/dialog-close-button")),
files: ["registry/default/example/dialog-close-button.tsx"],
},
"drawer-demo": {
name: "drawer-demo",
type: "components:example",
registryDependencies: ["drawer"],
component: React.lazy(() => import("@/registry/default/example/drawer-demo")),
files: ["registry/default/example/drawer-demo.tsx"],
},
"drawer-dialog": {
name: "drawer-dialog",
type: "components:example",
registryDependencies: ["drawer","dialog"],
component: React.lazy(() => import("@/registry/default/example/drawer-dialog")),
files: ["registry/default/example/drawer-dialog.tsx"],
},
"dropdown-menu-demo": {
name: "dropdown-menu-demo",
type: "components:example",
@@ -663,6 +775,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/navigation-menu-demo")),
files: ["registry/default/example/navigation-menu-demo.tsx"],
},
"pagination-demo": {
name: "pagination-demo",
type: "components:example",
registryDependencies: ["pagination"],
component: React.lazy(() => import("@/registry/default/example/pagination-demo")),
files: ["registry/default/example/pagination-demo.tsx"],
},
"popover-demo": {
name: "popover-demo",
type: "components:example",
@@ -691,6 +810,34 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/radio-group-form")),
files: ["registry/default/example/radio-group-form.tsx"],
},
"resizable-demo": {
name: "resizable-demo",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/default/example/resizable-demo")),
files: ["registry/default/example/resizable-demo.tsx"],
},
"resizable-demo-with-handle": {
name: "resizable-demo-with-handle",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/default/example/resizable-demo-with-handle")),
files: ["registry/default/example/resizable-demo-with-handle.tsx"],
},
"resizable-vertical": {
name: "resizable-vertical",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/default/example/resizable-vertical")),
files: ["registry/default/example/resizable-vertical.tsx"],
},
"resizable-handle": {
name: "resizable-handle",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/default/example/resizable-handle")),
files: ["registry/default/example/resizable-handle.tsx"],
},
"scroll-area-demo": {
name: "scroll-area-demo",
type: "components:example",
@@ -698,6 +845,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/scroll-area-demo")),
files: ["registry/default/example/scroll-area-demo.tsx"],
},
"scroll-area-horizontal-demo": {
name: "scroll-area-horizontal-demo",
type: "components:example",
registryDependencies: ["scroll-area"],
component: React.lazy(() => import("@/registry/default/example/scroll-area-horizontal-demo")),
files: ["registry/default/example/scroll-area-horizontal-demo.tsx"],
},
"select-demo": {
name: "select-demo",
type: "components:example",
@@ -705,6 +859,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/select-demo")),
files: ["registry/default/example/select-demo.tsx"],
},
"select-scrollable": {
name: "select-scrollable",
type: "components:example",
registryDependencies: ["select"],
component: React.lazy(() => import("@/registry/default/example/select-scrollable")),
files: ["registry/default/example/select-scrollable.tsx"],
},
"select-form": {
name: "select-form",
type: "components:example",
@@ -747,6 +908,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/slider-demo")),
files: ["registry/default/example/slider-demo.tsx"],
},
"sonner-demo": {
name: "sonner-demo",
type: "components:example",
registryDependencies: ["sonner"],
component: React.lazy(() => import("@/registry/default/example/sonner-demo")),
files: ["registry/default/example/sonner-demo.tsx"],
},
"switch-demo": {
name: "switch-demo",
type: "components:example",
@@ -852,6 +1020,48 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/toast-with-title")),
files: ["registry/default/example/toast-with-title.tsx"],
},
"toggle-group-demo": {
name: "toggle-group-demo",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/default/example/toggle-group-demo")),
files: ["registry/default/example/toggle-group-demo.tsx"],
},
"toggle-group-disabled": {
name: "toggle-group-disabled",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/default/example/toggle-group-disabled")),
files: ["registry/default/example/toggle-group-disabled.tsx"],
},
"toggle-group-lg": {
name: "toggle-group-lg",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/default/example/toggle-group-lg")),
files: ["registry/default/example/toggle-group-lg.tsx"],
},
"toggle-group-outline": {
name: "toggle-group-outline",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/default/example/toggle-group-outline")),
files: ["registry/default/example/toggle-group-outline.tsx"],
},
"toggle-group-sm": {
name: "toggle-group-sm",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/default/example/toggle-group-sm")),
files: ["registry/default/example/toggle-group-sm.tsx"],
},
"toggle-group-single": {
name: "toggle-group-single",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/default/example/toggle-group-single")),
files: ["registry/default/example/toggle-group-single.tsx"],
},
"toggle-demo": {
name: "toggle-demo",
type: "components:example",
@@ -1006,6 +1216,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/default/example/mode-toggle")),
files: ["registry/default/example/mode-toggle.tsx"],
},
"cards": {
name: "cards",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/cards")),
files: ["registry/default/example/cards/cards.tsx"],
},
}, "new-york": {
"accordion": {
name: "accordion",
@@ -1070,6 +1287,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/ui/card")),
files: ["registry/new-york/ui/card.tsx"],
},
"carousel": {
name: "carousel",
type: "components:ui",
registryDependencies: ["button"],
component: React.lazy(() => import("@/registry/new-york/ui/carousel")),
files: ["registry/new-york/ui/carousel.tsx"],
},
"checkbox": {
name: "checkbox",
type: "components:ui",
@@ -1105,6 +1329,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/ui/dialog")),
files: ["registry/new-york/ui/dialog.tsx"],
},
"drawer": {
name: "drawer",
type: "components:ui",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/new-york/ui/drawer")),
files: ["registry/new-york/ui/drawer.tsx"],
},
"dropdown-menu": {
name: "dropdown-menu",
type: "components:ui",
@@ -1154,6 +1385,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/ui/navigation-menu")),
files: ["registry/new-york/ui/navigation-menu.tsx"],
},
"pagination": {
name: "pagination",
type: "components:ui",
registryDependencies: ["button"],
component: React.lazy(() => import("@/registry/new-york/ui/pagination")),
files: ["registry/new-york/ui/pagination.tsx"],
},
"popover": {
name: "popover",
type: "components:ui",
@@ -1175,6 +1413,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/ui/radio-group")),
files: ["registry/new-york/ui/radio-group.tsx"],
},
"resizable": {
name: "resizable",
type: "components:ui",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/new-york/ui/resizable")),
files: ["registry/new-york/ui/resizable.tsx"],
},
"scroll-area": {
name: "scroll-area",
type: "components:ui",
@@ -1217,6 +1462,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/ui/slider")),
files: ["registry/new-york/ui/slider.tsx"],
},
"sonner": {
name: "sonner",
type: "components:ui",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/new-york/ui/sonner")),
files: ["registry/new-york/ui/sonner.tsx"],
},
"switch": {
name: "switch",
type: "components:ui",
@@ -1259,6 +1511,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/ui/toggle")),
files: ["registry/new-york/ui/toggle.tsx"],
},
"toggle-group": {
name: "toggle-group",
type: "components:ui",
registryDependencies: ["toggle"],
component: React.lazy(() => import("@/registry/new-york/ui/toggle-group")),
files: ["registry/new-york/ui/toggle-group.tsx"],
},
"tooltip": {
name: "tooltip",
type: "components:ui",
@@ -1434,6 +1693,48 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/card-with-form")),
files: ["registry/new-york/example/card-with-form.tsx"],
},
"carousel-demo": {
name: "carousel-demo",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/new-york/example/carousel-demo")),
files: ["registry/new-york/example/carousel-demo.tsx"],
},
"carousel-size": {
name: "carousel-size",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/new-york/example/carousel-size")),
files: ["registry/new-york/example/carousel-size.tsx"],
},
"carousel-spacing": {
name: "carousel-spacing",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/new-york/example/carousel-spacing")),
files: ["registry/new-york/example/carousel-spacing.tsx"],
},
"carousel-orientation": {
name: "carousel-orientation",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/new-york/example/carousel-orientation")),
files: ["registry/new-york/example/carousel-orientation.tsx"],
},
"carousel-api": {
name: "carousel-api",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/new-york/example/carousel-api")),
files: ["registry/new-york/example/carousel-api.tsx"],
},
"carousel-plugin": {
name: "carousel-plugin",
type: "components:example",
registryDependencies: ["carousel"],
component: React.lazy(() => import("@/registry/new-york/example/carousel-plugin")),
files: ["registry/new-york/example/carousel-plugin.tsx"],
},
"checkbox-demo": {
name: "checkbox-demo",
type: "components:example",
@@ -1504,6 +1805,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/combobox-popover")),
files: ["registry/new-york/example/combobox-popover.tsx"],
},
"combobox-responsive": {
name: "combobox-responsive",
type: "components:example",
registryDependencies: ["combobox","popover","drawer"],
component: React.lazy(() => import("@/registry/new-york/example/combobox-responsive")),
files: ["registry/new-york/example/combobox-responsive.tsx"],
},
"command-demo": {
name: "command-demo",
type: "components:example",
@@ -1567,6 +1875,27 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/dialog-demo")),
files: ["registry/new-york/example/dialog-demo.tsx"],
},
"dialog-close-button": {
name: "dialog-close-button",
type: "components:example",
registryDependencies: ["dialog","button"],
component: React.lazy(() => import("@/registry/new-york/example/dialog-close-button")),
files: ["registry/new-york/example/dialog-close-button.tsx"],
},
"drawer-demo": {
name: "drawer-demo",
type: "components:example",
registryDependencies: ["drawer"],
component: React.lazy(() => import("@/registry/new-york/example/drawer-demo")),
files: ["registry/new-york/example/drawer-demo.tsx"],
},
"drawer-dialog": {
name: "drawer-dialog",
type: "components:example",
registryDependencies: ["drawer","dialog"],
component: React.lazy(() => import("@/registry/new-york/example/drawer-dialog")),
files: ["registry/new-york/example/drawer-dialog.tsx"],
},
"dropdown-menu-demo": {
name: "dropdown-menu-demo",
type: "components:example",
@@ -1665,6 +1994,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/navigation-menu-demo")),
files: ["registry/new-york/example/navigation-menu-demo.tsx"],
},
"pagination-demo": {
name: "pagination-demo",
type: "components:example",
registryDependencies: ["pagination"],
component: React.lazy(() => import("@/registry/new-york/example/pagination-demo")),
files: ["registry/new-york/example/pagination-demo.tsx"],
},
"popover-demo": {
name: "popover-demo",
type: "components:example",
@@ -1693,6 +2029,34 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/radio-group-form")),
files: ["registry/new-york/example/radio-group-form.tsx"],
},
"resizable-demo": {
name: "resizable-demo",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/new-york/example/resizable-demo")),
files: ["registry/new-york/example/resizable-demo.tsx"],
},
"resizable-demo-with-handle": {
name: "resizable-demo-with-handle",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/new-york/example/resizable-demo-with-handle")),
files: ["registry/new-york/example/resizable-demo-with-handle.tsx"],
},
"resizable-vertical": {
name: "resizable-vertical",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/new-york/example/resizable-vertical")),
files: ["registry/new-york/example/resizable-vertical.tsx"],
},
"resizable-handle": {
name: "resizable-handle",
type: "components:example",
registryDependencies: ["resizable"],
component: React.lazy(() => import("@/registry/new-york/example/resizable-handle")),
files: ["registry/new-york/example/resizable-handle.tsx"],
},
"scroll-area-demo": {
name: "scroll-area-demo",
type: "components:example",
@@ -1700,6 +2064,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/scroll-area-demo")),
files: ["registry/new-york/example/scroll-area-demo.tsx"],
},
"scroll-area-horizontal-demo": {
name: "scroll-area-horizontal-demo",
type: "components:example",
registryDependencies: ["scroll-area"],
component: React.lazy(() => import("@/registry/new-york/example/scroll-area-horizontal-demo")),
files: ["registry/new-york/example/scroll-area-horizontal-demo.tsx"],
},
"select-demo": {
name: "select-demo",
type: "components:example",
@@ -1707,6 +2078,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/select-demo")),
files: ["registry/new-york/example/select-demo.tsx"],
},
"select-scrollable": {
name: "select-scrollable",
type: "components:example",
registryDependencies: ["select"],
component: React.lazy(() => import("@/registry/new-york/example/select-scrollable")),
files: ["registry/new-york/example/select-scrollable.tsx"],
},
"select-form": {
name: "select-form",
type: "components:example",
@@ -1749,6 +2127,13 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/slider-demo")),
files: ["registry/new-york/example/slider-demo.tsx"],
},
"sonner-demo": {
name: "sonner-demo",
type: "components:example",
registryDependencies: ["sonner"],
component: React.lazy(() => import("@/registry/new-york/example/sonner-demo")),
files: ["registry/new-york/example/sonner-demo.tsx"],
},
"switch-demo": {
name: "switch-demo",
type: "components:example",
@@ -1854,6 +2239,48 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/toast-with-title")),
files: ["registry/new-york/example/toast-with-title.tsx"],
},
"toggle-group-demo": {
name: "toggle-group-demo",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/new-york/example/toggle-group-demo")),
files: ["registry/new-york/example/toggle-group-demo.tsx"],
},
"toggle-group-disabled": {
name: "toggle-group-disabled",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/new-york/example/toggle-group-disabled")),
files: ["registry/new-york/example/toggle-group-disabled.tsx"],
},
"toggle-group-lg": {
name: "toggle-group-lg",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/new-york/example/toggle-group-lg")),
files: ["registry/new-york/example/toggle-group-lg.tsx"],
},
"toggle-group-outline": {
name: "toggle-group-outline",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/new-york/example/toggle-group-outline")),
files: ["registry/new-york/example/toggle-group-outline.tsx"],
},
"toggle-group-sm": {
name: "toggle-group-sm",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/new-york/example/toggle-group-sm")),
files: ["registry/new-york/example/toggle-group-sm.tsx"],
},
"toggle-group-single": {
name: "toggle-group-single",
type: "components:example",
registryDependencies: ["toggle-group"],
component: React.lazy(() => import("@/registry/new-york/example/toggle-group-single")),
files: ["registry/new-york/example/toggle-group-single.tsx"],
},
"toggle-demo": {
name: "toggle-demo",
type: "components:example",
@@ -2008,5 +2435,12 @@ export const Index: Record<string, any> = {
component: React.lazy(() => import("@/registry/new-york/example/mode-toggle")),
files: ["registry/new-york/example/mode-toggle.tsx"],
},
"cards": {
name: "cards",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/new-york/example/cards")),
files: ["registry/new-york/example/cards/cards.tsx"],
},
},
}

View File

@@ -4,13 +4,12 @@ import { allDocs } from "contentlayer/generated"
import "@/styles/mdx.css"
import type { Metadata } from "next"
import Link from "next/link"
import { ChevronRightIcon } from "@radix-ui/react-icons"
import { ChevronRightIcon, ExternalLinkIcon } from "@radix-ui/react-icons"
import Balancer from "react-wrap-balancer"
import { siteConfig } from "@/config/site"
import { getTableOfContents } from "@/lib/toc"
import { absoluteUrl, cn } from "@/lib/utils"
import { Icons } from "@/components/icons"
import { Mdx } from "@/components/mdx-components"
import { DocsPager } from "@/components/pager"
import { DashboardTableOfContents } from "@/components/toc"
@@ -28,7 +27,7 @@ async function getDocFromParams({ params }: DocPageProps) {
const doc = allDocs.find((doc) => doc.slugAsParams === slug)
if (!doc) {
null
return null
}
return doc
@@ -107,27 +106,28 @@ export default async function DocPage({ params }: DocPageProps) {
</p>
)}
</div>
{doc.radix ? (
{doc.links ? (
<div className="flex items-center space-x-2 pt-4">
{doc.radix?.link && (
{doc.links?.doc && (
<Link
href={doc.radix.link}
href={doc.links.doc}
target="_blank"
rel="noreferrer"
className={cn(badgeVariants({ variant: "secondary" }))}
className={cn(badgeVariants({ variant: "secondary" }), "gap-1")}
>
<Icons.radix className="mr-1 h-3 w-3" />
Radix UI
Docs
<ExternalLinkIcon className="h-3 w-3" />
</Link>
)}
{doc.radix?.api && (
{doc.links?.api && (
<Link
href={doc.radix.api}
href={doc.links.api}
target="_blank"
rel="noreferrer"
className={cn(badgeVariants({ variant: "secondary" }))}
className={cn(badgeVariants({ variant: "secondary" }), "gap-1")}
>
API Reference
<ExternalLinkIcon className="h-3 w-3" />
</Link>
)}
</div>
@@ -139,9 +139,11 @@ export default async function DocPage({ params }: DocPageProps) {
</div>
{doc.toc && (
<div className="hidden text-sm xl:block">
<div className="sticky top-16 -mt-10 h-[calc(100vh-3.5rem)] overflow-hidden pt-6">
<div className="sticky top-16 -mt-10 pt-4">
<ScrollArea className="pb-10">
<DashboardTableOfContents toc={toc} />
<div className="sticky top-16 -mt-10 h-[calc(100vh-3.5rem)] py-12">
<DashboardTableOfContents toc={toc} />
</div>
</ScrollArea>
</div>
</div>

View File

@@ -11,7 +11,7 @@ export default function DocsLayout({ children }: DocsLayoutProps) {
<div className="border-b">
<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 md:sticky md:block">
<ScrollArea className="h-full py-6 pl-8 pr-6 lg:py-8">
<ScrollArea className="h-full py-6 pr-6 lg:py-8">
<DocsSidebarNav items={docsConfig.sidebarNav} />
</ScrollArea>
</aside>

View File

@@ -64,7 +64,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
) : (
<Icons.gitHub className="mr-2 h-4 w-4" />
)}{" "}
Github
GitHub
</Button>
</div>
)

View File

@@ -40,7 +40,7 @@ export default function AuthenticationPage() {
>
Login
</Link>
<div className="relative hidden h-full flex-col bg-muted p-10 text-white dark:border-r lg:flex">
<div className="relative hidden h-full flex-col bg-muted p-10 text-white lg:flex dark:border-r">
<div className="absolute inset-0 bg-zinc-900" />
<div className="relative z-20 flex items-center text-lg font-medium">
<svg

View File

@@ -31,8 +31,8 @@ export function DemoGithub() {
<div className="space-y-1">
<CardTitle>shadcn/ui</CardTitle>
<CardDescription>
Beautifully designed components built with Radix UI and Tailwind
CSS.
Beautifully designed components that you can copy and paste into
your apps. Accessible. Customizable. Open Source.
</CardDescription>
</div>
<div className="flex items-center space-x-1 rounded-md bg-secondary text-secondary-foreground">

View File

@@ -30,42 +30,52 @@ export function DemoPaymentMethod() {
</CardHeader>
<CardContent className="grid gap-6">
<RadioGroup defaultValue="card" className="grid grid-cols-3 gap-4">
<Label
htmlFor="card"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary"
>
<RadioGroupItem value="card" id="card" className="sr-only" />
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="mb-3 h-6 w-6"
<div>
<RadioGroupItem value="card" id="card" className="peer sr-only" />
<Label
htmlFor="card"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
>
<rect width="20" height="14" x="2" y="5" rx="2" />
<path d="M2 10h20" />
</svg>
Card
</Label>
<Label
htmlFor="paypal"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary"
>
<RadioGroupItem value="paypal" id="paypal" className="sr-only" />
<Icons.paypal className="mb-3 h-6 w-6" />
Paypal
</Label>
<Label
htmlFor="apple"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground [&:has([data-state=checked])]:border-primary"
>
<RadioGroupItem value="apple" id="apple" className="sr-only" />
<Icons.apple className="mb-3 h-6 w-6" />
Apple
</Label>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
className="mb-3 h-6 w-6"
>
<rect width="20" height="14" x="2" y="5" rx="2" />
<path d="M2 10h20" />
</svg>
Card
</Label>
</div>
<div>
<RadioGroupItem
value="paypal"
id="paypal"
className="peer sr-only"
/>
<Label
htmlFor="paypal"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
>
<Icons.paypal className="mb-3 h-6 w-6" />
Paypal
</Label>
</div>
<div>
<RadioGroupItem value="apple" id="apple" className="peer sr-only" />
<Label
htmlFor="apple"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-popover p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
>
<Icons.apple className="mb-3 h-6 w-6" />
Apple
</Label>
</div>
</RadioGroup>
<div className="grid gap-2">
<Label htmlFor="name">Name</Label>

View File

@@ -75,7 +75,7 @@ export default function CardsPage() {
<DemoNotifications />
</DemoContainer>
</div>
<div className="col-span-2 grid items-start gap-6 lg:col-span-1 lg:grid-cols-2 xl:grid-cols-1">
<div className="col-span-2 grid items-start gap-6 lg:col-span-2 lg:grid-cols-2 xl:col-span-1 xl:grid-cols-1">
<DemoContainer>
<DemoReportAnIssue />
</DemoContainer>

View File

@@ -71,7 +71,12 @@ export function Overview() {
axisLine={false}
tickFormatter={(value) => `$${value}`}
/>
<Bar dataKey="total" fill="#adfa1d" radius={[4, 4, 0, 0]} />
<Bar
dataKey="total"
fill="currentColor"
radius={[4, 4, 0, 0]}
className="fill-primary"
/>
</BarChart>
</ResponsiveContainer>
)

View File

@@ -100,6 +100,7 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) {
<AvatarImage
src={`https://avatar.vercel.sh/${selectedTeam.value}.png`}
alt={selectedTeam.label}
className="grayscale"
/>
<AvatarFallback>SC</AvatarFallback>
</Avatar>

View File

@@ -25,7 +25,7 @@ import { UserNav } from "@/app/examples/dashboard/components/user-nav"
export const metadata: Metadata = {
title: "Dashboard",
description: "Example dashboard app using the components.",
description: "Example dashboard app built using the components.",
}
export default function DashboardPage() {

View File

@@ -184,10 +184,10 @@ export function AccountForm() {
<CommandGroup>
{languages.map((language) => (
<CommandItem
value={language.value}
value={language.label}
key={language.value}
onSelect={(value) => {
form.setValue("language", value)
onSelect={() => {
form.setValue("language", language.value)
}}
>
<CheckIcon

View File

@@ -1,16 +1,16 @@
import { Metadata } from "next"
import Link from "next/link"
import { ArrowRightIcon } from "@radix-ui/react-icons"
import { cn } from "@/lib/utils"
import { Announcement } from "@/components/announcement"
import { ExamplesNav } from "@/components/examples-nav"
import {
PageActions,
PageHeader,
PageHeaderDescription,
PageHeaderHeading,
} from "@/components/page-header"
import { buttonVariants } from "@/registry/new-york/ui/button"
import { Separator } from "@/registry/new-york/ui/separator"
export const metadata: Metadata = {
title: "Examples",
@@ -25,27 +25,17 @@ export default function ExamplesLayout({ children }: ExamplesLayoutProps) {
return (
<>
<div className="container relative">
<PageHeader className="page-header pb-8">
<Link
href="/docs/changelog"
className="inline-flex items-center rounded-lg bg-muted px-3 py-1 text-sm font-medium"
>
🎉 <Separator className="mx-2 h-4" orientation="vertical" />{" "}
<span className="sm:hidden">Style, a new CLI and more.</span>
<span className="hidden sm:inline">
Introducing Style, a new CLI and more.
</span>
<ArrowRightIcon className="ml-1 h-4 w-4" />
</Link>
<PageHeader>
<Announcement />
<PageHeaderHeading className="hidden md:block">
Check out some examples.
Check out some examples
</PageHeaderHeading>
<PageHeaderHeading className="md:hidden">Examples</PageHeaderHeading>
<PageHeaderDescription>
Dashboard, cards, authentication. Some examples built using the
components. Use this as a guide to build your own.
</PageHeaderDescription>
<section className="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
<PageActions>
<Link
href="/docs"
className={cn(buttonVariants(), "rounded-[6px]")}
@@ -61,11 +51,11 @@ export default function ExamplesLayout({ children }: ExamplesLayoutProps) {
>
Components
</Link>
</section>
</PageActions>
</PageHeader>
<section>
<ExamplesNav />
<div className="overflow-hidden rounded-[0.5rem] border bg-background shadow">
<div className="overflow-hidden rounded-[0.5rem] border bg-background shadow-md md:shadow-xl">
{children}
</div>
</section>

View File

@@ -0,0 +1,63 @@
"use client"
import * as React from "react"
import { cn } from "@/lib/utils"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/registry/new-york/ui/select"
interface AccountSwitcherProps {
isCollapsed: boolean
accounts: {
label: string
email: string
icon: React.ReactNode
}[]
}
export function AccountSwitcher({
isCollapsed,
accounts,
}: AccountSwitcherProps) {
const [selectedAccount, setSelectedAccount] = React.useState<string>(
accounts[0].email
)
return (
<Select defaultValue={selectedAccount} onValueChange={setSelectedAccount}>
<SelectTrigger
className={cn(
"flex items-center gap-2 [&>span]:line-clamp-1 [&>span]:flex [&>span]:w-full [&>span]:items-center [&>span]:gap-1 [&>span]:truncate [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0",
isCollapsed &&
"flex h-9 w-9 shrink-0 items-center justify-center p-0 [&>span]:w-auto [&>svg]:hidden"
)}
aria-label="Select account"
>
<SelectValue placeholder="Select an account">
{accounts.find((account) => account.email === selectedAccount)?.icon}
<span className={cn("ml-2", isCollapsed && "hidden")}>
{
accounts.find((account) => account.email === selectedAccount)
?.label
}
</span>
</SelectValue>
</SelectTrigger>
<SelectContent>
{accounts.map((account) => (
<SelectItem key={account.email} value={account.email}>
<div className="flex items-center gap-3 [&_svg]:h-4 [&_svg]:w-4 [&_svg]:shrink-0 [&_svg]:text-foreground">
{account.icon}
{account.email}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
)
}

View File

@@ -0,0 +1,258 @@
import addDays from "date-fns/addDays"
import addHours from "date-fns/addHours"
import format from "date-fns/format"
import nextSaturday from "date-fns/nextSaturday"
import {
Archive,
ArchiveX,
Clock,
Forward,
MoreVertical,
Reply,
ReplyAll,
Trash2,
} from "lucide-react"
import {
DropdownMenuContent,
DropdownMenuItem,
} from "@/registry/default/ui/dropdown-menu"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/registry/new-york/ui/avatar"
import { Button } from "@/registry/new-york/ui/button"
import { Calendar } from "@/registry/new-york/ui/calendar"
import {
DropdownMenu,
DropdownMenuTrigger,
} from "@/registry/new-york/ui/dropdown-menu"
import { Label } from "@/registry/new-york/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/registry/new-york/ui/popover"
import { Separator } from "@/registry/new-york/ui/separator"
import { Switch } from "@/registry/new-york/ui/switch"
import { Textarea } from "@/registry/new-york/ui/textarea"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/registry/new-york/ui/tooltip"
import { Mail } from "@/app/examples/mail/data"
interface MailDisplayProps {
mail: Mail | null
}
export function MailDisplay({ mail }: MailDisplayProps) {
const today = new Date()
return (
<div className="flex h-full flex-col">
<div className="flex items-center p-2">
<div className="flex items-center gap-2">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<Archive className="h-4 w-4" />
<span className="sr-only">Archive</span>
</Button>
</TooltipTrigger>
<TooltipContent>Archive</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<ArchiveX className="h-4 w-4" />
<span className="sr-only">Move to junk</span>
</Button>
</TooltipTrigger>
<TooltipContent>Move to junk</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<Trash2 className="h-4 w-4" />
<span className="sr-only">Move to trash</span>
</Button>
</TooltipTrigger>
<TooltipContent>Move to trash</TooltipContent>
</Tooltip>
<Separator orientation="vertical" className="mx-1 h-6" />
<Tooltip>
<Popover>
<PopoverTrigger asChild>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<Clock className="h-4 w-4" />
<span className="sr-only">Snooze</span>
</Button>
</TooltipTrigger>
</PopoverTrigger>
<PopoverContent className="flex w-[535px] p-0">
<div className="flex flex-col gap-2 border-r px-2 py-4">
<div className="px-4 text-sm font-medium">Snooze until</div>
<div className="grid min-w-[250px] gap-1">
<Button
variant="ghost"
className="justify-start font-normal"
>
Later today{" "}
<span className="ml-auto text-muted-foreground">
{format(addHours(today, 4), "E, h:m b")}
</span>
</Button>
<Button
variant="ghost"
className="justify-start font-normal"
>
Tomorrow
<span className="ml-auto text-muted-foreground">
{format(addDays(today, 1), "E, h:m b")}
</span>
</Button>
<Button
variant="ghost"
className="justify-start font-normal"
>
This weekend
<span className="ml-auto text-muted-foreground">
{format(nextSaturday(today), "E, h:m b")}
</span>
</Button>
<Button
variant="ghost"
className="justify-start font-normal"
>
Next week
<span className="ml-auto text-muted-foreground">
{format(addDays(today, 7), "E, h:m b")}
</span>
</Button>
</div>
</div>
<div className="p-2">
<Calendar />
</div>
</PopoverContent>
</Popover>
<TooltipContent>Snooze</TooltipContent>
</Tooltip>
</div>
<div className="ml-auto flex items-center gap-2">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<Reply className="h-4 w-4" />
<span className="sr-only">Reply</span>
</Button>
</TooltipTrigger>
<TooltipContent>Reply</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<ReplyAll className="h-4 w-4" />
<span className="sr-only">Reply all</span>
</Button>
</TooltipTrigger>
<TooltipContent>Reply all</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<Forward className="h-4 w-4" />
<span className="sr-only">Forward</span>
</Button>
</TooltipTrigger>
<TooltipContent>Forward</TooltipContent>
</Tooltip>
</div>
<Separator orientation="vertical" className="mx-2 h-6" />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" disabled={!mail}>
<MoreVertical className="h-4 w-4" />
<span className="sr-only">More</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Mark as unread</DropdownMenuItem>
<DropdownMenuItem>Star thread</DropdownMenuItem>
<DropdownMenuItem>Add label</DropdownMenuItem>
<DropdownMenuItem>Mute thread</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
<Separator />
{mail ? (
<div className="flex flex-1 flex-col">
<div className="flex items-start p-4">
<div className="flex items-start gap-4 text-sm">
<Avatar>
<AvatarImage alt={mail.name} />
<AvatarFallback>
{mail.name
.split(" ")
.map((chunk) => chunk[0])
.join("")}
</AvatarFallback>
</Avatar>
<div className="grid gap-1">
<div className="font-semibold">{mail.name}</div>
<div className="line-clamp-1 text-xs">{mail.subject}</div>
<div className="line-clamp-1 text-xs">
<span className="font-medium">Reply-To:</span> {mail.email}
</div>
</div>
</div>
{mail.date && (
<div className="ml-auto text-xs text-muted-foreground">
{format(new Date(mail.date), "PPpp")}
</div>
)}
</div>
<Separator />
<div className="flex-1 whitespace-pre-wrap p-4 text-sm">
{mail.text}
</div>
<Separator className="mt-auto" />
<div className="p-4">
<form>
<div className="grid gap-4">
<Textarea
className="p-4"
placeholder={`Reply ${mail.name}...`}
/>
<div className="flex items-center">
<Label
htmlFor="mute"
className="flex items-center gap-2 text-xs font-normal"
>
<Switch id="mute" aria-label="Mute thread" /> Mute this
thread
</Label>
<Button
onClick={(e) => e.preventDefault()}
size="sm"
className="ml-auto"
>
Send
</Button>
</div>
</div>
</form>
</div>
</div>
) : (
<div className="p-8 text-center text-muted-foreground">
No message selected
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,89 @@
import { ComponentProps } from "react"
import formatDistanceToNow from "date-fns/formatDistanceToNow"
import { cn } from "@/lib/utils"
import { Badge } from "@/registry/new-york/ui/badge"
import { ScrollArea } from "@/registry/new-york/ui/scroll-area"
import { Separator } from "@/registry/new-york/ui/separator"
import { Mail } from "@/app/examples/mail/data"
import { useMail } from "@/app/examples/mail/use-mail"
interface MailListProps {
items: Mail[]
}
export function MailList({ items }: MailListProps) {
const [mail, setMail] = useMail()
return (
<ScrollArea className="h-screen">
<div className="flex flex-col gap-2 p-4 pt-0">
{items.map((item) => (
<button
key={item.id}
className={cn(
"flex flex-col items-start gap-2 rounded-lg border p-3 text-left text-sm transition-all hover:bg-accent",
mail.selected === item.id && "bg-muted"
)}
onClick={() =>
setMail({
...mail,
selected: item.id,
})
}
>
<div className="flex w-full flex-col gap-1">
<div className="flex items-center">
<div className="flex items-center gap-2">
<div className="font-semibold">{item.name}</div>
{!item.read && (
<span className="flex h-2 w-2 rounded-full bg-blue-600" />
)}
</div>
<div
className={cn(
"ml-auto text-xs",
mail.selected === item.id
? "text-foreground"
: "text-muted-foreground"
)}
>
{formatDistanceToNow(new Date(item.date), {
addSuffix: true,
})}
</div>
</div>
<div className="text-xs font-medium">{item.subject}</div>
</div>
<div className="line-clamp-2 text-xs text-muted-foreground">
{item.text.substring(0, 300)}
</div>
{item.labels.length ? (
<div className="flex items-center gap-2">
{item.labels.map((label) => (
<Badge key={label} variant={getBadgeVariantFromLabel(label)}>
{label}
</Badge>
))}
</div>
) : null}
</button>
))}
</div>
</ScrollArea>
)
}
function getBadgeVariantFromLabel(
label: string
): ComponentProps<typeof Badge>["variant"] {
if (["work"].includes(label.toLowerCase())) {
return "default"
}
if (["personal"].includes(label.toLowerCase())) {
return "outline"
}
return "secondary"
}

View File

@@ -0,0 +1,201 @@
"use client"
import * as React from "react"
import {
AlertCircle,
Archive,
ArchiveX,
File,
Inbox,
MessagesSquare,
PenBox,
Search,
Send,
ShoppingCart,
Trash2,
Users2,
} from "lucide-react"
import { AccountSwitcher } from "@/app/examples/mail/components/account-switcher"
import { MailDisplay } from "@/app/examples/mail/components/mail-display"
import { MailList } from "@/app/examples/mail/components/mail-list"
import { Nav } from "@/app/examples/mail/components/nav"
import { Mail } from "@/app/examples/mail/data"
import { useMail } from "@/app/examples/mail/use-mail"
import { cn } from "@/lib/utils"
import { Separator } from "@/registry/new-york/ui/separator"
import { Input } from "@/registry/new-york/ui/input"
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/registry/new-york/ui/tabs"
import { TooltipProvider } from "@/registry/new-york/ui/tooltip"
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/registry/new-york/ui/resizable"
interface MailProps {
accounts: {
label: string
email: string
icon: React.ReactNode
}[]
mails: Mail[]
defaultLayout: number[] | undefined
defaultCollapsed?: boolean
navCollapsedSize: number
}
export function Mail({
accounts,
mails,
defaultLayout = [265, 440, 655],
defaultCollapsed = false,
navCollapsedSize,
}: MailProps) {
const [isCollapsed, setIsCollapsed] = React.useState(defaultCollapsed)
const [mail] = useMail()
return (
<TooltipProvider delayDuration={0}>
<ResizablePanelGroup
direction="horizontal"
onLayout={(sizes: number[]) => {
document.cookie = `react-resizable-panels:layout=${JSON.stringify(
sizes
)}`
}}
className="h-full max-h-[800px] items-stretch"
>
<ResizablePanel
defaultSize={defaultLayout[0]}
collapsedSize={navCollapsedSize}
collapsible={true}
minSize={15}
maxSize={20}
onCollapse={(collapsed) => {
setIsCollapsed(collapsed)
document.cookie = `react-resizable-panels:collapsed=${JSON.stringify(
collapsed
)}`
}}
className={cn(isCollapsed && "min-w-[50px] transition-all duration-300 ease-in-out")}
>
<div className={cn("flex h-[52px] items-center justify-center", isCollapsed ? 'h-[52px]': 'px-2')}>
<AccountSwitcher isCollapsed={isCollapsed} accounts={accounts} />
</div>
<Separator />
<Nav
isCollapsed={isCollapsed}
links={[
{
title: "Inbox",
label: "128",
icon: Inbox,
variant: "default",
},
{
title: "Drafts",
label: "9",
icon: File,
variant: "ghost",
},
{
title: "Sent",
label: "",
icon: Send,
variant: "ghost",
},
{
title: "Junk",
label: "23",
icon: ArchiveX,
variant: "ghost",
},
{
title: "Trash",
label: "",
icon: Trash2,
variant: "ghost",
},
{
title: "Archive",
label: "",
icon: Archive,
variant: "ghost",
},
]}
/>
<Separator />
<Nav
isCollapsed={isCollapsed}
links={[
{
title: "Social",
label: "972",
icon: Users2,
variant: "ghost",
},
{
title: "Updates",
label: "342",
icon: AlertCircle,
variant: "ghost",
},
{
title: "Forums",
label: "128",
icon: MessagesSquare,
variant: "ghost",
},
{
title: "Shopping",
label: "8",
icon: ShoppingCart,
variant: "ghost",
},
{
title: "Promotions",
label: "21",
icon: Archive,
variant: "ghost",
},
]}
/>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={defaultLayout[1]} minSize={30}>
<Tabs defaultValue="all">
<div className="flex items-center px-4 py-2">
<h1 className="text-xl font-bold">Inbox</h1>
<TabsList className="ml-auto">
<TabsTrigger value="all" className="text-zinc-600 dark:text-zinc-200">All mail</TabsTrigger>
<TabsTrigger value="unread" className="text-zinc-600 dark:text-zinc-200">Unread</TabsTrigger>
</TabsList>
</div>
<Separator />
<div className="bg-background/95 p-4 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<form>
<div className="relative">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input placeholder="Search" className="pl-8" />
</div>
</form>
</div>
<TabsContent value="all" className="m-0">
<MailList items={mails} />
</TabsContent>
<TabsContent value="unread" className="m-0">
<MailList items={mails.filter((item) => !item.read)} />
</TabsContent>
</Tabs>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={defaultLayout[2]}>
<MailDisplay
mail={mails.find((item) => item.id === mail.selected) || null}
/>
</ResizablePanel>
</ResizablePanelGroup>
</TooltipProvider>
)
}

View File

@@ -0,0 +1,87 @@
"use client"
import Link from "next/link"
import { LucideIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/registry/default/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/registry/new-york/ui/tooltip"
interface NavProps {
isCollapsed: boolean
links: {
title: string
label?: string
icon: LucideIcon
variant: "default" | "ghost"
}[]
}
export function Nav({ links, isCollapsed }: NavProps) {
return (
<div
data-collapsed={isCollapsed}
className="group flex flex-col gap-4 py-2 data-[collapsed=true]:py-2"
>
<nav className="grid gap-1 px-2 group-[[data-collapsed=true]]:justify-center group-[[data-collapsed=true]]:px-2">
{links.map((link, index) =>
isCollapsed ? (
<Tooltip key={index} delayDuration={0}>
<TooltipTrigger asChild>
<Link
href="#"
className={cn(
buttonVariants({ variant: link.variant, size: "icon" }),
"h-9 w-9",
link.variant === "default" &&
"dark:bg-muted dark:text-muted-foreground dark:hover:bg-muted dark:hover:text-white"
)}
>
<link.icon className="h-4 w-4" />
<span className="sr-only">{link.title}</span>
</Link>
</TooltipTrigger>
<TooltipContent side="right" className="flex items-center gap-4">
{link.title}
{link.label && (
<span className="ml-auto text-muted-foreground">
{link.label}
</span>
)}
</TooltipContent>
</Tooltip>
) : (
<Link
key={index}
href="#"
className={cn(
buttonVariants({ variant: link.variant, size: "sm" }),
link.variant === "default" &&
"dark:bg-muted dark:text-white dark:hover:bg-muted dark:hover:text-white",
"justify-start"
)}
>
<link.icon className="mr-2 h-4 w-4" />
{link.title}
{link.label && (
<span
className={cn(
"ml-auto",
link.variant === "default" &&
"text-background dark:text-white"
)}
>
{link.label}
</span>
)}
</Link>
)
)}
</nav>
</div>
)
}

View File

@@ -0,0 +1,300 @@
export const mails = [
{
id: "6c84fb90-12c4-11e1-840d-7b25c5ee775a",
name: "William Smith",
email: "williamsmith@example.com",
subject: "Meeting Tomorrow",
text: "Hi, let's have a meeting tomorrow to discuss the project. I've been reviewing the project details and have some ideas I'd like to share. It's crucial that we align on our next steps to ensure the project's success.\n\nPlease come prepared with any questions or insights you may have. Looking forward to our meeting!\n\nBest regards, William",
date: "2023-10-22T09:00:00",
read: true,
labels: ["meeting", "work", "important"],
},
{
id: "110e8400-e29b-11d4-a716-446655440000",
name: "Alice Smith",
email: "alicesmith@example.com",
subject: "Re: Project Update",
text: "Thank you for the project update. It looks great! I've gone through the report, and the progress is impressive. The team has done a fantastic job, and I appreciate the hard work everyone has put in.\n\nI have a few minor suggestions that I'll include in the attached document.\n\nLet's discuss these during our next meeting. Keep up the excellent work!\n\nBest regards, Alice",
date: "2023-10-22T10:30:00",
read: true,
labels: ["work", "important"],
},
{
id: "3e7c3f6d-bdf5-46ae-8d90-171300f27ae2",
name: "Bob Johnson",
email: "bobjohnson@example.com",
subject: "Weekend Plans",
text: "Any plans for the weekend? I was thinking of going hiking in the nearby mountains. It's been a while since we had some outdoor fun.\n\nIf you're interested, let me know, and we can plan the details. It'll be a great way to unwind and enjoy nature.\n\nLooking forward to your response!\n\nBest, Bob",
date: "2023-04-10T11:45:00",
read: true,
labels: ["personal"],
},
{
id: "61c35085-72d7-42b4-8d62-738f700d4b92",
name: "Emily Davis",
email: "emilydavis@example.com",
subject: "Re: Question about Budget",
text: "I have a question about the budget for the upcoming project. It seems like there's a discrepancy in the allocation of resources.\n\nI've reviewed the budget report and identified a few areas where we might be able to optimize our spending without compromising the project's quality.\n\nI've attached a detailed analysis for your reference. Let's discuss this further in our next meeting.\n\nThanks, Emily",
date: "2023-03-25T13:15:00",
read: false,
labels: ["work", "budget"],
},
{
id: "8f7b5db9-d935-4e42-8e05-1f1d0a3dfb97",
name: "Michael Wilson",
email: "michaelwilson@example.com",
subject: "Important Announcement",
text: "I have an important announcement to make during our team meeting. It pertains to a strategic shift in our approach to the upcoming product launch. We've received valuable feedback from our beta testers, and I believe it's time to make some adjustments to better meet our customers' needs.\n\nThis change is crucial to our success, and I look forward to discussing it with the team. Please be prepared to share your insights during the meeting.\n\nRegards, Michael",
date: "2023-03-10T15:00:00",
read: false,
labels: ["meeting", "work", "important"],
},
{
id: "1f0f2c02-e299-40de-9b1d-86ef9e42126b",
name: "Sarah Brown",
email: "sarahbrown@example.com",
subject: "Re: Feedback on Proposal",
text: "Thank you for your feedback on the proposal. It looks great! I'm pleased to hear that you found it promising. The team worked diligently to address all the key points you raised, and I believe we now have a strong foundation for the project.\n\nI've attached the revised proposal for your review.\n\nPlease let me know if you have any further comments or suggestions. Looking forward to your response.\n\nBest regards, Sarah",
date: "2023-02-15T16:30:00",
read: true,
labels: ["work"],
},
{
id: "17c0a96d-4415-42b1-8b4f-764efab57f66",
name: "David Lee",
email: "davidlee@example.com",
subject: "New Project Idea",
text: "I have an exciting new project idea to discuss with you. It involves expanding our services to target a niche market that has shown considerable growth in recent months.\n\nI've prepared a detailed proposal outlining the potential benefits and the strategy for execution.\n\nThis project has the potential to significantly impact our business positively. Let's set up a meeting to dive into the details and determine if it aligns with our current goals.\n\nBest regards, David",
date: "2023-01-28T17:45:00",
read: false,
labels: ["meeting", "work", "important"],
},
{
id: "2f0130cb-39fc-44c4-bb3c-0a4337edaaab",
name: "Olivia Wilson",
email: "oliviawilson@example.com",
subject: "Vacation Plans",
text: "Let's plan our vacation for next month. What do you think? I've been thinking of visiting a tropical paradise, and I've put together some destination options.\n\nI believe it's time for us to unwind and recharge. Please take a look at the options and let me know your preferences.\n\nWe can start making arrangements to ensure a smooth and enjoyable trip.\n\nExcited to hear your thoughts! Olivia",
date: "2022-12-20T18:30:00",
read: true,
labels: ["personal"],
},
{
id: "de305d54-75b4-431b-adb2-eb6b9e546014",
name: "James Martin",
email: "jamesmartin@example.com",
subject: "Re: Conference Registration",
text: "I've completed the registration for the conference next month. The event promises to be a great networking opportunity, and I'm looking forward to attending the various sessions and connecting with industry experts.\n\nI've also attached the conference schedule for your reference.\n\nIf there are any specific topics or sessions you'd like me to explore, please let me know. It's an exciting event, and I'll make the most of it.\n\nBest regards, James",
date: "2022-11-30T19:15:00",
read: true,
labels: ["work", "conference"],
},
{
id: "7dd90c63-00f6-40f3-bd87-5060a24e8ee7",
name: "Sophia White",
email: "sophiawhite@example.com",
subject: "Team Dinner",
text: "Let's have a team dinner next week to celebrate our success. We've achieved some significant milestones, and it's time to acknowledge our hard work and dedication.\n\nI've made reservations at a lovely restaurant, and I'm sure it'll be an enjoyable evening.\n\nPlease confirm your availability and any dietary preferences. Looking forward to a fun and memorable dinner with the team!\n\nBest, Sophia",
date: "2022-11-05T20:30:00",
read: false,
labels: ["meeting", "work"],
},
{
id: "99a88f78-3eb4-4d87-87b7-7b15a49a0a05",
name: "Daniel Johnson",
email: "danieljohnson@example.com",
subject: "Feedback Request",
text: "I'd like your feedback on the latest project deliverables. We've made significant progress, and I value your input to ensure we're on the right track.\n\nI've attached the deliverables for your review, and I'm particularly interested in any areas where you think we can further enhance the quality or efficiency.\n\nYour feedback is invaluable, and I appreciate your time and expertise. Let's work together to make this project a success.\n\nRegards, Daniel",
date: "2022-10-22T09:30:00",
read: false,
labels: ["work"],
},
{
id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
name: "Ava Taylor",
email: "avataylor@example.com",
subject: "Re: Meeting Agenda",
text: "Here's the agenda for our meeting next week. I've included all the topics we need to cover, as well as time allocations for each.\n\nIf you have any additional items to discuss or any specific points to address, please let me know, and we can integrate them into the agenda.\n\nIt's essential that our meeting is productive and addresses all relevant matters.\n\nLooking forward to our meeting! Ava",
date: "2022-10-10T10:45:00",
read: true,
labels: ["meeting", "work"],
},
{
id: "c1a0ecb4-2540-49c5-86f8-21e5ce79e4e6",
name: "William Anderson",
email: "williamanderson@example.com",
subject: "Product Launch Update",
text: "The product launch is on track. I'll provide an update during our call. We've made substantial progress in the development and marketing of our new product.\n\nI'm excited to share the latest updates with you during our upcoming call. It's crucial that we coordinate our efforts to ensure a successful launch. Please come prepared with any questions or insights you may have.\n\nLet's make this product launch a resounding success!\n\nBest regards, William",
date: "2022-09-20T12:00:00",
read: false,
labels: ["meeting", "work", "important"],
},
{
id: "ba54eefd-4097-4949-99f2-2a9ae4d1a836",
name: "Mia Harris",
email: "miaharris@example.com",
subject: "Re: Travel Itinerary",
text: "I've received the travel itinerary. It looks great! Thank you for your prompt assistance in arranging the details. I've reviewed the schedule and the accommodations, and everything seems to be in order. I'm looking forward to the trip, and I'm confident it'll be a smooth and enjoyable experience.\n\nIf there are any specific activities or attractions you recommend at our destination, please feel free to share your suggestions.\n\nExcited for the trip! Mia",
date: "2022-09-10T13:15:00",
read: true,
labels: ["personal", "travel"],
},
{
id: "df09b6ed-28bd-4e0c-85a9-9320ec5179aa",
name: "Ethan Clark",
email: "ethanclark@example.com",
subject: "Team Building Event",
text: "Let's plan a team-building event for our department. Team cohesion and morale are vital to our success, and I believe a well-organized team-building event can be incredibly beneficial. I've done some research and have a few ideas for fun and engaging activities.\n\nPlease let me know your thoughts and availability. We want this event to be both enjoyable and productive.\n\nTogether, we'll strengthen our team and boost our performance.\n\nRegards, Ethan",
date: "2022-08-25T15:30:00",
read: false,
labels: ["meeting", "work"],
},
{
id: "d67c1842-7f8b-4b4b-9be1-1b3b1ab4611d",
name: "Chloe Hall",
email: "chloehall@example.com",
subject: "Re: Budget Approval",
text: "The budget has been approved. We can proceed with the project. I'm delighted to inform you that our budget proposal has received the green light from the finance department. This is a significant milestone, and it means we can move forward with the project as planned.\n\nI've attached the finalized budget for your reference. Let's ensure that we stay on track and deliver the project on time and within budget.\n\nIt's an exciting time for us! Chloe",
date: "2022-08-10T16:45:00",
read: true,
labels: ["work", "budget"],
},
{
id: "6c9a7f94-8329-4d70-95d3-51f68c186ae1",
name: "Samuel Turner",
email: "samuelturner@example.com",
subject: "Weekend Hike",
text: "Who's up for a weekend hike in the mountains? I've been craving some outdoor adventure, and a hike in the mountains sounds like the perfect escape. If you're up for the challenge, we can explore some scenic trails and enjoy the beauty of nature.\n\nI've done some research and have a few routes in mind.\n\nLet me know if you're interested, and we can plan the details.\n\nIt's sure to be a memorable experience! Samuel",
date: "2022-07-28T17:30:00",
read: false,
labels: ["personal"],
},
]
export type Mail = (typeof mails)[number]
export const accounts = [
{
label: "Alicia Koch",
email: "alicia@example.com",
icon: (
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Vercel</title>
<path d="M24 22.525H0l12-21.05 12 21.05z" fill="currentColor" />
</svg>
),
},
{
label: "Alicia Koch",
email: "alicia@gmail.com",
icon: (
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>Gmail</title>
<path
d="M24 5.457v13.909c0 .904-.732 1.636-1.636 1.636h-3.819V11.73L12 16.64l-6.545-4.91v9.273H1.636A1.636 1.636 0 0 1 0 19.366V5.457c0-2.023 2.309-3.178 3.927-1.964L5.455 4.64 12 9.548l6.545-4.91 1.528-1.145C21.69 2.28 24 3.434 24 5.457z"
fill="currentColor"
/>
</svg>
),
},
{
label: "Alicia Koch",
email: "alicia@me.com",
icon: (
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<title>iCloud</title>
<path
d="M13.762 4.29a6.51 6.51 0 0 0-5.669 3.332 3.571 3.571 0 0 0-1.558-.36 3.571 3.571 0 0 0-3.516 3A4.918 4.918 0 0 0 0 14.796a4.918 4.918 0 0 0 4.92 4.914 4.93 4.93 0 0 0 .617-.045h14.42c2.305-.272 4.041-2.258 4.043-4.589v-.009a4.594 4.594 0 0 0-3.727-4.508 6.51 6.51 0 0 0-6.511-6.27z"
fill="currentColor"
/>
</svg>
),
},
]
export type Account = (typeof accounts)[number]
export const contacts = [
{
name: "Emma Johnson",
email: "emma.johnson@example.com",
},
{
name: "Liam Wilson",
email: "liam.wilson@example.com",
},
{
name: "Olivia Davis",
email: "olivia.davis@example.com",
},
{
name: "Noah Martinez",
email: "noah.martinez@example.com",
},
{
name: "Ava Taylor",
email: "ava.taylor@example.com",
},
{
name: "Lucas Brown",
email: "lucas.brown@example.com",
},
{
name: "Sophia Smith",
email: "sophia.smith@example.com",
},
{
name: "Ethan Wilson",
email: "ethan.wilson@example.com",
},
{
name: "Isabella Jackson",
email: "isabella.jackson@example.com",
},
{
name: "Mia Clark",
email: "mia.clark@example.com",
},
{
name: "Mason Lee",
email: "mason.lee@example.com",
},
{
name: "Layla Harris",
email: "layla.harris@example.com",
},
{
name: "William Anderson",
email: "william.anderson@example.com",
},
{
name: "Ella White",
email: "ella.white@example.com",
},
{
name: "James Thomas",
email: "james.thomas@example.com",
},
{
name: "Harper Lewis",
email: "harper.lewis@example.com",
},
{
name: "Benjamin Moore",
email: "benjamin.moore@example.com",
},
{
name: "Aria Hall",
email: "aria.hall@example.com",
},
{
name: "Henry Turner",
email: "henry.turner@example.com",
},
{
name: "Scarlett Adams",
email: "scarlett.adams@example.com",
},
]
export type Contact = (typeof contacts)[number]

View File

@@ -0,0 +1,43 @@
import { cookies } from "next/headers"
import Image from "next/image"
import { Mail } from "@/app/examples/mail/components/mail"
import { accounts, mails } from "@/app/examples/mail/data"
export default function MailPage() {
const layout = cookies().get("react-resizable-panels:layout")
const collapsed = cookies().get("react-resizable-panels:collapsed")
const defaultLayout = layout ? JSON.parse(layout.value) : undefined
const defaultCollapsed = collapsed ? JSON.parse(collapsed.value) : undefined
return (
<>
<div className="md:hidden">
<Image
src="/examples/mail-dark.png"
width={1280}
height={727}
alt="Mail"
className="hidden dark:block"
/>
<Image
src="/examples/mail-light.png"
width={1280}
height={727}
alt="Mail"
className="block dark:hidden"
/>
</div>
<div className="hidden flex-col md:flex">
<Mail
accounts={accounts}
mails={mails}
defaultLayout={defaultLayout}
defaultCollapsed={defaultCollapsed}
navCollapsedSize={4}
/>
</div>
</>
)
}

View File

@@ -0,0 +1,15 @@
import { atom, useAtom } from "jotai"
import { Mail, mails } from "@/app/examples/mail/data"
type Config = {
selected: Mail["id"] | null
}
const configAtom = atom<Config>({
selected: mails[0].id,
})
export function useMail() {
return useAtom(configAtom)
}

View File

@@ -190,7 +190,7 @@ export function Menu() {
<MenubarRadioItem value="Luis">Luis</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator />
<MenubarItem inset>Manage Famliy...</MenubarItem>
<MenubarItem inset>Manage Family...</MenubarItem>
<MenubarSeparator />
<MenubarItem inset>Add Account...</MenubarItem>
</MenubarContent>

View File

@@ -35,7 +35,7 @@ export function PodcastEmptyPlaceholder() {
You have not added any podcasts. Add one below.
</p>
<Dialog>
<DialogTrigger>
<DialogTrigger asChild>
<Button size="sm" className="relative">
Add Podcast
</Button>

View File

@@ -95,7 +95,7 @@ export function PresetActions() {
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure absolutely sure?</AlertDialogTitle>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This preset will no longer be
accessible by you or others you&apos;ve shared it with.

View File

@@ -36,7 +36,7 @@ export const models: Model<ModelType>[] = [
strengths: "Moderate classification, semantic search",
},
{
id: " be638fb1-973b-4471-a49c-290325085802",
id: "be638fb1-973b-4471-a49c-290325085802",
name: "text-ada-001",
description:
"Capable of very simple tasks, usually the fastest model in the GPT-3 series, and lowest cost.",

View File

@@ -15,7 +15,10 @@ export const columns: ColumnDef<Task>[] = [
id: "select",
header: ({ table }) => (
<Checkbox
checked={table.getIsAllPageRowsSelected()}
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
className="translate-y-[2px]"

View File

@@ -21,7 +21,7 @@ import {
} from "@/registry/new-york/ui/popover"
import { Separator } from "@/registry/new-york/ui/separator"
interface DataTableFacetedFilter<TData, TValue> {
interface DataTableFacetedFilterProps<TData, TValue> {
column?: Column<TData, TValue>
title?: string
options: {
@@ -35,7 +35,7 @@ export function DataTableFacetedFilter<TData, TValue>({
column,
title,
options,
}: DataTableFacetedFilter<TData, TValue>) {
}: DataTableFacetedFilterProps<TData, TValue>) {
const facets = column?.getFacetedUniqueValues()
const selectedValues = new Set(column?.getFilterValue() as string[])

View File

@@ -77,7 +77,7 @@ export function DataTable<TData, TValue>({
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
<TableHead key={header.id} colSpan={header.colSpan}>
{header.isPlaceholder
? null
: flexRender(

View File

@@ -5,7 +5,7 @@ import { faker } from "@faker-js/faker"
import { labels, priorities, statuses } from "./data"
const tasks = Array.from({ length: 100 }, () => ({
id: `TASK-${faker.datatype.number({ min: 1000, max: 9999 })}`,
id: `TASK-${faker.number.int({ min: 1000, max: 9999 })}`,
title: faker.hacker.phrase().replace(/^./, (letter) => letter.toUpperCase()),
status: faker.helpers.arrayElement(statuses).value,
label: faker.helpers.arrayElement(labels).value,

View File

@@ -1,5 +1,5 @@
import "@/styles/globals.css"
import { Metadata } from "next"
import { Metadata, Viewport } from "next"
import { siteConfig } from "@/config/site"
import { fontSans } from "@/lib/fonts"
@@ -9,7 +9,9 @@ import { ThemeProvider } from "@/components/providers"
import { SiteFooter } from "@/components/site-footer"
import { SiteHeader } from "@/components/site-header"
import { TailwindIndicator } from "@/components/tailwind-indicator"
import { ThemeSwitcher } from "@/components/theme-switcher"
import { Toaster as DefaultToaster } from "@/registry/default/ui/toaster"
import { Toaster as NewYorkSonner } from "@/registry/new-york/ui/sonner"
import { Toaster as NewYorkToaster } from "@/registry/new-york/ui/toaster"
export const metadata: Metadata = {
@@ -17,6 +19,7 @@ export const metadata: Metadata = {
default: siteConfig.name,
template: `%s - ${siteConfig.name}`,
},
metadataBase: new URL(siteConfig.url),
description: siteConfig.description,
keywords: [
"Next.js",
@@ -32,10 +35,6 @@ export const metadata: Metadata = {
},
],
creator: "shadcn",
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "white" },
{ media: "(prefers-color-scheme: dark)", color: "black" },
],
openGraph: {
type: "website",
locale: "en_US",
@@ -67,6 +66,13 @@ export const metadata: Metadata = {
manifest: `${siteConfig.url}/site.webmanifest`,
}
export const viewport: Viewport = {
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "white" },
{ media: "(prefers-color-scheme: dark)", color: "black" },
],
}
interface RootLayoutProps {
children: React.ReactNode
}
@@ -79,20 +85,29 @@ export default function RootLayout({ children }: RootLayoutProps) {
<body
className={cn(
"min-h-screen bg-background font-sans antialiased",
fontSans.variable
fontSans.className
)}
>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<div className="relative flex min-h-screen flex-col">
<SiteHeader />
<div className="flex-1">{children}</div>
<SiteFooter />
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<div vaul-drawer-wrapper="">
<div className="relative flex min-h-screen flex-col bg-background">
<SiteHeader />
<main className="flex-1">{children}</main>
<SiteFooter />
</div>
</div>
<TailwindIndicator />
<ThemeSwitcher />
<Analytics />
<NewYorkToaster />
<DefaultToaster />
<NewYorkSonner />
</ThemeProvider>
<Analytics />
<NewYorkToaster />
<DefaultToaster />
</body>
</html>
</>

View File

@@ -1,41 +1,31 @@
import Image from "next/image"
import Link from "next/link"
import { ArrowRightIcon } from "@radix-ui/react-icons"
import { siteConfig } from "@/config/site"
import { cn } from "@/lib/utils"
import { Announcement } from "@/components/announcement"
import { ExamplesNav } from "@/components/examples-nav"
import { Icons } from "@/components/icons"
import {
PageActions,
PageHeader,
PageHeaderDescription,
PageHeaderHeading,
} from "@/components/page-header"
import { buttonVariants } from "@/registry/new-york/ui/button"
import { Separator } from "@/registry/new-york/ui/separator"
import DashboardPage from "@/app/examples/dashboard/page"
import MailPage from "@/app/examples/mail/page"
export default function IndexPage() {
return (
<div className="container relative">
<PageHeader className="pb-8">
<Link
href="/docs/changelog"
className="inline-flex items-center rounded-lg bg-muted px-3 py-1 text-sm font-medium"
>
🎉 <Separator className="mx-2 h-4" orientation="vertical" />{" "}
<span className="sm:hidden">Style, a new CLI and more.</span>
<span className="hidden sm:inline">
Introducing Style, a new CLI and more.
</span>
<ArrowRightIcon className="ml-1 h-4 w-4" />
</Link>
<PageHeaderHeading>Build your component library.</PageHeaderHeading>
<PageHeader>
<Announcement />
<PageHeaderHeading>Build your component library</PageHeaderHeading>
<PageHeaderDescription>
Beautifully designed components that you can copy and paste into your
apps. Accessible. Customizable. Open Source.
</PageHeaderDescription>
<div className="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
<PageActions>
<Link href="/docs" className={cn(buttonVariants())}>
Get Started
</Link>
@@ -48,28 +38,28 @@ export default function IndexPage() {
<Icons.gitHub className="mr-2 h-4 w-4" />
GitHub
</Link>
</div>
</PageActions>
</PageHeader>
<ExamplesNav className="[&>a:first-child]:text-primary" />
<section className="space-y-8 overflow-hidden rounded-lg border-2 border-primary dark:border-muted md:hidden">
<section className="overflow-hidden rounded-lg border bg-background shadow-md md:hidden md:shadow-xl">
<Image
src="/examples/dashboard-light.png"
src="/examples/mail-dark.png"
width={1280}
height={866}
alt="Dashboard"
className="block dark:hidden"
height={727}
alt="Mail"
className="hidden dark:block"
/>
<Image
src="/examples/dashboard-dark.png"
src="/examples/mail-light.png"
width={1280}
height={866}
alt="Dashboard"
className="hidden dark:block"
height={727}
alt="Mail"
className="block dark:hidden"
/>
</section>
<section className="hidden md:block">
<div className="overflow-hidden rounded-lg border bg-background shadow">
<DashboardPage />
<div className="overflow-hidden rounded-lg border bg-background shadow-lg">
<MailPage />
</div>
</section>
</div>

View File

@@ -43,6 +43,7 @@ import TabsDemo from "@/registry/default/example/tabs-demo"
import ToastDemo from "@/registry/default/example/toast-demo"
import ToggleDemo from "@/registry/default/example/toggle-demo"
import ToggleDisabled from "@/registry/default/example/toggle-disabled"
import ToggleGroupDemo from "@/registry/default/example/toggle-group-demo"
import ToggleOutline from "@/registry/default/example/toggle-outline"
import ToggleWithText from "@/registry/default/example/toggle-with-text"
import TooltipDemo from "@/registry/default/example/tooltip-demo"
@@ -126,6 +127,9 @@ export default function KitchenSinkPage() {
<SwitchDemo />
<SelectDemo />
</ComponentWrapper>
<ComponentWrapper>
<ToggleGroupDemo />
</ComponentWrapper>
<ComponentWrapper>
<SeparatorDemo />
</ComponentWrapper>

View File

@@ -0,0 +1,46 @@
import { Metadata } from "next"
import "public/registry/themes.css"
import { Announcement } from "@/components/announcement"
import {
PageActions,
PageHeader,
PageHeaderDescription,
PageHeaderHeading,
} from "@/components/page-header"
import { ThemeCustomizer } from "@/components/theme-customizer"
import { ThemeWrapper } from "@/components/theme-wrapper"
import { ThemesTabs } from "@/app/themes/tabs"
export const metadata: Metadata = {
title: "Themes",
description: "Hand-picked themes that you can copy and paste into your apps.",
}
export default function ThemesPage() {
return (
<div className="container">
<ThemeWrapper
defaultTheme="zinc"
className="relative flex flex-col items-start md:flex-row md:items-center"
>
<PageHeader>
<Announcement />
<PageHeaderHeading className="hidden md:block">
Add colors. Make it yours.
</PageHeaderHeading>
<PageHeaderHeading className="md:hidden">
Make it yours
</PageHeaderHeading>
<PageHeaderDescription>
Hand-picked themes that you can copy and paste into your apps.
</PageHeaderDescription>
<PageActions>
<ThemeCustomizer />
</PageActions>
</PageHeader>
</ThemeWrapper>
<ThemesTabs />
</div>
)
}

View File

@@ -0,0 +1,73 @@
"use client"
import * as React from "react"
import { useConfig } from "@/hooks/use-config"
import { ThemeWrapper } from "@/components/theme-wrapper"
import CardsDefault from "@/registry/default/example/cards"
import { Skeleton } from "@/registry/default/ui/skeleton"
import CardsNewYork from "@/registry/new-york/example/cards"
export function ThemesTabs() {
const [mounted, setMounted] = React.useState(false)
const [config] = useConfig()
React.useEffect(() => {
setMounted(true)
}, [])
return (
<div className="space-y-8">
{!mounted ? (
<div className="md:grids-col-2 grid md:gap-4 lg:grid-cols-10 xl:gap-6">
<div className="space-y-4 lg:col-span-4 xl:col-span-6 xl:space-y-6">
<Skeleton className="h-[218px] w-full" />
<div className="grid gap-1 sm:grid-cols-[260px_1fr] md:hidden">
<Skeleton className="h-[218px] w-full" />
<div className="pt-3 sm:pl-2 sm:pt-0 xl:pl-4">
<Skeleton className="h-[218px] w-full" />
</div>
<div className="pt-3 sm:col-span-2 xl:pt-4">
<Skeleton className="h-[218px] w-full" />
</div>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
<div className="space-y-4 xl:space-y-6">
<Skeleton className="h-[218px] w-full" />
<Skeleton className="h-[218px] w-full" />
<Skeleton className="h-[218px] w-full" />
</div>
<div className="space-y-4 xl:space-y-6">
<Skeleton className="h-[218px] w-full" />
<Skeleton className="h-[218px] w-full" />
<div className="hidden xl:block">
<Skeleton className="h-[218px] w-full" />
</div>
</div>
</div>
</div>
<div className="space-y-4 lg:col-span-6 xl:col-span-4 xl:space-y-6">
<div className="hidden gap-1 sm:grid-cols-[260px_1fr] md:grid">
<Skeleton className="h-[218px] w-full" />
<div className="pt-3 sm:pl-2 sm:pt-0 xl:pl-4">
<Skeleton className="h-[218px] w-full" />
</div>
<div className="pt-3 sm:col-span-2 xl:pt-4">
<Skeleton className="h-[218px] w-full" />
</div>
</div>
<div className="hidden md:block">
<Skeleton className="h-[218px] w-full" />
</div>
<Skeleton className="h-[218px] w-full" />
</div>
</div>
) : (
<ThemeWrapper>
{config.style === "new-york" && <CardsNewYork />}
{config.style === "default" && <CardsDefault />}
</ThemeWrapper>
)}
</div>
)
}

View File

@@ -0,0 +1,20 @@
import Link from "next/link"
import { ArrowRightIcon } from "@radix-ui/react-icons"
import { Separator } from "@/registry/new-york/ui/separator"
export function Announcement() {
return (
<Link
href="/docs/changelog"
className="inline-flex items-center rounded-lg bg-muted px-3 py-1 text-sm font-medium"
>
🎉 <Separator className="mx-2 h-4" orientation="vertical" />{" "}
<span className="sm:hidden">New components and more.</span>
<span className="hidden sm:inline">
New components, cli updates and more.
</span>
<ArrowRightIcon className="ml-1 h-4 w-4" />
</Link>
)
}

View File

@@ -32,7 +32,16 @@ export function CommandMenu({ ...props }: DialogProps) {
React.useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
if ((e.key === "k" && (e.metaKey || e.ctrlKey)) || e.key === "/") {
if (
(e.target instanceof HTMLElement && e.target.isContentEditable) ||
e.target instanceof HTMLInputElement ||
e.target instanceof HTMLTextAreaElement ||
e.target instanceof HTMLSelectElement
) {
return
}
e.preventDefault()
setOpen((open) => !open)
}
@@ -52,14 +61,14 @@ export function CommandMenu({ ...props }: DialogProps) {
<Button
variant="outline"
className={cn(
"relative w-full justify-start text-sm text-muted-foreground sm:pr-12 md:w-40 lg:w-64"
"relative h-8 w-full justify-start rounded-[0.5rem] bg-background text-sm font-normal text-muted-foreground shadow-none sm:pr-12 md:w-40 lg:w-64"
)}
onClick={() => setOpen(true)}
{...props}
>
<span className="hidden lg:inline-flex">Search documentation...</span>
<span className="inline-flex lg:hidden">Search...</span>
<kbd className="pointer-events-none absolute right-1.5 top-1.5 hidden h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex">
<kbd className="pointer-events-none absolute right-[0.3rem] top-[0.3rem] hidden h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex">
<span className="text-xs"></span>K
</kbd>
</Button>

View File

@@ -102,7 +102,7 @@ export function ComponentPreview({
codeString && <CopyButton value={codeString} />
)}
</div>
<ThemeWrapper>
<ThemeWrapper defaultTheme="zinc">
<div
className={cn(
"preview flex min-h-[350px] w-full justify-center p-10",

View File

@@ -21,7 +21,7 @@ interface CopyButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
event?: Event["name"]
}
async function copyToClipboardWithMeta(value: string, event?: Event) {
export async function copyToClipboardWithMeta(value: string, event?: Event) {
navigator.clipboard.writeText(value)
if (event) {
trackEvent(event)
@@ -151,7 +151,7 @@ export function CopyNpmCommandButton({
}, [hasCopied])
const copyCommand = React.useCallback(
(value: string, pm: "npm" | "pnpm" | "yarn") => {
(value: string, pm: "npm" | "pnpm" | "yarn" | "bun") => {
copyToClipboardWithMeta(value, {
name: "copy_npm_command",
properties: {
@@ -199,6 +199,11 @@ export function CopyNpmCommandButton({
>
pnpm
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => copyCommand(commands.__bunCommand__, "bun")}
>
bun
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)

View File

@@ -0,0 +1,31 @@
"use client"
import { forwardRef } from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import { cn } from "@/lib/utils"
const DrawerTrigger = DrawerPrimitive.Trigger
const DrawerContent = forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPrimitive.Portal>
<DrawerPrimitive.Overlay className="fixed inset-0 z-50 bg-black/80" />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 h-[96%] rounded-t-[10px] bg-background",
className
)}
{...props}
>
<div className="absolute left-1/2 top-3 h-2 w-[100px] translate-x-[-50%] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPrimitive.Portal>
))
DrawerContent.displayName = "DrawerContent"
export { DrawerTrigger, DrawerContent }

View File

@@ -8,6 +8,11 @@ import { cn } from "@/lib/utils"
import { ScrollArea, ScrollBar } from "@/registry/new-york/ui/scroll-area"
const examples = [
{
name: "Mail",
href: "/examples/mail",
code: "https://github.com/shadcn/ui/tree/main/apps/www/app/examples/mail",
},
{
name: "Dashboard",
href: "/examples/dashboard",
@@ -54,15 +59,16 @@ export function ExamplesNav({ className, ...props }: ExamplesNavProps) {
<div className="relative">
<ScrollArea className="max-w-[600px] lg:max-w-none">
<div className={cn("mb-4 flex items-center", className)} {...props}>
{examples.map((example) => (
{examples.map((example, index) => (
<Link
href={example.href}
key={example.href}
className={cn(
"flex items-center px-4",
pathname?.startsWith(example.href)
? "font-bold text-primary"
: "font-medium text-muted-foreground"
"flex h-7 items-center justify-center rounded-full px-4 text-center text-sm transition-colors hover:text-primary",
pathname?.startsWith(example.href) ||
(index === 0 && pathname === "/")
? "bg-muted font-medium text-primary"
: "text-muted-foreground"
)}
>
{example.name}
@@ -71,9 +77,6 @@ export function ExamplesNav({ className, ...props }: ExamplesNavProps) {
</div>
<ScrollBar orientation="horizontal" className="invisible" />
</ScrollArea>
<ExampleCodeLink
pathname={pathname === "/" ? "/examples/dashboard" : pathname}
/>
</div>
)
}

View File

@@ -29,8 +29,14 @@ export const Icons = {
</svg>
),
twitter: (props: IconProps) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
<path d="M21.543 7.104c.015.211.015.423.015.636 0 6.507-4.954 14.01-14.01 14.01v-.003A13.94 13.94 0 0 1 0 19.539a9.88 9.88 0 0 0 7.287-2.041 4.93 4.93 0 0 1-4.6-3.42 4.916 4.916 0 0 0 2.223-.084A4.926 4.926 0 0 1 .96 9.167v-.062a4.887 4.887 0 0 0 2.235.616A4.928 4.928 0 0 1 1.67 3.148a13.98 13.98 0 0 0 10.15 5.144 4.929 4.929 0 0 1 8.39-4.49 9.868 9.868 0 0 0 3.128-1.196 4.941 4.941 0 0 1-2.165 2.724A9.828 9.828 0 0 0 24 4.555a10.019 10.019 0 0 1-2.457 2.549z" />
<svg
{...props}
height="23"
viewBox="0 0 1200 1227"
width="23"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" />
</svg>
),
gitHub: (props: IconProps) => (

View File

@@ -7,6 +7,7 @@ import { usePathname } from "next/navigation"
import { siteConfig } from "@/config/site"
import { cn } from "@/lib/utils"
import { Icons } from "@/components/icons"
import { Badge } from "@/registry/new-york/ui/badge"
export function MainNav() {
const pathname = usePathname()
@@ -19,7 +20,7 @@ export function MainNav() {
{siteConfig.name}
</span>
</Link>
<nav className="flex items-center space-x-6 text-sm font-medium">
<nav className="flex items-center gap-6 text-sm">
<Link
href="/docs"
className={cn(
@@ -27,7 +28,7 @@ export function MainNav() {
pathname === "/docs" ? "text-foreground" : "text-foreground/60"
)}
>
Documentation
Docs
</Link>
<Link
href="/docs/components"
@@ -40,6 +41,17 @@ export function MainNav() {
>
Components
</Link>
<Link
href="/themes"
className={cn(
"transition-colors hover:text-foreground/80",
pathname?.startsWith("/themes")
? "text-foreground"
: "text-foreground/60"
)}
>
Themes
</Link>
<Link
href="/examples"
className={cn(

View File

@@ -2,7 +2,7 @@
import * as React from "react"
import Image from "next/image"
import Link, { LinkProps } from "next/link"
import Link from "next/link"
import { useMDXComponent } from "next-contentlayer/hooks"
import { NpmCommands } from "types/unist"
@@ -170,8 +170,9 @@ const components = {
className,
__rawString__,
__npmCommand__,
__pnpmCommand__,
__yarnCommand__,
__pnpmCommand__,
__bunCommand__,
__withMeta__,
__src__,
__event__,
@@ -201,16 +202,20 @@ const components = {
className={cn("absolute right-4 top-4", __withMeta__ && "top-16")}
/>
)}
{__npmCommand__ && __yarnCommand__ && __pnpmCommand__ && (
<CopyNpmCommandButton
commands={{
__npmCommand__,
__pnpmCommand__,
__yarnCommand__,
}}
className={cn("absolute right-4 top-4", __withMeta__ && "top-16")}
/>
)}
{__npmCommand__ &&
__yarnCommand__ &&
__pnpmCommand__ &&
__bunCommand__ && (
<CopyNpmCommandButton
commands={{
__npmCommand__,
__yarnCommand__,
__pnpmCommand__,
__bunCommand__,
}}
className={cn("absolute right-4 top-4", __withMeta__ && "top-16")}
/>
)}
</StyleWrapper>
)
},
@@ -292,6 +297,12 @@ const components = {
}: React.ComponentProps<typeof FrameworkDocs>) => (
<FrameworkDocs className={cn(className)} {...props} />
),
Link: ({ className, ...props }: React.ComponentProps<typeof Link>) => (
<Link
className={cn("font-medium underline underline-offset-4", className)}
{...props}
/>
),
LinkedCard: ({ className, ...props }: React.ComponentProps<typeof Link>) => (
<Link
className={cn(

View File

@@ -23,7 +23,35 @@ export function MobileNav() {
variant="ghost"
className="mr-2 px-0 text-base hover:bg-transparent focus-visible:bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 md:hidden"
>
<ViewVerticalIcon className="h-5 w-5" />
<svg
strokeWidth="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
>
<path
d="M3 5H11"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<path
d="M3 12H16"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
></path>
<path
d="M3 19H21"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
></path>
</svg>
<span className="sr-only">Toggle Menu</span>
</Button>
</SheetTrigger>
@@ -66,6 +94,11 @@ export function MobileNav() {
className="text-muted-foreground"
>
{item.title}
{item.label && (
<span className="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000] no-underline group-hover:no-underline">
{item.label}
</span>
)}
</MobileLink>
) : (
item.title

View File

@@ -10,7 +10,7 @@ function PageHeader({
return (
<section
className={cn(
"flex max-w-[980px] flex-col items-start gap-2 px-4 pt-8 md:pt-12",
"mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20",
className
)}
{...props}
@@ -27,7 +27,7 @@ function PageHeaderHeading({
return (
<h1
className={cn(
"text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1]",
"text-center text-3xl font-bold leading-tight tracking-tighter md:text-6xl lg:leading-[1.1]",
className
)}
{...props}
@@ -42,7 +42,7 @@ function PageHeaderDescription({
return (
<Balance
className={cn(
"max-w-[750px] text-lg text-muted-foreground sm:text-xl",
"max-w-[750px] text-center text-lg text-muted-foreground sm:text-xl",
className
)}
{...props}
@@ -50,4 +50,19 @@ function PageHeaderDescription({
)
}
export { PageHeader, PageHeaderHeading, PageHeaderDescription }
function PageActions({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn(
"flex w-full items-center justify-center space-x-4 py-4 md:pb-10",
className
)}
{...props}
/>
)
}
export { PageHeader, PageHeaderHeading, PageHeaderDescription, PageActions }

View File

@@ -4,7 +4,7 @@ export function SiteFooter() {
return (
<footer className="py-6 md:px-8 md:py-0">
<div className="container flex flex-col items-center justify-between gap-4 md:h-24 md:flex-row">
<p className="text-center text-sm leading-loose text-muted-foreground md:text-left">
<p className="text-balance text-center text-sm leading-loose text-muted-foreground md:text-left">
Built by{" "}
<a
href={siteConfig.links.twitter}

View File

@@ -11,8 +11,8 @@ import { buttonVariants } from "@/registry/new-york/ui/button"
export function SiteHeader() {
return (
<header className="supports-backdrop-blur:bg-background/60 sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur">
<div className="container flex h-14 items-center">
<header className="sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-14 max-w-screen-2xl items-center">
<MainNav />
<MobileNav />
<div className="flex flex-1 items-center justify-between space-x-2 md:justify-end">
@@ -50,7 +50,7 @@ export function SiteHeader() {
"w-9 px-0"
)}
>
<Icons.twitter className="h-4 w-4 fill-current" />
<Icons.twitter className="h-3 w-3 fill-current" />
<span className="sr-only">Twitter</span>
</div>
</Link>

View File

@@ -0,0 +1,52 @@
"use client"
import * as React from "react"
import { Index } from "@/__registry__"
import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"
import { Icons } from "@/components/icons"
interface ThemeComponentProps extends React.HTMLAttributes<HTMLDivElement> {
name: string
extractClassname?: boolean
extractedClassNames?: string
align?: "center" | "start" | "end"
}
export function ThemeComponent({ name, ...props }: ThemeComponentProps) {
const [config] = useConfig()
const Preview = React.useMemo(() => {
const Component = Index[config.style][name]?.component
if (!Component) {
return (
<p className="text-sm text-muted-foreground">
Component{" "}
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
{name}
</code>{" "}
not found in registry.
</p>
)
}
return <Component />
}, [name, config.style])
return (
<div className={cn("relative")} {...props}>
<React.Suspense
fallback={
<div className="flex items-center text-sm text-muted-foreground">
<Icons.spinner className="mr-2 h-4 w-4 animate-spin" />
Loading...
</div>
}
>
{Preview}
</React.Suspense>
</div>
)
}

View File

@@ -0,0 +1,631 @@
"use client"
import * as React from "react"
import {
CheckIcon,
CopyIcon,
InfoCircledIcon,
MoonIcon,
ResetIcon,
SunIcon,
} from "@radix-ui/react-icons"
import template from "lodash.template"
import { Paintbrush } from "lucide-react"
import { useTheme } from "next-themes"
import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"
import { copyToClipboardWithMeta } from "@/components/copy-button"
import { ThemeWrapper } from "@/components/theme-wrapper"
import { Button } from "@/registry/new-york/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/registry/new-york/ui/dialog"
import {
Drawer,
DrawerContent,
DrawerTrigger,
} from "@/registry/new-york/ui/drawer"
import { Label } from "@/registry/new-york/ui/label"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/registry/new-york/ui/popover"
import { Skeleton } from "@/registry/new-york/ui/skeleton"
import { Theme, themes } from "@/registry/themes"
import "@/styles/mdx.css"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/registry/new-york/ui/tooltip"
export function ThemeCustomizer() {
const [config, setConfig] = useConfig()
const { resolvedTheme: mode } = useTheme()
const [mounted, setMounted] = React.useState(false)
React.useEffect(() => {
setMounted(true)
}, [])
return (
<div className="flex items-center space-x-2">
<Drawer>
<DrawerTrigger asChild>
<Button variant="outline" className="md:hidden">
<Paintbrush className="mr-2 h-4 w-4" />
Customize
</Button>
</DrawerTrigger>
<DrawerContent className="p-6 pt-0">
<Customizer />
</DrawerContent>
</Drawer>
<div className="hidden md:flex">
<div className="mr-2 hidden items-center space-x-0.5 lg:flex">
{mounted ? (
<>
{["zinc", "rose", "blue", "green", "orange"].map((color) => {
const theme = themes.find((theme) => theme.name === color)
const isActive = config.theme === color
if (!theme) {
return null
}
return (
<Tooltip key={theme.name}>
<TooltipTrigger asChild>
<button
onClick={() =>
setConfig({
...config,
theme: theme.name,
})
}
className={cn(
"flex h-9 w-9 items-center justify-center rounded-full border-2 text-xs",
isActive
? "border-[--theme-primary]"
: "border-transparent"
)}
style={
{
"--theme-primary": `hsl(${
theme?.activeColor[
mode === "dark" ? "dark" : "light"
]
})`,
} as React.CSSProperties
}
>
<span
className={cn(
"flex h-6 w-6 items-center justify-center rounded-full bg-[--theme-primary]"
)}
>
{isActive && (
<CheckIcon className="h-4 w-4 text-white" />
)}
</span>
<span className="sr-only">{theme.label}</span>
</button>
</TooltipTrigger>
<TooltipContent
align="center"
className="rounded-[0.5rem] bg-zinc-900 text-zinc-50"
>
{theme.label}
</TooltipContent>
</Tooltip>
)
})}
</>
) : (
<div className="mr-1 flex items-center gap-4">
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-6 w-6 rounded-full" />
<Skeleton className="h-6 w-6 rounded-full" />
</div>
)}
</div>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline">
<Paintbrush className="mr-2 h-4 w-4" />
Customize
</Button>
</PopoverTrigger>
<PopoverContent
align="center"
className="z-40 w-[340px] rounded-[0.5rem] bg-white p-6 dark:bg-zinc-950"
>
<Customizer />
</PopoverContent>
</Popover>
</div>
<CopyCodeButton />
</div>
)
}
function Customizer() {
const [mounted, setMounted] = React.useState(false)
const { setTheme: setMode, resolvedTheme: mode } = useTheme()
const [config, setConfig] = useConfig()
React.useEffect(() => {
setMounted(true)
}, [])
return (
<ThemeWrapper
defaultTheme="zinc"
className="flex flex-col space-y-4 md:space-y-6"
>
<div className="flex items-start pt-4 md:pt-0">
<div className="space-y-1 pr-2">
<div className="font-semibold leading-none tracking-tight">
Customize
</div>
<div className="text-xs text-muted-foreground">
Pick a style and color for your components.
</div>
</div>
<Button
variant="ghost"
size="icon"
className="ml-auto rounded-[0.5rem]"
onClick={() => {
setConfig({
...config,
theme: "zinc",
radius: 0.5,
})
}}
>
<ResetIcon />
<span className="sr-only">Reset</span>
</Button>
</div>
<div className="flex flex-1 flex-col space-y-4 md:space-y-6">
<div className="space-y-1.5">
<div className="flex w-full items-center">
<Label className="text-xs">Style</Label>
<Popover>
<PopoverTrigger>
<InfoCircledIcon className="ml-1 h-3 w-3" />
<span className="sr-only">About styles</span>
</PopoverTrigger>
<PopoverContent
className="space-y-3 rounded-[0.5rem] text-sm"
side="right"
align="start"
alignOffset={-20}
>
<p className="font-medium">
What is the difference between the New York and Default style?
</p>
<p>
A style comes with its own set of components, animations,
icons and more.
</p>
<p>
The <span className="font-medium">Default</span> style has
larger inputs, uses lucide-react for icons and
tailwindcss-animate for animations.
</p>
<p>
The <span className="font-medium">New York</span> style ships
with smaller buttons and cards with shadows. It uses icons
from Radix Icons.
</p>
</PopoverContent>
</Popover>
</div>
<div className="grid grid-cols-3 gap-2">
<Button
variant={"outline"}
size="sm"
onClick={() => setConfig({ ...config, style: "default" })}
className={cn(
config.style === "default" && "border-2 border-primary"
)}
>
Default
</Button>
<Button
variant={"outline"}
size="sm"
onClick={() => setConfig({ ...config, style: "new-york" })}
className={cn(
config.style === "new-york" && "border-2 border-primary"
)}
>
New York
</Button>
</div>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Color</Label>
<div className="grid grid-cols-3 gap-2">
{themes.map((theme) => {
const isActive = config.theme === theme.name
return mounted ? (
<Button
variant={"outline"}
size="sm"
key={theme.name}
onClick={() => {
setConfig({
...config,
theme: theme.name,
})
}}
className={cn(
"justify-start",
isActive && "border-2 border-primary"
)}
style={
{
"--theme-primary": `hsl(${
theme?.activeColor[mode === "dark" ? "dark" : "light"]
})`,
} as React.CSSProperties
}
>
<span
className={cn(
"mr-1 flex h-5 w-5 shrink-0 -translate-x-1 items-center justify-center rounded-full bg-[--theme-primary]"
)}
>
{isActive && <CheckIcon className="h-4 w-4 text-white" />}
</span>
{theme.label}
</Button>
) : (
<Skeleton className="h-8 w-full" key={theme.name} />
)
})}
</div>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Radius</Label>
<div className="grid grid-cols-5 gap-2">
{["0", "0.3", "0.5", "0.75", "1.0"].map((value) => {
return (
<Button
variant={"outline"}
size="sm"
key={value}
onClick={() => {
setConfig({
...config,
radius: parseFloat(value),
})
}}
className={cn(
config.radius === parseFloat(value) &&
"border-2 border-primary"
)}
>
{value}
</Button>
)
})}
</div>
</div>
<div className="space-y-1.5">
<Label className="text-xs">Mode</Label>
<div className="grid grid-cols-3 gap-2">
{mounted ? (
<>
<Button
variant={"outline"}
size="sm"
onClick={() => setMode("light")}
className={cn(mode === "light" && "border-2 border-primary")}
>
<SunIcon className="mr-1 -translate-x-1" />
Light
</Button>
<Button
variant={"outline"}
size="sm"
onClick={() => setMode("dark")}
className={cn(mode === "dark" && "border-2 border-primary")}
>
<MoonIcon className="mr-1 -translate-x-1" />
Dark
</Button>
</>
) : (
<>
<Skeleton className="h-8 w-full" />
<Skeleton className="h-8 w-full" />
</>
)}
</div>
</div>
</div>
</ThemeWrapper>
)
}
function CopyCodeButton() {
const [config] = useConfig()
const activeTheme = themes.find((theme) => theme.name === config.theme)
const [hasCopied, setHasCopied] = React.useState(false)
React.useEffect(() => {
setTimeout(() => {
setHasCopied(false)
}, 2000)
}, [hasCopied])
return (
<>
{activeTheme && (
<Button
onClick={() => {
copyToClipboardWithMeta(getThemeCode(activeTheme, config.radius), {
name: "copy_theme_code",
properties: {
theme: activeTheme.name,
radius: config.radius,
},
})
setHasCopied(true)
}}
className="md:hidden"
>
{hasCopied ? (
<CheckIcon className="mr-2 h-4 w-4" />
) : (
<CopyIcon className="mr-2 h-4 w-4" />
)}
Copy
</Button>
)}
<Dialog>
<DialogTrigger asChild>
<Button className="hidden md:flex">Copy code</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl outline-none">
<DialogHeader>
<DialogTitle>Theme</DialogTitle>
<DialogDescription>
Copy and paste the following code into your CSS file.
</DialogDescription>
</DialogHeader>
<ThemeWrapper defaultTheme="zinc" className="relative">
<CustomizerCode />
{activeTheme && (
<Button
size="sm"
onClick={() => {
copyToClipboardWithMeta(
getThemeCode(activeTheme, config.radius),
{
name: "copy_theme_code",
properties: {
theme: activeTheme.name,
radius: config.radius,
},
}
)
setHasCopied(true)
}}
className="absolute right-4 top-4 bg-muted text-muted-foreground hover:bg-muted hover:text-muted-foreground"
>
{hasCopied ? (
<CheckIcon className="mr-2 h-4 w-4" />
) : (
<CopyIcon className="mr-2 h-4 w-4" />
)}
Copy
</Button>
)}
</ThemeWrapper>
</DialogContent>
</Dialog>
</>
)
}
function CustomizerCode() {
const [config] = useConfig()
const activeTheme = themes.find((theme) => theme.name === config.theme)
return (
<ThemeWrapper defaultTheme="zinc" className="relative space-y-4">
<div data-rehype-pretty-code-fragment="">
<pre className="max-h-[450px] overflow-x-auto rounded-lg border bg-zinc-950 py-4 dark:bg-zinc-900">
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
<span className="line text-white">@layer base &#123;</span>
<span className="line text-white">&nbsp;&nbsp;:root &#123;</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--background:{" "}
{activeTheme?.cssVars.light["background"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--foreground:{" "}
{activeTheme?.cssVars.light["foreground"]};
</span>
{[
"card",
"popover",
"primary",
"secondary",
"muted",
"accent",
"destructive",
].map((prefix) => (
<>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--{prefix}:{" "}
{
activeTheme?.cssVars.light[
prefix as keyof typeof activeTheme.cssVars.light
]
}
;
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--{prefix}-foreground:{" "}
{
activeTheme?.cssVars.light[
`${prefix}-foreground` as keyof typeof activeTheme.cssVars.light
]
}
;
</span>
</>
))}
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--border:{" "}
{activeTheme?.cssVars.light["border"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--input:{" "}
{activeTheme?.cssVars.light["input"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--ring:{" "}
{activeTheme?.cssVars.light["ring"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--radius: {config.radius}rem;
</span>
<span className="line text-white">&nbsp;&nbsp;&#125;</span>
<span className="line text-white">&nbsp;</span>
<span className="line text-white">&nbsp;&nbsp;.dark &#123;</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--background:{" "}
{activeTheme?.cssVars.dark["background"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--foreground:{" "}
{activeTheme?.cssVars.dark["foreground"]};
</span>
{[
"card",
"popover",
"primary",
"secondary",
"muted",
"accent",
"destructive",
].map((prefix) => (
<>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--{prefix}:{" "}
{
activeTheme?.cssVars.dark[
prefix as keyof typeof activeTheme.cssVars.dark
]
}
;
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--{prefix}-foreground:{" "}
{
activeTheme?.cssVars.dark[
`${prefix}-foreground` as keyof typeof activeTheme.cssVars.dark
]
}
;
</span>
</>
))}
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--border:{" "}
{activeTheme?.cssVars.dark["border"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--input:{" "}
{activeTheme?.cssVars.dark["input"]};
</span>
<span className="line text-white">
&nbsp;&nbsp;&nbsp;&nbsp;--ring:{" "}
{activeTheme?.cssVars.dark["ring"]};
</span>
<span className="line text-white">&nbsp;&nbsp;&#125;</span>
<span className="line text-white">&#125;</span>
</code>
</pre>
</div>
</ThemeWrapper>
)
}
function getThemeCode(theme: Theme, radius: number) {
if (!theme) {
return ""
}
return template(BASE_STYLES_WITH_VARIABLES)({
colors: theme.cssVars,
radius,
})
}
const BASE_STYLES_WITH_VARIABLES = `
@layer base {
:root {
--background: <%- colors.light["background"] %>;
--foreground: <%- colors.light["foreground"] %>;
--card: <%- colors.light["card"] %>;
--card-foreground: <%- colors.light["card-foreground"] %>;
--popover: <%- colors.light["popover"] %>;
--popover-foreground: <%- colors.light["popover-foreground"] %>;
--primary: <%- colors.light["primary"] %>;
--primary-foreground: <%- colors.light["primary-foreground"] %>;
--secondary: <%- colors.light["secondary"] %>;
--secondary-foreground: <%- colors.light["secondary-foreground"] %>;
--muted: <%- colors.light["muted"] %>;
--muted-foreground: <%- colors.light["muted-foreground"] %>;
--accent: <%- colors.light["accent"] %>;
--accent-foreground: <%- colors.light["accent-foreground"] %>;
--destructive: <%- colors.light["destructive"] %>;
--destructive-foreground: <%- colors.light["destructive-foreground"] %>;
--border: <%- colors.light["border"] %>;
--input: <%- colors.light["input"] %>;
--ring: <%- colors.light["ring"] %>;
--radius: <%- radius %>rem;
}
.dark {
--background: <%- colors.dark["background"] %>;
--foreground: <%- colors.dark["foreground"] %>;
--card: <%- colors.dark["card"] %>;
--card-foreground: <%- colors.dark["card-foreground"] %>;
--popover: <%- colors.dark["popover"] %>;
--popover-foreground: <%- colors.dark["popover-foreground"] %>;
--primary: <%- colors.dark["primary"] %>;
--primary-foreground: <%- colors.dark["primary-foreground"] %>;
--secondary: <%- colors.dark["secondary"] %>;
--secondary-foreground: <%- colors.dark["secondary-foreground"] %>;
--muted: <%- colors.dark["muted"] %>;
--muted-foreground: <%- colors.dark["muted-foreground"] %>;
--accent: <%- colors.dark["accent"] %>;
--accent-foreground: <%- colors.dark["accent-foreground"] %>;
--destructive: <%- colors.dark["destructive"] %>;
--destructive-foreground: <%- colors.dark["destructive-foreground"] %>;
--border: <%- colors.dark["border"] %>;
--input: <%- colors.dark["input"] %>;
--ring: <%- colors.dark["ring"] %>;
}
}
`

View File

@@ -0,0 +1,26 @@
"use client"
import * as React from "react"
import { useSelectedLayoutSegment } from "next/navigation"
import { useConfig } from "@/hooks/use-config"
export function ThemeSwitcher() {
const [config] = useConfig()
const segment = useSelectedLayoutSegment()
React.useEffect(() => {
document.body.classList.forEach((className) => {
if (className.match(/^theme.*/)) {
document.body.classList.remove(className)
}
})
const theme = segment === "themes" ? config.theme : null
if (theme) {
return document.body.classList.add(`theme-${theme}`)
}
}, [segment, config])
return null
}

View File

@@ -3,8 +3,31 @@
import { cn } from "@/lib/utils"
import { useConfig } from "@/hooks/use-config"
export function ThemeWrapper({ children }: React.ComponentProps<"div">) {
interface ThemeWrapperProps extends React.ComponentProps<"div"> {
defaultTheme?: string
}
export function ThemeWrapper({
defaultTheme,
children,
className,
}: ThemeWrapperProps) {
const [config] = useConfig()
return <div className={cn(`theme-${config.theme}`, "w-full")}>{children}</div>
return (
<div
className={cn(
`theme-${defaultTheme || config.theme}`,
"w-full",
className
)}
style={
{
"--radius": `${defaultTheme ? 0.5 : config.radius}rem`,
} as React.CSSProperties
}
>
{children}
</div>
)
}

View File

@@ -15,6 +15,10 @@ export const docsConfig: DocsConfig = {
title: "Components",
href: "/docs/components/accordion",
},
{
title: "Themes",
href: "/themes",
},
{
title: "Examples",
href: "/examples",
@@ -48,6 +52,11 @@ export const docsConfig: DocsConfig = {
href: "/docs/installation",
items: [],
},
{
title: "components.json",
href: "/docs/components-json",
items: [],
},
{
title: "Theming",
href: "/docs/theming",
@@ -78,46 +87,6 @@ export const docsConfig: DocsConfig = {
href: "/docs/changelog",
items: [],
},
{
title: "About",
href: "/docs/about",
items: [],
},
],
},
{
title: "Installation",
items: [
{
title: "Next.js",
href: "/docs/installation/next",
items: [],
},
{
title: "Vite",
href: "/docs/installation/vite",
items: [],
},
{
title: "Remix",
href: "/docs/installation/remix",
items: [],
},
{
title: "Gatsby",
href: "/docs/installation/gatsby",
items: [],
},
{
title: "Astro",
href: "/docs/installation/astro",
items: [],
},
{
title: "Manual",
href: "/docs/installation/manual",
items: [],
},
],
},
{
@@ -168,6 +137,12 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/card",
items: [],
},
{
title: "Carousel",
href: "/docs/components/carousel",
items: [],
label: "New",
},
{
title: "Checkbox",
href: "/docs/components/checkbox",
@@ -208,6 +183,12 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/dialog",
items: [],
},
{
title: "Drawer",
href: "/docs/components/drawer",
items: [],
label: "New",
},
{
title: "Dropdown Menu",
href: "/docs/components/dropdown-menu",
@@ -243,6 +224,12 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/navigation-menu",
items: [],
},
{
title: "Pagination",
href: "/docs/components/pagination",
items: [],
label: "New",
},
{
title: "Popover",
href: "/docs/components/popover",
@@ -258,6 +245,12 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/radio-group",
items: [],
},
{
title: "Resizable",
href: "/docs/components/resizable",
items: [],
label: "New",
},
{
title: "Scroll Area",
href: "/docs/components/scroll-area",
@@ -288,6 +281,12 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/slider",
items: [],
},
{
title: "Sonner",
href: "/docs/components/sonner",
items: [],
label: "New",
},
{
title: "Switch",
href: "/docs/components/switch",
@@ -318,6 +317,11 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/toggle",
items: [],
},
{
title: "Toggle Group",
href: "/docs/components/toggle-group",
items: [],
},
{
title: "Tooltip",
href: "/docs/components/tooltip",

View File

@@ -3,10 +3,10 @@ export const siteConfig = {
url: "https://ui.shadcn.com",
ogImage: "https://ui.shadcn.com/og.jpg",
description:
"Beautifully designed components built with Radix UI and Tailwind CSS.",
"Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.",
links: {
twitter: "https://twitter.com/shadcn",
github: "https://github.com/shadcn/ui",
github: "https://github.com/shadcn-ui/ui",
},
}

View File

@@ -4,11 +4,76 @@ description: Latest updates and announcements.
toc: false
---
## December 2023 - New components, CLI and more
We've added new components to shadcn/ui and made a lot of improvements to the CLI.
Here's a quick overview of what's new:
- [**Carousel**](#carousel) - A carousel component with motion, swipe gestures and keyboard support.
- [**Drawer**](#drawer) - A drawer component that looks amazing on mobile.
- [**Pagination**](#pagination) - A pagination component with page navigation, previous and next buttons.
- [**Resizable**](#resizable) - A resizable component for building resizable panel groups and layouts.
- [**Sonner**](#sonner) - The last toast component you'll ever need.
- [**CLI updates**](#cli-updates) - Support for custom **Tailwind prefix** and `tailwind.config.ts`.
### Carousel
We've added a fully featured carousel component with motion, swipe gestures and keyboard support. Built on top of [Embla Carousel](https://www.embla-carousel.com).
It has support for infinite looping, autoplay, vertical orientation, and more.
<ComponentPreview name="carousel-demo" />
### Drawer
Oh the drawer component 😍. Built on top of [Vaul](https://github.com/emilkowalski/vaul) by [emilkowalski\_](https://twitter.com/emilkowalski_).
Try opening the following drawer on mobile. It looks amazing!
<ComponentPreview name="drawer-demo" />
### Pagination
We've added a pagination component with page navigation, previous and next buttons. Simple, flexible and works with your framework's `<Link />` component.
<ComponentPreview name="pagination-demo" />
### Resizable
Build resizable panel groups and layouts with this `<Resizable />` component.
<ComponentPreview name="resizable-demo-with-handle" />
`<Resizable />` is built using [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) by [bvaughn](https://github.com/bvaughn). It has support for mouse, touch and keyboard.
### Sonner
Another one by [emilkowalski\_](https://twitter.com/emilkowalski_). The last toast component you'll ever need. Sonner is now availabe in shadcn/ui.
<ComponentPreview name="sonner-demo" />
### CLI updates
This has been one of the most requested features. You can now configure a custom Tailwind prefix and the cli will automatically prefix your utility classes when adding components.
This means you can now easily add shadcn/ui components to existing projects like Docusaurus, Nextra...etc. A drop-in for your existing design system with no conflict. 🔥
```tsx /tw-/
<AlertDialog className="tw-grid tw-gap-4 tw-border tw-bg-background tw-shadow-lg" />
```
It works with `cn`, `cva` and CSS variables.
The cli can now also detect `tailwind.config.ts` and add the TypeScript version of the config for you.
That's it. Happy Holidays.
## July 2023 - JavaScript
This project and the components are written in TypeScript. We recommend using TypeScript for your project as well.
This project and the components are written in TypeScript. **We recommend using TypeScript for your project as well**.
However we provide a JavaScript version of the components as well. The JavaScript version is available via the [cli](/docs/cli).
However we provide a JavaScript version of the components, available via the [cli](/docs/cli).
```txt
Would you like to use TypeScript (recommended)? no

View File

@@ -16,6 +16,7 @@ npx shadcn-ui@latest init
You will be asked a few questions to configure `components.json`:
```txt showLineNumbers
Would you like to use TypeScript (recommended)? no/yes
Which style would you like to use? Default
Which color would you like to use as base color? Slate
Where is your global CSS file? app/globals.css
@@ -50,7 +51,8 @@ npx shadcn-ui@latest add [component]
You will be presented with a list of components to choose from:
```txt
Which components would you like to add? Space to select. Return to submit.
Which components would you like to add? Space to select. A to toggle all.
Enter to submit.
◯ accordion
◯ alert

View File

@@ -0,0 +1,189 @@
---
title: components.json
description: Configuration for your project.
---
The `components.json` file holds configuration for your project.
We use it to understand how your project is set up and how to generate components customized for your project.
<Callout className="mt-6">
Note: The `components.json` file is optional and **only required if you're
using the CLI** to add components to your project. If you're using the copy
and paste method, you don't need this file.
</Callout>
You can create a `components.json` file in your project by running the following command:
```bash
npx shadcn-ui@latest init
```
See the <Link href="/docs/cli">CLI section</Link> for more information.
## $schema
You can see the JSON Schema for `components.json` [here](https://ui.shadcn.com/schema.json).
```json title="components.json"
{
"$schema": "https://ui.shadcn.com/schema.json"
}
```
## style
The style for your components. **This cannot be changed after initialization.**
```json title="components.json"
{
"style": "default" | "new-york"
}
```
<ComponentPreview name="card-with-form" />
## tailwind
Configuration to help the CLI understand how Tailwind CSS is set up in your project.
See the <Link href="/docs/installation">installation section</Link> for how to set up Tailwind CSS.
### tailwind.config
Path to where your `tailwind.config.js` file is located.
```json title="components.json"
{
"tailwind": {
"config": "tailwind.config.js" | "tailwind.config.ts"
}
}
```
### tailwind.css
Path to the CSS file that imports Tailwind CSS into your project.
```json title="components.json"
{
"tailwind": {
"css": "styles/global.css"
}
}
```
### tailwind.baseColor
This is used to generate the default color palette for your components. **This cannot be changed after initialization.**
```json title="components.json"
{
"tailwind": {
"baseColor": "gray" | "neutral" | "slate" | "stone" | "zinc"
}
}
```
### tailwind.cssVariables
You can choose between using CSS variables or Tailwind CSS utility classes for theming.
To use utility classes for theming set `tailwind.cssVariables` to `false`. For CSS variables, set `tailwind.cssVariables` to `true`.
```json title="components.json"
{
"tailwind": {
"cssVariables": `true` | `false`
}
}
```
For more information, see the <Link href="/docs/theming">theming docs</Link>.
**This cannot be changed after initialization.** To switch between CSS variables and utility classes, you'll have to delete and re-install your components.
### tailwind.prefix
The prefix to use for your Tailwind CSS utility classes. Components will be added with this prefix.
```json title="components.json"
{
"tailwind": {
"prefix": "tw-"
}
}
```
## rsc
Whether or not to enable support for React Server Components.
The CLI automatically adds a `use client` directive to client components when set to `true`.
```json title="components.json"
{
"rsc": `true` | `false`
}
```
## tsx
Choose between TypeScript or JavaScript components.
Setting this option to `false` allows components to be added as JavaScript with the `.jsx` file extension.
```json title="components.json"
{
"tsx": `true` | `false`
}
```
## aliases
The CLI uses these values and the `paths` config from your `tsconfig.json` or `jsconfig.json` file to place generated components in the correct location.
Path aliases have to be set up in your `tsconfig.json` or `jsconfig.json` file.
<Callout className="mt-6">
**Important:** If you're using the `src` directory, make sure it is included
under `paths` in your `tsconfig.json` or `jsconfig.json` file.
</Callout>
### aliases.utils
Import alias for your utility functions.
```json title="components.json"
{
"aliases": {
"utils": "@/lib/utils"
}
}
```
### aliases.components
Import alias for your components.
```json title="components.json"
{
"aliases": {
"components": "@/components"
}
}
```
### aliases.ui
Import alias for `ui` components.
The CLI will use the `aliases.ui` value to determine where to place your `ui` components. Use this config if you want to customize the installation directory for your `ui` components.
```json title="components.json"
{
"aliases": {
"ui": "@/app/ui"
}
}
```

View File

@@ -2,8 +2,8 @@
title: Accordion
description: A vertically stacked set of interactive headings that each reveal a section of content.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/accordion
links:
doc: https://www.radix-ui.com/docs/primitives/components/accordion
api: https://www.radix-ui.com/docs/primitives/components/accordion#api-reference
---
@@ -42,12 +42,12 @@ module.exports = {
extend: {
keyframes: {
"accordion-down": {
from: { height: 0 },
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
to: { height: "0" },
},
},
animation: {
@@ -90,12 +90,12 @@ module.exports = {
extend: {
keyframes: {
"accordion-down": {
from: { height: 0 },
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
to: { height: "0" },
},
},
animation: {

View File

@@ -3,8 +3,8 @@ title: Alert Dialog
description: A modal dialog that interrupts the user with important content and expects a response.
featured: true
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/alert-dialog
links:
doc: https://www.radix-ui.com/docs/primitives/components/alert-dialog
api: https://www.radix-ui.com/docs/primitives/components/alert-dialog#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Aspect Ratio
description: Displays content within a desired ratio.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/aspect-ratio
links:
doc: https://www.radix-ui.com/docs/primitives/components/aspect-ratio
api: https://www.radix-ui.com/docs/primitives/components/aspect-ratio#api-reference
---
@@ -58,11 +58,7 @@ import { AspectRatio } from "@/components/ui/aspect-ratio"
```tsx
<div className="w-[450px]">
<AspectRatio ratio={16 / 9}>
<Image
src="..."
alt=Image""
className="rounded-md object-cover"
/>
<Image src="..." alt="Image" className="rounded-md object-cover" />
</AspectRatio>
</div>
```

View File

@@ -2,8 +2,8 @@
title: Avatar
description: An image element with a fallback for representing the user.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/avatar
links:
doc: https://www.radix-ui.com/docs/primitives/components/avatar
api: https://www.radix-ui.com/docs/primitives/components/avatar#api-reference
---

View File

@@ -2,6 +2,8 @@
title: Calendar
description: A date field component that allows users to enter and edit date.
component: true
links:
doc: https://react-day-picker.js.org
---
<ComponentPreview name="calendar-demo" />

View File

@@ -0,0 +1,277 @@
---
title: Carousel
description: A carousel with motion and swipe built using Embla.
component: true
links:
doc: https://www.embla-carousel.com/get-started/react
api: https://www.embla-carousel.com/api
---
<ComponentPreview name="carousel-demo" />
## About
The carousel component is built using the [Embla Carousel](https://www.embla-carousel.com/) library.
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn-ui@latest add carousel
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install the following dependencies:</Step>
```bash
npm install embla-carousel-react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="carousel" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
```
```tsx
<Carousel>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
```
## Examples
### Sizes
To set the size of the items, you can use the `basis` utility class on the `<CarouselItem />`.
<ComponentPreview name="carousel-size" />
```tsx title="Example" showLineNumbers {4-6}
// 33% of the carousel width.
<Carousel>
<CarouselContent>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx title="Responsive" showLineNumbers {4-6}
// 50% on small screens and 33% on larger screens.
<Carousel>
<CarouselContent>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
### Spacing
To set the spacing between the items, we use a `pl-[VALUE]` utility on the `<CarouselItem />` and a negative `-ml-[VALUE]` on the `<CarouselContent />`.
<Callout className="mt-6">
**Why:** I tried to use the `gap` property or a `grid` layout on the `
<CarouselContent />` but it required a lot of math and mental effort to get the
spacing right. I found `pl-[VALUE]` and `-ml-[VALUE]` utilities much easier to
use.
You can always adjust this in your own project if you need to.
</Callout>
<ComponentPreview name="carousel-spacing" />
```tsx title="Example" showLineNumbers /-ml-4/ /pl-4/
<Carousel>
<CarouselContent className="-ml-4">
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx title="Responsive" showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
<Carousel>
<CarouselContent className="-ml-2 md:-ml-4">
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
### Orientation
Use the `orientation` prop to set the orientation of the carousel.
<ComponentPreview name="carousel-orientation" />
```tsx showLineNumbers /vertical | horizontal/
<Carousel orientation="vertical | horizontal">
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## Options
You can pass options to the carousel using the `opts` prop. See the [Embla Carousel docs](https://www.embla-carousel.com/api/options/) for more information.
```tsx showLineNumbers {2-5}
<Carousel
opts={{
align: "start",
loop: true,
}}
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## API
Use a state and the `setApi` props to get an instance of the carousel API.
<ComponentPreview name="carousel-api" />
```tsx showLineNumbers {1,4,22}
import { type CarouselApi } from "@/components/ui/carousel"
export function Example() {
const [api, setApi] = React.useState<CarouselApi>()
const [current, setCurrent] = React.useState(0)
const [count, setCount] = React.useState(0)
React.useEffect(() => {
if (!api) {
return
}
setCount(api.scrollSnapList().length)
setCurrent(api.selectedScrollSnap() + 1)
api.on("select", () => {
setCurrent(api.selectedScrollSnap() + 1)
})
}, [api])
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
)
}
```
## Events
You can listen to events using the api instance from `setApi`.
```tsx showLineNumbers {1,4-14,16}
import { type CarouselApi } from "@/components/ui/carousel"
export function Example() {
const [api, setApi] = React.useState<CarouselApi>()
React.useEffect(() => {
if (!api) {
return
}
api.on("select", () => {
// Do something on select.
})
}, [api])
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
)
}
```
See the [Embla Carousel docs](https://www.embla-carousel.com/api/events/) for more information on using events.
## Plugins
You can use the `plugins` prop to add plugins to the carousel.
```ts showLineNumbers {1,6-10}
import Autoplay from "embla-carousel-autoplay"
export function Example() {
return (
<Carousel
plugins={[
Autoplay({
delay: 2000,
}),
]}
>
// ...
</Carousel>
)
}
```
<ComponentPreview name="carousel-plugin" />
See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on using plugins.

View File

@@ -2,8 +2,8 @@
title: Checkbox
description: A control that allows the user to toggle between checked and not checked.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/checkbox
links:
doc: https://www.radix-ui.com/docs/primitives/components/checkbox
api: https://www.radix-ui.com/docs/primitives/components/checkbox#api-reference
---

View File

@@ -3,8 +3,8 @@ title: Collapsible
description: An interactive component which expands/collapses a panel.
component: true
featured: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/collapsible
links:
doc: https://www.radix-ui.com/docs/primitives/components/collapsible
api: https://www.radix-ui.com/docs/primitives/components/collapsible#api-reference
---

View File

@@ -85,6 +85,7 @@ export function ComboboxDemo() {
{frameworks.map((framework) => (
<CommandItem
key={framework.value}
value={framework.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue)
setOpen(false)
@@ -121,6 +122,12 @@ export function ComboboxDemo() {
<ComponentPreview name="combobox-dropdown-menu" />
### Responsive
You can create a responsive combobox by using the `<Popover />` on desktop and the `<Drawer />` components on mobile.
<ComponentPreview name="combobox-responsive" />
### Form
<ComponentPreview name="combobox-form" />

View File

@@ -2,6 +2,8 @@
title: Command
description: Fast, composable, unstyled command menu for React.
component: true
links:
doc: https://cmdk.paco.me
---
<ComponentPreview
@@ -56,6 +58,7 @@ npm install cmdk
```tsx
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
@@ -101,7 +104,8 @@ export function CommandMenu() {
React.useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === "k" && e.metaKey) {
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
e.preventDefault()
setOpen((open) => !open)
}
}

View File

@@ -2,8 +2,8 @@
title: Context Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/context-menu
links:
doc: https://www.radix-ui.com/docs/primitives/components/context-menu
api: https://www.radix-ui.com/docs/primitives/components/context-menu#api-reference
---

View File

@@ -2,6 +2,8 @@
title: Data Table
description: Powerful table and datagrids built using TanStack Table.
component: true
links:
doc: https://tanstack.com/table/v8/docs/guide/introduction
---
<ComponentPreview name="data-table-demo" />
@@ -746,7 +748,10 @@ export const columns: ColumnDef<Payment>[] = [
id: "select",
header: ({ table }) => (
<Checkbox
checked={table.getIsAllPageRowsSelected()}
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() && "indeterminate")
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>

View File

@@ -3,8 +3,8 @@ title: Dialog
description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
featured: true
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/dialog
links:
doc: https://www.radix-ui.com/docs/primitives/components/dialog
api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference
---
@@ -66,7 +66,7 @@ import {
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure absolutely sure?</DialogTitle>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
@@ -76,6 +76,12 @@ import {
</Dialog>
```
## Examples
### Custom close button
<ComponentPreview name="dialog-close-button" />
## Notes
To activate the `Dialog` component from within a `Context Menu` or `Dropdown Menu`, you must encase the `Context Menu` or
@@ -97,7 +103,7 @@ To activate the `Dialog` component from within a `Context Menu` or `Dropdown Men
</ContextMenu>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure absolutely sure?</DialogTitle>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. Are you sure you want to permanently
delete this file from our servers?

View File

@@ -0,0 +1,92 @@
---
title: Drawer
description: A drawer component for React.
component: true
links:
doc: https://github.com/emilkowalski/vaul
---
<ComponentPreview name="drawer-demo" />
## About
Drawer is built on top of [Vaul](https://github.com/emilkowalski/vaul) by [emilkowalski\_](https://twitter.com/emilkowalski_).
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn-ui@latest add drawer
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install the following dependencies:</Step>
```bash
npm install vaul
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="drawer" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx showLineNumbers
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
```
```tsx showLineNumbers
<Drawer>
<DrawerTrigger>Open</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Are you absolutely sure?</DrawerTitle>
<DrawerDescription>This action cannot be undone.</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose>
<Button variant="outline">Cancel</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
```
## Examples
### Responsive Dialog
You can combine the `Dialog` and `Drawer` components to create a responsive dialog. This renders a `Dialog` component on desktop and a `Drawer` on mobile.
<ComponentPreview name="drawer-dialog" />

View File

@@ -3,8 +3,8 @@ title: Dropdown Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
featured: true
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/dropdown-menu
links:
doc: https://www.radix-ui.com/docs/primitives/components/dropdown-menu
api: https://www.radix-ui.com/docs/primitives/components/dropdown-menu#api-reference
---

View File

@@ -1,6 +1,8 @@
---
title: React Hook Form
description: Building forms with React Hook Form and Zod.
links:
doc: https://react-hook-form.com
---
Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex.
@@ -73,6 +75,14 @@ const form = useForm()
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
<Steps>
### Command
@@ -83,6 +93,30 @@ npx shadcn-ui@latest add form
</Steps>
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install the following dependencies:</Step>
```bash
npm install @radix-ui/react-label @radix-ui/react-slot react-hook-form @hookform/resolvers zod
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="form" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
<Steps>
@@ -91,10 +125,9 @@ npx shadcn-ui@latest add form
Define the shape of your form using a Zod schema. You can read more about using Zod in the [Zod documentation](https://zod.dev).
```tsx showLineNumbers {4,6-8}
```tsx showLineNumbers {3,5-7}
"use client"
import Link from "next/link"
import * as z from "zod"
const formSchema = z.object({
@@ -106,11 +139,11 @@ const formSchema = z.object({
Use the `useForm` hook from `react-hook-form` to create a form.
```tsx showLineNumbers {4,14-20,22-27}
```tsx showLineNumbers {3-4,14-20,22-27}
"use client"
import Link from "next/link"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as z from "zod"
const formSchema = z.object({
@@ -146,8 +179,8 @@ We can now use the `<Form />` components to build our form.
```tsx showLineNumbers {7-17,28-50}
"use client"
import Link from "next/link"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as z from "zod"
import { Button } from "@/components/ui/button"

View File

@@ -2,8 +2,8 @@
title: Hover Card
description: For sighted users to preview content available behind a link.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/hover-card
links:
doc: https://www.radix-ui.com/docs/primitives/components/hover-card
api: https://www.radix-ui.com/docs/primitives/components/hover-card#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Label
description: Renders an accessible label associated with controls.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/label
links:
doc: https://www.radix-ui.com/docs/primitives/components/label
api: https://www.radix-ui.com/docs/primitives/components/label#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Menubar
description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/menubar
links:
doc: https://www.radix-ui.com/docs/primitives/components/menubar
api: https://www.radix-ui.com/docs/primitives/components/menubar#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Navigation Menu
description: A collection of links for navigating websites.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/navigation-menu
links:
doc: https://www.radix-ui.com/docs/primitives/components/navigation-menu
api: https://www.radix-ui.com/docs/primitives/components/navigation-menu#api-reference
---

View File

@@ -0,0 +1,102 @@
---
title: Pagination
description: Pagination with page navigation, next and previous links.
component: true
---
<ComponentPreview name="pagination-demo" />
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn-ui@latest add pagination
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="pagination" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"
```
```tsx
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>
```
### Next.js
By default the `<PaginationLink />` component will render an `<a />` tag.
To use the Next.js `<Link />` component, make the following updates to `pagination.tsx`.
```diff showLineNumbers /typeof Link/ {1}
+ import Link from "next/link"
- type PaginationLinkProps = ... & React.ComponentProps<"a">
+ type PaginationLinkProps = ... & React.ComponentProps<typeof Link>
const PaginationLink = ({...props }: ) => (
<PaginationItem>
- <a>
+ <Link>
// ...
- </a>
+ </Link>
</PaginationItem>
)
```
<Callout className="mt-6">
**Note:** We are making updates to the cli to automatically do this for you.
</Callout>

View File

@@ -2,8 +2,8 @@
title: Popover
description: Displays rich content in a portal, triggered by a button.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/popover
links:
doc: https://www.radix-ui.com/docs/primitives/components/popover
api: https://www.radix-ui.com/docs/primitives/components/popover#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Progress
description: Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/progress
links:
doc: https://www.radix-ui.com/docs/primitives/components/progress
api: https://www.radix-ui.com/docs/primitives/components/progress#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Radio Group
description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/radio-group
links:
doc: https://www.radix-ui.com/docs/primitives/components/radio-group
api: https://www.radix-ui.com/docs/primitives/components/radio-group#api-reference
---

View File

@@ -0,0 +1,120 @@
---
title: Resizable
description: Accessible resizable panel groups and layouts with keyboard support.
component: true
links:
doc: https://github.com/bvaughn/react-resizable-panels
api: https://github.com/bvaughn/react-resizable-panels/tree/main/packages/react-resizable-panels
---
<ComponentPreview name="resizable-demo" />
## About
The `Resizable` component is built on top of [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) by [bvaughn](https://github.com/bvaughn).
## Installation
<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn-ui@latest add resizable
```
</TabsContent>
<TabsContent value="manual">
<Steps>
<Step>Install the following dependencies:</Step>
```bash
npm install react-resizable-panels
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource name="resizable" />
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</Tabs>
## Usage
```tsx
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
```
```tsx
<ResizablePanelGroup direction="horizontal">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>
```
## Examples
### Vertical
Use the `direction` prop to set the direction of the resizable panels.
<ComponentPreview name="resizable-vertical" />
```tsx showLineNumbers {9}
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
export default function Example() {
return (
<ResizablePanelGroup direction="vertical">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>
)
}
```
### Handle
You can set or hide the handle by using the `withHandle` prop on the `ResizableHandle` component.
<ComponentPreview name="resizable-handle" />
```tsx showLineNumbers {11}
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
export default function Example() {
return (
<ResizablePanelGroup direction="horizontal">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>
)
}
```

View File

@@ -2,8 +2,8 @@
title: Scroll-area
description: Augments native scroll functionality for custom, cross-browser styling.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/scroll-area
links:
doc: https://www.radix-ui.com/docs/primitives/components/scroll-area
api: https://www.radix-ui.com/docs/primitives/components/scroll-area#api-reference
---
@@ -63,3 +63,9 @@ import { ScrollArea } from "@/components/ui/scroll-area"
started laughing, they couldn't stop.
</ScrollArea>
```
## Examples
### Horizontal Scrolling
<ComponentPreview name="scroll-area-horizontal-demo" />

View File

@@ -3,8 +3,8 @@ title: Select
description: Displays a list of options for the user to pick from—triggered by a button.
component: true
featured: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/select
links:
doc: https://www.radix-ui.com/docs/primitives/components/select
api: https://www.radix-ui.com/docs/primitives/components/select#api-reference
---
@@ -75,6 +75,10 @@ import {
## Examples
### Scrollable
<ComponentPreview name="select-scrollable" />
### Form
<ComponentPreview name="select-form" />

View File

@@ -2,8 +2,8 @@
title: Separator
description: Visually or semantically separates content.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/separator
links:
doc: https://www.radix-ui.com/docs/primitives/components/separator
api: https://www.radix-ui.com/docs/primitives/components/separator#api-reference
---

View File

@@ -2,8 +2,8 @@
title: Sheet
description: Extends the Dialog component to display content that complements the main content of the screen.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/dialog
links:
doc: https://www.radix-ui.com/docs/primitives/components/dialog
api: https://www.radix-ui.com/docs/primitives/components/dialog#api-reference
---
@@ -65,7 +65,7 @@ import {
<SheetTrigger>Open</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Are you sure absolutely sure?</SheetTitle>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
@@ -92,7 +92,7 @@ You can adjust the size of the sheet using CSS classes:
<SheetTrigger>Open</SheetTrigger>
<SheetContent className="w-[400px] sm:w-[540px]">
<SheetHeader>
<SheetTitle>Are you sure absolutely sure?</SheetTitle>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.

View File

@@ -2,8 +2,8 @@
title: Slider
description: An input where the user selects a value from within a given range.
component: true
radix:
link: https://www.radix-ui.com/docs/primitives/components/slider
links:
doc: https://www.radix-ui.com/docs/primitives/components/slider
api: https://www.radix-ui.com/docs/primitives/components/slider#api-reference
---

Some files were not shown because too many files have changed in this diff Show More