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
or are unsure if this is really a bug, make sure to:
- Read the [docs](https://radix-vue.com/)
- Ask on [Discord Chat](https://chat.radix-vue.com/)
- Read the [docs](https://reka-ui.com/)
- Ask on [Discord Chat](https://chat.unovue.com/)
- Ask on [GitHub Discussions](https://github.com/shadcn-vue/shadcn-vue/discussions)
- type: input
id: reproduction

View File

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

View File

@ -11,7 +11,7 @@ body:
id: feature-description
attributes:
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
validations:
required: true

View File

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

4
.gitignore vendored
View File

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

1
.npmrc
View File

@ -1 +1,2 @@
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.
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
@ -36,7 +36,7 @@ packages
| ----------------------------| -------------------------------------------|
| `apps/www/.vitepress` | The Vitepress application 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. |
## Development
@ -44,7 +44,7 @@ packages
### 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
@ -83,7 +83,7 @@ Documentation is written using [md](https://vitepress.dev/guide/markdown). You c
## 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
apps

View File

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

View File

@ -1,5 +1,5 @@
<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">
shadcn-vue
</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 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.
- [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: dark)', content: 'black' }],
['meta', { name: 'creator', content: 'radix-vue' }],
['meta', { name: 'creator', content: 'reka-ui' }],
['meta', { name: 'theme-color', content: '#41b883' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'en' }],
@ -45,7 +45,7 @@ export default defineConfig({
provider: 'local',
},
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',
},
carbonAds: {

View File

@ -1,5 +1,4 @@
<script setup lang="ts">
import { Separator } from '@/lib/registry/default/ui/separator'
import ArrowRightIcon from '~icons/radix-icons/arrow-right'
import { announcementConfig } from '../config/site'
</script>
@ -7,11 +6,10 @@ import { announcementConfig } from '../config/site'
<template>
<a
: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">{{ announcementConfig.title }}</span>
<span class="hidden sm:inline">
<span class="sm:hidden underline-offset-4 group-hover:underline">{{ announcementConfig.title }}</span>
<span class="hidden sm:inline underline-offset-4 group-hover:underline">
{{ announcementConfig.title }}
</span>
<ArrowRightIcon class="ml-1 h-4 w-4" />

View File

@ -1,31 +1,33 @@
<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 { 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 { Badge } from '@/lib/registry/new-york/ui/badge'
import { Popover, PopoverContent, PopoverTrigger } from '@/lib/registry/new-york/ui/popover'
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/lib/registry/new-york/ui/resizable'
import { Separator } from '@/lib/registry/new-york/ui/separator'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/new-york/ui/tabs'
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/new-york/ui/toggle-group'
import { useClipboard } from '@vueuse/core'
import { Check, Fullscreen, Monitor, Smartphone, Tablet, Terminal } from 'lucide-vue-next'
import MagicString from 'magic-string'
import { computed, reactive, ref, watch } from 'vue'
import { compileScript, parse, walk } from 'vue/compiler-sfc'
import { Index } from '../../../__registry__/block'
import { highlight } from '../config/shiki'
import BlockPreview from './BlockPreview.vue'
import BlockViewerCode from './BlockViewerCode.vue'
const props = defineProps<{
name: string
}>()
const { style, codeConfig } = useConfigStore()
const { copied, copy } = useClipboard()
const isLoading = ref(true)
const tabValue = ref('preview')
const resizableRef = ref<InstanceType<typeof ResizablePanel>>()
const componentRegistry = ref<Block>()
const rawString = ref('')
const codeHtml = ref('')
@ -35,6 +37,19 @@ const metadata = reactive({
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) {
const s = new MagicString(code)
const scriptTagRegex = /<script\s+lang="ts"\s*>[\s\S]+?<\/script>/g
@ -50,18 +65,21 @@ function removeScript(code: string) {
function transformImportPath(code: string) {
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)
return s.toString()
}
watch([style, codeConfig], async () => {
try {
const baseRawString = await import(`../../../src/lib/registry/${style.value}/block/${props.name}.vue?raw`).then(res => res.default.trim())
rawString.value = transformImportPath(removeScript(baseRawString))
const styleIndex = Index[style.value]
componentRegistry.value = styleIndex[props.name]
if (!componentRegistry.value)
return
const rawString = await componentRegistry.value.raw()
if (!metadata.description) {
const { descriptor } = parse(baseRawString)
const { descriptor } = parse(rawString)
const ast = compileScript(descriptor, { id: '' })
walk(ast.scriptAst, {
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) {
console.error(err)
@ -90,48 +108,47 @@ watch([style, codeConfig], async () => {
<Tabs
:id="name"
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=" {
'--container-height': metadata.iframeHeight ?? '600px',
'--height': metadata.iframeHeight ?? '600px',
}"
>
<div class="flex flex-col items-center gap-4 sm:flex-row">
<div class="flex items-center gap-2">
<TabsList class="hidden sm:flex">
<TabsTrigger value="preview">
<div class="hidden items-center gap-2 sm:flex">
<TabsList class="h-7 items-center rounded-md p-0 px-[calc(theme(spacing.1)_-_2px)] py-[theme(spacing.1)]">
<TabsTrigger class="h-[1.45rem] rounded-sm px-2 text-xs" value="preview">
Preview
</TabsTrigger>
<TabsTrigger value="code">
<TabsTrigger class="h-[1.45rem] rounded-sm px-2 text-xs" value="code">
Code
</TabsTrigger>
</TabsList>
<div class="hidden items-center gap-2 sm:flex">
<Separator
orientation="vertical"
class="mx-2 hidden h-4 md:flex"
/>
<div class="flex items-center gap-2">
<a :href="`#${name}`">
<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>
<Separator
orientation="vertical"
class="mx-2 hidden h-4 md:flex"
/>
<div class="text-sm font-medium underline-offset-2 hover:underline">
<a :href="`#${name}`">{{ metadata.description }}</a>
</div>
</div>
<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
type="single"
default-value="100"
@ -157,44 +174,22 @@ watch([style, codeConfig], async () => {
>
<Smartphone class="h-3.5 w-3.5" />
</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>
</div>
<Separator
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" />
<!-- <BlockCopyButton :code="rawString" /> -->
<!-- <V0Button
name="{block.name}"
description="{block.description" || "Edit in v0"}
@ -207,7 +202,7 @@ watch([style, codeConfig], async () => {
v-show="tabValue === 'preview'"
force-mount
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">
<ResizablePanel
@ -217,17 +212,14 @@ watch([style, codeConfig], async () => {
:min-size="30"
:as-child="true"
>
<BlockPreview :name="name" styles="default" :container-class="metadata.containerClass ?? ''" container />
<BlockPreview :url="iframeURL" container />
</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" />
<ResizablePanel id="block-resizable-panel-2" :default-size="0" :min-size="0" />
</ResizablePanelGroup>
</TabsContent>
<TabsContent value="code" class="h-[--container-height]">
<div
class="language-vue !h-full !max-h-[none] !mt-0"
v-html="codeHtml"
/>
<TabsContent value="code" class="h-[--height]">
<BlockViewerCode v-if="componentRegistry" :item="componentRegistry" />
</TabsContent>
</Tabs>
</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">
import { cn } from '@/lib/utils'
import { useUrlSearchParams } from '@vueuse/core'
import ComponentLoader from './ComponentLoader.vue'
@ -6,7 +7,10 @@ const params = useUrlSearchParams('history')
</script>
<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'" />
</div>
</template>

View File

@ -1,33 +1,18 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { ref } from 'vue'
import Spinner from './Spinner.vue'
const props = defineProps<{
name: string
styles?: string
containerClass?: string
container?: boolean
url: string
}>()
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>
<template>
<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 />
</div>
<div
@ -35,8 +20,8 @@ const iframeURL = computed(() => {
>
<iframe
v-show="!isLoading"
:src="iframeURL"
class="relative z-20 w-full bg-background" :class="[container ? 'h-[--container-height]' : 'size-full']"
:src="url"
class="relative z-20 w-full bg-background" :class="[container ? 'h-[--height]' : 'size-full']"
@load="isLoading = false"
/>
</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">
import { buttonVariants } from '@/lib/registry/new-york/ui/button'
import { cn } from '@/lib/utils'
import GitHubIcon from '~icons/radix-icons/github-logo'
import { ref } from 'vue'
import { Button } from '@/registry/new-york/ui/button'
import Announcement from '../components/Announcement.vue'
import PageAction from '../components/PageAction.vue'
import PageHeader from '../components/PageHeader.vue'
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
import BlockContainer from './BlockContainer.vue'
const blocks = ref<string[]>([])
import('../../../__registry__/index').then((res) => {
blocks.value = Object.values(res.Index.default).filter(i => i.type === 'components:block').map(i => i.name)
})
const blocks = ['Sidebar01', 'Sidebar02', 'Sidebar03', 'Sidebar04', 'Sidebar05', 'Sidebar06', 'Sidebar07', 'Sidebar08', 'Sidebar09', 'Sidebar10', 'Sidebar11', 'Sidebar12', 'Sidebar13', 'Sidebar14', 'Sidebar15', 'Login01']
</script>
<template>
@ -27,27 +21,21 @@ import('../../../__registry__/index').then((res) => {
</PageHeaderDescription>
<PageAction>
<a
href="/blocks.html#blocks"
:class="cn(buttonVariants(), 'rounded-[6px]')"
>
Browse
</a>
<a
href="https://github.com/radix-vue/shadcn-vue"
target="_blank"
:class="cn(
buttonVariants({ variant: 'outline' }),
'rounded-[6px]',
)"
>
<GitHubIcon class="mr-2 h-4 w-4" />
GitHub
</a>
<Button as-child size="sm">
<a href="#blocks">Browse Blocks</a>
</Button>
<Button as-child variant="ghost" size="sm">
<a
href="https://github.com/shadcn-ui/ui/discussions/new?category=blocks-request"
target="_blank"
>
Request a block
</a>
</Button>
</PageAction>
</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" />
</section>
</template>

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
import { cn } from '@/lib/utils'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/registry/default/ui/tabs'
import { useConfigStore } from '@/stores/config'
import { useClipboard } from '@vueuse/core'
import MagicString from 'magic-string'
@ -28,14 +28,14 @@ const transformedRawString = computed(() => transformImportPath(rawString.value)
function transformImportPath(code: string) {
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)
return s.toString()
}
watch([style, codeConfig], async () => {
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')
}
catch (err) {

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { themes } from '@/lib/registry'
import { Button } from '@/lib/registry/new-york/ui/button'
import { Button } from '@/registry/new-york/ui/button'
import { baseColors } from '@/registry/registry-base-colors'
import { useConfigStore } from '@/stores/config'
import { useClipboard } from '@vueuse/core'
import CheckIcon from '~icons/radix-icons/check'
@ -9,7 +9,7 @@ import { computed, ref } from 'vue'
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()
@ -25,28 +25,28 @@ async function copyCode() {
<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">:root &#123;</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;--background: {{ activeTheme?.cssVars?.light?.background }};</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">
<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 }}: {{ activeTheme?.cssVars?.light?.[prefix] }};</span>
<span class="line text-white">--{{ prefix }}-foreground: {{ activeTheme?.cssVars?.light?.[ `${prefix}-foreground`] }};</span>
</template>
<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;--ring:{{ activeTheme?.cssVars.light.ring }};</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;--ring:{{ activeTheme?.cssVars?.light?.ring }};</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">&nbsp;</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;--foreground:{{ activeTheme?.cssVars.dark.foreground }};</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>
<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 }}-foreground:{{ activeTheme?.cssVars.dark[ `${prefix}-foreground`] }};</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>
</template>
<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;--ring:{{ activeTheme?.cssVars.dark.ring }};</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;--ring:{{ activeTheme?.cssVars?.dark?.ring }};</span>
<span class="line text-white">&#125;</span>
<span class="line text-white">&#125;</span>
</code>

View File

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

View File

@ -1,5 +1,5 @@
<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 { useData } from 'vitepress'
import { computed } from 'vue'

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { ScrollArea, ScrollBar } from '@/lib/registry/default/ui/scroll-area'
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 { computed, toRefs } from 'vue'
@ -11,42 +10,42 @@ const examples = [
{
name: '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',
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',
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',
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',
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',
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',
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',
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"
:href="example.href"
:class="cn(
'flex items-center px-4',
path?.startsWith(example.href) || (path === '/' && example.name === 'Mail')
? 'font-bold text-primary'
: 'font-medium text-muted-foreground',
'flex h-7 items-center justify-center rounded-full px-4 text-center text-sm transition-colors hover:text-primary',
path?.startsWith(example.href)
? 'bg-muted font-medium text-primary'
: 'text-muted-foreground',
)"
>
{{ example.name }}
@ -73,14 +72,5 @@ const currentExample = computed(() => examples.find(ex => path.value.startsWith(
</div>
<ScrollBar orientation="horizontal" class="invisible" />
</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>
</template>

View File

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

View File

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

View File

@ -3,20 +3,10 @@
<template>
<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">
<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>
<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>
<span class="font-bold">
shadcn-vue
shadcn/vue
</span>
</a>
</template>

View File

@ -1,5 +1,5 @@
<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>
<template>

View File

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

View File

@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
<template>
<section
: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 ?? '',
)"
>

View File

@ -7,10 +7,12 @@ import { cn } from '@/lib/utils'
<template>
<section
: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 ?? '',
)"
>
<slot />
<div class="container">
<slot />
</div>
</section>
</template>

View File

@ -1,10 +1,9 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import WrapBalancer from 'vue-wrap-balancer'
</script>
<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 />
</WrapBalancer>
</p>
</template>

View File

@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
<template>
<h1
: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 ?? '',
)"
>

View File

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

View File

@ -1,6 +1,6 @@
<template>
<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 />
</div>

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<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<{
name: string

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<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'
const slots = useSlots()

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<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 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 ShareDocument from '@/examples/cards/components/ShareDocument.vue'
import TeamMembers from '@/examples/cards/components/TeamMembers.vue'
import CardChat from '@/lib/registry/new-york/example/CardChat.vue'
import ActivityGoal from '@/lib/registry/new-york/example/Cards/ActivityGoal.vue'
import DataTable from '@/lib/registry/new-york/example/Cards/DataTable.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 '@/lib/registry/new-york/example/Cards/Metric.vue'
import CardStats from '@/lib/registry/new-york/example/CardStats.vue'
import { Card } from '@/lib/registry/new-york/ui/card'
import { RangeCalendar } from '@/lib/registry/new-york/ui/range-calendar'
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'

View File

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

View File

@ -30,22 +30,13 @@ export const docsConfig: DocsConfig = {
title: 'Components',
href: '/docs/components/accordion',
},
{
title: 'Themes',
href: '/themes',
},
{
title: 'Examples',
href: '/examples/mail',
},
{
title: 'Blocks',
href: '/blocks',
},
{
title: 'GitHub',
href: 'https://github.com/radix-vue/shadcn-vue',
external: true,
title: 'Themes',
href: '/themes',
},
],
sidebarNav: [
@ -377,42 +368,42 @@ export const examples: Example[] = [
{
name: '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',
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',
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",
// href: "/examples/tasks",
// 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',
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',
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',
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',
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">
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
import { cn } from '@/lib/utils'
import RadixIconsCode from '~icons/radix-icons/code'
import RadixIconsExternalLink from '~icons/radix-icons/external-link'
import { useData, useRoute } from 'vitepress'
@ -11,41 +11,33 @@ import { docsConfig } from '../config/docs'
const $route = useRoute()
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>
<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">
<aside
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"
>
<ScrollArea orientation="vertical" class="relative overflow-hidden h-full py-6 pr-6 lg:py-8" :type="'auto'">
<div class="w-full">
<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 }}
<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">
<div class="no-scrollbar h-full overflow-auto py-6 pr-6 lg:py-8">
<div v-for="docsGroup in docsConfig.sidebarNav" :key="docsGroup.title">
<div 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">
{{ docsGroup.label }}
</span>
</h4>
<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 }}
</span>
</h4>
<div
<div class="grid grid-flow-row auto-rows-max gap-0.5 text-sm">
<template
v-for="doc in docsGroup.items "
:key="doc.title"
class="grid grid-flow-row auto-rows-max text-sm"
>
<a
v-if="doc.href"
:disabled="doc.disabled"
: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="{
'!font-semibold !text-foreground': $route.path === `${doc.href}.html`,
}"
: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')"
>
{{ doc.title }}
@ -53,61 +45,61 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
{{ doc.label }}
</span>
</a>
</div>
</template>
</div>
</div>
</ScrollArea>
</aside>
</div>
</div>
</aside>
<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="block xl:hidden">
<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 />
<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 max-w-3xl">
<div class="block xl:hidden">
<TableOfContent />
</div>
<div class="hidden text-sm xl:block">
<div class="sticky top-16 -mt-10 h-[calc(100vh-3.5rem)] overflow-hidden pt-6">
<TableOfContent show-carbon-ads />
<DocsBreadcrumb class="mb-4" />
<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>
<p class="text-base text-muted-foreground">
{{ frontmatter.description }}
</p>
</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>
</template>

View File

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

View File

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

View File

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

View File

@ -2,10 +2,19 @@
@tailwind components;
@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 {
:root {
--font-geist-sans: "geist-sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
--font-geist-sans: "Geist";
--font-geist-mono: "GeistMono";
--background: 0 0% 100%;
--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-color: hsl(var(--border)) transparent;
}
html {
-webkit-text-size-adjust: 100%;
font-variation-settings: normal;
}
}
body {
@apply bg-background text-foreground min-h-screen antialiased font-sans;
/* 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 span {
color: var(--shiki-dark);
@ -147,21 +171,40 @@
@layer utilities {
.step {
counter-increment: step;
}
.step {
counter-increment: step;
}
.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 -ml-[50px] -mt-1;
content: counter(step);
}
.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 ml-[-50px] mt-[-4px];
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) {
.container {
@apply px-4;
}
.container {
@apply px-4;
}
}
div[class^="language-"] {
@ -180,18 +223,28 @@ pre code {
}
.line-numbers-wrapper {
@apply font-mono;
@apply !font-mono;
}
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 {
@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-new(root) {
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-c-divider: hsl(var(--muted));
--vp-code-block-color: #fff
}
}
/**
@ -22,6 +22,10 @@
outline: none;
}
.vp-doc h2:first-child {
@apply mt-0 pt-0;
}
.vp-doc h1:not(:where(.not-docs *)) {
letter-spacing: -0.02em;
line-height: 40px;
@ -167,39 +171,26 @@
* Table
* -------------------------------------------------------------------------- */
/* .vp-doc table {
display: block;
border-collapse: collapse;
margin: 20px 0;
overflow-x: auto;
.vp-doc table:not(:where(.not-docs *)) {
@apply relative w-full overflow-hidden border-none text-sm;
}
.vp-doc tr {
border-top: 1px solid var(--vp-c-divider);
transition: background-color 0.5s;
.vp-doc tr:not(:where(.not-docs *)) {
@apply m-0 border-b;
}
.vp-doc tbody:not(:where(.not-docs *)) tr:last-child {
@apply border-b-0;
}
.vp-doc tr:nth-child(2n) {
background-color: var(--vp-c-bg-soft);
.vp-doc th:not(:where(.not-docs *)) {
@apply px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right;
}
.vp-doc th,
.vp-doc td {
border: 1px solid var(--vp-c-divider);
padding: 8px 16px;
.vp-doc td:not(:where(.not-docs *)) {
@apply px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right;
}
.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
@ -328,18 +319,15 @@
position: relative;
z-index: 1;
margin: 0;
/* padding: 20px 0; */
background: transparent;
overflow-x: auto;
@apply bg-zinc-950 dark:bg-zinc-900;
}
.vp-doc [class*='language-'] code {
display: block;
/* padding: 0 24px; */
width: fit-content;
min-width: 100%;
line-height: var(--vp-code-line-height);
/* font-size: var(--vp-code-font-size); */
color: var(--vp-code-block-color);
transition: color 0.5s;
}
@ -350,8 +338,8 @@
padding: 0 24px; */
width: calc(100% + 2 * 24px);
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 {
background-color: var(--vp-code-line-error-color);
@ -421,15 +409,16 @@
.vp-doc .line-numbers-wrapper {
position: absolute;
top: 0;
bottom: 0;
bottom: 0;
left: 0;
z-index: 3;
z-index: 3;
border-right: 1px solid var(--vp-code-block-divider-color);
padding-top: 16px;
padding-top: 14px;
padding-left: 20px;
width: 32px;
text-align: center;
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);
color: var(--vp-code-line-number-color);
transition:
@ -441,20 +430,20 @@
/*rtl:ignore*/
direction: ltr;
position: absolute;
top: 12px;
top: 16px;
/*rtl:ignore*/
right: 12px;
right: 16px;
z-index: 3;
border: 1px solid var(--vp-code-copy-code-border-color);
border-radius: 4px;
width: 40px;
height: 40px;
width: 30px;
height: 30px;
background-color: var(--vp-code-copy-code-bg);
opacity: 0;
/* opacity: 0; */
cursor: pointer;
background-image: var(--vp-icon-copy);
background-position: 50%;
background-size: 20px;
background-size: 16px;
background-repeat: no-repeat;
transition:
border-color 0.25s,
@ -518,14 +507,10 @@
transition:
color 0.4s,
opacity 0.4s;
@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
@ -575,4 +560,4 @@
.line-numbers-mode pre code .line {
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 { 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__'
// @ts-expect-error ?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> = {}
files = constructFiles(componentName, style, sources)
files['.codesandbox/Dockerfile'] = {
@ -16,12 +16,12 @@ export function makeCodeSandboxParams(componentName: string, style: Style, sourc
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> = {}
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({
title: `${componentName} - Radix Vue`,
title: `${componentName} - Reka UI`,
files,
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 = {
style,
tailwind: {
@ -86,19 +86,19 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
utils: '@/utils',
components: '@/components',
},
iconLibrary: 'lucide',
}
const iconPackage = style === 'default' ? 'lucide-vue-next' : '@radix-icons/vue'
const dependencies = {
'vue': 'latest',
'radix-vue': 'latest',
'reka-ui': 'latest',
'@radix-ui/colors': 'latest',
'clsx': 'latest',
'class-variance-authority': 'latest',
'tailwind-merge': 'latest',
'tailwindcss-animate': 'latest',
[iconPackage]: 'latest',
'shadcn-vue': 'latest',
'lucide-vue-next': 'latest',
'shadcn-vue': 'next',
'typescript': 'latest',
'vaul-vue': '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
const transformImportPath = (code: string) => {
let parsed = code
parsed = parsed.replaceAll(`@/lib/registry/${style}`, '@/components')
parsed = parsed.replaceAll(`@/registry/${style}`, '@/components')
parsed = parsed.replaceAll('@/lib/utils', '@/utils')
return parsed
}
@ -132,7 +132,7 @@ function constructFiles(componentName: string, style: Style, sources: Record<str
})
// @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 = {
'package.json': {
@ -206,7 +206,7 @@ createApp(App).mount('#app')`,
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
#app {
@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",
"type": "module",
"version": "0.11.3",
"version": "1.0.0-next.0",
"files": [
"dist"
],
@ -17,50 +17,49 @@
},
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@internationalized/date": "^3.5.5",
"@internationalized/date": "^3.5.6",
"@radix-icons/vue": "^1.0.0",
"@stackblitz/sdk": "^1.11.0",
"@tanstack/vue-table": "^8.20.5",
"@unovis/ts": "^1.4.4",
"@unovis/vue": "^1.4.4",
"@vee-validate/zod": "^4.13.2",
"@vueuse/core": "^11.1.0",
"@vueuse/core": "^11.2.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"codesandbox": "^2.2.3",
"date-fns": "^4.1.0",
"embla-carousel-autoplay": "^8.3.0",
"embla-carousel-vue": "^8.3.0",
"embla-carousel-autoplay": "^8.4.0",
"embla-carousel-vue": "^8.4.0",
"lucide-vue-next": "^0.441.0",
"magic-string": "^0.30.11",
"radix-vue": "catalog:",
"magic-string": "^0.30.13",
"reka-ui": "catalog:",
"tailwindcss-animate": "^1.0.7",
"v-calendar": "^3.1.2",
"vaul-vue": "^0.2.0",
"vee-validate": "4.13.2",
"vue": "^3.5.6",
"vue-sonner": "^1.1.5",
"vue": "^3.5.13",
"vue-sonner": "^1.2.5",
"vue-wrap-balancer": "^1.2.1",
"zod": "catalog:"
},
"devDependencies": {
"@babel/traverse": "^7.25.6",
"@iconify-json/gravity-ui": "^1.1.3",
"@iconify-json/lucide": "^1.1.198",
"@iconify-json/ph": "^1.1.13",
"@iconify-json/radix-icons": "^1.1.14",
"@iconify-json/ri": "^1.1.21",
"@iconify-json/simple-icons": "^1.1.108",
"@iconify-json/tabler": "^1.1.116",
"@babel/traverse": "^7.25.9",
"@iconify-json/gravity-ui": "^1.2.2",
"@iconify-json/lucide": "^1.2.15",
"@iconify-json/ph": "^1.2.1",
"@iconify-json/radix-icons": "^1.2.1",
"@iconify-json/ri": "^1.2.3",
"@iconify-json/simple-icons": "^1.2.11",
"@iconify-json/tabler": "^1.2.8",
"@iconify/vue": "^4.1.2",
"@oxc-parser/wasm": "catalog:",
"@shikijs/transformers": "^1.17.7",
"@shikijs/transformers": "^1.23.1",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.5.5",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/compiler-core": "^3.5.6",
"@vue/compiler-dom": "^3.5.6",
"@types/node": "^22.9.0",
"@vitejs/plugin-vue": "^5.2.0",
"@vitejs/plugin-vue-jsx": "^4.1.0",
"@vue/compiler-core": "^3.5.13",
"@vue/compiler-dom": "^3.5.13",
"@vue/tsconfig": "^0.5.1",
"autoprefixer": "^10.4.20",
"fast-glob": "^3.3.2",
@ -68,14 +67,14 @@
"markdown-it": "^14.1.0",
"pathe": "^1.1.2",
"rimraf": "^6.0.1",
"shiki": "^1.22.1",
"tailwind-merge": "^2.5.2",
"tailwindcss": "^3.4.12",
"tsx": "^4.19.1",
"shiki": "^1.23.1",
"tailwind-merge": "^2.5.4",
"tailwindcss": "^3.4.15",
"tsx": "^4.19.2",
"typescript": "catalog:",
"unplugin-icons": "^0.19.3",
"vitepress": "^1.3.4",
"vue-component-meta": "^2.1.6",
"vue-tsc": "^2.1.6"
"vitepress": "^1.5.0",
"vue-component-meta": "^2.1.10",
"vue-tsc": "^2.1.10"
}
}

View File

@ -24,7 +24,7 @@ const tsconfigChecker = createComponentMetaChecker(
)
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,
})

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">
<mxGeometry x="570" y="500" width="120" height="60" as="geometry" />
</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" />
</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">

View File

@ -5,16 +5,16 @@ description: Powered by amazing open source projects.
## 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
- [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.
- [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`.
## 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
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.
@ -104,7 +104,7 @@ And if you're looking for a date picker input, check out the [`Date Picker`](/do
### 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" />

View File

@ -91,7 +91,7 @@ However, you can always pass in the desired `color` into each chart.
## Custom tooltip
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:

View File

@ -1,7 +1,7 @@
---
title: Area
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
---

View File

@ -1,7 +1,7 @@
---
title: Bar
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
---

View File

@ -1,7 +1,7 @@
---
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.
source: apps/www/src/lib/registry/default/ui/chart-donut
source: apps/www/registry/default/ui/chart-donut
label: Alpha
---

View File

@ -1,7 +1,7 @@
---
title: Line
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
---

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.
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
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`:
```ansi:line-numbers
Would you like to use TypeScript (recommended)? no / yes
Which framework are you using? Vite / Nuxt / Laravel
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
```:line-numbers
Which style would you like to use? New York
Which color would you like to use as base color? Zinc
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
```ansi
Usage: shadcn-vue init [options]
```txt
Usage: shadcn-vue init [options] [components...]
initialize your project and install dependencies
Arguments:
components the components to add or a url to the component.
Options:
-y, --yes skip confirmation prompt. (default: false)
-c, --cwd <cwd> the working directory. (default: the current directory)
-d, --defaults use default values i.e new-york, zinc and css variables. (default: false)
-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
```
@ -50,8 +49,9 @@ npx shadcn-vue@latest add [component]
You will be presented with a list of components to choose from:
```ansi
Which components would you like to add? Space to select. Return to submit.
```txt
Which components would you like to add? Space to select. A to toggle all.
Enter to submit.
◯ accordion
◯ alert
@ -60,45 +60,40 @@ Which components would you like to add? Space to select. Return to submit.
◯ avatar
◯ badge
◯ button
◯ calendar
◯ card
◯ checkbox
◯ collapsible
```
### Options
```ansi
```txt
Usage: shadcn-vue add [options] [components...]
add components to your project
add a component to your project
Arguments:
components name of components
components the components to add or a url to the component.
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)
-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.
-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.
```ansi
Usage: shadcn-vue update [options] [components...]
update components in your project
Arguments:
components name of components
Options:
-c, --cwd <cwd> the working directory. (default: the current directory)
-h, --help display help for command
```bash
npx shadcn-vue@latest init -c ./apps/www
```
or
```bash
npx shadcn-vue@latest add alert-dialog -c ./apps/www
```

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

View File

@ -1,8 +1,8 @@
---
title: Alert Dialog
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
primitive: https://www.radix-vue.com/components/alert-dialog.html
source: apps/www/registry/default/ui/alert-dialog
primitive: https://www.reka-ui.com/docs/components/alert-dialog.html
---
<ComponentPreview name="AlertDialogDemo" />

View File

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

View File

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

View File

@ -1,21 +1,15 @@
---
title: Calendar
description: A date field component that allows users to enter and edit date.
source: apps/www/src/lib/registry/default/ui/calendar
primitive: https://www.radix-vue.com/components/calendar.html
source: apps/www/registry/default/ui/calendar
primitive: https://www.reka-ui.com/docs/components/calendar.html
---
<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
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.
@ -26,7 +20,7 @@ npx shadcn-vue@latest add calendar
```
::: 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.
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

View File

@ -1,7 +1,7 @@
---
title: Carousel
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
---

View File

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

View File

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

View File

@ -1,22 +1,19 @@
---
title: Combobox
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" />
<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
The Combobox is built using a composition of the `<Popover />` and the `<Command />` components.
See installation instructions for the [Popover](/docs/components/popover#installation) and the [Command](/docs/components/command#installation) components.
```bash
npx shadcn-vue@latest add combobox
```
## Usage
@ -97,11 +94,11 @@ const value = ref('')
## Examples
### Combobox
### Combobox Trigger
<ComponentPreview name="ComboboxDemo" />
<ComponentPreview name="ComboboxTrigger" />
### Popover
<!-- ### Popover
<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.
<ComponentPreview name="ComboboxResponsive" />
<ComponentPreview name="ComboboxResponsive" /> -->
### Form

View File

@ -1,8 +1,8 @@
---
title: Command
description: Fast, composable, unstyled command menu.
source: apps/www/src/lib/registry/default/ui/command
primitive: https://www.radix-vue.com/components/combobox.html
source: apps/www/registry/default/ui/command
primitive: https://www.reka-ui.com/docs/components/listbox.html
---
<ComponentPreview name="CommandDemo" />
@ -134,6 +134,28 @@ watch(CmdJ, (v) => {
</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
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
primitive: https://www.radix-vue.com/components/context-menu.html
source: apps/www/registry/default/ui/context-menu
primitive: https://www.reka-ui.com/docs/components/context-menu.html
---
<ComponentPreview name="ContextMenuDemo" />

View File

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

View File

@ -1,18 +1,12 @@
---
title: Date Picker
description: A date picker component with range and presets.
source: apps/www/src/lib/registry/default/example/DatePickerDemo.vue
primitive: https://www.radix-vue.com/components/calendar.html
source: apps/www/registry/default/example/DatePickerDemo.vue
primitive: https://www.reka-ui.com/docs/components/calendar.html
---
<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
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
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
primitive: https://www.radix-vue.com/components/dialog.html
source: apps/www/registry/default/ui/dialog
primitive: https://www.reka-ui.com/docs/components/dialog.html
---
<ComponentPreview name="DialogDemo" />

View File

@ -1,15 +1,15 @@
---
title: Drawer
description: A drawer component for vue.
source: apps/www/src/lib/registry/default/ui/drawer
primitive: https://github.com/radix-vue/vaul-vue
source: apps/www/registry/default/ui/drawer
primitive: https://github.com/unovue/vaul-vue
---
<ComponentPreview name="DrawerDemo" />
## 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

View File

@ -1,8 +1,8 @@
---
title: Dropdown Menu
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
primitive: https://www.radix-vue.com/components/dropdown-menu.html
source: apps/www/registry/default/ui/dropdown-menu
primitive: https://www.reka-ui.com/docs/components/dropdown-menu.html
---
<ComponentPreview name="DropdownMenuDemo" />

View File

@ -108,34 +108,34 @@ npx shadcn-vue@latest add form
### Install the following dependency:
```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:
`index.ts`
<<< @/lib/registry/default/ui/form/index.ts
<<< @/registry/default/ui/form/index.ts
`FormItem.vue`
<<< @/lib/registry/default/ui/form/FormItem.vue
<<< @/registry/default/ui/form/FormItem.vue
`FormLabel.vue`
<<< @/lib/registry/default/ui/form/FormLabel.vue
<<< @/registry/default/ui/form/FormLabel.vue
`FormControl.vue`
<<< @/lib/registry/default/ui/form/FormControl.vue
<<< @/registry/default/ui/form/FormControl.vue
`FormMessage.vue`
<<< @/lib/registry/default/ui/form/FormMessage.vue
<<< @/registry/default/ui/form/FormMessage.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.

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
---
title: Menubar
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
primitive: https://www.radix-vue.com/components/menubar.html
source: apps/www/registry/default/ui/menubar
primitive: https://www.reka-ui.com/docs/components/menubar.html
---
<ComponentPreview name="MenubarDemo" />

View File

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

View File

@ -1,8 +1,8 @@
---
title: Number Field
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
primitive: https://www.radix-vue.com/components/number-field.html
source: apps/www/registry/default/ui/number-field
primitive: https://www.reka-ui.com/docs/components/number-field.html
---
<ComponentPreview name="NumberFieldDemo" class="max-w-[180px]" />

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