Compare commits

...

41 Commits

Author SHA1 Message Date
zernonia
18040192c8 refactor(Command, Combobox): adapt to respective component 2024-12-11 15:05:55 +08:00
zernonia
d7c4f34bab refactor(Command): adapt command component to use listbox 2024-12-10 12:33:34 +08:00
zernonia
b5cf49e8ae chore: bump reka 2024-12-10 09:17:53 +08:00
Sadegh Barati
4d87066777 chore: bump cli tag 2024-12-05 00:06:05 +03:30
Sadegh Barati
5eee449df5 chore: build registry 2024-12-05 00:04:34 +03:30
Sadegh Barati
8a8d1ef20a refactor: use get-tsconfig instead of tsconfig-paths
refactor: replace `node:path` with `pathe`
chore: add `tinyexec` instead of `execa`
2024-12-05 00:00:10 +03:30
Sadegh Barati
3f0ded8e7f refactor: replace kleur with consola colors 2024-12-04 23:24:33 +03:30
Sadegh Barati
b8f60e6883 Merge branch 'dev' into next-reka 2024-12-04 23:22:21 +03:30
zernonia
20bb9c612b chore: update demo 2024-11-27 13:26:29 +08:00
zernonia
69fbfb3545 chore: release v1.0.0-next.0 2024-11-27 11:54:54 +08:00
zernonia
2326784ba0 chore: release next tag 2024-11-27 11:54:38 +08:00
zernonia
dc5c3fbb3c chore: update playground 2024-11-27 11:47:22 +08:00
zernonia
124f28240e test: update 2024-11-27 11:28:21 +08:00
zernonia
47c4fbf815 chore: cleanup 2024-11-27 11:21:46 +08:00
zernonia
8fec27eed4 refactor: replace with lucide icon, dropped v-calendar 2024-11-27 11:10:55 +08:00
zernonia
b4e1135b15 feat: transform icons 2024-11-27 11:10:34 +08:00
zernonia
b3e10e480f chore: make sure to detect reka-ui as deps 2024-11-26 17:34:54 +08:00
zernonia
ec790cb5ba chore: fix regsitry dependencies adding .vue files 2024-11-26 13:46:07 +08:00
zernonia
6d2515f02a chore: fix crawled content 2024-11-26 12:15:04 +08:00
zernonia
d963607719 chore: fix json 2024-11-25 21:55:02 +08:00
zernonia
41d836335f docs: sidebar 2024-11-25 18:01:47 +08:00
zernonia
99c685e411 chore: add sidebars block (2/2) 2024-11-25 13:35:17 +08:00
zernonia
360e55fd3d chore: add sidebars block 2024-11-25 12:00:15 +08:00
zernonia
bb5d5b2a71 docs: block preview and codes 2024-11-23 00:49:59 +08:00
zernonia
097830a15c docs: fix build, update paths 2024-11-22 17:58:53 +08:00
zernonia
01808de25c refactor: cli, add test 2024-11-22 15:03:41 +08:00
zernonia
ec54afa796 chore: lint generated files 2024-11-21 15:56:39 +08:00
zernonia
aec80c9342 refactor: build registry 2024-11-21 15:23:29 +08:00
zernonia
ac14ca835a chore: move registry, update import path, run app 2024-11-21 12:40:47 +08:00
zernonia
5ff0b20ac2 refactor: build registry 2024-11-21 11:52:31 +08:00
zernonia
8cd51af246 refactor: new CLI 2024-11-20 18:07:34 +08:00
zernonia
6927943477 docs: update content, styling 2024-11-20 12:54:16 +08:00
zernonia
f3f84b8e4e chore: revamp sitte 2024-11-20 00:15:52 +08:00
zernonia
5c4b16c76b docs: update reference api link 2024-11-19 20:13:56 +08:00
zernonia
da5f36227f chore: run pnpm i and build regsitry 2024-11-19 17:12:19 +08:00
zernonia
215e365d16 Merge remote-tracking branch 'origin/dev' into next-reka 2024-11-19 17:11:44 +08:00
zernonia
5ff9cda0aa chore: update deps 2024-11-19 17:10:16 +08:00
zernonia
19aacd90f2 chore: bump reka version 2024-11-08 12:02:19 +08:00
zernonia
f079f0161b refactor: perform migration 2024-11-05 07:12:04 +08:00
zernonia
f878cd1140 chore: bump reka-ui version 2024-11-05 06:41:06 +08:00
zernonia
d2b3a8783c refactor: radix-vue to reka-ui 2024-11-04 18:19:28 +08:00
3282 changed files with 138821 additions and 62260 deletions

View File

@ -10,8 +10,8 @@ body:
This form is only for submitting bug reports. If you have a usage question This form is only for submitting bug reports. If you have a usage question
or are unsure if this is really a bug, make sure to: or are unsure if this is really a bug, make sure to:
- Read the [docs](https://radix-vue.com/) - Read the [docs](https://reka-ui.com/)
- Ask on [Discord Chat](https://chat.radix-vue.com/) - Ask on [Discord Chat](https://chat.unovue.com/)
- Ask on [GitHub Discussions](https://github.com/shadcn-vue/shadcn-vue/discussions) - Ask on [GitHub Discussions](https://github.com/shadcn-vue/shadcn-vue/discussions)
- type: input - type: input
id: reproduction id: reproduction

View File

@ -1,8 +1,8 @@
blank_issues_enabled: true blank_issues_enabled: true
contact_links: contact_links:
# - name: 📚 Documentation # - name: 📚 Documentation
# url: https://www.radix-vue.com/ # url: https://www.reka-ui.com/
# about: Check the documentation for usage of Radix Vue. # about: Check the documentation for usage of Radix Vue.
- name: 🗨️ Discord - name: 🗨️ Discord
url: https://chat.radix-vue.com/ url: https://chat.unovue.com/
about: Join the Radix Vue Discord server. about: Join the Radix Vue Discord server.

View File

@ -11,7 +11,7 @@ body:
id: feature-description id: feature-description
attributes: attributes:
label: Describe the feature label: Describe the feature
description: A clear and concise description of what you think would be a helpful addition to radix-vue, including the possible use cases and alternatives you have considered. If you have a working prototype or module that implements it, please include a link. description: A clear and concise description of what you think would be a helpful addition to shadcn-vue, including the possible use cases and alternatives you have considered. If you have a working prototype or module that implements it, please include a link.
placeholder: Feature description placeholder: Feature description
validations: validations:
required: true required: true

View File

@ -1,6 +1,6 @@
# .github/workflows/release.yml # .github/workflows/release.yml
name: Release name: Release (next)
permissions: permissions:
contents: write contents: write
@ -29,11 +29,11 @@ jobs:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Build CLI & Publish to npm - name: Build CLI & Publish to npm
run: pnpm --filter shadcn-vue pub:release run: pnpm --filter shadcn-vue pub:next
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Build Module & Publish to npm - name: Build Module & Publish to npm
run: pnpm --filter shadcn-nuxt pub:release run: pnpm --filter shadcn-nuxt pub:next
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

4
.gitignore vendored
View File

@ -7,7 +7,7 @@ yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
lerna-debug.log* lerna-debug.log*
.nuxt # .nuxt
.env .env
node_modules node_modules
.DS_Store .DS_Store
@ -34,4 +34,4 @@ test-results/
playwright-report/ playwright-report/
vite.config.ts.timestamp* vite.config.ts.timestamp*
**/.vitepress/cache/* **/.vitepress/cache/*

1
.npmrc
View File

@ -1 +1,2 @@
shell-emulator=true shell-emulator=true
auto-install-peers=true

View File

@ -4,7 +4,7 @@ Thanks for your interest in contributing to shadcn-vue.com. We're happy to have
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. 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 the core team on [Discord](https://chat.radix-vue.com/). If you need any help, feel free to reach out to the core team on [Discord](https://chat.unovue.com/).
## About this repository ## About this repository
@ -36,7 +36,7 @@ packages
| ----------------------------| -------------------------------------------| | ----------------------------| -------------------------------------------|
| `apps/www/.vitepress` | The Vitepress application for the website. | | `apps/www/.vitepress` | The Vitepress application for the website. |
| `apps/www/src/content` | The content for the website. | | `apps/www/src/content` | The content for the website. |
| `apps/www/src/lib/registry` | The registry for the components. | | `apps/www/registry` | The registry for the components. |
| `packages/cli` | The `shadcn-vue` package. | | `packages/cli` | The `shadcn-vue` package. |
## Development ## Development
@ -44,7 +44,7 @@ packages
### Start by cloning the repository: ### Start by cloning the repository:
``` ```
git clone git@github.com:radix-vue/shadcn-vue.git git clone git@github.com:unovue/shadcn-vue.git
``` ```
### Install dependencies ### Install dependencies
@ -83,7 +83,7 @@ Documentation is written using [md](https://vitepress.dev/guide/markdown). You c
## Components ## Components
We use a registry system for developing components. You can find the source code for the components under `apps/www/src/lib/registry`. The components are organized by styles. 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 ```bash
apps apps

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 radix-vue Copyright (c) 2023 unovue
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
<p align="center"> <p align="center">
<img align="center" src="https://raw.githubusercontent.com/radix-vue/shadcn-vue/dev/apps/www/src/public/android-chrome-192x192.png" height="96" /> <img align="center" src="https://raw.githubusercontent.com/unovue/shadcn-vue/dev/apps/www/src/public/android-chrome-192x192.png" height="96" />
<h1 align="center"> <h1 align="center">
shadcn-vue shadcn-vue
</h1> </h1>
@ -23,7 +23,7 @@ All credits go to these open-source works and resources
- [Shadcn UI](https://ui.shadcn.com) for creating this beautiful project. - [Shadcn UI](https://ui.shadcn.com) for creating this beautiful project.
- [Shadcn Svelte](https://shadcn-svelte.com) for some inspiration for registry. - [Shadcn Svelte](https://shadcn-svelte.com) for some inspiration for registry.
- [Radix Vue](https://radix-vue.com) for doing all the hard work to make sure components are accessible. - [Radix Vue](https://reka-ui.com) for doing all the hard work to make sure components are accessible.
- [VueUse](https://vueuse.org) for providing many useful utilities. - [VueUse](https://vueuse.org) for providing many useful utilities.
- [ahmedmayara](https://github.com/ahmedmayara/shadcn-vue) for populating many components - [ahmedmayara](https://github.com/ahmedmayara/shadcn-vue) for populating many components

View File

@ -23,7 +23,7 @@ export default defineConfig({
['meta', { name: 'theme-color', media: '(prefers-color-scheme: light)', content: 'white' }], ['meta', { name: 'theme-color', media: '(prefers-color-scheme: light)', content: 'white' }],
['meta', { name: 'theme-color', media: '(prefers-color-scheme: dark)', content: 'black' }], ['meta', { name: 'theme-color', media: '(prefers-color-scheme: dark)', content: 'black' }],
['meta', { name: 'creator', content: 'radix-vue' }], ['meta', { name: 'creator', content: 'reka-ui' }],
['meta', { name: 'theme-color', content: '#41b883' }], ['meta', { name: 'theme-color', content: '#41b883' }],
['meta', { name: 'og:type', content: 'website' }], ['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'en' }], ['meta', { name: 'og:locale', content: 'en' }],
@ -45,7 +45,7 @@ export default defineConfig({
provider: 'local', provider: 'local',
}, },
editLink: { editLink: {
pattern: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/:path', pattern: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/:path',
text: 'Edit this page on GitHub', text: 'Edit this page on GitHub',
}, },
carbonAds: { carbonAds: {

View File

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { Separator } from '@/lib/registry/default/ui/separator'
import ArrowRightIcon from '~icons/radix-icons/arrow-right' import ArrowRightIcon from '~icons/radix-icons/arrow-right'
import { announcementConfig } from '../config/site' import { announcementConfig } from '../config/site'
</script> </script>
@ -7,11 +6,10 @@ import { announcementConfig } from '../config/site'
<template> <template>
<a <a
:href="announcementConfig.link" :href="announcementConfig.link"
class="inline-flex items-center rounded-lg bg-muted px-3 py-1 text-sm font-medium" class="group mb-2 inline-flex items-center px-0.5 text-sm font-medium"
> >
{{ announcementConfig.icon }} <Separator class="mx-2 h-4" orientation="vertical" /> <span class="sm:hidden underline-offset-4 group-hover:underline">{{ announcementConfig.title }}</span>
<span class="sm:hidden">{{ announcementConfig.title }}</span> <span class="hidden sm:inline underline-offset-4 group-hover:underline">
<span class="hidden sm:inline">
{{ announcementConfig.title }} {{ announcementConfig.title }}
</span> </span>
<ArrowRightIcon class="ml-1 h-4 w-4" /> <ArrowRightIcon class="ml-1 h-4 w-4" />

View File

@ -1,31 +1,33 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Block } from '@/registry/schema'
import Button from '@/registry/new-york/ui/button/Button.vue'
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/registry/new-york/ui/resizable'
import { Separator } from '@/registry/new-york/ui/separator'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/registry/new-york/ui/tabs'
import { ToggleGroup, ToggleGroupItem } from '@/registry/new-york/ui/toggle-group'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { CircleHelp, Info, Monitor, Smartphone, Tablet } from 'lucide-vue-next'
import MagicString from 'magic-string'
import { reactive, ref, watch } from 'vue'
import { compileScript, parse, walk } from 'vue/compiler-sfc'
import { highlight } from '../config/shiki'
import BlockCopyButton from './BlockCopyButton.vue'
import StyleSwitcher from './StyleSwitcher.vue'
// import { V0Button } from '@/components/v0-button' import { useClipboard } from '@vueuse/core'
import { Badge } from '@/lib/registry/new-york/ui/badge' import { Check, Fullscreen, Monitor, Smartphone, Tablet, Terminal } from 'lucide-vue-next'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover' import MagicString from 'magic-string'
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/lib/registry/new-york/ui/resizable' import { computed, reactive, ref, watch } from 'vue'
import { Separator } from '@/lib/registry/new-york/ui/separator' import { compileScript, parse, walk } from 'vue/compiler-sfc'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/new-york/ui/tabs' import { Index } from '../../../__registry__/block'
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/new-york/ui/toggle-group' import { highlight } from '../config/shiki'
import BlockPreview from './BlockPreview.vue' import BlockPreview from './BlockPreview.vue'
import BlockViewerCode from './BlockViewerCode.vue'
const props = defineProps<{ const props = defineProps<{
name: string name: string
}>() }>()
const { style, codeConfig } = useConfigStore() const { style, codeConfig } = useConfigStore()
const { copied, copy } = useClipboard()
const isLoading = ref(true) const isLoading = ref(true)
const tabValue = ref('preview') const tabValue = ref('preview')
const resizableRef = ref<InstanceType<typeof ResizablePanel>>() const resizableRef = ref<InstanceType<typeof ResizablePanel>>()
const componentRegistry = ref<Block>()
const rawString = ref('') const rawString = ref('')
const codeHtml = ref('') const codeHtml = ref('')
@ -35,6 +37,19 @@ const metadata = reactive({
containerClass: null as string | null, containerClass: null as string | null,
}) })
const iframeURL = computed(() => {
// @ts-expect-error env available in import.meta
if (import.meta.env.SSR)
return ''
const url = new URL(`${window.location.origin}/blocks/renderer`)
url.searchParams.append('name', props.name)
url.searchParams.append('styles', 'new-york')
url.searchParams.append('containerClass', metadata.containerClass ?? '')
return url.href
})
function removeScript(code: string) { function removeScript(code: string) {
const s = new MagicString(code) const s = new MagicString(code)
const scriptTagRegex = /<script\s+lang="ts"\s*>[\s\S]+?<\/script>/g const scriptTagRegex = /<script\s+lang="ts"\s*>[\s\S]+?<\/script>/g
@ -50,18 +65,21 @@ function removeScript(code: string) {
function transformImportPath(code: string) { function transformImportPath(code: string) {
const s = new MagicString(code) const s = new MagicString(code)
s.replaceAll(`@/lib/registry/${style.value}`, codeConfig.value.componentsPath) s.replaceAll(`@/registry/${style.value}`, codeConfig.value.componentsPath)
s.replaceAll(`@/lib/utils`, codeConfig.value.utilsPath) s.replaceAll(`@/lib/utils`, codeConfig.value.utilsPath)
return s.toString() return s.toString()
} }
watch([style, codeConfig], async () => { watch([style, codeConfig], async () => {
try { try {
const baseRawString = await import(`../../../src/lib/registry/${style.value}/block/${props.name}.vue?raw`).then(res => res.default.trim()) const styleIndex = Index[style.value]
rawString.value = transformImportPath(removeScript(baseRawString)) componentRegistry.value = styleIndex[props.name]
if (!componentRegistry.value)
return
const rawString = await componentRegistry.value.raw()
if (!metadata.description) { if (!metadata.description) {
const { descriptor } = parse(baseRawString) const { descriptor } = parse(rawString)
const ast = compileScript(descriptor, { id: '' }) const ast = compileScript(descriptor, { id: '' })
walk(ast.scriptAst, { walk(ast.scriptAst, {
enter(node: any) { enter(node: any) {
@ -78,7 +96,7 @@ watch([style, codeConfig], async () => {
}) })
} }
codeHtml.value = highlight(rawString.value, 'vue') codeHtml.value = highlight(removeScript(rawString), 'vue')
} }
catch (err) { catch (err) {
console.error(err) console.error(err)
@ -90,48 +108,47 @@ watch([style, codeConfig], async () => {
<Tabs <Tabs
:id="name" :id="name"
v-model="tabValue" v-model="tabValue"
class="relative grid w-full scroll-m-20 gap-4" class="group/block-view-wrapper flex min-w-0 flex-col items-stretch gap-4"
:style=" { :style=" {
'--container-height': metadata.iframeHeight ?? '600px', '--height': metadata.iframeHeight ?? '600px',
}" }"
> >
<div class="flex flex-col items-center gap-4 sm:flex-row"> <div class="flex flex-col items-center gap-4 sm:flex-row">
<div class="flex items-center gap-2"> <div class="hidden items-center gap-2 sm:flex">
<TabsList class="hidden sm:flex"> <TabsList class="h-7 items-center rounded-md p-0 px-[calc(theme(spacing.1)_-_2px)] py-[theme(spacing.1)]">
<TabsTrigger value="preview"> <TabsTrigger class="h-[1.45rem] rounded-sm px-2 text-xs" value="preview">
Preview Preview
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="code"> <TabsTrigger class="h-[1.45rem] rounded-sm px-2 text-xs" value="code">
Code Code
</TabsTrigger> </TabsTrigger>
</TabsList> </TabsList>
<div class="hidden items-center gap-2 sm:flex">
<Separator <Separator
orientation="vertical" orientation="vertical"
class="mx-2 hidden h-4 md:flex" class="mx-2 hidden h-4 md:flex"
/> />
<div class="flex items-center gap-2"> <div class="text-sm font-medium underline-offset-2 hover:underline">
<a :href="`#${name}`"> <a :href="`#${name}`">{{ metadata.description }}</a>
<Badge variant="outline">{{ name }}</Badge>
</a>
<Popover>
<PopoverTrigger class="hidden text-muted-foreground hover:text-foreground sm:flex">
<Info class="h-3.5 w-3.5" />
<span class="sr-only">Block description</span>
</PopoverTrigger>
<PopoverContent
side="right"
:side-offset="10"
class="text-sm"
>
{{ metadata.description }}
</PopoverContent>
</Popover>
</div>
</div> </div>
</div> </div>
<div class="flex items-center gap-2 pr-[14px] sm:ml-auto"> <div class="flex items-center gap-2 pr-[14px] sm:ml-auto">
<div class="hidden h-[28px] items-center gap-1.5 rounded-md border p-[2px] shadow-sm md:flex"> <Button
variant="ghost"
class="hidden h-7 w-7 rounded-md border bg-transparent shadow-none md:flex lg:w-auto"
size="sm"
@click="copy(`npx shadcn-vue@latest add ${name}`)"
>
<Check v-if="copied" />
<Terminal v-else />
<span class="hidden lg:inline">npx shadcn-vue add {{ name }}</span>
</Button>
<Separator
orientation="vertical"
class="mx-2 hidden h-4 md:flex"
/>
<div class="hidden h-7 items-center gap-1.5 rounded-md border p-[2px] shadow-none lg:flex">
<ToggleGroup <ToggleGroup
type="single" type="single"
default-value="100" default-value="100"
@ -157,44 +174,22 @@ watch([style, codeConfig], async () => {
> >
<Smartphone class="h-3.5 w-3.5" /> <Smartphone class="h-3.5 w-3.5" />
</ToggleGroupItem> </ToggleGroupItem>
<Separator orientation="vertical" class="h-4" />
<Button
size="icon"
variant="ghost"
class="h-[22px] w-[22px] rounded-sm p-0"
as-child
title="Open in New Tab"
>
<a :href="iframeURL" target="_blank">
<span class="sr-only">Open in New Tab</span>
<Fullscreen class="h-3.5 w-3.5" />
</a>
</Button>
</ToggleGroup> </ToggleGroup>
</div> </div>
<Separator <!-- <BlockCopyButton :code="rawString" /> -->
orientation="vertical"
class="mx-2 hidden h-4 md:flex"
/>
<StyleSwitcher class="h-7" />
<Popover>
<PopoverTrigger class="hidden text-muted-foreground hover:text-foreground sm:flex">
<CircleHelp class="h-3.5 w-3.5" />
<span class="sr-only">Block description</span>
</PopoverTrigger>
<PopoverContent
side="top"
:side-offset="20"
class="space-y-3 rounded-[0.5rem] text-sm"
>
<p class="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 class="font-medium">Default</span> style has
larger inputs, uses lucide-vue-next for icons and
tailwindcss-animate for animations.
</p>
<p>
The <span class="font-medium">New York</span> style ships
with smaller buttons and inputs. It also uses shadows on cards
and buttons.
</p>
</PopoverContent>
</Popover>
<Separator orientation="vertical" class="mx-2 h-4" />
<BlockCopyButton :code="rawString" />
<!-- <V0Button <!-- <V0Button
name="{block.name}" name="{block.name}"
description="{block.description" || "Edit in v0"} description="{block.description" || "Edit in v0"}
@ -207,7 +202,7 @@ watch([style, codeConfig], async () => {
v-show="tabValue === 'preview'" v-show="tabValue === 'preview'"
force-mount force-mount
value="preview" value="preview"
class="relative after:absolute after:inset-0 after:right-3 after:z-0 after:rounded-lg after:bg-muted h-[--container-height] px-0" class="relative after:absolute after:inset-0 after:right-3 after:z-0 after:rounded-lg after:bg-muted h-[--height] px-0"
> >
<ResizablePanelGroup id="block-resizable" direction="horizontal" class="relative z-10"> <ResizablePanelGroup id="block-resizable" direction="horizontal" class="relative z-10">
<ResizablePanel <ResizablePanel
@ -217,17 +212,14 @@ watch([style, codeConfig], async () => {
:min-size="30" :min-size="30"
:as-child="true" :as-child="true"
> >
<BlockPreview :name="name" styles="default" :container-class="metadata.containerClass ?? ''" container /> <BlockPreview :url="iframeURL" container />
</ResizablePanel> </ResizablePanel>
<ResizableHandle id="block-resizable-handle" class="relative hidden w-3 bg-transparent p-0 after:absolute after:right-0 after:top-1/2 after:h-8 after:w-[6px] after:-translate-y-1/2 after:translate-x-[-1px] after:rounded-full after:bg-border after:transition-all after:hover:h-10 sm:block" /> <ResizableHandle id="block-resizable-handle" class="relative hidden w-3 bg-transparent p-0 after:absolute after:right-0 after:top-1/2 after:h-8 after:w-[6px] after:-translate-y-1/2 after:translate-x-[-1px] after:rounded-full after:bg-border after:transition-all after:hover:h-10 sm:block" />
<ResizablePanel id="block-resizable-panel-2" :default-size="0" :min-size="0" /> <ResizablePanel id="block-resizable-panel-2" :default-size="0" :min-size="0" />
</ResizablePanelGroup> </ResizablePanelGroup>
</TabsContent> </TabsContent>
<TabsContent value="code" class="h-[--container-height]"> <TabsContent value="code" class="h-[--height]">
<div <BlockViewerCode v-if="componentRegistry" :item="componentRegistry" />
class="language-vue !h-full !max-h-[none] !mt-0"
v-html="codeHtml"
/>
</TabsContent> </TabsContent>
</Tabs> </Tabs>
</template> </template>

View File

@ -1,38 +0,0 @@
<script setup lang="ts">
import { Button } from '@/lib/registry/new-york/ui/button'
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/lib/registry/new-york/ui/tooltip'
import { CheckIcon, ClipboardIcon } from '@radix-icons/vue'
import { useClipboard } from '@vueuse/core'
import { toRefs } from 'vue'
const props = withDefaults(defineProps<{
code?: string
}>(), {
code: '',
})
const { code } = toRefs(props)
const { copy, copied } = useClipboard({ source: code })
</script>
<template>
<Tooltip :delay-duration="100">
<TooltipTrigger as-child>
<Button
size="icon"
variant="outline"
class="h-7 w-7 [&_svg]:size-3.5"
@click="copy()"
>
<span class="sr-only">Copy</span>
<CheckIcon v-if="copied" />
<ClipboardIcon v-else />
</Button>
</TooltipTrigger>
<TooltipContent>Copy code</TooltipContent>
</Tooltip>
</template>

View File

@ -0,0 +1,38 @@
<script setup lang="ts">
import { Button } from '@/registry/new-york/ui/button'
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/registry/new-york/ui/tooltip'
import { useClipboard } from '@vueuse/core'
import { Check, Clipboard } from 'lucide-vue-next'
import { toRefs } from 'vue'
const props = withDefaults(defineProps<{
code?: string
}>(), {
code: '',
})
const { code } = toRefs(props)
const { copy, copied } = useClipboard({ source: code })
</script>
<template>
<Tooltip :delay-duration="100">
<TooltipTrigger as-child>
<Button
size="icon"
variant="outline"
class="h-7 w-7 [&_svg]:size-3.5"
@click="copy()"
>
<span class="sr-only">Copy</span>
<Check v-if="copied" />
<Clipboard v-else />
</Button>
</TooltipTrigger>
<TooltipContent>Copy code</TooltipContent>
</Tooltip>
</template>

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils'
import { useUrlSearchParams } from '@vueuse/core' import { useUrlSearchParams } from '@vueuse/core'
import ComponentLoader from './ComponentLoader.vue' import ComponentLoader from './ComponentLoader.vue'
@ -6,7 +7,10 @@ const params = useUrlSearchParams('history')
</script> </script>
<template> <template>
<div v-if="params.name" :class="params.containerClass"> <div
v-if="params.name"
:class="cn('preview flex h-screen w-full justify-center items-center', params.containerClass)"
>
<ComponentLoader :key="params.style?.toString()" :name="params.name?.toString()" :type-name="'block'" /> <ComponentLoader :key="params.style?.toString()" :name="params.name?.toString()" :type-name="'block'" />
</div> </div>
</template> </template>

View File

@ -1,33 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue' import { ref } from 'vue'
import Spinner from './Spinner.vue' import Spinner from './Spinner.vue'
const props = defineProps<{ const props = defineProps<{
name: string
styles?: string
containerClass?: string
container?: boolean container?: boolean
url: string
}>() }>()
const isLoading = ref(true) const isLoading = ref(true)
const iframeURL = computed(() => {
// @ts-expect-error env available in import.meta
if (import.meta.env.SSR)
return ''
const url = new URL(`${window.location.origin}/blocks/renderer`)
Object.entries(props).forEach(([key, value]) => {
if (value)
url.searchParams.append(key, value as string)
})
return url.href
})
</script> </script>
<template> <template>
<div class="relative rounded-lg border overflow-hidden bg-background" :class="[container ? '' : 'aspect-[4/2.5]']"> <div class="relative rounded-lg border overflow-hidden bg-background" :class="[container ? '' : 'aspect-[4/2.5]']">
<div v-if="isLoading" class="flex items-center justify-center h-full"> <div v-if="isLoading" class="flex items-center justify-center h-full w-full z-10 relative">
<Spinner /> <Spinner />
</div> </div>
<div <div
@ -35,8 +20,8 @@ const iframeURL = computed(() => {
> >
<iframe <iframe
v-show="!isLoading" v-show="!isLoading"
:src="iframeURL" :src="url"
class="relative z-20 w-full bg-background" :class="[container ? 'h-[--container-height]' : 'size-full']" class="relative z-20 w-full bg-background" :class="[container ? 'h-[--height]' : 'size-full']"
@load="isLoading = false" @load="isLoading = false"
/> />
</div> </div>

View File

@ -0,0 +1,70 @@
<script setup lang="ts">
import type { Block } from '@/registry/schema'
import { File } from 'lucide-vue-next'
import { computed, onBeforeMount, ref } from 'vue'
import { highlight } from '../config/shiki'
import BlockCopyCodeButton from './BlockCopyCodeButton.vue'
import BlockViewerFileTree, { type FileTree } from './BlockViewerFileTree.vue'
const props = defineProps<{
item: Block
}>()
const activeFile = ref<FileTree>()
const cacheCodes = ref<Map<string, string>>(new Map<string, string>())
const activeCode = computed(() => cacheCodes.value.get(activeFile.value?.path ?? ''))
onBeforeMount(async () => {
for (const file of (props.item.files ?? [])) {
const raw = await file.raw()
const highlighted = highlight(raw, 'vue')
cacheCodes.value.set(file.target || file.path.split(`${props.item.name}/`)[1], highlighted)
}
})
</script>
<template>
<div class="mr-[14px] flex h-[--height] overflow-hidden rounded-xl bg-zinc-950 text-white group-data-[view=preview]/block-view-wrapper:hidden">
<div class="w-[280px]">
<BlockViewerFileTree v-model="activeFile" :item />
</div>
<div class="flex min-w-0 flex-1 flex-col">
<div class="flex h-12 flex-shrink-0 items-center gap-2 border-b border-zinc-700 bg-zinc-900 px-4 text-sm font-medium">
<File class="size-4" />
{{ activeFile?.path }}
<div class="ml-auto flex items-center gap-2">
<BlockCopyCodeButton :code="activeCode" />
</div>
</div>
<div :key="activeFile?.path" data-line-codeblock class="relative flex-1 overflow-hidden after:absolute after:inset-y-0 after:left-0 after:w-10 after:bg-zinc-950 [&_.line:before]:sticky [&_.line:before]:left-2 [&_.line:before]:z-10 [&_.line:before]:translate-y-[-1px] [&_.line:before]:pr-1 [&_pre]:h-[--height] [&_pre]:overflow-auto [&_pre]:!bg-transparent [&_pre]:pb-20 [&_pre]:pt-4 [&_pre]:font-mono [&_pre]:text-sm [&_pre]:leading-relaxed" v-html="activeCode" />
</div>
</div>
</template>
<style>
[data-line-codeblock] code {
display: grid;
min-width: 100%;
overflow-wrap: break-word;
border-radius: 0;
border-width: 0;
background-color: transparent;
padding: 0;
counter-reset: line;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
[data-line-codeblock] .line:before {
font-size: .75rem;
line-height: 1rem;
color: hsla(0, 0%, 98%, .4);
counter-increment: line;
content: counter(line);
display: inline-block;
width: 1.8rem;
margin-right: 1.4rem;
text-align: right;
}
</style>

View File

@ -0,0 +1,150 @@
<script lang="ts">
export interface FileTree {
name: string
path?: string
children?: FileTree[]
}
</script>
<script setup lang="ts">
import type { Block } from '@/registry/schema'
import Button from '@/registry/new-york/ui/button/Button.vue'
import { ChevronRight, File, Folder } from 'lucide-vue-next'
import { TreeItem, TreeRoot } from 'reka-ui'
import { computed, ref, watch } from 'vue'
const props = defineProps<{
item: Block
}>()
const activeFile = defineModel<FileTree>()
// TODO: Improve the getter logics
const flattenFiles = computed(() => {
const root: FileTree[] = []
for (const file of props.item.files ?? []) {
const path = file.target || file.path.split(`${props.item.name}/`)[1]
const parts = path.split('/')
for (let i = 0; i < parts.length; i++) {
const part = parts[i]
const isFile = i === parts.length - 1
const newNode: FileTree = isFile
? { name: part, path }
: { name: part, children: [] }
root.push(newNode)
}
}
return root
})
const treeItem = computed(() => {
return createFileTreeForRegistryItemFiles([...(props.item.files ?? [])])
})
const expandedKeys = ref<string[]>([])
function createFileTreeForRegistryItemFiles(
files: Array<{ path: string, target?: string }>,
) {
const root: FileTree[] = []
for (const file of files) {
const path = file.target || file.path.split(`${props.item.name}/`)[1]
const parts = path.split('/')
let currentLevel = root
for (let i = 0; i < parts.length; i++) {
const part = parts[i]
const isFile = i === parts.length - 1
const existingNode = currentLevel.find(node => node.name === part)
if (existingNode) {
if (isFile) {
// Update existing file node with full path
existingNode.path = path
}
else {
// Move to next level in the tree
currentLevel = existingNode.children!
}
}
else {
const newNode: FileTree = isFile
? { name: part, path }
: { name: part, children: [] }
currentLevel.push(newNode)
if (!isFile) {
currentLevel = newNode.children!
}
}
}
}
return root
}
watch(flattenFiles, (n) => {
activeFile.value = n.filter(i => i.path)[0]
expandedKeys.value = n.map(i => i.name)
}, { immediate: true })
</script>
<template>
<div class="min-h-full w-full has-[[data-variant=inset]]:bg-sidebar flex flex-col">
<div class="flex h-full flex-col w-full flex-1 border-r border-zinc-700 bg-zinc-900 text-white">
<div class="duration-200 flex shrink-0 items-center font-medium outline-none ease-linear h-12 rounded-none border-b border-zinc-700 px-4 text-sm text-white">
Files
</div>
<TreeRoot
v-slot="{ flattenItems }"
v-model="activeFile"
v-model:expanded="expandedKeys"
class="list-none select-none"
:items="treeItem"
:get-key="(item) => item.name"
>
<TreeItem
v-for="item in flattenItems"
:key="item._id"
v-slot="{ isSelected, isExpanded }"
v-bind="item.bind"
as-child
@select="(ev) => {
if (item.hasChildren || ev.detail.isSelected)
ev.preventDefault()
}"
>
<Button
variant="ghost"
:data-active="isSelected"
class="flex w-full justify-start whitespace-nowrap rounded-none pl-[--index] hover:bg-zinc-700 hover:text-white focus-visible:bg-zinc-700 focus-visible:text-white active:bg-zinc-700 active:text-white data-[active=true]:bg-zinc-700 data-[active=true]:text-white"
:style="{ 'padding-left': `${(item.level - 0.25) * 1.5}rem` }"
>
<template v-if="item.hasChildren">
<ChevronRight
icon="lucide:folder"
class="h-4 w-4 transition-transform"
:class="{ 'rotate-90': isExpanded } "
/>
<Folder class="h-4 w-4" />
</template>
<template v-else>
<ChevronRight
icon="lucide:folder"
class="invisible"
/>
<File class="h-4 w-4" />
</template>
<div>
{{ item.value.name }}
</div>
</Button>
</TreeItem>
</TreeRoot>
</div>
</div>
</template>

View File

@ -1,21 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import { buttonVariants } from '@/lib/registry/new-york/ui/button' import { Button } from '@/registry/new-york/ui/button'
import { cn } from '@/lib/utils'
import GitHubIcon from '~icons/radix-icons/github-logo'
import { ref } from 'vue'
import Announcement from '../components/Announcement.vue' import Announcement from '../components/Announcement.vue'
import PageAction from '../components/PageAction.vue' import PageAction from '../components/PageAction.vue'
import PageHeader from '../components/PageHeader.vue' import PageHeader from '../components/PageHeader.vue'
import PageHeaderDescription from '../components/PageHeaderDescription.vue' import PageHeaderDescription from '../components/PageHeaderDescription.vue'
import PageHeaderHeading from '../components/PageHeaderHeading.vue' import PageHeaderHeading from '../components/PageHeaderHeading.vue'
import BlockContainer from './BlockContainer.vue' import BlockContainer from './BlockContainer.vue'
const blocks = ref<string[]>([]) const blocks = ['Sidebar01', 'Sidebar02', 'Sidebar03', 'Sidebar04', 'Sidebar05', 'Sidebar06', 'Sidebar07', 'Sidebar08', 'Sidebar09', 'Sidebar10', 'Sidebar11', 'Sidebar12', 'Sidebar13', 'Sidebar14', 'Sidebar15', 'Login01']
import('../../../__registry__/index').then((res) => {
blocks.value = Object.values(res.Index.default).filter(i => i.type === 'components:block').map(i => i.name)
})
</script> </script>
<template> <template>
@ -27,27 +21,21 @@ import('../../../__registry__/index').then((res) => {
</PageHeaderDescription> </PageHeaderDescription>
<PageAction> <PageAction>
<a <Button as-child size="sm">
href="/blocks.html#blocks" <a href="#blocks">Browse Blocks</a>
:class="cn(buttonVariants(), 'rounded-[6px]')" </Button>
> <Button as-child variant="ghost" size="sm">
Browse <a
</a> href="https://github.com/shadcn-ui/ui/discussions/new?category=blocks-request"
<a target="_blank"
href="https://github.com/radix-vue/shadcn-vue" >
target="_blank" Request a block
:class="cn( </a>
buttonVariants({ variant: 'outline' }), </Button>
'rounded-[6px]',
)"
>
<GitHubIcon class="mr-2 h-4 w-4" />
GitHub
</a>
</PageAction> </PageAction>
</PageHeader> </PageHeader>
<section id="blocks" class="grid scroll-mt-24 gap-24 lg:gap-48"> <section id="blocks" class="grid scroll-mt-24 gap-24 lg:gap-48 container py-6">
<BlockContainer v-for="block in blocks" :key="block" :name="block" /> <BlockContainer v-for="block in blocks" :key="block" :name="block" />
</section> </section>
</template> </template>

View File

@ -3,7 +3,7 @@ import {
Alert, Alert,
AlertDescription, AlertDescription,
AlertTitle, AlertTitle,
} from '@/lib/registry/default/ui/alert' } from '@/registry/default/ui/alert'
interface CalloutProps { interface CalloutProps {
icon?: string icon?: string

View File

@ -1,8 +1,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { Button } from '@/lib/registry/new-york/ui/button' import { Button } from '@/registry/new-york/ui/button'
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/lib/registry/new-york/ui/form' import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/registry/new-york/ui/form'
import { Input } from '@/lib/registry/new-york/ui/input' import { Input } from '@/registry/new-york/ui/input'
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from '@/lib/registry/new-york/ui/sheet' import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger } from '@/registry/new-york/ui/sheet'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { toTypedSchema } from '@vee-validate/zod' import { toTypedSchema } from '@vee-validate/zod'
import RadixIconsGear from '~icons/radix-icons/gear' import RadixIconsGear from '~icons/radix-icons/gear'
@ -36,11 +36,11 @@ const onSubmit = handleSubmit((values) => {
> >
<SheetTrigger as-child> <SheetTrigger as-child>
<Button <Button
class="w-9 h-9" class="w-8 h-8"
:variant="'ghost'" :variant="'ghost'"
:size="'icon'" :size="'icon'"
> >
<RadixIconsGear class="w-5 h-5" /> <RadixIconsGear class="w-4 h-4" />
</Button> </Button>
</SheetTrigger> </SheetTrigger>
<SheetContent> <SheetContent>

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Style } from '@/lib/registry/styles' import type { RegistryStyle } from '@/registry/registry-styles'
import { Button } from '@/lib/registry/new-york/ui/button' import { Button } from '@/registry/new-york/ui/button'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { ref, toRefs, watch } from 'vue' import { ref, toRefs, watch } from 'vue'
import { makeCodeSandboxParams } from '../utils/codeeditor' import { makeCodeSandboxParams } from '../utils/codeeditor'
@ -9,7 +9,7 @@ import Tooltip from './Tooltip.vue'
const props = defineProps<{ const props = defineProps<{
name: string name: string
code: string code: string
style: Style style: RegistryStyle
}>() }>()
const { code } = toRefs(props) const { code } = toRefs(props)

View File

@ -1,6 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { Index } from '../../../__registry__'
import Spinner from './Spinner.vue' import Spinner from './Spinner.vue'
const props = defineProps<{ const props = defineProps<{
@ -9,9 +10,12 @@ const props = defineProps<{
}>() }>()
const { style } = useConfigStore() const { style } = useConfigStore()
const styleIndex = Index[style.value]
const componentRegistry = styleIndex[props.name]
const Component = defineAsyncComponent({ const Component = defineAsyncComponent({
loadingComponent: Spinner, loadingComponent: Spinner,
loader: () => import(`../../../src/lib/registry/${style.value}/${props.typeName}/${props.name}.vue`), loader: componentRegistry.component,
timeout: 5000, timeout: 5000,
}) })
</script> </script>

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/registry/default/ui/tabs'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { useClipboard } from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import MagicString from 'magic-string' import MagicString from 'magic-string'
@ -28,14 +28,14 @@ const transformedRawString = computed(() => transformImportPath(rawString.value)
function transformImportPath(code: string) { function transformImportPath(code: string) {
const s = new MagicString(code) const s = new MagicString(code)
s.replaceAll(`@/lib/registry/${style.value}`, codeConfig.value.componentsPath) s.replaceAll(`@/registry/${style.value}`, codeConfig.value.componentsPath)
s.replaceAll(`@/lib/utils`, codeConfig.value.utilsPath) s.replaceAll(`@/lib/utils`, codeConfig.value.utilsPath)
return s.toString() return s.toString()
} }
watch([style, codeConfig], async () => { watch([style, codeConfig], async () => {
try { try {
rawString.value = await import(`../../../src/lib/registry/${style.value}/example/${props.name}.vue?raw`).then(res => res.default.trim()) rawString.value = await import(`../../../src/registry/${style.value}/example/${props.name}.vue?raw`).then(res => res.default.trim())
codeHtml.value = highlight(transformedRawString.value, 'vue') codeHtml.value = highlight(transformedRawString.value, 'vue')
} }
catch (err) { catch (err) {

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { themes } from '@/lib/registry' import { Button } from '@/registry/new-york/ui/button'
import { Button } from '@/lib/registry/new-york/ui/button' import { baseColors } from '@/registry/registry-base-colors'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { useClipboard } from '@vueuse/core' import { useClipboard } from '@vueuse/core'
import CheckIcon from '~icons/radix-icons/check' import CheckIcon from '~icons/radix-icons/check'
@ -9,7 +9,7 @@ import { computed, ref } from 'vue'
const { theme, config } = useConfigStore() const { theme, config } = useConfigStore()
const activeTheme = computed(() => themes.find(i => i.name === theme.value)) const activeTheme = computed(() => baseColors.find(i => i.name === theme.value))
const { copy, copied } = useClipboard() const { copy, copied } = useClipboard()
@ -25,28 +25,28 @@ async function copyCode() {
<code ref="codeRef" class="relative block rounded font-mono text-sm"> <code ref="codeRef" class="relative block rounded font-mono text-sm">
<span class="line text-white">@layer base &#123;</span> <span class="line text-white">@layer base &#123;</span>
<span class="line text-white">:root &#123;</span> <span class="line text-white">:root &#123;</span>
<span class="line text-white">&nbsp;&nbsp;--background: {{ activeTheme?.cssVars.light.background }};</span> <span class="line text-white">&nbsp;&nbsp;--background: {{ activeTheme?.cssVars?.light?.background }};</span>
<span class="line text-white">&nbsp;&nbsp;--foreground: {{ activeTheme?.cssVars.light.foreground }};</span> <span class="line text-white">&nbsp;&nbsp;--foreground: {{ activeTheme?.cssVars?.light?.foreground }};</span>
<template v-for="prefix in (['card', 'popover', 'primary', 'secondary', 'muted', 'accent', 'destructive'] as const)" :key="prefix"> <template v-for="prefix in (['card', 'popover', 'primary', 'secondary', 'muted', 'accent', 'destructive'] as const)" :key="prefix">
<span class="line text-white">--{{ prefix }}: {{ activeTheme?.cssVars.light[prefix] }};</span> <span class="line text-white">--{{ prefix }}: {{ activeTheme?.cssVars?.light?.[prefix] }};</span>
<span class="line text-white">--{{ prefix }}-foreground: {{ activeTheme?.cssVars.light[ `${prefix}-foreground`] }};</span> <span class="line text-white">--{{ prefix }}-foreground: {{ activeTheme?.cssVars?.light?.[ `${prefix}-foreground`] }};</span>
</template> </template>
<span class="line text-white">&nbsp;&nbsp;--border:{{ activeTheme?.cssVars.light.border }};</span> <span class="line text-white">&nbsp;&nbsp;--border:{{ activeTheme?.cssVars?.light?.border }};</span>
<span class="line text-white">&nbsp;&nbsp;--input:{{ activeTheme?.cssVars.light.input }};</span> <span class="line text-white">&nbsp;&nbsp;--input:{{ activeTheme?.cssVars?.light?.input }};</span>
<span class="line text-white">&nbsp;&nbsp;--ring:{{ activeTheme?.cssVars.light.ring }};</span> <span class="line text-white">&nbsp;&nbsp;--ring:{{ activeTheme?.cssVars?.light?.ring }};</span>
<span class="line text-white">&nbsp;&nbsp;--radius: {{ config.radius }}rem;</span> <span class="line text-white">&nbsp;&nbsp;--radius: {{ config.radius }}rem;</span>
<span class="line text-white">&#125;</span> <span class="line text-white">&#125;</span>
<span class="line text-white">&nbsp;</span> <span class="line text-white">&nbsp;</span>
<span class="line text-white">.dark &#123;</span> <span class="line text-white">.dark &#123;</span>
<span class="line text-white">&nbsp;&nbsp;--background:{{ activeTheme?.cssVars.dark.background }};</span> <span class="line text-white">&nbsp;&nbsp;--background:{{ activeTheme?.cssVars?.dark?.background }};</span>
<span class="line text-white">&nbsp;&nbsp;--foreground:{{ activeTheme?.cssVars.dark.foreground }};</span> <span class="line text-white">&nbsp;&nbsp;--foreground:{{ activeTheme?.cssVars?.dark?.foreground }};</span>
<template v-for="prefix in (['card', 'popover', 'primary', 'secondary', 'muted', 'accent', 'destructive'] as const)" :key="prefix"> <template v-for="prefix in (['card', 'popover', 'primary', 'secondary', 'muted', 'accent', 'destructive'] as const)" :key="prefix">
<span class="line text-white">--{{ prefix }}:{{ activeTheme?.cssVars.dark[ prefix] }};</span> <span class="line text-white">--{{ prefix }}:{{ activeTheme?.cssVars?.dark?.[ prefix] }};</span>
<span class="line text-white">--{{ prefix }}-foreground:{{ activeTheme?.cssVars.dark[ `${prefix}-foreground`] }};</span> <span class="line text-white">--{{ prefix }}-foreground:{{ activeTheme?.cssVars?.dark?.[ `${prefix}-foreground`] }};</span>
</template> </template>
<span class="line text-white">&nbsp;&nbsp;--border:{{ activeTheme?.cssVars.dark.border }};</span> <span class="line text-white">&nbsp;&nbsp;--border:{{ activeTheme?.cssVars?.dark?.border }};</span>
<span class="line text-white">&nbsp;&nbsp;--input:{{ activeTheme?.cssVars.dark.input }};</span> <span class="line text-white">&nbsp;&nbsp;--input:{{ activeTheme?.cssVars?.dark?.input }};</span>
<span class="line text-white">&nbsp;&nbsp;--ring:{{ activeTheme?.cssVars.dark.ring }};</span> <span class="line text-white">&nbsp;&nbsp;--ring:{{ activeTheme?.cssVars?.dark?.ring }};</span>
<span class="line text-white">&#125;</span> <span class="line text-white">&#125;</span>
<span class="line text-white">&#125;</span> <span class="line text-white">&#125;</span>
</code> </code>

View File

@ -5,7 +5,7 @@ import {
BreadcrumbLink, BreadcrumbLink,
BreadcrumbList, BreadcrumbList,
BreadcrumbSeparator, BreadcrumbSeparator,
} from '@/lib/registry/new-york/ui/breadcrumb' } from '@/registry/new-york/ui/breadcrumb'
import { useRoute } from 'vitepress' import { useRoute } from 'vitepress'
import { computed } from 'vue' import { computed } from 'vue'

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { Button } from '@/lib/registry/default/ui/button' import { Button } from '@/registry/default/ui/button'
import Pencil2Icon from '~icons/radix-icons/pencil-2' import Pencil2Icon from '~icons/radix-icons/pencil-2'
import { useData } from 'vitepress' import { useData } from 'vitepress'
import { computed } from 'vue' import { computed } from 'vue'

View File

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ScrollArea, ScrollBar } from '@/lib/registry/default/ui/scroll-area'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import ArrowRightIcon from '~icons/radix-icons/arrow-right' import { ScrollArea, ScrollBar } from '@/registry/default/ui/scroll-area'
import { useRoute } from 'vitepress' import { useRoute } from 'vitepress'
import { computed, toRefs } from 'vue' import { computed, toRefs } from 'vue'
@ -11,42 +10,42 @@ const examples = [
{ {
name: 'Mail', name: 'Mail',
href: '/examples/mail', href: '/examples/mail',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/mail', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/mail',
}, },
{ {
name: 'Dashboard', name: 'Dashboard',
href: '/examples/dashboard', href: '/examples/dashboard',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/dashboard', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/dashboard',
}, },
{ {
name: 'Cards', name: 'Cards',
href: '/examples/cards', href: '/examples/cards',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/cards', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/cards',
}, },
{ {
name: 'Tasks', name: 'Tasks',
href: '/examples/tasks', href: '/examples/tasks',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/tasks', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/tasks',
}, },
{ {
name: 'Playground', name: 'Playground',
href: '/examples/playground', href: '/examples/playground',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/playground', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/playground',
}, },
{ {
name: 'Forms', name: 'Forms',
href: '/examples/forms', href: '/examples/forms',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/forms', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/forms',
}, },
{ {
name: 'Music', name: 'Music',
href: '/examples/music', href: '/examples/music',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/music', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/music',
}, },
{ {
name: 'Authentication', name: 'Authentication',
href: '/examples/authentication', href: '/examples/authentication',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/authentication', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/authentication',
}, },
] ]
@ -62,10 +61,10 @@ const currentExample = computed(() => examples.find(ex => path.value.startsWith(
:key="example.href" :key="example.href"
:href="example.href" :href="example.href"
:class="cn( :class="cn(
'flex items-center px-4', 'flex h-7 items-center justify-center rounded-full px-4 text-center text-sm transition-colors hover:text-primary',
path?.startsWith(example.href) || (path === '/' && example.name === 'Mail') path?.startsWith(example.href)
? 'font-bold text-primary' ? 'bg-muted font-medium text-primary'
: 'font-medium text-muted-foreground', : 'text-muted-foreground',
)" )"
> >
{{ example.name }} {{ example.name }}
@ -73,14 +72,5 @@ const currentExample = computed(() => examples.find(ex => path.value.startsWith(
</div> </div>
<ScrollBar orientation="horizontal" class="invisible" /> <ScrollBar orientation="horizontal" class="invisible" />
</ScrollArea> </ScrollArea>
<a
v-if="currentExample"
:href="currentExample?.code" target="_blank" rel="nofollow"
class="absolute right-0 top-0 hidden items-center rounded-[0.5rem] text-sm font-medium md:flex"
>
View code
<ArrowRightIcon class="ml-1 h-4 w-4" />
</a>
</div> </div>
</template> </template>

View File

@ -1,21 +1,20 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { Color } from '../types/colors' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/registry/new-york/ui/tooltip'
import { colors } from '@/lib/registry' import { baseColors } from '@/registry/registry-base-colors'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/lib/registry/new-york/ui/tooltip'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import RadixIconsCheck from '~icons/radix-icons/check' import { Check } from 'lucide-vue-next'
import { useData } from 'vitepress'
defineProps<{
allColors: Color[]
}>()
const { theme, setTheme } = useConfigStore() const { theme, setTheme } = useConfigStore()
const { isDark } = useData()
const pickedColors = baseColors.filter((color, index) => [0, 6, 8, 9, 10].includes(index))
</script> </script>
<template> <template>
<div> <div>
<TooltipProvider <TooltipProvider
v-for="(color, index) in allColors.slice(0, 5)" v-for="(color, index) in pickedColors"
:key="index" :key="index"
> >
<Tooltip> <Tooltip>
@ -24,18 +23,22 @@ const { theme, setTheme } = useConfigStore()
:key="index" :key="index"
class="flex h-9 w-9 items-center justify-center rounded-full border-2 border-border text-xs" class="flex h-9 w-9 items-center justify-center rounded-full border-2 border-border text-xs"
:class=" :class="
color === theme color.name === theme
? 'border-primary' ? 'border-primary'
: 'border-transparent' : 'border-transparent'
" "
@click="setTheme(color)" :style="{
'--theme-primary': `hsl(${
color?.activeColor[isDark ? 'dark' : 'light']
})`,
}"
@click="setTheme(color.name)"
> >
<span <span
class="flex h-6 w-6 items-center justify-center rounded-full" class="flex h-6 w-6 items-center justify-center rounded-full bg-[--theme-primary]"
:style="{ backgroundColor: colors[color][6].rgb }"
> >
<RadixIconsCheck <Check
v-if="color === theme" v-if="color.name === theme"
class="h-4 w-4 text-white" class="h-4 w-4 text-white"
/> />
</span> </span>
@ -46,7 +49,7 @@ const { theme, setTheme } = useConfigStore()
:side-offset="1" :side-offset="1"
class="capitalize bg-zinc-900 text-zinc-50" class="capitalize bg-zinc-900 text-zinc-50"
> >
{{ allColors[index] }} {{ color.label }}
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
</TooltipProvider> </TooltipProvider>

View File

@ -14,7 +14,7 @@ const props = withDefaults(defineProps<KbdProps>(), {
const kbdClass = computed(() => { const kbdClass = computed(() => {
return cva( return cva(
'inline-flex items-center pointer-events-none h-5 select-none items-center gap-1 rounded border border-border bg-muted font-sans font-medium', 'inline-flex items-center pointer-events-none h-5 select-none gap-1 rounded border border-border bg-muted font-sans font-medium',
{ {
variants: { variants: {
size: { size: {

View File

@ -0,0 +1,74 @@
<script setup lang="ts">
import type { DateRange } from 'reka-ui'
import CookieSettings from '@/examples/cards/components/CookieSettings.vue'
import CreateAccount from '@/examples/cards/components/CreateAccount.vue'
import PaymentMethod from '@/examples/cards/components/PaymentMethod.vue'
import ReportAnIssue from '@/examples/cards/components/ReportAnIssue.vue'
import ShareDocument from '@/examples/cards/components/ShareDocument.vue'
import TeamMembers from '@/examples/cards/components/TeamMembers.vue'
import CardChat from '@/registry/new-york/example/CardChat.vue'
import ActivityGoal from '@/registry/new-york/example/Cards/ActivityGoal.vue'
import DataTable from '@/registry/new-york/example/Cards/DataTable.vue'
import Metric from '@/registry/new-york/example/Cards/Metric.vue'
import CardStats from '@/registry/new-york/example/CardStats.vue'
import { Card } from '@/registry/new-york/ui/card'
import { RangeCalendar } from '@/registry/new-york/ui/range-calendar'
import { getLocalTimeZone, today } from '@internationalized/date'
import { type Ref, ref } from 'vue'
const now = today(getLocalTimeZone())
const range = ref({
start: now,
end: now.add({ days: 8 }),
}) as Ref<DateRange>
</script>
<template>
<div
class="items-start justify-center gap-6 rounded-lg md:grids-col-2 grid md:gap-4 lg:grid-cols-10 xl:grid-cols-11 xl:gap-4"
>
<div class="space-y-4 lg:col-span-4 xl:col-span-6 xl:space-y-4">
<CardStats />
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
<div class="space-y-4">
<TeamMembers />
<CookieSettings />
<PaymentMethod />
</div>
<div class="space-y-4">
<CardChat />
<CreateAccount />
<ReportAnIssue />
</div>
</div>
</div>
<div class="space-y-4 lg:col-span-6 xl:col-span-5 xl:space-y-4">
<div class="hidden gap-1 sm:grid-cols-[280px_1fr] md:grid">
<Card class="max-w-[280px]">
<RangeCalendar v-model="range" />
</Card>
<div class="pt-3 sm:pl-2 sm:pt-0 xl:pl-3">
<ActivityGoal />
</div>
<div class="pt-3 sm:col-span-2 xl:pt-3">
<Metric />
</div>
<div class="pt-3 sm:col-span-2 xl:pt-3">
<DataTable />
</div>
<div class="pt-3 sm:col-span-2 xl:pt-3">
<ShareDocument />
</div>
</div>
</div>
</div>
</template>

View File

@ -1,8 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import MailExample from '@/examples/mail/Example.vue' import Button from '@/registry/new-york/ui/button/Button.vue'
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
import { cn } from '@/lib/utils'
import GitHubIcon from '~icons/radix-icons/github-logo'
import Announcement from '../components/Announcement.vue' import Announcement from '../components/Announcement.vue'
import ExamplesNav from '../components/ExamplesNav.vue' import ExamplesNav from '../components/ExamplesNav.vue'
import PageAction from '../components/PageAction.vue' import PageAction from '../components/PageAction.vue'
@ -11,51 +8,52 @@ import PageHeader from '../components/PageHeader.vue'
import PageHeaderDescription from '../components/PageHeaderDescription.vue' import PageHeaderDescription from '../components/PageHeaderDescription.vue'
import PageHeaderHeading from '../components/PageHeaderHeading.vue' import PageHeaderHeading from '../components/PageHeaderHeading.vue'
import LandingExample from './LandingExample.vue'
</script> </script>
<template> <template>
<PageHeader class="page-header pb-8"> <div class="relative">
<Announcement /> <PageHeader>
<PageHeaderHeading>Build your component library.</PageHeaderHeading> <Announcement />
<PageHeaderDescription> <PageHeaderHeading>Build your component library</PageHeaderHeading>
Beautifully designed components that you can copy and paste into your <PageHeaderDescription>
apps. Accessible. Customizable. Open Source. Beautifully designed components that you can copy and paste into your apps. Made with Tailwind CSS. Open source.
</PageHeaderDescription> </PageHeaderDescription>
<PageAction> <PageAction>
<a <Button as-child size="sm">
href="/docs/introduction" <a href="/docs/introduction">
:class="cn(buttonVariants(), 'rounded-[6px]')" Get Started
> </a>
Get Started </Button>
</a> <Button as-child size="sm" variant="ghost">
<a <a
href="https://github.com/radix-vue/shadcn-vue" href="https://github.com/unovue/shadcn-vue"
target="_blank" target="_blank"
:class="cn( rel="noreferrer"
buttonVariants({ variant: 'outline' }), >
'rounded-[6px]', GitHub
)" </a>
> </Button>
<GitHubIcon class="mr-2 h-4 w-4" /> </PageAction>
GitHub </PageHeader>
</a>
</PageAction> <div class="container py-6">
</PageHeader> <ExamplesNav class="[&>a:first-child]:text-primary" />
<ExamplesNav />
<section class="space-y-8 overflow-hidden rounded-lg border-2 border-primary dark:border-muted md:hidden"> <section class="space-y-8 overflow-hidden rounded-lg border-2 border-primary dark:border-muted md:hidden">
<VPImage <VPImage
alt="Mail" alt="Mail"
width="1280" width="1280"
height="866" class="block" :image="{ height="866" class="block" :image="{
dark: '/examples/mail-dark.png', dark: '/examples/mail-dark.png',
light: '/examples/mail-light.png', light: '/examples/mail-light.png',
}" }"
/> />
</section> </section>
<section class="hidden md:block"> <section class="hidden md:block">
<div class="overflow-hidden rounded-[0.5rem] border bg-background shadow"> <LandingExample />
<MailExample /> </section>
</div> </div>
</section> </div>
</template> </template>

View File

@ -3,20 +3,10 @@
<template> <template>
<a href="/" class="mr-4 md:mr-2 lg:mr-6 flex items-center lg:space-x1 xl:space-x-2"> <a href="/" class="mr-4 md:mr-2 lg:mr-6 flex items-center lg:space-x1 xl:space-x-2">
<svg class="h-6 w-6" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" class="h-6 w-6 text-[#41B883]"><rect width="256" height="256" fill="none" /><line x1="208" y1="128" x2="128" y2="208" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" /><line x1="192" y1="40" x2="40" y2="192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" /></svg>
<g clip-path="url(#clip0_102_1338)">
<path d="M208 128L128 208" stroke="#41B883" stroke-width="16" stroke-linecap="round" stroke-linejoin="round" />
<path d="M192 40L40 192" stroke="#41B883" stroke-width="16" stroke-linecap="round" stroke-linejoin="round" />
</g>
<defs>
<clipPath id="clip0_102_1338">
<rect width="256" height="256" fill="white" />
</clipPath>
</defs>
</svg>
<span class="font-bold"> <span class="font-bold">
shadcn-vue shadcn/vue
</span> </span>
</a> </a>
</template> </template>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/lib/registry/default/ui/accordion' import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/registry/default/ui/accordion'
</script> </script>
<template> <template>

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { Button } from '@/lib/registry/default/ui/button' import { Button } from '@/registry/default/ui/button'
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area' import { ScrollArea } from '@/registry/default/ui/scroll-area'
import { Sheet, SheetContent, SheetTrigger } from '@/lib/registry/default/ui/sheet' import { Sheet, SheetContent, SheetTrigger } from '@/registry/default/ui/sheet'
import { ref } from 'vue' import { ref } from 'vue'
import { docsConfig } from '../config/docs' import { docsConfig } from '../config/docs'
import Logo from './Logo.vue' import Logo from './Logo.vue'

View File

@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
<template> <template>
<section <section
:class="cn( :class="cn(
'flex w-full items-center justify-center space-x-4 py-4 md:pb-10', 'flex w-full items-center justify-start gap-2 py-2',
$attrs.class ?? '', $attrs.class ?? '',
)" )"
> >

View File

@ -7,10 +7,12 @@ import { cn } from '@/lib/utils'
<template> <template>
<section <section
:class="cn( :class="cn(
'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', 'flex flex-col items-start gap-2 border-b border-border/40 py-8 dark:border-border md:py-10 lg:py-12',
$attrs.class ?? '', $attrs.class ?? '',
)" )"
> >
<slot /> <div class="container">
<slot />
</div>
</section> </section>
</template> </template>

View File

@ -1,10 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import WrapBalancer from 'vue-wrap-balancer'
</script> </script>
<template> <template>
<WrapBalancer :class="cn('max-w-[750px] text-center text-lg font-light text-foreground', $attrs.class ?? '')" :prefer-native="false"> <p :class="cn('max-w-2xl text-lg font-light text-foreground', $attrs.class ?? '')">
<slot /> <slot />
</WrapBalancer> </p>
</template> </template>

View File

@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
<template> <template>
<h1 <h1
:class="cn( :class="cn(
'text-center text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1]', 'text-3xl font-bold leading-tight tracking-tighter md:text-4xl lg:leading-[1.1]',
$attrs.class ?? '', $attrs.class ?? '',
)" )"
> >

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Style } from '@/lib/registry/styles' import type { RegistryStyle } from '@/registry/registry-styles'
import { Button } from '@/lib/registry/new-york/ui/button' import { Button } from '@/registry/new-york/ui/button'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { ref, toRefs, watch } from 'vue' import { ref, toRefs, watch } from 'vue'
import { makeStackblitzParams } from '../utils/codeeditor' import { makeStackblitzParams } from '../utils/codeeditor'
@ -9,7 +9,7 @@ import Tooltip from './Tooltip.vue'
const props = defineProps<{ const props = defineProps<{
name: string name: string
code: string code: string
style: Style style: RegistryStyle
}>() }>()
const { code } = toRefs(props) const { code } = toRefs(props)

View File

@ -1,6 +1,6 @@
<template> <template>
<div <div
class="[&>h3]:step mb-12 ml-4 border-l pl-8 [counter-reset:step]" class="[&>h3]:step steps mb-12 ml-4 border-l pl-8 [counter-reset:step]"
> >
<slot /> <slot />
</div> </div>

View File

@ -1,15 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectTriggerProps } from 'radix-vue' import type { SelectTriggerProps } from 'reka-ui'
import { cn } from '@/lib/utils'
import { import {
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from '@/lib/registry/new-york/ui/select' } from '@/registry/new-york/ui/select'
import { styles } from '@/registry/registry-styles'
import { styles } from '@/lib/registry/styles'
import { cn } from '@/lib/utils'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
const props = defineProps<SelectTriggerProps & { class?: string }>() const props = defineProps<SelectTriggerProps & { class?: string }>()

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { TabsContent } from '@/lib/registry/default/ui/tabs' import { TabsContent } from '@/registry/default/ui/tabs'
withDefaults(defineProps<{ withDefaults(defineProps<{
title?: string title?: string

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/registry/default/ui/tabs'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
name: string name: string

View File

@ -1,8 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { TableOfContents, TableOfContentsItem } from '../types/docs' import type { TableOfContents, TableOfContentsItem } from '../types/docs'
import { buttonVariants } from '@/lib/registry/default/ui/button' import { buttonVariants } from '@/registry/default/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/lib/registry/default/ui/collapsible' import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/registry/default/ui/collapsible'
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
import { onContentUpdated } from 'vitepress' import { onContentUpdated } from 'vitepress'
import { shallowRef } from 'vue' import { shallowRef } from 'vue'
import CarbonAds from '../components/CarbonAds.vue' import CarbonAds from '../components/CarbonAds.vue'
@ -61,16 +60,14 @@ onContentUpdated(() => {
</script> </script>
<template> <template>
<div class="hidden xl:block"> <div class="hidden xl:block no-scrollbar h-full overflow-auto pb-16">
<ScrollArea orientation="vertical" class="h-[calc(100vh-6.5rem)] z-30 md:block overflow-y-auto" type="hover"> <div class="space-y-2">
<div class="space-y-2"> <p class="font-medium">
<p class="font-medium"> On This Page
On This Page </p>
</p> <TableOfContentTree :tree="headers" :level="1" />
<TableOfContentTree :tree="headers" :level="1" /> <CarbonAds v-if="showCarbonAds" />
<CarbonAds v-if="showCarbonAds" /> </div>
</div>
</ScrollArea>
</div> </div>
<div class="block xl:hidden mb-6"> <div class="block xl:hidden mb-6">

View File

@ -42,7 +42,9 @@ watch(() => route.path, () => {
item.url === hash item.url === hash
? 'font-medium text-foreground' ? 'font-medium text-foreground'
: 'text-muted-foreground')" : 'text-muted-foreground')"
>{{ item.title }} </a> >
{{ item.title }}
</a>
<TableOfContentTree v-if="item.items?.length" :tree="item" :level="level + 1" /> <TableOfContentTree v-if="item.items?.length" :tree="item" :level="level + 1" />
</li> </li>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { Tabs, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs' import { Tabs, TabsList, TabsTrigger } from '@/registry/default/ui/tabs'
import { computed, useSlots } from 'vue' import { computed, useSlots } from 'vue'
const slots = useSlots() const slots = useSlots()

View File

@ -1,105 +1,121 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { Color } from '../types/colors' import { Button } from '@/registry/new-york/ui/button'
import { colors } from '@/lib/registry' import { Label } from '@/registry/new-york/ui/label'
import { Button } from '@/lib/registry/new-york/ui/button' import { baseColors } from '@/registry/registry-base-colors'
import { Label } from '@/lib/registry/new-york/ui/label'
import { RADII, useConfigStore } from '@/stores/config' import { RADII, useConfigStore } from '@/stores/config'
import RadixIconsCheck from '~icons/radix-icons/check' import { Check, Moon, Repeat, Sun } from 'lucide-vue-next'
import RadixIconsMoon from '~icons/radix-icons/moon'
import RadixIconsSun from '~icons/radix-icons/sun'
import { useData } from 'vitepress' import { useData } from 'vitepress'
defineProps<{ const { config, theme, radius, setRadius, setTheme } = useConfigStore()
allColors: Color[]
}>()
const { theme, radius, setRadius, setTheme } = useConfigStore()
const { isDark } = useData() const { isDark } = useData()
</script> </script>
<template> <template>
<div class="p-4"> <div class="flex flex-col space-y-4 md:space-y-6">
<div class="grid space-y-1"> <div class="flex items-start pt-4 md:pt-0">
<h1 class="text-md text-foreground font-semibold"> <div class="space-y-1 pr-2">
Customize <div class="font-semibold leading-none tracking-tight">
</h1> Theme Customizer
<p class="text-xs text-muted-foreground"> </div>
Pick a style and color for your components. <div class="text-xs text-muted-foreground">
</p> Customize your components colors.
</div>
</div>
<Button
variant="ghost"
size="icon"
class="ml-auto rounded-[0.5rem]"
@click="() => {
config = {
...config,
theme: 'zinc',
radius: 0.5,
}
}"
>
<Repeat />
<span class="sr-only">Reset</span>
</Button>
</div> </div>
<div class="space-y-1.5 pt-6"> <div class="flex flex-1 flex-col space-y-4 md:space-y-6">
<Label for="color" class="text-xs"> Color </Label> <div class="space-y-1.5 ">
<div class="grid grid-cols-3 gap-2 py-1.5"> <Label for="color" class="text-xs"> Color </Label>
<Button <div class="grid grid-cols-3 gap-2">
v-for="(color, index) in allColors" <Button
:key="index" v-for="(color, index) in baseColors"
variant="outline" :key="index"
class="h-8 justify-start px-3" variant="outline"
:class=" class="h-8 justify-start px-3"
color === theme :class="
? 'border-foreground border-2' color.name === theme
: '' ? 'border-foreground border-2'
" : ''
@click="setTheme(color)" "
> :style="{
<span '--theme-primary': `hsl(${
class="h-5 w-5 rounded-full flex items-center justify-center shrink-0" color?.activeColor[isDark ? 'dark' : 'light']
:style="{ backgroundColor: colors[color][7].rgb }" })`,
}"
@click="setTheme(color.name)"
> >
<RadixIconsCheck <span
v-if="color === theme" class="h-5 w-5 rounded-full flex items-center justify-center shrink-0 bg-[--theme-primary]"
class="h-3 w-3 text-white" >
/> <Check
</span> v-if="color.name === theme"
<span class="ml-2 text-xs capitalize"> class="h-3 w-3 text-white"
{{ color }} />
</span> </span>
</Button> <span class="ml-2 text-xs capitalize">
{{ color.name }}
</span>
</Button>
</div>
</div> </div>
</div> <div class="space-y-1.5 ">
<div class="space-y-1.5 pt-6"> <Label for="radius" class="text-xs"> Radius </Label>
<Label for="radius" class="text-xs"> Radius </Label> <div class="grid grid-cols-5 gap-2">
<div class="grid grid-cols-5 gap-2 py-1.5"> <Button
<Button v-for="(r, index) in RADII"
v-for="(r, index) in RADII" :key="index"
:key="index" variant="outline"
variant="outline" class="h-8 justify-center px-3"
class="h-8 justify-center px-3" :class="
:class=" r === radius
r === radius ? 'border-foreground border-2'
? 'border-foreground border-2' : ''
: '' "
" @click="setRadius(r)"
@click="setRadius(r)" >
> <span class="text-xs">
<span class="text-xs"> {{ r }}
{{ r }} </span>
</span> </Button>
</Button> </div>
</div> </div>
</div> <div class="space-y-1.5 ">
<div class="space-y-1.5 pt-6"> <Label for="theme" class="text-xs"> Theme </Label>
<Label for="theme" class="text-xs"> Theme </Label>
<div class="flex space-x-2 py-1.5"> <div class="flex space-x-2">
<Button <Button
class="h-8" class="h-8"
variant="outline" variant="outline"
:class="{ 'border-2 border-foreground': !isDark }" :class="{ 'border-2 border-foreground': !isDark }"
@click="isDark = false" @click="isDark = false"
> >
<RadixIconsSun class="w-4 h-4 mr-2" /> <Sun class="w-4 h-4 mr-2" />
<span class="text-xs">Light</span> <span class="text-xs">Light</span>
</Button> </Button>
<Button <Button
class="h-8" class="h-8"
variant="outline" variant="outline"
:class="{ 'border-2 border-foreground': isDark }" :class="{ 'border-2 border-foreground': isDark }"
@click="isDark = true" @click="isDark = true"
> >
<RadixIconsMoon class="w-4 h-4 mr-2" /> <Moon class="w-4 h-4 mr-2" />
<span class="text-xs">Dark</span> <span class="text-xs">Dark</span>
</Button> </Button>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { Button } from '@/lib/registry/new-york/ui/button' import { Button } from '@/registry/new-york/ui/button'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover' import { Popover, PopoverContent, PopoverTrigger } from '@/registry/new-york/ui/popover'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { Paintbrush } from 'lucide-vue-next' import { Paintbrush } from 'lucide-vue-next'
import { onMounted, watch } from 'vue' import { onMounted, watch } from 'vue'
@ -33,7 +33,7 @@ watch(radius, (radius) => {
<Popover> <Popover>
<PopoverTrigger as-child> <PopoverTrigger as-child>
<Button <Button
class="w-9 h-9" class="w-8 h-8"
:variant="'ghost'" :variant="'ghost'"
:size="'icon'" :size="'icon'"
> >

View File

@ -4,7 +4,7 @@ import {
TooltipContent, TooltipContent,
TooltipProvider, TooltipProvider,
TooltipTrigger, TooltipTrigger,
} from '@/lib/registry/default/ui/tooltip' } from '@/registry/default/ui/tooltip'
defineProps<{ defineProps<{
content: string content: string

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import type { DateRange } from 'radix-vue' import type { DateRange } from 'reka-ui'
import CookieSettings from '@/examples/cards/components/CookieSettings.vue' import CookieSettings from '@/examples/cards/components/CookieSettings.vue'
import CreateAccount from '@/examples/cards/components/CreateAccount.vue' import CreateAccount from '@/examples/cards/components/CreateAccount.vue'
@ -8,14 +8,14 @@ import PaymentMethod from '@/examples/cards/components/PaymentMethod.vue'
import ReportAnIssue from '@/examples/cards/components/ReportAnIssue.vue' import ReportAnIssue from '@/examples/cards/components/ReportAnIssue.vue'
import ShareDocument from '@/examples/cards/components/ShareDocument.vue' import ShareDocument from '@/examples/cards/components/ShareDocument.vue'
import TeamMembers from '@/examples/cards/components/TeamMembers.vue' import TeamMembers from '@/examples/cards/components/TeamMembers.vue'
import CardChat from '@/lib/registry/new-york/example/CardChat.vue' import CardChat from '@/registry/new-york/example/CardChat.vue'
import ActivityGoal from '@/lib/registry/new-york/example/Cards/ActivityGoal.vue' import ActivityGoal from '@/registry/new-york/example/Cards/ActivityGoal.vue'
import DataTable from '@/lib/registry/new-york/example/Cards/DataTable.vue' import DataTable from '@/registry/new-york/example/Cards/DataTable.vue'
import Metric from '@/lib/registry/new-york/example/Cards/Metric.vue' import Metric from '@/registry/new-york/example/Cards/Metric.vue'
import CardStats from '@/lib/registry/new-york/example/CardStats.vue' import CardStats from '@/registry/new-york/example/CardStats.vue'
import { Card } from '@/lib/registry/new-york/ui/card' import { Card } from '@/registry/new-york/ui/card'
import { RangeCalendar } from '@/lib/registry/new-york/ui/range-calendar' import { RangeCalendar } from '@/registry/new-york/ui/range-calendar'
import { getLocalTimeZone, today } from '@internationalized/date' import { getLocalTimeZone, today } from '@internationalized/date'
import { type Ref, ref } from 'vue' import { type Ref, ref } from 'vue'

View File

@ -1,4 +1,4 @@
import { styles } from '@/registry/registry-styles'
import { useStorage } from '@vueuse/core' import { useStorage } from '@vueuse/core'
import { styles } from '../../../src/lib/registry/styles'
export const useStyle = () => useStorage('selected-style', styles[0].name) export const useStyle = () => useStorage('selected-style', styles[0].name)

View File

@ -30,22 +30,13 @@ export const docsConfig: DocsConfig = {
title: 'Components', title: 'Components',
href: '/docs/components/accordion', href: '/docs/components/accordion',
}, },
{
title: 'Themes',
href: '/themes',
},
{
title: 'Examples',
href: '/examples/mail',
},
{ {
title: 'Blocks', title: 'Blocks',
href: '/blocks', href: '/blocks',
}, },
{ {
title: 'GitHub', title: 'Themes',
href: 'https://github.com/radix-vue/shadcn-vue', href: '/themes',
external: true,
}, },
], ],
sidebarNav: [ sidebarNav: [
@ -377,42 +368,42 @@ export const examples: Example[] = [
{ {
name: 'Mail', name: 'Mail',
href: '/examples/mail', href: '/examples/mail',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/mail', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/mail',
}, },
{ {
name: 'Dashboard', name: 'Dashboard',
href: '/examples/dashboard', href: '/examples/dashboard',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/dashboard', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/dashboard',
}, },
{ {
name: 'Cards', name: 'Cards',
href: '/examples/cards', href: '/examples/cards',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/cards', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/cards',
}, },
// { // {
// name: "Tasks", // name: "Tasks",
// href: "/examples/tasks", // href: "/examples/tasks",
// label: "New", // label: "New",
// code: "https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/tasks" // code: "https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/tasks"
// }, // },
{ {
name: 'Playground', name: 'Playground',
href: '/examples/playground', href: '/examples/playground',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/playground', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/playground',
}, },
{ {
name: 'Music', name: 'Music',
href: '/examples/music', href: '/examples/music',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/music', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/music',
}, },
{ {
name: 'Authentication', name: 'Authentication',
href: '/examples/authentication', href: '/examples/authentication',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/examples/authentication', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/examples/authentication',
}, },
{ {
name: 'Forms', name: 'Forms',
href: '/examples/forms', href: '/examples/forms',
code: 'https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/routes/examples/forms', code: 'https://github.com/unovue/shadcn-vue/tree/dev/apps/www/src/routes/examples/forms',
}, },
] ]

View File

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area' import { cn } from '@/lib/utils'
import RadixIconsCode from '~icons/radix-icons/code' import RadixIconsCode from '~icons/radix-icons/code'
import RadixIconsExternalLink from '~icons/radix-icons/external-link' import RadixIconsExternalLink from '~icons/radix-icons/external-link'
import { useData, useRoute } from 'vitepress' import { useData, useRoute } from 'vitepress'
@ -11,41 +11,33 @@ import { docsConfig } from '../config/docs'
const $route = useRoute() const $route = useRoute()
const { frontmatter } = useData() const { frontmatter } = useData()
const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/' const sourceLink = 'https://github.com/unovue/shadcn-vue/tree/dev/'
</script> </script>
<template> <template>
<div class="border-b"> <div class="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">
<div class="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 class="fixed top-14 z-30 hidden h-[calc(100vh-3.5rem)] w-full shrink-0 border-r border-border/40 dark:border-border md:sticky md:block">
<aside <div class="no-scrollbar h-full overflow-auto py-6 pr-6 lg:py-8">
class="fixed top-14 z-30 -ml-2 hidden h-[calc(100vh-3.5rem)] w-full shrink-0 md:sticky md:block overflow-y-auto" <div v-for="docsGroup in docsConfig.sidebarNav" :key="docsGroup.title">
> <div class="pb-4">
<ScrollArea orientation="vertical" class="relative overflow-hidden h-full py-6 pr-6 lg:py-8" :type="'auto'"> <h4 class="mb-1 rounded-md px-2 py-1 text-sm font-semibold">
<div class="w-full"> {{ docsGroup.title }}
<div v-for="docsGroup in docsConfig.sidebarNav" :key="docsGroup.title" class="pb-4">
<h4
class="mb-1 rounded-md px-2 py-1 text-sm font-semibold"
>
{{ docsGroup.title }}
<span v-if="docsGroup.label" class="ml-2 font-normal rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000] no-underline group-hover:no-underline"> <span v-if="docsGroup.label" class="ml-2 font-normal rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000] no-underline group-hover:no-underline">
{{ docsGroup.label }} {{ docsGroup.label }}
</span> </span>
</h4> </h4>
<div <div class="grid grid-flow-row auto-rows-max gap-0.5 text-sm">
<template
v-for="doc in docsGroup.items " v-for="doc in docsGroup.items "
:key="doc.title" :key="doc.title"
class="grid grid-flow-row auto-rows-max text-sm"
> >
<a <a
v-if="doc.href" v-if="doc.href"
:disabled="doc.disabled" :disabled="doc.disabled"
:href="doc.href" :href="doc.href"
class="group flex w-full items-center rounded-md border border-transparent px-2 py-1 hover:underline text-muted-foreground" :class="cn('group flex w-full items-center px-2 py-1 font-normal text-foreground underline-offset-2 hover:underline', doc.disabled && 'cursor-not-allowed opacity-60', $route.path === `${doc.href}.html` && 'underline')"
:class="{
'!font-semibold !text-foreground': $route.path === `${doc.href}.html`,
}"
> >
{{ doc.title }} {{ doc.title }}
@ -53,61 +45,61 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
{{ doc.label }} {{ doc.label }}
</span> </span>
</a> </a>
</div> </template>
</div> </div>
</div> </div>
</ScrollArea> </div>
</aside> </div>
</aside>
<main class="relative py-6 lg:gap-10 lg:py-8 xl:grid xl:grid-cols-[1fr_300px]"> <main class="relative py-6 lg:gap-10 lg:py-8 xl:grid xl:grid-cols-[1fr_300px]">
<div class="mx-auto w-full min-w-0"> <div class="mx-auto w-full min-w-0 max-w-3xl">
<div class="block xl:hidden"> <div class="block xl:hidden">
<TableOfContent /> <TableOfContent />
</div>
<DocsBreadcrumb class="mb-4" />
<div class="space-y-2">
<div class="flex items-center space-x-4">
<h1 class="scroll-m-20 text-4xl font-bold tracking-tight">
{{ frontmatter.title }}
</h1>
<span v-if="frontmatter.label" class="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000] no-underline group-hover:no-underline">
{{ frontmatter.label }}
</span>
</div>
<p class="text-lg text-muted-foreground">
{{ frontmatter.description }}
</p>
</div>
<div class="flex items-center space-x-2 pt-4">
<a v-if="frontmatter.docs" :href="frontmatter.docs" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
<RadixIconsExternalLink class="mr-1" />
Docs
</a>
<a v-if="frontmatter.source" :href="sourceLink + frontmatter.source" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
<RadixIconsCode class="mr-1" />
Component Source
</a>
<a v-if="frontmatter.primitive" :href="frontmatter.primitive" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
Primitive API Reference
</a>
</div>
<div class="vp-doc">
<slot />
</div>
<EditLink />
</div> </div>
<div class="hidden text-sm xl:block"> <DocsBreadcrumb class="mb-4" />
<div class="sticky top-16 -mt-10 h-[calc(100vh-3.5rem)] overflow-hidden pt-6">
<TableOfContent show-carbon-ads /> <div class="space-y-2">
<div class="flex items-center space-x-4">
<h1 class="scroll-m-20 text-3xl font-bold tracking-tight">
{{ frontmatter.title }}
</h1>
<span v-if="frontmatter.label" class="ml-2 rounded-md bg-[#adfa1d] px-1.5 py-0.5 text-xs leading-none text-[#000000] no-underline group-hover:no-underline">
{{ frontmatter.label }}
</span>
</div> </div>
<p class="text-base text-muted-foreground">
{{ frontmatter.description }}
</p>
</div> </div>
</main>
</div> <div v-if="frontmatter.docs || frontmatter.source || frontmatter.primitive" class="flex items-center space-x-2 pt-4">
<a v-if="frontmatter.docs" :href="frontmatter.docs" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
<RadixIconsExternalLink class="mr-1" />
Docs
</a>
<a v-if="frontmatter.source" :href="sourceLink + frontmatter.source" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
<RadixIconsCode class="mr-1" />
Component Source
</a>
<a v-if="frontmatter.primitive" :href="frontmatter.primitive" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
Primitive API Reference
</a>
</div>
<div class="vp-doc py-8">
<slot />
</div>
<EditLink />
</div>
<div class="hidden text-sm xl:block">
<div class="sticky top-20 -mt-6 h-[calc(100vh-3.5rem)] pt-4">
<TableOfContent show-carbon-ads />
</div>
</div>
</main>
</div> </div>
</template> </template>

View File

@ -1,6 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { buttonVariants } from '@/lib/registry/new-york/ui/button' import Button from '@/registry/new-york/ui/button/Button.vue'
import { cn } from '@/lib/utils'
import Announcement from '../components/Announcement.vue' import Announcement from '../components/Announcement.vue'
import ExamplesNav from '../components/ExamplesNav.vue' import ExamplesNav from '../components/ExamplesNav.vue'
import PageAction from '../components/PageAction.vue' import PageAction from '../components/PageAction.vue'
@ -11,43 +10,39 @@ import PageHeaderHeading from '../components/PageHeaderHeading.vue'
</script> </script>
<template> <template>
<div class="container relative"> <div class="relative">
<PageHeader class="page-header pb-8"> <PageHeader>
<Announcement /> <Announcement />
<PageHeaderHeading class="hidden md:block"> <PageHeaderHeading>Build your component library</PageHeaderHeading>
Check out some examples.
</PageHeaderHeading>
<PageHeaderHeading class="md:hidden">
Examples
</PageHeaderHeading>
<PageHeaderDescription> <PageHeaderDescription>
Dashboard, cards, authentication. Some examples built using the Beautifully designed components that you can copy and paste into your apps. Made with Tailwind CSS. Open source.
components. Use this as a guide to build your own.
</PageHeaderDescription> </PageHeaderDescription>
<PageAction> <PageAction>
<a <Button as-child size="sm">
href="/docs/introduction" <a href="/docs/introduction">
:class="cn(buttonVariants(), 'rounded-[6px]')" Get Started
> </a>
Get Started </Button>
</a> <Button as-child size="sm" variant="ghost">
<a <a
href="/docs/components/accordion" href="https://github.com/unovue/shadcn-vue"
:class="cn( target="_blank"
buttonVariants({ variant: 'outline' }), rel="noreferrer"
'rounded-[6px]', >
)" GitHub
> </a>
Components </Button>
</a>
</PageAction> </PageAction>
</PageHeader> </PageHeader>
<section>
<ExamplesNav /> <div class="container py-6">
<div class="overflow-hidden rounded-[0.5rem] border bg-background shadow"> <section>
<slot /> <ExamplesNav class="[&>a:first-child]:text-primary" />
</div> <div class="overflow-hidden rounded-[0.5rem] border bg-background shadow">
</section> <slot />
</div>
</section>
</div>
</div> </div>
</template> </template>

View File

@ -1,27 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { Button } from '@/lib/registry/default/ui/button' import { cn } from '@/lib/utils'
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from '@/lib/registry/default/ui/command' import { Button } from '@/registry/default/ui/button'
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog' import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator } from '@/registry/default/ui/command'
import { Toaster as DefaultToaster } from '@/lib/registry/default/ui/toast' import { Dialog, DialogContent } from '@/registry/default/ui/dialog'
import { Toaster as NewYorkSonner } from '@/lib/registry/new-york/ui/sonner' import { Toaster as DefaultToaster } from '@/registry/default/ui/toast'
import { Toaster as NewYorkToaster } from '@/lib/registry/new-york/ui/toast' import { Toaster as NewYorkSonner } from '@/registry/new-york/ui/sonner'
import { TooltipProvider } from '@/lib/registry/new-york/ui/tooltip' import { Toaster as NewYorkToaster } from '@/registry/new-york/ui/toast'
import { TooltipProvider } from '@/registry/new-york/ui/tooltip'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { useMagicKeys, useToggle } from '@vueuse/core' import { useMagicKeys, useToggle } from '@vueuse/core'
import Circle from '~icons/radix-icons/circle'
import MoonIcon from '~icons/lucide/moon'
import SunIcon from '~icons/lucide/sun'
import Circle from '~icons/radix-icons/circle'
import File from '~icons/radix-icons/file' import File from '~icons/radix-icons/file'
import RadixIconsGithubLogo from '~icons/radix-icons/github-logo' import GithubLogoIcon from '~icons/radix-icons/github-logo'
import RadixIconsMoon from '~icons/radix-icons/moon'
import RadixIconsSun from '~icons/radix-icons/sun'
import { Content, useData, useRoute, useRouter } from 'vitepress' import { Content, useData, useRoute, useRouter } from 'vitepress'
import { onMounted, ref, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import CodeConfigCustomizer from '../components/CodeConfigCustomizer.vue' import CodeConfigCustomizer from '../components/CodeConfigCustomizer.vue'
import Kbd from '../components/Kbd.vue' import Kbd from '../components/Kbd.vue'
import Logo from '../components/Logo.vue' import Logo from '../components/Logo.vue'
import MobileNav from '../components/MobileNav.vue'
import MobileNav from '../components/MobileNav.vue'
import ThemePopover from '../components/ThemePopover.vue' import ThemePopover from '../components/ThemePopover.vue'
import { docsConfig, type NavItem } from '../config/docs' import { docsConfig, type NavItem } from '../config/docs'
@ -42,13 +43,8 @@ const links = [
{ {
name: 'GitHub', name: 'GitHub',
href: 'https://github.com/unovue/shadcn-vue', href: 'https://github.com/unovue/shadcn-vue',
icon: RadixIconsGithubLogo, icon: GithubLogoIcon,
}, },
// {
// name: 'X',
// href: 'https://x.com',
// icon: TablerBrandX,
// },
] ]
const isOpen = ref(false) const isOpen = ref(false)
@ -75,9 +71,7 @@ function handleSelectLink(item: NavItem) {
} }
watch(() => $route.path, (n) => { watch(() => $route.path, (n) => {
// @ts-expect-error View Transition API not supported by all the browser yet
if (document.startViewTransition) { if (document.startViewTransition) {
// @ts-expect-error View Transition API not supported by all the browser yet
document.startViewTransition(() => { document.startViewTransition(() => {
console.log('soft navigating to: ', n) console.log('soft navigating to: ', n)
}) })
@ -90,27 +84,19 @@ watch(() => $route.path, (n) => {
<div v-if="$route.data.frontmatter.layout === false"> <div v-if="$route.data.frontmatter.layout === false">
<Content :key="$route.path" /> <Content :key="$route.path" />
</div> </div>
<div v-else vaul-drawer-wrapper class="flex min-h-screen flex-col bg-background"> <div v-else vaul-drawer-wrapper class="mx-auto w-full border-border/40 dark:border-border min-[1800px]:max-w-[1536px] min-[1800px]:border-x">
<header class="sticky z-40 top-0 bg-background/80 backdrop-blur-lg border-b border-border"> <header class="sticky top-0 z-50 w-full border-b border-border/40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 dark:border-border">
<div <div class="flex h-14 items-center px-4">
class="container flex h-14 max-w-screen-2xl items-center"
>
<div class="mr-4 md:mr-1 hidden md:flex"> <div class="mr-4 md:mr-1 hidden md:flex">
<Logo /> <Logo />
<nav <nav class="flex items-center gap-4 text-sm xl:gap-6">
class="flex items-center max-lg:space-x-4 space-x-6 text-sm font-medium"
>
<a <a
v-for="route in docsConfig.mainNav" v-for="route in docsConfig.mainNav"
:key="route.title" :key="route.title"
:href="route.href" :href="route.href"
:target="route.external ? '_target' : undefined" :target="route.external ? '_target' : undefined"
class="transition-colors hover:text-foreground/80 text-foreground/60" :class="cn('transition-colors hover:text-foreground/80', $route.path === `${route.href}.html` ? 'text-foreground' : 'text-foreground/80')"
:class="{
'font-semibold !text-foreground': $route.path === `${route.href}.html`,
'hidden lg:block': route?.href?.includes('github'),
}"
> >
{{ route.title }} {{ route.title }}
</a> </a>
@ -122,18 +108,18 @@ watch(() => $route.path, (n) => {
<div class="w-full flex-1 md:w-auto md:flex-none"> <div class="w-full flex-1 md:w-auto md:flex-none">
<Button <Button
variant="outline" variant="outline"
class="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" class="relative h-8 w-full justify-start rounded-[0.5rem] bg-muted/50 text-sm font-normal text-muted-foreground shadow-none sm:pr-12 md:w-40 lg:w-56 xl:w-64"
@click="isOpen = true" @click="isOpen = true"
> >
<span class="hidden lg:inline-flex">Search documentation...</span> <span class="hidden lg:inline-flex">Search documentation...</span>
<span class="inline-flex lg:hidden">Search...</span> <span class="inline-flex lg:hidden">Search...</span>
<Kbd class="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"> <Kbd :size="'xs'" class="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 class="text-xs"></span>K K
</Kbd> </Kbd>
</Button> </Button>
</div> </div>
<nav class="flex items-center"> <nav class="flex items-center gap-0.5">
<ThemePopover /> <ThemePopover />
<CodeConfigCustomizer /> <CodeConfigCustomizer />
@ -142,28 +128,26 @@ watch(() => $route.path, (n) => {
v-for="link in links" v-for="link in links"
:key="link.name" :key="link.name"
as="a" as="a"
class="w-9 h-9" class="w-8 h-8"
:href="link.href" target="_blank" :href="link.href" target="_blank"
:variant="'ghost'" :variant="'ghost'"
:size="'icon'" :size="'icon'"
> >
<component :is="link.icon" class="w-5 h-5" /> <component :is="link.icon" class="w-4 h-4" />
</Button> </Button>
<ClientOnly> <Button
<Button class="w-8 h-8"
class="w-9 h-9" aria-label="Toggle dark mode"
aria-label="Toggle dark mode" :variant="'ghost'"
:variant="'ghost'" :size="'icon'"
:size="'icon'" @click="toggleDark()"
@click="toggleDark()" >
> <component
<component :is="isDark ? SunIcon : MoonIcon"
:is="isDark ? RadixIconsSun : RadixIconsMoon" class="w-4 h-4 text-foreground"
class="w-5 h-5 text-foreground" />
/> </Button>
</Button>
</ClientOnly>
</nav> </nav>
</div> </div>
</div> </div>
@ -184,7 +168,7 @@ watch(() => $route.path, (n) => {
<component :is="frontmatter.layout" v-else-if="frontmatter.layout"> <component :is="frontmatter.layout" v-else-if="frontmatter.layout">
<slot /> <slot />
</component> </component>
<main v-else class="container"> <main v-else class="flex-1">
<Transition name="fade" mode="out-in"> <Transition name="fade" mode="out-in">
<Content :key="$route.path" /> <Content :key="$route.path" />
</Transition> </Transition>
@ -192,42 +176,38 @@ watch(() => $route.path, (n) => {
</Transition> </Transition>
</div> </div>
<footer class="py-6 md:px-8 md:py-0"> <footer class="border-t border-border/40 py-6 dark:border-border md:px-8 md:py-0">
<div class="container flex flex-col items-center justify-between gap-4 md:h-24 md:flex-row"> <div class="container flex flex-col items-center justify-between gap-4 md:h-24 md:flex-row">
<div class="text-center text-sm leading-loose text-muted-foreground md:text-left"> <p class="text-balance text-center text-sm leading-loose text-muted-foreground md:text-left">
<span class="inline-block"> <span>
Built and designed by Built by
<a <a
href="https://twitter.com/shadcn" href="https://twitter.com/shadcn"
target="_blank" target="_blank"
class="underline underline-offset-4 font-bold decoration-foreground" class="font-medium underline underline-offset-4"
> >
shadcn shadcn</a>.
</a>
</span> </span>
<span class="ml-0.5"> . </span> <span class="inline-block ml-1">
<span class="inline-block ml-2">
Ported to Vue by Ported to Vue by
<a <a
href="https://github.com/radix-vue" href="https://twitter.com/unovue"
target="_blank" target="_blank"
class="underline underline-offset-4 font-bold decoration-foreground" class="font-medium underline underline-offset-4"
> >
Radix Vue unovue
</a> </a>
</span> </span>.
<span class="ml-0.5"> . </span> <span class="inline-block ml-1">
<span class="inline-block ml-2">
The code source is available on The code source is available on
<a <a
href="https://github.com/unovue/shadcn-vue" href="https://github.com/unovue/shadcn-vue"
target="_blank" target="_blank"
class="underline underline-offset-4 font-bold decoration-foreground" class="font-medium underline underline-offset-4"
> >
GitHub GitHub</a>.
</a>
</span> </span>
</div> </p>
</div> </div>
</footer> </footer>
@ -281,7 +261,7 @@ watch(() => $route.path, (n) => {
} }
" "
> >
<RadixIconsSun class="mr-2 h-5 w-5" /> <SunIcon class="mr-2 h-5 w-5" />
<span>Light Theme</span> <span>Light Theme</span>
</CommandItem> </CommandItem>
<CommandItem <CommandItem
@ -294,7 +274,7 @@ watch(() => $route.path, (n) => {
} }
" "
> >
<RadixIconsMoon class="mr-2 h-5 w-5" /> <MoonIcon class="mr-2 h-5 w-5" />
<span>Dark Theme</span> <span>Dark Theme</span>
</CommandItem> </CommandItem>
</CommandGroup> </CommandGroup>

View File

@ -1,12 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Color } from '../types/colors' import type { Color } from '../types/colors'
import { Button } from '@/lib/registry/new-york/ui/button' import { Button } from '@/registry/new-york/ui/button'
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/lib/registry/new-york/ui/dialog' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/registry/new-york/ui/dialog'
import { Drawer, DrawerContent, DrawerTrigger } from '@/lib/registry/new-york/ui/drawer' import { Drawer, DrawerContent, DrawerTrigger } from '@/registry/new-york/ui/drawer'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover' import { Popover, PopoverContent, PopoverTrigger } from '@/registry/new-york/ui/popover'
import { useConfigStore } from '@/stores/config' import { useConfigStore } from '@/stores/config'
import { Paintbrush } from 'lucide-vue-next'
import { onMounted, watch } from 'vue' import { onMounted, watch } from 'vue'
import Announcement from '../components/Announcement.vue'
import CustomizerCode from '../components/CustomizerCode.vue' import CustomizerCode from '../components/CustomizerCode.vue'
import InlineThemePicker from '../components/InlineThemePicker.vue' import InlineThemePicker from '../components/InlineThemePicker.vue'
import PageAction from '../components/PageAction.vue' import PageAction from '../components/PageAction.vue'
@ -54,8 +54,9 @@ watch(radius, (radius) => {
</script> </script>
<template> <template>
<div class="container relative"> <div>
<PageHeader> <PageHeader>
<Announcement />
<PageHeaderHeading class="hidden md:block"> <PageHeaderHeading class="hidden md:block">
Add colors. Make it yours. Add colors. Make it yours.
</PageHeaderHeading> </PageHeaderHeading>
@ -67,35 +68,33 @@ watch(radius, (radius) => {
</PageHeaderDescription> </PageHeaderDescription>
<PageAction> <PageAction>
<InlineThemePicker class="gap-x-1 me-4 hidden lg:flex" :all-colors="allColors" /> <InlineThemePicker class="gap-x-1 me-4 hidden lg:flex" />
<Drawer> <Drawer>
<DrawerTrigger as-child> <DrawerTrigger as-child>
<Button variant="outline" class="md:hidden h-9 rounded-[0.5rem]"> <Button size="sm" class="md:hidden">
<Paintbrush class="w-4 h-4 mr-2" />
Customize Customize
</Button> </Button>
</DrawerTrigger> </DrawerTrigger>
<DrawerContent class="p-6 pt-0"> <DrawerContent class="p-6 pt-0">
<ThemeCustomizer :all-colors="allColors" /> <ThemeCustomizer />
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
<Popover> <Popover>
<PopoverTrigger as-child> <PopoverTrigger as-child>
<Button variant="outline" class="hidden md:flex h-9 rounded-[0.5rem]"> <Button size="sm">
<Paintbrush class="w-4 h-4 mr-2" />
Customize Customize
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent :side-offset="8" align="end" class="w-96"> <PopoverContent :side-offset="8" :align-offset="-76" align="end" class="w-[380px] p-6">
<ThemeCustomizer :all-colors="allColors" /> <ThemeCustomizer />
</PopoverContent> </PopoverContent>
</Popover> </Popover>
<Dialog> <Dialog>
<DialogTrigger as-child> <DialogTrigger as-child>
<Button class="h-9 ml-2 rounded-[0.5rem]"> <Button variant="ghost" size="sm">
Copy code Copy code
</Button> </Button>
</DialogTrigger> </DialogTrigger>
@ -111,9 +110,8 @@ watch(radius, (radius) => {
</Dialog> </Dialog>
</PageAction> </PageAction>
</PageHeader> </PageHeader>
<section>
<slot />
</section>
</div> </div>
<section class="container py-6">
<slot />
</section>
</template> </template>

View File

@ -2,10 +2,19 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@font-face {
font-family: "Geist";
src: url("/fonts/Geist[wght].ttf");
}
@font-face {
font-family: "GeistMono";
src: url("/fonts/GeistMono[wght].ttf");
}
@layer base { @layer base {
:root { :root {
--font-geist-sans: "geist-sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, --font-geist-sans: "Geist";
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; --font-geist-mono: "GeistMono";
--background: 0 0% 100%; --background: 0 0% 100%;
--foreground: 240 10% 3.9%; --foreground: 240 10% 3.9%;
@ -86,15 +95,40 @@
} }
* { * {
@apply border-border; @apply border-border;
}
html {
@apply scroll-smooth;
}
body {
@apply bg-background text-foreground overscroll-none;
/* font-feature-settings: "rlig" 1, "calt" 1; */
font-synthesis-weight: none;
text-rendering: optimizeLegibility;
}
@supports (font: -apple-system-body) and (-webkit-appearance: none) {
[data-wrapper] {
@apply min-[1800px]:border-t;
}
}
/* Custom scrollbar styling. Thanks @pranathiperii. */
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: hsl(var(--border));
border-radius: 5px;
}
* {
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: hsl(var(--border)) transparent; scrollbar-color: hsl(var(--border)) transparent;
} }
html {
-webkit-text-size-adjust: 100%;
font-variation-settings: normal;
}
body { body {
@apply bg-background text-foreground min-h-screen antialiased font-sans; @apply bg-background text-foreground min-h-screen antialiased font-sans;
/* font-feature-settings: "rlig" 1, "calt" 1; */ /* font-feature-settings: "rlig" 1, "calt" 1; */
@ -119,16 +153,6 @@
} }
/* Firefox */
/* https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color#browser_compatibility */
html {
scrollbar-color: hsl(215.4 16.3% 46.9% / 0.3);
}
html.dark {
scrollbar-color: hsl(215.4 16.3% 56.9% / 0.3);
}
html.dark .shiki, html.dark .shiki,
html.dark .shiki span { html.dark .shiki span {
color: var(--shiki-dark); color: var(--shiki-dark);
@ -147,21 +171,40 @@
@layer utilities { @layer utilities {
.step { .step {
counter-increment: step; counter-increment: step;
} }
.step:before { .step:before {
@apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background; @apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background;
@apply -ml-[50px] -mt-1; @apply ml-[-50px] mt-[-4px];
content: counter(step); content: counter(step);
} }
.chunk-container {
@apply shadow-none;
}
.chunk-container::after {
content: "";
@apply absolute -inset-4 shadow-xl rounded-xl border;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
} }
@media (max-width: 640px) { @media (max-width: 640px) {
.container { .container {
@apply px-4; @apply px-4;
} }
} }
div[class^="language-"] { div[class^="language-"] {
@ -180,18 +223,28 @@ pre code {
} }
.line-numbers-wrapper { .line-numbers-wrapper {
@apply font-mono; @apply !font-mono;
} }
pre code .line { pre code .line {
@apply px-4 min-h-4 !py-0.5 w-full inline-block leading-[--vp-code-line-height]; @apply px-4 min-h-4 w-full inline-block leading-[--vp-code-line-height];
} }
.line-number { .line-number {
@apply !text-[.75rem] !inline-block text-muted-foreground leading-[--vp-code-line-height]; font-size: .75rem ;
color: hsla(0, 0%, 98%, .4) ;
@apply !inline-block leading-[--vp-code-line-height];
} }
::view-transition-old(root), ::view-transition-old(root),
::view-transition-new(root) { ::view-transition-new(root) {
animation-duration: 0.3s; animation-duration: 0.3s;
} }
.steps:first-child > h3:first-child {
@apply mt-0;
}
.steps > h3 {
@apply mt-8 mb-4 text-base font-semibold !important;
}

View File

@ -4,7 +4,7 @@
--vp-code-bg: hsl(var(--muted)); --vp-code-bg: hsl(var(--muted));
--vp-c-divider: hsl(var(--muted)); --vp-c-divider: hsl(var(--muted));
--vp-code-block-color: #fff --vp-code-block-color: #fff
} }
/** /**
@ -22,6 +22,10 @@
outline: none; outline: none;
} }
.vp-doc h2:first-child {
@apply mt-0 pt-0;
}
.vp-doc h1:not(:where(.not-docs *)) { .vp-doc h1:not(:where(.not-docs *)) {
letter-spacing: -0.02em; letter-spacing: -0.02em;
line-height: 40px; line-height: 40px;
@ -167,39 +171,26 @@
* Table * Table
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
/* .vp-doc table { .vp-doc table:not(:where(.not-docs *)) {
display: block; @apply relative w-full overflow-hidden border-none text-sm;
border-collapse: collapse;
margin: 20px 0;
overflow-x: auto;
} }
.vp-doc tr { .vp-doc tr:not(:where(.not-docs *)) {
border-top: 1px solid var(--vp-c-divider); @apply m-0 border-b;
transition: background-color 0.5s; }
.vp-doc tbody:not(:where(.not-docs *)) tr:last-child {
@apply border-b-0;
} }
.vp-doc tr:nth-child(2n) { .vp-doc th:not(:where(.not-docs *)) {
background-color: var(--vp-c-bg-soft); @apply px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right;
} }
.vp-doc th, .vp-doc td:not(:where(.not-docs *)) {
.vp-doc td { @apply px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right;
border: 1px solid var(--vp-c-divider);
padding: 8px 16px;
} }
.vp-doc th {
text-align: left;
font-size: 14px;
font-weight: 600;
color: var(--vp-c-text-2);
background-color: var(--vp-c-bg-soft);
}
.vp-doc td {
font-size: 14px;
} */
/** /**
* Decorational elements * Decorational elements
@ -328,18 +319,15 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
margin: 0; margin: 0;
/* padding: 20px 0; */
background: transparent;
overflow-x: auto; overflow-x: auto;
@apply bg-zinc-950 dark:bg-zinc-900;
} }
.vp-doc [class*='language-'] code { .vp-doc [class*='language-'] code {
display: block; display: block;
/* padding: 0 24px; */
width: fit-content; width: fit-content;
min-width: 100%; min-width: 100%;
line-height: var(--vp-code-line-height); line-height: var(--vp-code-line-height);
/* font-size: var(--vp-code-font-size); */
color: var(--vp-code-block-color); color: var(--vp-code-block-color);
transition: color 0.5s; transition: color 0.5s;
} }
@ -350,8 +338,8 @@
padding: 0 24px; */ padding: 0 24px; */
width: calc(100% + 2 * 24px); width: calc(100% + 2 * 24px);
display: inline-block; display: inline-block;
@apply bg-[hsl(var(--muted))] dark:bg-[hsl(var(--muted))] @apply bg-zinc-700/50;
} }
.vp-doc [class*='language-'] code .highlighted.error { .vp-doc [class*='language-'] code .highlighted.error {
background-color: var(--vp-code-line-error-color); background-color: var(--vp-code-line-error-color);
@ -421,15 +409,16 @@
.vp-doc .line-numbers-wrapper { .vp-doc .line-numbers-wrapper {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 3; z-index: 3;
border-right: 1px solid var(--vp-code-block-divider-color); border-right: 1px solid var(--vp-code-block-divider-color);
padding-top: 16px; padding-top: 14px;
padding-left: 20px;
width: 32px; width: 32px;
text-align: center; text-align: center;
font-family: var(--vp-font-family-mono); font-family: var(--vp-font-family-mono);
line-height: var(--vp-code-line-height); /* line-height: var(--vp-code-line-height); */
font-size: var(--vp-code-font-size); font-size: var(--vp-code-font-size);
color: var(--vp-code-line-number-color); color: var(--vp-code-line-number-color);
transition: transition:
@ -441,20 +430,20 @@
/*rtl:ignore*/ /*rtl:ignore*/
direction: ltr; direction: ltr;
position: absolute; position: absolute;
top: 12px; top: 16px;
/*rtl:ignore*/ /*rtl:ignore*/
right: 12px; right: 16px;
z-index: 3; z-index: 3;
border: 1px solid var(--vp-code-copy-code-border-color); border: 1px solid var(--vp-code-copy-code-border-color);
border-radius: 4px; border-radius: 4px;
width: 40px; width: 30px;
height: 40px; height: 30px;
background-color: var(--vp-code-copy-code-bg); background-color: var(--vp-code-copy-code-bg);
opacity: 0; /* opacity: 0; */
cursor: pointer; cursor: pointer;
background-image: var(--vp-icon-copy); background-image: var(--vp-icon-copy);
background-position: 50%; background-position: 50%;
background-size: 20px; background-size: 16px;
background-repeat: no-repeat; background-repeat: no-repeat;
transition: transition:
border-color 0.25s, border-color 0.25s,
@ -518,14 +507,10 @@
transition: transition:
color 0.4s, color 0.4s,
opacity 0.4s; opacity 0.4s;
@apply text-gray-600; @apply text-gray-600;
} }
.vp-doc [class*='language-']:hover > button.copy + span.lang,
.vp-doc [class*='language-'] > button.copy:focus + span.lang {
opacity: 0;
}
/** /**
* Component: Team * Component: Team
@ -575,4 +560,4 @@
.line-numbers-mode pre code .line { .line-numbers-mode pre code .line {
padding-left: 3rem !important; padding-left: 3rem !important;
} }

View File

@ -1,13 +1,13 @@
import type { Style } from '@/lib/registry/styles' import type { RegistryStyle } from '@/registry/registry-styles'
import sdk from '@stackblitz/sdk' import sdk from '@stackblitz/sdk'
import { getParameters } from 'codesandbox/lib/api/define' import { getParameters } from 'codesandbox/lib/api/define'
// @ts-expect-error ?raw
import cssRaw from '../../../../../packages/cli/test/fixtures/frameworks/nuxt/assets/css/tailwind.css?raw'
import { Index as demoIndex } from '../../../../www/__registry__' import { Index as demoIndex } from '../../../../www/__registry__'
// @ts-expect-error ?raw // @ts-expect-error ?raw
import tailwindConfigRaw from '../../../tailwind.config?raw' import tailwindConfigRaw from '../../../tailwind.config?raw'
// @ts-expect-error ?raw
import cssRaw from '../../../../../packages/cli/test/fixtures/nuxt/assets/css/tailwind.css?raw'
export function makeCodeSandboxParams(componentName: string, style: Style, sources: Record<string, string>) { export function makeCodeSandboxParams(componentName: string, style: RegistryStyle, sources: Record<string, string>) {
let files: Record<string, any> = {} let files: Record<string, any> = {}
files = constructFiles(componentName, style, sources) files = constructFiles(componentName, style, sources)
files['.codesandbox/Dockerfile'] = { files['.codesandbox/Dockerfile'] = {
@ -16,12 +16,12 @@ export function makeCodeSandboxParams(componentName: string, style: Style, sourc
return getParameters({ files, template: 'node' }) return getParameters({ files, template: 'node' })
} }
export function makeStackblitzParams(componentName: string, style: Style, sources: Record<string, string>) { export function makeStackblitzParams(componentName: string, style: RegistryStyle, sources: Record<string, string>) {
const files: Record<string, string> = {} const files: Record<string, string> = {}
Object.entries(constructFiles(componentName, style, sources)).forEach(([k, v]) => (files[`${k}`] = typeof v.content === 'object' ? JSON.stringify(v.content, null, 2) : v.content)) Object.entries(constructFiles(componentName, style, sources)).forEach(([k, v]) => (files[`${k}`] = typeof v.content === 'object' ? JSON.stringify(v.content, null, 2) : v.content))
return sdk.openProject({ return sdk.openProject({
title: `${componentName} - Radix Vue`, title: `${componentName} - Reka UI`,
files, files,
template: 'node', template: 'node',
}, { }, {
@ -73,7 +73,7 @@ export default defineConfig({
}, },
} }
function constructFiles(componentName: string, style: Style, sources: Record<string, string>) { function constructFiles(componentName: string, style: RegistryStyle, sources: Record<string, string>) {
const componentsJson = { const componentsJson = {
style, style,
tailwind: { tailwind: {
@ -86,19 +86,19 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
utils: '@/utils', utils: '@/utils',
components: '@/components', components: '@/components',
}, },
iconLibrary: 'lucide',
} }
const iconPackage = style === 'default' ? 'lucide-vue-next' : '@radix-icons/vue'
const dependencies = { const dependencies = {
'vue': 'latest', 'vue': 'latest',
'radix-vue': 'latest', 'reka-ui': 'latest',
'@radix-ui/colors': 'latest', '@radix-ui/colors': 'latest',
'clsx': 'latest', 'clsx': 'latest',
'class-variance-authority': 'latest', 'class-variance-authority': 'latest',
'tailwind-merge': 'latest', 'tailwind-merge': 'latest',
'tailwindcss-animate': 'latest', 'tailwindcss-animate': 'latest',
[iconPackage]: 'latest', 'lucide-vue-next': 'latest',
'shadcn-vue': 'latest', 'shadcn-vue': 'next',
'typescript': 'latest', 'typescript': 'latest',
'vaul-vue': 'latest', 'vaul-vue': 'latest',
'vue-sonner': 'latest', 'vue-sonner': 'latest',
@ -117,7 +117,7 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
// We have static replace here as this is only showing for code reproduction, doesn't need dynamic codeConfig // We have static replace here as this is only showing for code reproduction, doesn't need dynamic codeConfig
const transformImportPath = (code: string) => { const transformImportPath = (code: string) => {
let parsed = code let parsed = code
parsed = parsed.replaceAll(`@/lib/registry/${style}`, '@/components') parsed = parsed.replaceAll(`@/registry/${style}`, '@/components')
parsed = parsed.replaceAll('@/lib/utils', '@/utils') parsed = parsed.replaceAll('@/lib/utils', '@/utils')
return parsed return parsed
} }
@ -132,7 +132,7 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
}) })
// @ts-expect-error componentName might not exist in Index // @ts-expect-error componentName might not exist in Index
const registryDependencies = demoIndex[style][componentName as any]?.registryDependencies?.filter(i => i !== 'utils') const registryDependencies = demoIndex[style][componentName as any]?.registryDependencies?.filter(i => i !== 'utils') ?? []
const files = { const files = {
'package.json': { 'package.json': {
@ -206,7 +206,7 @@ createApp(App).mount('#app')`,
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
font-feature-settings: "rlig" 1, "calt" 1; font-feature-settings: "rlig" 1, "calt" 1;
} }
#app { #app {
@apply w-full flex items-center justify-center px-12; @apply w-full flex items-center justify-center px-12;

View File

@ -0,0 +1 @@
// The content of this directory is autogenerated by the registry server.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "www", "name": "www",
"type": "module", "type": "module",
"version": "0.11.3", "version": "1.0.0-next.0",
"files": [ "files": [
"dist" "dist"
], ],
@ -17,50 +17,49 @@
}, },
"dependencies": { "dependencies": {
"@formkit/auto-animate": "^0.8.2", "@formkit/auto-animate": "^0.8.2",
"@internationalized/date": "^3.5.5", "@internationalized/date": "^3.5.6",
"@radix-icons/vue": "^1.0.0", "@radix-icons/vue": "^1.0.0",
"@stackblitz/sdk": "^1.11.0", "@stackblitz/sdk": "^1.11.0",
"@tanstack/vue-table": "^8.20.5", "@tanstack/vue-table": "^8.20.5",
"@unovis/ts": "^1.4.4", "@unovis/ts": "^1.4.4",
"@unovis/vue": "^1.4.4", "@unovis/vue": "^1.4.4",
"@vee-validate/zod": "^4.13.2", "@vee-validate/zod": "^4.13.2",
"@vueuse/core": "^11.1.0", "@vueuse/core": "^11.2.0",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"codesandbox": "^2.2.3", "codesandbox": "^2.2.3",
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"embla-carousel-autoplay": "^8.3.0", "embla-carousel-autoplay": "^8.4.0",
"embla-carousel-vue": "^8.3.0", "embla-carousel-vue": "^8.4.0",
"lucide-vue-next": "^0.441.0", "lucide-vue-next": "^0.441.0",
"magic-string": "^0.30.11", "magic-string": "^0.30.13",
"radix-vue": "catalog:", "reka-ui": "catalog:",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"v-calendar": "^3.1.2",
"vaul-vue": "^0.2.0", "vaul-vue": "^0.2.0",
"vee-validate": "4.13.2", "vee-validate": "4.13.2",
"vue": "^3.5.6", "vue": "^3.5.13",
"vue-sonner": "^1.1.5", "vue-sonner": "^1.2.5",
"vue-wrap-balancer": "^1.2.1", "vue-wrap-balancer": "^1.2.1",
"zod": "catalog:" "zod": "catalog:"
}, },
"devDependencies": { "devDependencies": {
"@babel/traverse": "^7.25.6", "@babel/traverse": "^7.25.9",
"@iconify-json/gravity-ui": "^1.1.3", "@iconify-json/gravity-ui": "^1.2.2",
"@iconify-json/lucide": "^1.1.198", "@iconify-json/lucide": "^1.2.15",
"@iconify-json/ph": "^1.1.13", "@iconify-json/ph": "^1.2.1",
"@iconify-json/radix-icons": "^1.1.14", "@iconify-json/radix-icons": "^1.2.1",
"@iconify-json/ri": "^1.1.21", "@iconify-json/ri": "^1.2.3",
"@iconify-json/simple-icons": "^1.1.108", "@iconify-json/simple-icons": "^1.2.11",
"@iconify-json/tabler": "^1.1.116", "@iconify-json/tabler": "^1.2.8",
"@iconify/vue": "^4.1.2", "@iconify/vue": "^4.1.2",
"@oxc-parser/wasm": "catalog:", "@oxc-parser/wasm": "catalog:",
"@shikijs/transformers": "^1.17.7", "@shikijs/transformers": "^1.23.1",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^22.5.5", "@types/node": "^22.9.0",
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.2.0",
"@vitejs/plugin-vue-jsx": "^4.0.1", "@vitejs/plugin-vue-jsx": "^4.1.0",
"@vue/compiler-core": "^3.5.6", "@vue/compiler-core": "^3.5.13",
"@vue/compiler-dom": "^3.5.6", "@vue/compiler-dom": "^3.5.13",
"@vue/tsconfig": "^0.5.1", "@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"fast-glob": "^3.3.2", "fast-glob": "^3.3.2",
@ -68,14 +67,14 @@
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"pathe": "^1.1.2", "pathe": "^1.1.2",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"shiki": "^1.22.1", "shiki": "^1.23.1",
"tailwind-merge": "^2.5.2", "tailwind-merge": "^2.5.4",
"tailwindcss": "^3.4.12", "tailwindcss": "^3.4.15",
"tsx": "^4.19.1", "tsx": "^4.19.2",
"typescript": "catalog:", "typescript": "catalog:",
"unplugin-icons": "^0.19.3", "unplugin-icons": "^0.19.3",
"vitepress": "^1.3.4", "vitepress": "^1.5.0",
"vue-component-meta": "^2.1.6", "vue-component-meta": "^2.1.10",
"vue-tsc": "^2.1.6" "vue-tsc": "^2.1.10"
} }
} }

View File

@ -24,7 +24,7 @@ const tsconfigChecker = createComponentMetaChecker(
) )
const components = fg.sync(['chart/**/*.vue', 'chart*/**/*.vue'], { const components = fg.sync(['chart/**/*.vue', 'chart*/**/*.vue'], {
cwd: resolve(__dirname, ROOTPATH, 'src/lib/registry/default/ui/'), cwd: resolve(__dirname, ROOTPATH, 'registry/default/ui/'),
absolute: true, absolute: true,
}) })

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
export function fixImport(content: string) {
// eslint-disable-next-line regexp/no-super-linear-backtracking
const regex = /@\/(.+?)\/((?:.*?\/)?(?:components|ui|hooks|lib))\/([\w-]+)/g
const replacement = (
match: string,
path: string,
type: string,
component: string,
) => {
if (type.endsWith('components')) {
return `@/components/${component}`
}
else if (type.endsWith('ui')) {
return `@/components/ui/${component}`
}
else if (type.endsWith('hooks')) {
return `@/hooks/${component}`
}
else if (type.endsWith('lib')) {
return `@/lib/${component}`
}
return match
}
return content.replace(regex, replacement)
}

View File

@ -86,7 +86,7 @@
<mxCell id="PaMXV6_IjdSjTMUUNi7L-12" value="Examples" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;labelBackgroundColor=none;strokeWidth=1;fontFamily=Garamond;fontSize=17;align=center;sketch=1;curveFitting=1;jiggle=2;" vertex="1" parent="1"> <mxCell id="PaMXV6_IjdSjTMUUNi7L-12" value="Examples" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;labelBackgroundColor=none;strokeWidth=1;fontFamily=Garamond;fontSize=17;align=center;sketch=1;curveFitting=1;jiggle=2;" vertex="1" parent="1">
<mxGeometry x="570" y="500" width="120" height="60" as="geometry" /> <mxGeometry x="570" y="500" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="PaMXV6_IjdSjTMUUNi7L-13" value="Lib/Registry" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;labelBackgroundColor=none;strokeWidth=1;fontFamily=Garamond;fontSize=17;align=center;sketch=1;curveFitting=1;jiggle=2;" vertex="1" parent="1"> <mxCell id="PaMXV6_IjdSjTMUUNi7L-13" value="registry" style="whiteSpace=wrap;html=1;rounded=1;shadow=0;labelBackgroundColor=none;strokeWidth=1;fontFamily=Garamond;fontSize=17;align=center;sketch=1;curveFitting=1;jiggle=2;" vertex="1" parent="1">
<mxGeometry x="720" y="500" width="120" height="60" as="geometry" /> <mxGeometry x="720" y="500" width="120" height="60" as="geometry" />
</mxCell> </mxCell>
<mxCell id="PaMXV6_IjdSjTMUUNi7L-14" value="" style="rounded=0;html=1;labelBackgroundColor=none;startArrow=none;startFill=0;startSize=5;endArrow=none;endFill=0;endSize=5;jettySize=auto;orthogonalLoop=1;strokeWidth=1;fontFamily=Garamond;fontSize=17;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.308;exitY=1.033;exitDx=0;exitDy=0;exitPerimeter=0;sketch=1;curveFitting=1;jiggle=2;shadow=0;" edge="1" parent="1" source="PaMXV6_IjdSjTMUUNi7L-4" target="PaMXV6_IjdSjTMUUNi7L-11"> <mxCell id="PaMXV6_IjdSjTMUUNi7L-14" value="" style="rounded=0;html=1;labelBackgroundColor=none;startArrow=none;startFill=0;startSize=5;endArrow=none;endFill=0;endSize=5;jettySize=auto;orthogonalLoop=1;strokeWidth=1;fontFamily=Garamond;fontSize=17;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0.308;exitY=1.033;exitDx=0;exitDy=0;exitPerimeter=0;sketch=1;curveFitting=1;jiggle=2;shadow=0;" edge="1" parent="1" source="PaMXV6_IjdSjTMUUNi7L-4" target="PaMXV6_IjdSjTMUUNi7L-11">

View File

@ -5,16 +5,16 @@ description: Powered by amazing open source projects.
## About ## About
[shadcn-vue](https://shadcn-vue.com) is a port of [shadcn/ui](https://ui.shadcn.com) for Vue/Nuxt. It's maintained by [radix-vue](https://github.com/radix-vue). [shadcn-vue](https://shadcn-vue.com) is a port of [shadcn/ui](https://ui.shadcn.com) for Vue/Nuxt. It's maintained by [unovue](https://github.com/unovue).
## Credits ## Credits
- [shadcn](https://twitter.com/shadcn) - The brilliant mind behind the designs, methodology, and implementation of the original [shadcn/ui](https://ui.shadcn.com). - [shadcn](https://twitter.com/shadcn) - The brilliant mind behind the designs, methodology, and implementation of the original [shadcn/ui](https://ui.shadcn.com).
- [Radix Vue](https://radix-vue.com) - The headless components that power this project. - [Radix Vue](https://reka-ui.com) - The headless components that power this project.
- [Radix UI](https://radix-ui.com) - The headless components and examples that the original [shadcn/ui](https://ui.shadcn.com) was built on. - [Radix UI](https://radix-ui.com) - The headless components and examples that the original [shadcn/ui](https://ui.shadcn.com) was built on.
- [Shu Ding](https://shud.in) - The typography style is adapted from his work on Nextra. - [Shu Ding](https://shud.in) - The typography style is adapted from his work on Nextra.
- [Cal](https://cal.com) - Where shad copied the styles for the first component: the `Button`. - [Cal](https://cal.com) - Where shad copied the styles for the first component: the `Button`.
## License ## License
MIT © [shadcn](https://shadcn.com) & [radix-vue](https://github.com/radix-vue) MIT © [shadcn](https://shadcn.com) & [unovue](https://github.com/unovue)

View File

@ -49,7 +49,7 @@ The following form has been created by passing a `zod` schema object to our `Aut
### Component Updated - Calendar ### Component Updated - Calendar
The [`Calendar`](/docs/components/calendar.html) component has been updated and is now built on top of the [RadixVue Calendar](https://www.radix-vue.com/components/calendar.html) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates. The [`Calendar`](/docs/components/calendar.html) component has been updated and is now built on top of the [RadixVue Calendar](https://www.reka-ui.com/components/calendar.html) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates.
If you're looking for a range calendar, check out the [`Range Calendar`](/docs/components/range-calendar.html) component. If you're looking for a range calendar, check out the [`Range Calendar`](/docs/components/range-calendar.html) component.
@ -104,7 +104,7 @@ And if you're looking for a date picker input, check out the [`Date Picker`](/do
### New Component - Drawer ### New Component - Drawer
[`Drawer`](/docs/components/drawer.html) - A drawer component for vue that is built on top of [Vaul Vue](https://github.com/radix-vue/vaul-vue). [`Drawer`](/docs/components/drawer.html) - A drawer component for vue that is built on top of [Vaul Vue](https://github.com/unovue/vaul-vue).
<ComponentPreview name="DrawerDemo" /> <ComponentPreview name="DrawerDemo" />

View File

@ -91,7 +91,7 @@ However, you can always pass in the desired `color` into each chart.
## Custom tooltip ## Custom tooltip
If you want to customize the `Tooltip` for the chart, you can pass `customTooltip` prop with a custom Vue component. If you want to customize the `Tooltip` for the chart, you can pass `customTooltip` prop with a custom Vue component.
The custom component would receive `title` and `data` props, check out [ChartTooltip.vue component](https://github.com/radix-vue/shadcn-vue/tree/dev/apps/www/src/lib/registry/default/ui/chart/ChartTooltip.vue) for example. The custom component would receive `title` and `data` props, check out [ChartTooltip.vue component](https://github.com/unovue/shadcn-vue/tree/dev/apps/www/registry/default/ui/chart/ChartTooltip.vue) for example.
The expected prop definition would be: The expected prop definition would be:

View File

@ -1,7 +1,7 @@
--- ---
title: Area title: Area
description: An area chart visually represents data over time, displaying trends and patterns through filled-in areas under a line graph. description: An area chart visually represents data over time, displaying trends and patterns through filled-in areas under a line graph.
source: apps/www/src/lib/registry/default/ui/chart-area source: apps/www/registry/default/ui/chart-area
label: Alpha label: Alpha
--- ---

View File

@ -1,7 +1,7 @@
--- ---
title: Bar title: Bar
description: A line chart visually represents data using rectangular bars of varying lengths to compare quantities across different categories or groups. description: A line chart visually represents data using rectangular bars of varying lengths to compare quantities across different categories or groups.
source: apps/www/src/lib/registry/default/ui/chart-bar source: apps/www/registry/default/ui/chart-bar
label: Alpha label: Alpha
--- ---

View File

@ -1,7 +1,7 @@
--- ---
title: Donut title: Donut
description: A line chart visually represents data in a circular form, similar to a pie chart but with a central void, emphasizing proportions within categories. description: A line chart visually represents data in a circular form, similar to a pie chart but with a central void, emphasizing proportions within categories.
source: apps/www/src/lib/registry/default/ui/chart-donut source: apps/www/registry/default/ui/chart-donut
label: Alpha label: Alpha
--- ---

View File

@ -1,7 +1,7 @@
--- ---
title: Line title: Line
description: A line chart visually displays data points connected by straight lines, illustrating trends or relationships over a continuous axis. description: A line chart visually displays data points connected by straight lines, illustrating trends or relationships over a continuous axis.
source: apps/www/src/lib/registry/default/ui/chart-line source: apps/www/registry/default/ui/chart-line
label: Alpha label: Alpha
--- ---

View File

@ -7,7 +7,7 @@ description: Use the CLI to add components to your project.
Use the `init` command to initialize configuration and dependencies for a new project. Use the `init` command to initialize configuration and dependencies for a new project.
The `init` command installs dependencies, adds the `cn`, `useEmitsAsProps` utils, configures `tailwind.config.cjs`, and creates CSS variables for the project. The `init` command installs dependencies, adds the `cn` util, configures `tailwind.config.js`, and CSS variables for the project.
```bash ```bash
npx shadcn-vue@latest init npx shadcn-vue@latest init
@ -15,28 +15,27 @@ npx shadcn-vue@latest init
You will be asked a few questions to configure `components.json`: You will be asked a few questions to configure `components.json`:
```ansi:line-numbers ```:line-numbers
Would you like to use TypeScript (recommended)? no / yes Which style would you like to use? New York
Which framework are you using? Vite / Nuxt / Laravel Which color would you like to use as base color? Zinc
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? src/index.css
Do you want to use CSS variables for colors? no / yes Do you want to use CSS variables for colors? no / yes
Where is your tailwind.config.js located? tailwind.config.js
Configure the import alias for components: @/components
Configure the import alias for utils: @/lib/utils
``` ```
### Options ### Options
```ansi ```txt
Usage: shadcn-vue init [options] Usage: shadcn-vue init [options] [components...]
initialize your project and install dependencies initialize your project and install dependencies
Arguments:
components the components to add or a url to the component.
Options: Options:
-y, --yes skip confirmation prompt. (default: false) -d, --defaults use default values i.e new-york, zinc and css variables. (default: false)
-c, --cwd <cwd> the working directory. (default: the current directory) -f, --force force overwrite of existing components.json. (default: false)
-y, --yes skip confirmation prompt. (default: false)
-c, --cwd <cwd> the working directory. defaults to the current directory.
-h, --help display help for command -h, --help display help for command
``` ```
@ -50,8 +49,9 @@ npx shadcn-vue@latest add [component]
You will be presented with a list of components to choose from: You will be presented with a list of components to choose from:
```ansi ```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 ◯ accordion
◯ alert ◯ alert
@ -60,45 +60,40 @@ Which components would you like to add? Space to select. Return to submit.
◯ avatar ◯ avatar
◯ badge ◯ badge
◯ button ◯ button
◯ calendar
◯ card ◯ card
◯ checkbox ◯ checkbox
◯ collapsible
``` ```
### Options ### Options
```ansi ```txt
Usage: shadcn-vue add [options] [components...] Usage: shadcn-vue add [options] [components...]
add components to your project add a component to your project
Arguments: Arguments:
components name of components components the components to add or a url to the component.
Options: Options:
--nodep disable adding & installing dependencies (advanced) (default: false) -y, --yes skip confirmation prompt. (default: false)
-y, --yes Skip confirmation prompt. (default: false)
-o, --overwrite overwrite existing files. (default: false) -o, --overwrite overwrite existing files. (default: false)
-c, --cwd <cwd> the working directory. (default: the current directory) -c, --cwd <cwd> the working directory. defaults to the current directory.
-a, --all add all available components. (default: false)
-p, --path <path> the path to add the component to. -p, --path <path> the path to add the component to.
-h, --help display help for command -h, --help display help for command
``` ```
## update ## Monorepo
Use the `update` command to update components in your project. This will overwrite any modifications you've made to the components, so be sure to commit your changes before running this command. In a monorepo, you can specify the path to your workspace with the `-c` or `--cwd` option.
We plan on improving this command in the future to improve the update experience. ```bash
npx shadcn-vue@latest init -c ./apps/www
```ansi ```
Usage: shadcn-vue update [options] [components...]
or
update components in your project
```bash
Arguments: npx shadcn-vue@latest add alert-dialog -c ./apps/www
components name of components
Options:
-c, --cwd <cwd> the working directory. (default: the current directory)
-h, --help display help for command
``` ```

View File

@ -108,6 +108,18 @@ For more information, see the [theming docs](/docs/theming).
**This cannot be changed after initialization.** To switch between CSS variables and utility classes, you'll have to delete and re-install your components. **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-"
}
}
```
## aliases ## 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. 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.
@ -160,3 +172,27 @@ The CLI will use the `aliases.ui` value to determine where to place your `ui` co
} }
} }
``` ```
### aliases.lib
Import alias for `lib` functions such as `format-date` or `generate-id`.
```json title="components.json"
{
"aliases": {
"lib": "@/lib"
}
}
```
### aliases.hooks
Import alias for `hooks` such as `use-media-query` or `use-toast`.
```json title="components.json"
{
"aliases": {
"hooks": "@/hooks"
}
}
```

View File

@ -1,8 +1,8 @@
--- ---
title: Accordion title: Accordion
description: A vertically stacked set of interactive headings that each reveal a section of content. description: A vertically stacked set of interactive headings that each reveal a section of content.
source: apps/www/src/lib/registry/default/ui/accordion source: apps/www/registry/default/ui/accordion
primitive: https://www.radix-vue.com/components/accordion.html primitive: https://www.reka-ui.com/docs/components/accordion.html
--- ---
<ComponentPreview name="AccordionDemo" class="sm:max-w-[70%]" /> <ComponentPreview name="AccordionDemo" class="sm:max-w-[70%]" />
@ -29,10 +29,10 @@ module.exports = {
keyframes: { keyframes: {
'accordion-down': { 'accordion-down': {
from: { height: 0 }, from: { height: 0 },
to: { height: 'var(--radix-accordion-content-height)' }, to: { height: 'var(--reka-accordion-content-height)' },
}, },
'accordion-up': { 'accordion-up': {
from: { height: 'var(--radix-accordion-content-height)' }, from: { height: 'var(--reka-accordion-content-height)' },
to: { height: 0 }, to: { height: 0 },
}, },
}, },

View File

@ -1,8 +1,8 @@
--- ---
title: Alert Dialog title: Alert Dialog
description: A modal dialog that interrupts the user with important content and expects a response. description: A modal dialog that interrupts the user with important content and expects a response.
source: apps/www/src/lib/registry/default/ui/alert-dialog source: apps/www/registry/default/ui/alert-dialog
primitive: https://www.radix-vue.com/components/alert-dialog.html primitive: https://www.reka-ui.com/docs/components/alert-dialog.html
--- ---
<ComponentPreview name="AlertDialogDemo" /> <ComponentPreview name="AlertDialogDemo" />

View File

@ -1,8 +1,8 @@
--- ---
title: Aspect Ratio title: Aspect Ratio
description: Displays content within a desired ratio. description: Displays content within a desired ratio.
source: apps/www/src/lib/registry/default/ui/aspect-ratio source: apps/www/registry/default/ui/aspect-ratio
primitive: https://www.radix-vue.com/components/aspect-ratio.html primitive: https://www.reka-ui.com/docs/components/aspect-ratio.html
--- ---
<ComponentPreview name="AspectRatioDemo" /> <ComponentPreview name="AspectRatioDemo" />
@ -24,12 +24,12 @@ npx shadcn-vue@latest add aspect-ratio
### Install the following dependency: ### Install the following dependency:
```bash ```bash
npm install radix-vue npm install reka-ui
``` ```
### Copy and paste the following code into your project: ### Copy and paste the following code into your project:
<<< @/lib/registry/default/ui/aspect-ratio/AspectRatio.vue <<< @/registry/default/ui/aspect-ratio/AspectRatio.vue
</Steps> </Steps>

View File

@ -1,8 +1,8 @@
--- ---
title: Avatar title: Avatar
description: An image element with a fallback for representing the user. description: An image element with a fallback for representing the user.
source: apps/www/src/lib/registry/default/ui/avatar source: apps/www/registry/default/ui/avatar
primitive: https://www.radix-vue.com/components/avatar.html primitive: https://www.reka-ui.com/docs/components/avatar.html
--- ---
<ComponentPreview name="AvatarDemo" /> <ComponentPreview name="AvatarDemo" />
@ -22,7 +22,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
<template> <template>
<Avatar> <Avatar>
<AvatarImage src="https://github.com/radix-vue.png" alt="@radix-vue" /> <AvatarImage src="https://github.com/unovue.png" alt="@unovue" />
<AvatarFallback>CN</AvatarFallback> <AvatarFallback>CN</AvatarFallback>
</Avatar> </Avatar>
</template> </template>

View File

@ -1,21 +1,15 @@
--- ---
title: Calendar title: Calendar
description: A date field component that allows users to enter and edit date. description: A date field component that allows users to enter and edit date.
source: apps/www/src/lib/registry/default/ui/calendar source: apps/www/registry/default/ui/calendar
primitive: https://www.radix-vue.com/components/calendar.html primitive: https://www.reka-ui.com/docs/components/calendar.html
--- ---
<ComponentPreview name="CalendarDemo" /> <ComponentPreview name="CalendarDemo" />
<Callout class="text-base mt-12">
If you're looking for **previous** Calendar implementation, checkout to <span class="font-bold underline">[VCalendar](/docs/components/v-calendar)</span> component
</Callout>
## About ## About
The `<Calendar />` component is built on top of the [RadixVue Calendar](https://www.radix-vue.com/components/calendar.html) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates. The `<Calendar />` component is built on top of the [RadixVue Calendar](https://www.reka-ui.com/docs/components/calendar.html) component, which uses the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package to handle dates.
If you're looking for a range calendar, check out the [Range Calendar](/docs/components/range-calendar) component. If you're looking for a range calendar, check out the [Range Calendar](/docs/components/range-calendar) component.
@ -26,7 +20,7 @@ npx shadcn-vue@latest add calendar
``` ```
::: tip ::: tip
The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript. The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript.
Check [Dates & Times in Radix Vue](https://www.radix-vue.com/guides/dates.html) for more information and installation instructions. Check [Dates & Times in Radix Vue](https://www.reka-ui.com/docs/guides/dates.html) for more information and installation instructions.
::: :::
## Datepicker ## Datepicker

View File

@ -1,7 +1,7 @@
--- ---
title: Carousel title: Carousel
description: A carousel with motion and swipe built using Embla. description: A carousel with motion and swipe built using Embla.
source: apps/www/src/lib/registry/default/ui/carousel source: apps/www/registry/default/ui/carousel
primitive: https://www.embla-carousel.com/api primitive: https://www.embla-carousel.com/api
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: Checkbox title: Checkbox
description: A control that allows the user to toggle between checked and not checked. description: A control that allows the user to toggle between checked and not checked.
source: apps/www/src/lib/registry/default/ui/checkbox source: apps/www/registry/default/ui/checkbox
primitive: https://www.radix-vue.com/components/checkbox.html primitive: https://www.reka-ui.com/docs/components/checkbox.html
--- ---
<ComponentPreview name="CheckboxDemo" /> <ComponentPreview name="CheckboxDemo" />

View File

@ -1,8 +1,8 @@
--- ---
title: Collapsible title: Collapsible
description: An interactive component which expands/collapses a panel. description: An interactive component which expands/collapses a panel.
source: apps/www/src/lib/registry/default/ui/collapsible source: apps/www/registry/default/ui/collapsible
primitive: https://www.radix-vue.com/components/collapsible.html primitive: https://www.reka-ui.com/docs/components/collapsible.html
--- ---
<ComponentPreview name="CollapsibleDemo" /> <ComponentPreview name="CollapsibleDemo" />
@ -29,10 +29,10 @@ module.exports = {
keyframes: { keyframes: {
'collapsible-down': { 'collapsible-down': {
from: { height: 0 }, from: { height: 0 },
to: { height: 'var(--radix-collapsible-content-height)' }, to: { height: 'var(--reka-collapsible-content-height)' },
}, },
'collapsible-up': { 'collapsible-up': {
from: { height: 'var(--radix-collapsible-content-height)' }, from: { height: 'var(--reka-collapsible-content-height)' },
to: { height: 0 }, to: { height: 0 },
}, },
}, },

View File

@ -1,22 +1,19 @@
--- ---
title: Combobox title: Combobox
description: Autocomplete input and command palette with a list of suggestions. description: Autocomplete input and command palette with a list of suggestions.
source: apps/www/registry/default/ui/combobox
primitive: https://www.reka-ui.com/docs/components/combobox.html
--- ---
<ComponentPreview name="ComboboxDemo" /> <ComponentPreview name="ComboboxDemo" />
<br> <br>
<Callout title="Note" class="bg-destructive">
[Radix Vue](https://github.com/radix-vue/radix-vue/releases/tag/v1.2.0) introduced a breaking change. You will need to wrap `ComboboxGroup` and `ComboboxItem` inside of `ComboboxList` now.
</Callout>
## Installation ## Installation
The Combobox is built using a composition of the `<Popover />` and the `<Command />` components. ```bash
npx shadcn-vue@latest add combobox
See installation instructions for the [Popover](/docs/components/popover#installation) and the [Command](/docs/components/command#installation) components. ```
## Usage ## Usage
@ -97,11 +94,11 @@ const value = ref('')
## Examples ## Examples
### Combobox ### Combobox Trigger
<ComponentPreview name="ComboboxDemo" /> <ComponentPreview name="ComboboxTrigger" />
### Popover <!-- ### Popover
<ComponentPreview name="ComboboxPopover" /> <ComponentPreview name="ComboboxPopover" />
@ -113,7 +110,7 @@ const value = ref('')
You can create a responsive combobox by using the `<Popover />` on desktop and the `<Drawer />` components on mobile. You can create a responsive combobox by using the `<Popover />` on desktop and the `<Drawer />` components on mobile.
<ComponentPreview name="ComboboxResponsive" /> <ComponentPreview name="ComboboxResponsive" /> -->
### Form ### Form

View File

@ -1,8 +1,8 @@
--- ---
title: Command title: Command
description: Fast, composable, unstyled command menu. description: Fast, composable, unstyled command menu.
source: apps/www/src/lib/registry/default/ui/command source: apps/www/registry/default/ui/command
primitive: https://www.radix-vue.com/components/combobox.html primitive: https://www.reka-ui.com/docs/components/listbox.html
--- ---
<ComponentPreview name="CommandDemo" /> <ComponentPreview name="CommandDemo" />
@ -134,6 +134,28 @@ watch(CmdJ, (v) => {
</template> </template>
``` ```
### Combobox <br></br>
You can use the `<Command />` component as a combobox. See the [Combobox](/docs/components/combobox) page for more information. <Callout>
You can use the `<Command />` component like a combobox.
</Callout>
### Popover
<ComponentPreview name="CommandPopover" />
### Dropdown menu
<ComponentPreview name="CommandDropdownMenu" />
### Responsive
You can create a responsive combobox by using the `<Popover />` on desktop and the `<Drawer />` components on mobile.
<ComponentPreview name="CommandResponsive" />
### Form
<ComponentPreview name="CommandForm" />

View File

@ -1,8 +1,8 @@
--- ---
title: Context Menu title: Context Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button. description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
source: apps/www/src/lib/registry/default/ui/context-menu source: apps/www/registry/default/ui/context-menu
primitive: https://www.radix-vue.com/components/context-menu.html primitive: https://www.reka-ui.com/docs/components/context-menu.html
--- ---
<ComponentPreview name="ContextMenuDemo" /> <ComponentPreview name="ContextMenuDemo" />

View File

@ -751,7 +751,7 @@ const table = useVueTable({
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuCheckboxItem <DropdownMenuCheckboxItem
v-for="column in table.getAllColumns().filter((column) => column.getCanHide())" :key="column.id" v-for="column in table.getAllColumns().filter((column) => column.getCanHide())" :key="column.id"
class="capitalize" :checked="column.getIsVisible()" @update:checked="(value) => { class="capitalize" :modelValue="column.getIsVisible()" @update:modelValue="(value) => {
column.toggleVisibility(!!value) column.toggleVisibility(!!value)
}"> }">
{{ column.id }} {{ column.id }}
@ -814,13 +814,13 @@ export const columns: ColumnDef<Payment>[] = [
{ {
id: 'select', id: 'select',
header: ({ table }) => h(Checkbox, { header: ({ table }) => h(Checkbox, {
'checked': table.getIsAllPageRowsSelected(), 'modelValue': table.getIsAllPageRowsSelected(),
'onUpdate:checked': (value: boolean) => table.toggleAllPageRowsSelected(!!value), 'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all', 'ariaLabel': 'Select all',
}), }),
cell: ({ row }) => h(Checkbox, { cell: ({ row }) => h(Checkbox, {
'checked': row.getIsSelected(), 'modelValue': row.getIsSelected(),
'onUpdate:checked': (value: boolean) => row.toggleSelected(!!value), 'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
'ariaLabel': 'Select row', 'ariaLabel': 'Select row',
}), }),
enableSorting: false, enableSorting: false,
@ -995,7 +995,7 @@ const table = useVueTable({
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuCheckboxItem <DropdownMenuCheckboxItem
v-for="column in table.getAllColumns().filter((column) => column.getCanHide())" :key="column.id" v-for="column in table.getAllColumns().filter((column) => column.getCanHide())" :key="column.id"
class="capitalize" :checked="column.getIsVisible()" @update:checked="(value) => { class="capitalize" :modelValue="column.getIsVisible()" @update:modelValue="(value) => {
column.toggleVisibility(!!value) column.toggleVisibility(!!value)
}"> }">
{{ column.id }} {{ column.id }}
@ -1369,8 +1369,8 @@ const columns = computed(() => props.table.getAllColumns()
v-for="column in columns" v-for="column in columns"
:key="column.id" :key="column.id"
class="capitalize" class="capitalize"
:checked="column.getIsVisible()" :modelValue="column.getIsVisible()"
@update:checked="(value) => column.toggleVisibility(!!value)" @update:modelValue="(value) => column.toggleVisibility(!!value)"
> >
{{ column.id }} {{ column.id }}
</DropdownMenuCheckboxItem> </DropdownMenuCheckboxItem>

View File

@ -1,18 +1,12 @@
--- ---
title: Date Picker title: Date Picker
description: A date picker component with range and presets. description: A date picker component with range and presets.
source: apps/www/src/lib/registry/default/example/DatePickerDemo.vue source: apps/www/registry/default/example/DatePickerDemo.vue
primitive: https://www.radix-vue.com/components/calendar.html primitive: https://www.reka-ui.com/docs/components/calendar.html
--- ---
<ComponentPreview name="DatePickerDemo" /> <ComponentPreview name="DatePickerDemo" />
<Callout class="text-base mt-12">
If you're looking for **previous** Date Picker implementation, checkout to <span class="font-bold underline">[VCalendar Datepicker](/docs/components/v-date-picker)</span> component
</Callout>
## Installation ## Installation
The Date Picker is built using a composition of the `<Popover />` and either the `<Calendar />` or `<RangeCalendar />` components. The Date Picker is built using a composition of the `<Popover />` and either the `<Calendar />` or `<RangeCalendar />` components.

View File

@ -1,8 +1,8 @@
--- ---
title: Dialog title: Dialog
description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert. description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
source: apps/www/src/lib/registry/default/ui/dialog source: apps/www/registry/default/ui/dialog
primitive: https://www.radix-vue.com/components/dialog.html primitive: https://www.reka-ui.com/docs/components/dialog.html
--- ---
<ComponentPreview name="DialogDemo" /> <ComponentPreview name="DialogDemo" />

View File

@ -1,15 +1,15 @@
--- ---
title: Drawer title: Drawer
description: A drawer component for vue. description: A drawer component for vue.
source: apps/www/src/lib/registry/default/ui/drawer source: apps/www/registry/default/ui/drawer
primitive: https://github.com/radix-vue/vaul-vue primitive: https://github.com/unovue/vaul-vue
--- ---
<ComponentPreview name="DrawerDemo" /> <ComponentPreview name="DrawerDemo" />
## About ## About
Drawer is built on top of [Vaul Vue](https://github.com/radix-vue/vaul-vue). Drawer is built on top of [Vaul Vue](https://github.com/unovue/vaul-vue).
## Installation ## Installation

View File

@ -1,8 +1,8 @@
--- ---
title: Dropdown Menu title: Dropdown Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button. description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
source: apps/www/src/lib/registry/default/ui/dropdown-menu source: apps/www/registry/default/ui/dropdown-menu
primitive: https://www.radix-vue.com/components/dropdown-menu.html primitive: https://www.reka-ui.com/docs/components/dropdown-menu.html
--- ---
<ComponentPreview name="DropdownMenuDemo" /> <ComponentPreview name="DropdownMenuDemo" />

View File

@ -108,34 +108,34 @@ npx shadcn-vue@latest add form
### Install the following dependency: ### Install the following dependency:
```bash ```bash
npm install radix-vue vee-validate @vee-validate/zod zod npm install reka-ui vee-validate @vee-validate/zod zod
``` ```
### Copy and paste the following codes into your project: ### Copy and paste the following codes into your project:
`index.ts` `index.ts`
<<< @/lib/registry/default/ui/form/index.ts <<< @/registry/default/ui/form/index.ts
`FormItem.vue` `FormItem.vue`
<<< @/lib/registry/default/ui/form/FormItem.vue <<< @/registry/default/ui/form/FormItem.vue
`FormLabel.vue` `FormLabel.vue`
<<< @/lib/registry/default/ui/form/FormLabel.vue <<< @/registry/default/ui/form/FormLabel.vue
`FormControl.vue` `FormControl.vue`
<<< @/lib/registry/default/ui/form/FormControl.vue <<< @/registry/default/ui/form/FormControl.vue
`FormMessage.vue` `FormMessage.vue`
<<< @/lib/registry/default/ui/form/FormMessage.vue <<< @/registry/default/ui/form/FormMessage.vue
`FormDescription.vue` `FormDescription.vue`
<<< @/lib/registry/default/ui/form/FormDescription.vue <<< @/registry/default/ui/form/FormDescription.vue
### Update the import paths to match your project setup. ### Update the import paths to match your project setup.

View File

@ -1,8 +1,8 @@
--- ---
title: Hover Card title: Hover Card
description: For sighted users to preview content available behind a link. description: For sighted users to preview content available behind a link.
source: apps/www/src/lib/registry/default/ui/hover-card source: apps/www/registry/default/ui/hover-card
primitive: https://www.radix-vue.com/components/hover-card.html primitive: https://www.reka-ui.com/docs/components/hover-card.html
--- ---
<ComponentPreview name="HoverCardDemo" /> <ComponentPreview name="HoverCardDemo" />

View File

@ -21,7 +21,7 @@ npx shadcn-vue@latest add input
### Copy and paste the following code into your project: ### Copy and paste the following code into your project:
<<< @/lib/registry/default/ui/input/Input.vue <<< @/registry/default/ui/input/Input.vue
</Steps> </Steps>

View File

@ -1,8 +1,8 @@
--- ---
title: Label title: Label
description: Renders an accessible label associated with controls. description: Renders an accessible label associated with controls.
source: apps/www/src/lib/registry/default/ui/label source: apps/www/registry/default/ui/label
primitive: https://www.radix-vue.com/components/label.html primitive: https://www.reka-ui.com/docs/components/label.html
--- ---
<ComponentPreview name="LabelDemo" /> <ComponentPreview name="LabelDemo" />
@ -24,12 +24,12 @@ npx shadcn-vue@latest add label
### Install the following dependency: ### Install the following dependency:
```bash ```bash
npm install radix-vue npm install reka-ui
``` ```
### Copy and paste the following code into your project: ### Copy and paste the following code into your project:
<<< @/lib/registry/default/ui/label/Label.vue <<< @/registry/default/ui/label/Label.vue
</Steps> </Steps>

View File

@ -1,8 +1,8 @@
--- ---
title: Menubar title: Menubar
description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands. description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
source: apps/www/src/lib/registry/default/ui/menubar source: apps/www/registry/default/ui/menubar
primitive: https://www.radix-vue.com/components/menubar.html primitive: https://www.reka-ui.com/docs/components/menubar.html
--- ---
<ComponentPreview name="MenubarDemo" /> <ComponentPreview name="MenubarDemo" />

View File

@ -1,8 +1,8 @@
--- ---
title: Navigation Menu title: Navigation Menu
description: A collection of links for navigating websites. description: A collection of links for navigating websites.
source: apps/www/src/lib/registry/default/ui/navigation-menu source: apps/www/registry/default/ui/navigation-menu
primitive: https://www.radix-vue.com/components/navigation-menu.html primitive: https://www.reka-ui.com/docs/components/navigation-menu.html
--- ---
<ComponentPreview name="NavigationMenuDemo" /> <ComponentPreview name="NavigationMenuDemo" />

View File

@ -1,8 +1,8 @@
--- ---
title: Number Field title: Number Field
description: A number field allows a user to enter a number and increment or decrement the value using stepper buttons. description: A number field allows a user to enter a number and increment or decrement the value using stepper buttons.
source: apps/www/src/lib/registry/default/ui/number-field source: apps/www/registry/default/ui/number-field
primitive: https://www.radix-vue.com/components/number-field.html primitive: https://www.reka-ui.com/docs/components/number-field.html
--- ---
<ComponentPreview name="NumberFieldDemo" class="max-w-[180px]" /> <ComponentPreview name="NumberFieldDemo" class="max-w-[180px]" />

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