Merge remote-tracking branch 'origin/dev' into charting
This commit is contained in:
commit
595bbe04ea
77
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
77
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
|
|
@ -6,62 +6,27 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
**Before You Start...**
|
Thanks for taking the time to fill out this bug report!
|
||||||
|
|
||||||
This form is only for submitting bug reports. If you have a usage question
|
This form is only for submitting bug reports. If you have a usage question
|
||||||
or are unsure if this is really a bug, make sure to:
|
or are unsure if this is really a bug, make sure to:
|
||||||
|
|
||||||
- Read the [docs](https://radix-vue.com/)
|
- Read the [docs](https://radix-vue.com/)
|
||||||
- Ask on [Discord Chat](https://chat.radix-vue.com/)
|
- Ask on [Discord Chat](https://chat.radix-vue.com/)
|
||||||
- Ask on [GitHub Discussions](https://github.com/shadcn-vue/shadcn-vue/discussions)
|
- Ask on [GitHub Discussions](https://github.com/shadcn-vue/shadcn-vue/discussions)
|
||||||
|
|
||||||
Also try to search for your issue - it may have already been answered or even fixed.
|
|
||||||
However, if you find that an old, closed issue still persists in the latest version,
|
|
||||||
you should open a new issue using the form below instead of commenting on the old issue.
|
|
||||||
- type: textarea
|
|
||||||
id: bug-env
|
|
||||||
attributes:
|
|
||||||
label: Environment
|
|
||||||
description: Please provide the following information about your environment.
|
|
||||||
value: |
|
|
||||||
Developement/Production OS: Windows 10 19043.1110
|
|
||||||
Node version: 16.0.0
|
|
||||||
Package manager: pnpm@8.6.0
|
|
||||||
Radix Vue version: 1.0.0
|
|
||||||
Shadcn Vue version: 1.0.0
|
|
||||||
Vue version: 3.0.0
|
|
||||||
Nuxt version: 3.0.0
|
|
||||||
Nuxt mode: universal
|
|
||||||
Nuxt target: server
|
|
||||||
CSS framework: tailwindcss@3.3.3
|
|
||||||
Client OS: Windows 10 19043.1110
|
|
||||||
Browser: Chrome 90.0.4430.212
|
|
||||||
render: bash
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
- type: input
|
||||||
id: reproduction-link
|
id: reproduction
|
||||||
attributes:
|
attributes:
|
||||||
label: Link to minimal reproduction
|
label: Reproduction
|
||||||
description: |
|
description: |
|
||||||
Please provide a link to a minimal reproduction of the bug.
|
A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is **required**, otherwise the issue might be closed without further notice. [**Why?**](https://antfu.me/posts/why-reproductions-are-required)
|
||||||
A minimal reproduction is a CodeSandbox, CodePen, or a StackBlitz that contains the bare minimum amount of code needed to show the bug.
|
|
||||||
A minimal reproduction is required unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem
|
|
||||||
|
|
||||||
This is **required** for us to be able to triage your issue in a timely manner.
|
To get started, you can use the StackBlitz and CodeSandbox playgrounds in shadcn-vue demos:
|
||||||
|
https://www.shadcn-vue.com/docs/components/accordion.html
|
||||||
|
|
||||||
Please do not just fill in a random link. The issue will be closed if no valid reproduction is provided.
|
or use template presets
|
||||||
placeholder: Reproduction Link
|
https://vite.new
|
||||||
validations:
|
https://nuxt.new
|
||||||
required: true
|
placeholder: Reproduction
|
||||||
- type: textarea
|
|
||||||
id: steps-to-reproduce
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce
|
|
||||||
description: |
|
|
||||||
How do you trigger this bug? Please walk us through it step by step.
|
|
||||||
Note that you can use [Markdown](https://guides.github.com/features/mastering-markdown/) to format lists and code.
|
|
||||||
placeholder: Steps to reproduce
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
@ -73,14 +38,18 @@ body:
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: expected-behavior
|
id: system-info
|
||||||
attributes:
|
attributes:
|
||||||
label: Expected behavior
|
label: System Info
|
||||||
description: A clear and concise description of what you expected to happen.
|
description: Output of `npx envinfo --system --npmPackages vue,@vueuse/core,radix-vue,nuxt,shadcn-vue,shadcn-nuxt,unplugin-auto-import --binaries --browsers`
|
||||||
- type: textarea
|
render: bash
|
||||||
id: screenshots
|
placeholder: System, Binaries, Browsers
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: contributes
|
||||||
attributes:
|
attributes:
|
||||||
label: Conext & Screenshots (if applicable)
|
label: Contributes
|
||||||
description: |
|
options:
|
||||||
If applicable, provide any additional context or screenshots of the bug.
|
- label: I am willing to submit a PR to fix this issue
|
||||||
You can drag and drop images here to add them to the issue.
|
- label: I am willing to submit a PR with failing tests
|
||||||
|
|
|
||||||
51
.github/workflows/publish.yaml
vendored
51
.github/workflows/publish.yaml
vendored
|
|
@ -11,14 +11,42 @@ on:
|
||||||
- dev
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- 'apps/www/**'
|
- 'apps/www/**'
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
# When a created pull request from forked repo, it will be comment 'Should deploy to add label'
|
||||||
|
- opened
|
||||||
|
# When a labeled '🚀request-deploy' pull request from forked repo, it will be deploy to Cloudflare Pages
|
||||||
|
- labeled
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
# eslint-disable-next-line yml/no-empty-mapping-value
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
# default contents: read & write (in forked repos, only read)
|
||||||
|
contents: write
|
||||||
|
# default deployments: read & write (in forked repos, only read)
|
||||||
|
deployments: write
|
||||||
|
# default pull-requests: read & write (in forked repos, only read)
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
deployments: write
|
|
||||||
name: Publish to Cloudflare Pages
|
name: Publish to Cloudflare Pages
|
||||||
|
# push event in main branch
|
||||||
|
# workflow_dispatch event
|
||||||
|
# pull_request event from not forked repo
|
||||||
|
# pull_request_target event with label "🚀request-deploy" from forked repo
|
||||||
|
if: ${{
|
||||||
|
github.event_name == 'push' ||
|
||||||
|
github.event_name == 'workflow_dispatch' ||
|
||||||
|
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) ||
|
||||||
|
(github.event_name == 'pull_request_target' &&
|
||||||
|
github.event.action == 'labeled' &&
|
||||||
|
github.event.pull_request.head.repo.fork == true &&
|
||||||
|
contains(github.event.label.name, '🚀request-deploy'))
|
||||||
|
}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
@ -56,7 +84,7 @@ jobs:
|
||||||
|
|
||||||
# Run a action to publish docs
|
# Run a action to publish docs
|
||||||
- name: Publish to Cloudflare Pages
|
- name: Publish to Cloudflare Pages
|
||||||
uses: cloudflare/pages-action@v1.5.0
|
uses: zernonia/cloudflare-pages-action@v0.0.7
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
|
@ -66,7 +94,20 @@ jobs:
|
||||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
# Optional: Switch what branch you are publishing to.
|
# Optional: Switch what branch you are publishing to.
|
||||||
# By default this will be the branch which triggered this workflow
|
# By default this will be the branch which triggered this workflow
|
||||||
# branch: main
|
branch: ${{ github.ref == 'refs/heads/dev' && 'dev' || format('refs/pull/{0}/merge', github.event.number) }}
|
||||||
# Optional: Change the working directory
|
# Optional: Change the working directory
|
||||||
workingDirectory: apps/www
|
workingDirectory: apps/www
|
||||||
wranglerVersion: '3'
|
wranglerVersion: '3'
|
||||||
|
|
||||||
|
- name: Remove label
|
||||||
|
if: ${{ github.event_name == 'pull_request_target' && contains(github.event.label.name, '🚀request-deploy') }}
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
github.rest.issues.removeLabel({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
name: ['🚀request-deploy']
|
||||||
|
})
|
||||||
|
|
|
||||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
|
@ -2,8 +2,8 @@
|
||||||
"prettier.enable": false,
|
"prettier.enable": false,
|
||||||
"editor.formatOnSave": false,
|
"editor.formatOnSave": false,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": true,
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.organizeImports": false
|
"source.organizeImports": "never"
|
||||||
},
|
},
|
||||||
|
|
||||||
"eslint.validate": [
|
"eslint.validate": [
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,17 @@ import { defineConfig } from 'vitepress'
|
||||||
import Icons from 'unplugin-icons/vite'
|
import Icons from 'unplugin-icons/vite'
|
||||||
import tailwind from 'tailwindcss'
|
import tailwind from 'tailwindcss'
|
||||||
import autoprefixer from 'autoprefixer'
|
import autoprefixer from 'autoprefixer'
|
||||||
|
import { createCssVariablesTheme } from 'shiki'
|
||||||
|
|
||||||
|
// import { transformerMetaWordHighlight, transformerNotationWordHighlight } from '@shikijs/transformers'
|
||||||
import { siteConfig } from './theme/config/site'
|
import { siteConfig } from './theme/config/site'
|
||||||
import ComponentPreviewPlugin from './theme/plugins/previewer'
|
import ComponentPreviewPlugin from './theme/plugins/previewer'
|
||||||
|
|
||||||
|
const cssVariables = createCssVariablesTheme({
|
||||||
|
variablePrefix: '--shiki-',
|
||||||
|
variableDefaults: {},
|
||||||
|
})
|
||||||
|
|
||||||
// https://vitepress.dev/reference/site-config
|
// https://vitepress.dev/reference/site-config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
title: siteConfig.name,
|
title: siteConfig.name,
|
||||||
|
|
@ -50,7 +58,11 @@ export default defineConfig({
|
||||||
|
|
||||||
srcDir: path.resolve(__dirname, '../src'),
|
srcDir: path.resolve(__dirname, '../src'),
|
||||||
markdown: {
|
markdown: {
|
||||||
theme: 'css-variables',
|
theme: cssVariables,
|
||||||
|
codeTransformers: [
|
||||||
|
// transformerMetaWordHighlight(),
|
||||||
|
// transformerNotationWordHighlight(),
|
||||||
|
],
|
||||||
config(md) {
|
config(md) {
|
||||||
md.use(ComponentPreviewPlugin)
|
md.use(ComponentPreviewPlugin)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ const { style } = useConfigStore()
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
:class="cn('preview flex min-h-[350px] w-full justify-center p-6 lg:p-10', {
|
:class="cn('preview flex min-h-[350px] w-full justify-center p-10 items-center', {
|
||||||
'items-center': align === 'center',
|
'items-center': align === 'center',
|
||||||
'items-start': align === 'start',
|
'items-start': align === 'start',
|
||||||
'items-end': align === 'end',
|
'items-end': align === 'end',
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const { copy, copied } = useClipboard()
|
||||||
|
|
||||||
const codeRef = ref<HTMLElement>()
|
const codeRef = ref<HTMLElement>()
|
||||||
async function copyCode() {
|
async function copyCode() {
|
||||||
await copy(codeRef.value?.innerText ?? '')
|
await copy(codeRef.value?.innerText.replace(/\u00A0/g, ' ') ?? '')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ const kbdClass = computed(() => {
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
xs: 'min-h-[16px] text-[10px] h-4 px-1',
|
xs: 'min-h-4 text-[10px] h-4 px-1',
|
||||||
sm: 'min-h-[20px] text-[11px] h-5 px-1',
|
sm: 'min-h-5 text-[11px] h-5 px-1',
|
||||||
md: 'min-h-[24px] text-[12px] h-6 px-1.5',
|
md: 'min-h-6 text-[12px] h-6 px-1.5',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import PageHeader from '../components/PageHeader.vue'
|
import PageHeader from '../components/PageHeader.vue'
|
||||||
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
||||||
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
||||||
|
import PageAction from '../components/PageAction.vue'
|
||||||
import ExamplesNav from '../components/ExamplesNav.vue'
|
import ExamplesNav from '../components/ExamplesNav.vue'
|
||||||
import { announcementConfig } from '../config/site'
|
import { announcementConfig } from '../config/site'
|
||||||
import GitHubIcon from '~icons/radix-icons/github-logo'
|
import GitHubIcon from '~icons/radix-icons/github-logo'
|
||||||
|
|
@ -31,7 +32,7 @@ import DashboardExample from '@/examples/dashboard/Example.vue'
|
||||||
apps. Accessible. Customizable. Open Source.
|
apps. Accessible. Customizable. Open Source.
|
||||||
</PageHeaderDescription>
|
</PageHeaderDescription>
|
||||||
|
|
||||||
<section class="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
|
<PageAction>
|
||||||
<a
|
<a
|
||||||
href="/docs/introduction"
|
href="/docs/introduction"
|
||||||
:class="cn(buttonVariants(), 'rounded-[6px]')"
|
:class="cn(buttonVariants(), 'rounded-[6px]')"
|
||||||
|
|
@ -49,7 +50,7 @@ import DashboardExample from '@/examples/dashboard/Example.vue'
|
||||||
<GitHubIcon class="mr-2 h-4 w-4" />
|
<GitHubIcon class="mr-2 h-4 w-4" />
|
||||||
GitHub
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</PageAction>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<ExamplesNav />
|
<ExamplesNav />
|
||||||
<section class="space-y-8 overflow-hidden rounded-lg border-2 border-primary dark:border-muted md:hidden">
|
<section class="space-y-8 overflow-hidden rounded-lg border-2 border-primary dark:border-muted md:hidden">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { cn } from '@/lib/utils'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a :class="cn('flex w-full flex-col items-center rounded-xl border bg-card p-6 text-card-foreground shadow transition-colors hover:bg-muted/50 sm:p-10', $attrs.class ?? '')">
|
<a :class="cn('flex w-full flex-col items-center rounded-lg border bg-card p-6 text-card-foreground shadow transition-colors hover:bg-muted/50 sm:p-10', $attrs.class ?? '')">
|
||||||
<slot />
|
<slot />
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
14
apps/www/.vitepress/theme/components/PageAction.vue
Normal file
14
apps/www/.vitepress/theme/components/PageAction.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section
|
||||||
|
:class="cn(
|
||||||
|
'flex w-full items-center justify-center space-x-4 py-4 md:pb-10',
|
||||||
|
$attrs.class ?? '',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
@ -7,7 +7,7 @@ import { cn } from '@/lib/utils'
|
||||||
<template>
|
<template>
|
||||||
<section
|
<section
|
||||||
:class="cn(
|
:class="cn(
|
||||||
'flex max-w-[980px] flex-col items-start gap-2 px-4 pt-8 md:pt-12',
|
'mx-auto flex max-w-[980px] flex-col items-center gap-2 py-8 md:py-12 md:pb-8 lg:py-24 lg:pb-20',
|
||||||
$attrs.class ?? '',
|
$attrs.class ?? '',
|
||||||
)"
|
)"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { cn } from '@/lib/utils'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<WrapBalancer :class="cn('max-w-[750px] text-lg text-muted-foreground sm:text-xl', $attrs.class ?? '')" :prefer-native="false">
|
<WrapBalancer :class="cn('max-w-[750px] text-center text-lg text-muted-foreground sm:text-xl', $attrs.class ?? '')" :prefer-native="false">
|
||||||
<slot />
|
<slot />
|
||||||
</WrapBalancer>
|
</WrapBalancer>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
|
||||||
<template>
|
<template>
|
||||||
<h1
|
<h1
|
||||||
:class="cn(
|
:class="cn(
|
||||||
'text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1]',
|
'text-center text-3xl font-bold leading-tight tracking-tighter md:text-6xl lg:leading-[1.1]',
|
||||||
$attrs.class ?? '',
|
$attrs.class ?? '',
|
||||||
)"
|
)"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
16
apps/www/.vitepress/theme/components/TabMarkdown.vue
Normal file
16
apps/www/.vitepress/theme/components/TabMarkdown.vue
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useSlots } from 'vue'
|
||||||
|
import { TabsContent, TabsTrigger } from '@/lib/registry/default/ui/tabs'
|
||||||
|
|
||||||
|
withDefaults(defineProps<{
|
||||||
|
title?: string
|
||||||
|
}>(), {
|
||||||
|
title: '',
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<TabsContent :value="title" class="relative space-y-10">
|
||||||
|
<slot />
|
||||||
|
</TabsContent>
|
||||||
|
</template>
|
||||||
22
apps/www/.vitepress/theme/components/TabsMarkdown.vue
Normal file
22
apps/www/.vitepress/theme/components/TabsMarkdown.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, useSlots } from 'vue'
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/lib/registry/default/ui/tabs'
|
||||||
|
|
||||||
|
const slots = useSlots()
|
||||||
|
|
||||||
|
const tabs = computed(() => slots.default?.()?.map(i => i?.props?.title as string) ?? [])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Tabs :default-value="tabs[0]" class="relative mr-auto w-full">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<TabsList class="w-full justify-start rounded-none border-b bg-transparent p-0">
|
||||||
|
<TabsTrigger v-for="tab in tabs" :key="tab" :value="tab" class="relative h-9 rounded-none border-b-2 border-b-transparent bg-transparent px-4 pb-3 pt-2 font-semibold text-muted-foreground shadow-none transition-none data-[state=active]:border-b-primary data-[state=active]:text-foreground data-[state=active]:shadow-none">
|
||||||
|
{{ tab }}
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot />
|
||||||
|
</Tabs>
|
||||||
|
</template>
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
export { default as ComponentPreview } from './ComponentPreview.vue'
|
export { default as ComponentPreview } from './ComponentPreview.vue'
|
||||||
export { default as TabPreview } from './TabPreview.vue'
|
export { default as TabPreview } from './TabPreview.vue'
|
||||||
|
export { default as TabMarkdown } from './TabMarkdown.vue'
|
||||||
|
export { default as TabsMarkdown } from './TabsMarkdown.vue'
|
||||||
export { default as Callout } from './Callout.vue'
|
export { default as Callout } from './Callout.vue'
|
||||||
export { default as LinkedCard } from './LinkedCard.vue'
|
export { default as LinkedCard } from './LinkedCard.vue'
|
||||||
export { default as ManualInstall } from './ManualInstall.vue'
|
export { default as ManualInstall } from './ManualInstall.vue'
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,12 @@ export const docsConfig: DocsConfig = {
|
||||||
title: 'Card',
|
title: 'Card',
|
||||||
href: '/docs/components/card',
|
href: '/docs/components/card',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Carousel',
|
||||||
|
href: '/docs/components/carousel',
|
||||||
|
label: 'New',
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Checkbox',
|
title: 'Checkbox',
|
||||||
href: '/docs/components/checkbox',
|
href: '/docs/components/checkbox',
|
||||||
|
|
@ -232,6 +238,12 @@ export const docsConfig: DocsConfig = {
|
||||||
title: 'Pagination',
|
title: 'Pagination',
|
||||||
href: '/docs/components/pagination',
|
href: '/docs/components/pagination',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Pin Input',
|
||||||
|
href: '/docs/components/pin-input',
|
||||||
|
label: 'New',
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Popover',
|
title: 'Popover',
|
||||||
href: '/docs/components/popover',
|
href: '/docs/components/popover',
|
||||||
|
|
@ -268,6 +280,12 @@ export const docsConfig: DocsConfig = {
|
||||||
title: 'Slider',
|
title: 'Slider',
|
||||||
href: '/docs/components/slider',
|
href: '/docs/components/slider',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Sonner',
|
||||||
|
href: '/docs/components/sonner',
|
||||||
|
label: 'New',
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Switch',
|
title: 'Switch',
|
||||||
href: '/docs/components/switch',
|
href: '/docs/components/switch',
|
||||||
|
|
@ -292,6 +310,10 @@ export const docsConfig: DocsConfig = {
|
||||||
title: 'Toggle',
|
title: 'Toggle',
|
||||||
href: '/docs/components/toggle',
|
href: '/docs/components/toggle',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Toggle Group',
|
||||||
|
href: '/docs/components/toggle-group',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Tooltip',
|
title: 'Tooltip',
|
||||||
href: '/docs/components/tooltip',
|
href: '/docs/components/tooltip',
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,6 @@ export const siteConfig = {
|
||||||
|
|
||||||
export const announcementConfig = {
|
export const announcementConfig = {
|
||||||
icon: '✨',
|
icon: '✨',
|
||||||
title: 'VSCode extension',
|
title: 'New components!',
|
||||||
link: '/docs/installation.html#vscode-extension',
|
link: '/docs/components/carousel.html',
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import EditLink from '../components/EditLink.vue'
|
||||||
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
|
import { ScrollArea } from '@/lib/registry/default/ui/scroll-area'
|
||||||
import { Badge } from '@/lib/registry/default/ui/badge'
|
import { Badge } from '@/lib/registry/default/ui/badge'
|
||||||
import RadixIconsCode from '~icons/radix-icons/code'
|
import RadixIconsCode from '~icons/radix-icons/code'
|
||||||
|
import RadixIconsExternalLink from '~icons/radix-icons/external-link'
|
||||||
import ChevronRightIcon from '~icons/lucide/chevron-right'
|
import ChevronRightIcon from '~icons/lucide/chevron-right'
|
||||||
|
|
||||||
const $route = useRoute()
|
const $route = useRoute()
|
||||||
|
|
@ -20,7 +21,7 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
|
||||||
<aside
|
<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"
|
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="h-full py-6 pl-8 pr-6 lg:py-8" :type="'auto'">
|
<ScrollArea orientation="vertical" class="relative overflow-hidden h-full py-6 pr-6 lg:py-8" :type="'auto'">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div v-for="docsGroup in docsConfig.sidebarNav" :key="docsGroup.title" class="pb-4">
|
<div v-for="docsGroup in docsConfig.sidebarNav" :key="docsGroup.title" class="pb-4">
|
||||||
<h4
|
<h4
|
||||||
|
|
@ -49,9 +50,9 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
|
||||||
>
|
>
|
||||||
{{ doc.title }}
|
{{ doc.title }}
|
||||||
|
|
||||||
<Badge v-if="doc.label" class="ml-2">
|
<span v-if="doc.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">
|
||||||
{{ doc.label }}
|
{{ doc.label }}
|
||||||
</Badge>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -90,6 +91,10 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center space-x-2 pt-4">
|
<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">
|
<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" />
|
<RadixIconsCode class="mr-1" />
|
||||||
Component Source
|
Component Source
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import PageHeader from '../components/PageHeader.vue'
|
import PageHeader from '../components/PageHeader.vue'
|
||||||
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
||||||
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
||||||
|
import PageAction from '../components/PageAction.vue'
|
||||||
import ExamplesNav from '../components/ExamplesNav.vue'
|
import ExamplesNav from '../components/ExamplesNav.vue'
|
||||||
import { announcementConfig } from '../config/site'
|
import { announcementConfig } from '../config/site'
|
||||||
import ArrowRightIcon from '~icons/radix-icons/arrow-right'
|
import ArrowRightIcon from '~icons/radix-icons/arrow-right'
|
||||||
|
|
@ -36,7 +37,7 @@ import { cn } from '@/lib/utils'
|
||||||
components. Use this as a guide to build your own.
|
components. Use this as a guide to build your own.
|
||||||
</PageHeaderDescription>
|
</PageHeaderDescription>
|
||||||
|
|
||||||
<section class="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
|
<PageAction>
|
||||||
<a
|
<a
|
||||||
href="/docs/introduction"
|
href="/docs/introduction"
|
||||||
:class="cn(buttonVariants(), 'rounded-[6px]')"
|
:class="cn(buttonVariants(), 'rounded-[6px]')"
|
||||||
|
|
@ -52,7 +53,7 @@ import { cn } from '@/lib/utils'
|
||||||
>
|
>
|
||||||
Components
|
Components
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</PageAction>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<section>
|
<section>
|
||||||
<ExamplesNav />
|
<ExamplesNav />
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import RadixIconsSun from '~icons/radix-icons/sun'
|
||||||
import { useConfigStore } from '@/stores/config'
|
import { useConfigStore } from '@/stores/config'
|
||||||
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog'
|
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog'
|
||||||
import { Toaster as DefaultToaster } from '@/lib/registry/default/ui/toast'
|
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 { Toaster as NewYorkToaster } from '@/lib/registry/new-york/ui/toast'
|
||||||
|
|
||||||
import File from '~icons/radix-icons/file'
|
import File from '~icons/radix-icons/file'
|
||||||
|
|
@ -50,7 +51,13 @@ const links = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const isOpen = ref(false)
|
const isOpen = ref(false)
|
||||||
const { Meta_K, Ctrl_K } = useMagicKeys()
|
const { Meta_K, Ctrl_K } = useMagicKeys({
|
||||||
|
passive: false,
|
||||||
|
onEventFired(e) {
|
||||||
|
if (e.key === 'k' && (e.metaKey || e.ctrlKey))
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
watch([Meta_K, Ctrl_K], (v) => {
|
watch([Meta_K, Ctrl_K], (v) => {
|
||||||
if (v[0] || v[1])
|
if (v[0] || v[1])
|
||||||
|
|
@ -81,7 +88,7 @@ watch(() => $route.path, (n) => {
|
||||||
<div class="flex min-h-screen flex-col bg-background">
|
<div 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">
|
<header class="sticky z-40 top-0 bg-background/80 backdrop-blur-lg border-b border-border">
|
||||||
<div
|
<div
|
||||||
class="container flex justify-between h-14 items-center"
|
class="container flex justify-between h-14 max-w-screen-2xl items-center"
|
||||||
>
|
>
|
||||||
<MobileNav />
|
<MobileNav />
|
||||||
|
|
||||||
|
|
@ -131,21 +138,22 @@ watch(() => $route.path, (n) => {
|
||||||
:variant="'ghost'"
|
:variant="'ghost'"
|
||||||
:size="'sm'"
|
:size="'sm'"
|
||||||
>
|
>
|
||||||
<component :is="link.icon" />
|
<component :is="link.icon" class="w-[20px] h-5" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<ClientOnly>
|
||||||
class="flex items-center justify-center"
|
<Button
|
||||||
aria-label="Toggle dark mode"
|
class="flex items-center justify-center"
|
||||||
:variant="'ghost'"
|
aria-label="Toggle dark mode"
|
||||||
:size="'sm'"
|
:variant="'ghost'"
|
||||||
@click="toggleDark()"
|
:size="'icon'" @click="toggleDark()"
|
||||||
>
|
>
|
||||||
<component
|
<component
|
||||||
:is="isDark ? RadixIconsSun : RadixIconsMoon"
|
:is="isDark ? RadixIconsSun : RadixIconsMoon"
|
||||||
class="text-foreground"
|
class="w-[20px] h-5 text-foreground"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
</ClientOnly>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -285,6 +293,9 @@ watch(() => $route.path, (n) => {
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<DefaultToaster />
|
<DefaultToaster />
|
||||||
|
<ClientOnly>
|
||||||
|
<NewYorkSonner :theme="isDark ? 'dark' : 'light'" />
|
||||||
|
</ClientOnly>
|
||||||
<NewYorkToaster />
|
<NewYorkToaster />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -5,57 +5,56 @@
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 240 10% 3.9%;
|
--foreground: 240 10% 3.9%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
--card-foreground: 240 10% 3.9%;
|
--card-foreground: 240 10% 3.9%;
|
||||||
--popover: 0 0% 100%;
|
--popover: 0 0% 100%;
|
||||||
--popover-foreground: 240 10% 3.9%;
|
--popover-foreground: 240 10% 3.9%;
|
||||||
--primary: 240 5.9% 10%;
|
--primary: 240 5.9% 10%;
|
||||||
--primary-foreground: 0 0% 98%;
|
--primary-foreground: 0 0% 98%;
|
||||||
--secondary: 240 4.8% 95.9%;
|
--secondary: 240 4.8% 95.9%;
|
||||||
--secondary-foreground: 240 5.9% 10%;
|
--secondary-foreground: 240 5.9% 10%;
|
||||||
--muted: 240 4.8% 95.9%;
|
--muted: 240 4.8% 95.9%;
|
||||||
--muted-foreground: 240 3.8% 46.1%;
|
--muted-foreground: 240 3.8% 46.1%;
|
||||||
--accent: 240 4.8% 95.9%;
|
--accent: 240 4.8% 95.9%;
|
||||||
--accent-foreground: 240 5.9% 10%;
|
--accent-foreground: 240 5.9% 10%;
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 72.22% 50.59%;
|
||||||
--destructive-foreground: 0 0% 98%;
|
--destructive-foreground: 0 0% 98%;
|
||||||
--border: 240 5.9% 90%;
|
--border: 240 5.9% 90%;
|
||||||
--input: 240 5.9% 90%;
|
--input: 240 5.9% 90%;
|
||||||
--ring: 240 5% 64.9%;
|
--ring: 240 5% 64.9%;
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
|
|
||||||
|
--vis-tooltip-background-color: none !important;
|
||||||
--vis-tooltip-background-color: none !important;
|
|
||||||
--vis-tooltip-border-color: none !important;
|
--vis-tooltip-border-color: none !important;
|
||||||
--vis-tooltip-text-color: none !important;
|
--vis-tooltip-text-color: none !important;
|
||||||
--vis-tooltip-shadow-color: none !important;
|
--vis-tooltip-shadow-color: none !important;
|
||||||
--vis-tooltip-backdrop-filter: none !important;
|
--vis-tooltip-backdrop-filter: none !important;
|
||||||
--vis-tooltip-padding: none !important;
|
--vis-tooltip-padding: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--background: 240 10% 3.9%;
|
--background: 240 10% 3.9%;
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 0 0% 98%;
|
||||||
--card: 240 10% 3.9%;
|
--card: 240 10% 3.9%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 0 0% 98%;
|
||||||
--popover: 240 10% 3.9%;
|
--popover: 240 10% 3.9%;
|
||||||
--popover-foreground: 0 0% 98%;
|
--popover-foreground: 0 0% 98%;
|
||||||
--primary: 0 0% 98%;
|
--primary: 0 0% 98%;
|
||||||
--primary-foreground: 240 5.9% 10%;
|
--primary-foreground: 240 5.9% 10%;
|
||||||
--secondary: 240 3.7% 15.9%;
|
--secondary: 240 3.7% 15.9%;
|
||||||
--secondary-foreground: 0 0% 98%;
|
--secondary-foreground: 0 0% 98%;
|
||||||
--muted: 240 3.7% 15.9%;
|
--muted: 240 3.7% 15.9%;
|
||||||
--muted-foreground: 240 5% 64.9%;
|
--muted-foreground: 240 5% 64.9%;
|
||||||
--accent: 240 3.7% 15.9%;
|
--accent: 240 3.7% 15.9%;
|
||||||
--accent-foreground: 0 0% 98%;
|
--accent-foreground: 0 0% 98%;
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 62.8% 30.6%;
|
||||||
--destructive-foreground: 0 85.7% 97.3%;
|
--destructive-foreground: 0 85.7% 97.3%;
|
||||||
--border: 240 3.7% 15.9%;
|
--border: 240 3.7% 15.9%;
|
||||||
--input: 240 3.7% 15.9%;
|
--input: 240 3.7% 15.9%;
|
||||||
--ring: 240 4.9% 83.9%;
|
--ring: 240 4.9% 83.9%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
|
@ -124,7 +123,7 @@
|
||||||
|
|
||||||
.step:before {
|
.step:before {
|
||||||
@apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background;
|
@apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background;
|
||||||
@apply ml-[-50px] mt-[-4px];
|
@apply -ml-[50px] -mt-1;
|
||||||
content: counter(step);
|
content: counter(step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +146,7 @@ pre code {
|
||||||
}
|
}
|
||||||
|
|
||||||
pre code .line {
|
pre code .line {
|
||||||
@apply px-4 min-h-[1.5rem] !py-0.5 w-full inline-block;
|
@apply px-4 min-h-6 !py-0.5 w-full inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line-number {
|
.line-number {
|
||||||
|
|
@ -157,4 +156,4 @@ pre code .line {
|
||||||
::view-transition-old(root),
|
::view-transition-old(root),
|
||||||
::view-transition-new(root) {
|
::view-transition-new(root) {
|
||||||
animation-duration: 0.3s;
|
animation-duration: 0.3s;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
:root {
|
:root {
|
||||||
--shiki-color-text: #EEEEEE;
|
--shiki-foreground: #FFF8;
|
||||||
--shiki-color-background: #ffffff;
|
--shiki-color-background: #ffffff;
|
||||||
--shiki-token-constant: #ffffff;
|
--shiki-token-constant: #ffffff;
|
||||||
--shiki-token-string: #ffffff88;
|
--shiki-token-string: #ffffff88;
|
||||||
|
|
@ -7,7 +7,14 @@
|
||||||
--shiki-token-keyword: #ffffff88;
|
--shiki-token-keyword: #ffffff88;
|
||||||
--shiki-token-parameter: #AA0000;
|
--shiki-token-parameter: #AA0000;
|
||||||
--shiki-token-function: #ffffff;
|
--shiki-token-function: #ffffff;
|
||||||
--shiki-token-string-expression: #ffffff88;
|
--shiki-token-string-expression: #ebebeb;
|
||||||
--shiki-token-punctuation: #ffffff;
|
--shiki-token-punctuation: #ffffff;
|
||||||
--shiki-token-link: #EE0000;
|
--shiki-token-link: #EE0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shiki .highlighted-word {
|
||||||
|
border-radius: calc(var(--radius) - 2px);
|
||||||
|
border-color: rgba(63,63,70,.7);
|
||||||
|
background-color: rgba(63,63,70,.5);
|
||||||
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E");
|
--vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E");
|
||||||
--vp-code-bg: hsl(var(--muted));
|
--vp-code-bg: hsl(var(--muted));
|
||||||
--vp-c-divider: hsl(var(--muted));
|
--vp-c-divider: hsl(var(--muted));
|
||||||
|
--vp-code-block-color: #fff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -414,7 +415,7 @@ hsl(var(--foreground) / 50%)
|
||||||
|
|
||||||
.vp-doc div[class*='language-'].line-numbers-mode {
|
.vp-doc div[class*='language-'].line-numbers-mode {
|
||||||
/*rtl:ignore*/
|
/*rtl:ignore*/
|
||||||
padding-left: 32px;
|
padding-left: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vp-doc .line-numbers-wrapper {
|
.vp-doc .line-numbers-wrapper {
|
||||||
|
|
@ -566,4 +567,12 @@ hsl(var(--foreground) / 50%)
|
||||||
|
|
||||||
.vp-external-link-icon::after {
|
.vp-external-link-icon::after {
|
||||||
content: '';
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.vp-doc [class*=language-] code {
|
||||||
|
color: var(--vp-code-block-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-numbers-mode pre code .line {
|
||||||
|
padding-left: 3rem !important;
|
||||||
}
|
}
|
||||||
|
|
@ -198,6 +198,48 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/CardWithForm.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/CardWithForm.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/CardWithForm.vue'],
|
files: ['../src/lib/registry/default/example/CardWithForm.vue'],
|
||||||
},
|
},
|
||||||
|
CarouselApi: {
|
||||||
|
name: 'CarouselApi',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/CarouselApi.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/CarouselApi.vue'],
|
||||||
|
},
|
||||||
|
CarouselDemo: {
|
||||||
|
name: 'CarouselDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/CarouselDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/CarouselDemo.vue'],
|
||||||
|
},
|
||||||
|
CarouselOrientation: {
|
||||||
|
name: 'CarouselOrientation',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/CarouselOrientation.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/CarouselOrientation.vue'],
|
||||||
|
},
|
||||||
|
CarouselPlugin: {
|
||||||
|
name: 'CarouselPlugin',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/CarouselPlugin.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/CarouselPlugin.vue'],
|
||||||
|
},
|
||||||
|
CarouselSize: {
|
||||||
|
name: 'CarouselSize',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/CarouselSize.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/CarouselSize.vue'],
|
||||||
|
},
|
||||||
|
CarouselSpacing: {
|
||||||
|
name: 'CarouselSpacing',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/CarouselSpacing.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/CarouselSpacing.vue'],
|
||||||
|
},
|
||||||
CheckboxDemo: {
|
CheckboxDemo: {
|
||||||
name: 'CheckboxDemo',
|
name: 'CheckboxDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -289,6 +331,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/ContextMenuDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/ContextMenuDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/ContextMenuDemo.vue'],
|
files: ['../src/lib/registry/default/example/ContextMenuDemo.vue'],
|
||||||
},
|
},
|
||||||
|
DataTableColumnPinningDemo: {
|
||||||
|
name: 'DataTableColumnPinningDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['button', 'checkbox', 'dropdown-menu', 'input', 'table', 'utils'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/DataTableColumnPinningDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/DataTableColumnPinningDemo.vue'],
|
||||||
|
},
|
||||||
DataTableDemo: {
|
DataTableDemo: {
|
||||||
name: 'DataTableDemo',
|
name: 'DataTableDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -331,6 +380,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/DatePickerWithRange.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/DatePickerWithRange.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/DatePickerWithRange.vue'],
|
files: ['../src/lib/registry/default/example/DatePickerWithRange.vue'],
|
||||||
},
|
},
|
||||||
|
DateTimePickerDemo: {
|
||||||
|
name: 'DateTimePickerDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['utils', 'button', 'calendar', 'popover'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/DateTimePickerDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/DateTimePickerDemo.vue'],
|
||||||
|
},
|
||||||
DialogCustomCloseButton: {
|
DialogCustomCloseButton: {
|
||||||
name: 'DialogCustomCloseButton',
|
name: 'DialogCustomCloseButton',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -457,6 +513,20 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/PaginationDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/PaginationDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/PaginationDemo.vue'],
|
files: ['../src/lib/registry/default/example/PaginationDemo.vue'],
|
||||||
},
|
},
|
||||||
|
PinInputDemo: {
|
||||||
|
name: 'PinInputDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['pin-input'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/PinInputDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/PinInputDemo.vue'],
|
||||||
|
},
|
||||||
|
PinInputFormDemo: {
|
||||||
|
name: 'PinInputFormDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['pin-input', 'button', 'form', 'toast'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/PinInputFormDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/PinInputFormDemo.vue'],
|
||||||
|
},
|
||||||
PopoverDemo: {
|
PopoverDemo: {
|
||||||
name: 'PopoverDemo',
|
name: 'PopoverDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -485,6 +555,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/RadioGroupForm.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/RadioGroupForm.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/RadioGroupForm.vue'],
|
files: ['../src/lib/registry/default/example/RadioGroupForm.vue'],
|
||||||
},
|
},
|
||||||
|
RangePickerWithSlot: {
|
||||||
|
name: 'RangePickerWithSlot',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['utils', 'button', 'calendar', 'popover'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/RangePickerWithSlot.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/RangePickerWithSlot.vue'],
|
||||||
|
},
|
||||||
ScrollAreaDemo: {
|
ScrollAreaDemo: {
|
||||||
name: 'ScrollAreaDemo',
|
name: 'ScrollAreaDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -548,6 +625,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/SliderDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/SliderDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/SliderDemo.vue'],
|
files: ['../src/lib/registry/default/example/SliderDemo.vue'],
|
||||||
},
|
},
|
||||||
|
SonnerDemo: {
|
||||||
|
name: 'SonnerDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['button'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/SonnerDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/SonnerDemo.vue'],
|
||||||
|
},
|
||||||
SwitchDemo: {
|
SwitchDemo: {
|
||||||
name: 'SwitchDemo',
|
name: 'SwitchDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -667,6 +751,48 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/default/example/ToggleDisabledDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/default/example/ToggleDisabledDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/default/example/ToggleDisabledDemo.vue'],
|
files: ['../src/lib/registry/default/example/ToggleDisabledDemo.vue'],
|
||||||
},
|
},
|
||||||
|
ToggleGroupDemo: {
|
||||||
|
name: 'ToggleGroupDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/ToggleGroupDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/ToggleGroupDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupDisabledDemo: {
|
||||||
|
name: 'ToggleGroupDisabledDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/ToggleGroupDisabledDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/ToggleGroupDisabledDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupLargeDemo: {
|
||||||
|
name: 'ToggleGroupLargeDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/ToggleGroupLargeDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/ToggleGroupLargeDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupOutlineDemo: {
|
||||||
|
name: 'ToggleGroupOutlineDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/ToggleGroupOutlineDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/ToggleGroupOutlineDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupSingleDemo: {
|
||||||
|
name: 'ToggleGroupSingleDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/ToggleGroupSingleDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/ToggleGroupSingleDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupSmallDemo: {
|
||||||
|
name: 'ToggleGroupSmallDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/default/example/ToggleGroupSmallDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/default/example/ToggleGroupSmallDemo.vue'],
|
||||||
|
},
|
||||||
ToggleItalicDemo: {
|
ToggleItalicDemo: {
|
||||||
name: 'ToggleItalicDemo',
|
name: 'ToggleItalicDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1019,6 +1145,48 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/CardWithForm.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/CardWithForm.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/CardWithForm.vue'],
|
files: ['../src/lib/registry/new-york/example/CardWithForm.vue'],
|
||||||
},
|
},
|
||||||
|
CarouselApi: {
|
||||||
|
name: 'CarouselApi',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/CarouselApi.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/CarouselApi.vue'],
|
||||||
|
},
|
||||||
|
CarouselDemo: {
|
||||||
|
name: 'CarouselDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/CarouselDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/CarouselDemo.vue'],
|
||||||
|
},
|
||||||
|
CarouselOrientation: {
|
||||||
|
name: 'CarouselOrientation',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/CarouselOrientation.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/CarouselOrientation.vue'],
|
||||||
|
},
|
||||||
|
CarouselPlugin: {
|
||||||
|
name: 'CarouselPlugin',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/CarouselPlugin.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/CarouselPlugin.vue'],
|
||||||
|
},
|
||||||
|
CarouselSize: {
|
||||||
|
name: 'CarouselSize',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/CarouselSize.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/CarouselSize.vue'],
|
||||||
|
},
|
||||||
|
CarouselSpacing: {
|
||||||
|
name: 'CarouselSpacing',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['carousel', 'card'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/CarouselSpacing.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/CarouselSpacing.vue'],
|
||||||
|
},
|
||||||
CheckboxDemo: {
|
CheckboxDemo: {
|
||||||
name: 'CheckboxDemo',
|
name: 'CheckboxDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1110,6 +1278,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/ContextMenuDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/ContextMenuDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/ContextMenuDemo.vue'],
|
files: ['../src/lib/registry/new-york/example/ContextMenuDemo.vue'],
|
||||||
},
|
},
|
||||||
|
DataTableColumnPinningDemo: {
|
||||||
|
name: 'DataTableColumnPinningDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['button', 'checkbox', 'dropdown-menu', 'input', 'table', 'utils'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/DataTableColumnPinningDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/DataTableColumnPinningDemo.vue'],
|
||||||
|
},
|
||||||
DataTableDemo: {
|
DataTableDemo: {
|
||||||
name: 'DataTableDemo',
|
name: 'DataTableDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1152,6 +1327,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/DatePickerWithRange.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/DatePickerWithRange.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/DatePickerWithRange.vue'],
|
files: ['../src/lib/registry/new-york/example/DatePickerWithRange.vue'],
|
||||||
},
|
},
|
||||||
|
DateTimePickerDemo: {
|
||||||
|
name: 'DateTimePickerDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['utils', 'button', 'calendar', 'popover'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/DateTimePickerDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/DateTimePickerDemo.vue'],
|
||||||
|
},
|
||||||
DialogCustomCloseButton: {
|
DialogCustomCloseButton: {
|
||||||
name: 'DialogCustomCloseButton',
|
name: 'DialogCustomCloseButton',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1278,6 +1460,20 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/PaginationDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/PaginationDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/PaginationDemo.vue'],
|
files: ['../src/lib/registry/new-york/example/PaginationDemo.vue'],
|
||||||
},
|
},
|
||||||
|
PinInputDemo: {
|
||||||
|
name: 'PinInputDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['pin-input'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/PinInputDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/PinInputDemo.vue'],
|
||||||
|
},
|
||||||
|
PinInputFormDemo: {
|
||||||
|
name: 'PinInputFormDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['pin-input', 'button', 'form', 'toast'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/PinInputFormDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/PinInputFormDemo.vue'],
|
||||||
|
},
|
||||||
PopoverDemo: {
|
PopoverDemo: {
|
||||||
name: 'PopoverDemo',
|
name: 'PopoverDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1306,6 +1502,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/RadioGroupForm.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/RadioGroupForm.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/RadioGroupForm.vue'],
|
files: ['../src/lib/registry/new-york/example/RadioGroupForm.vue'],
|
||||||
},
|
},
|
||||||
|
RangePickerWithSlot: {
|
||||||
|
name: 'RangePickerWithSlot',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['utils', 'button', 'calendar', 'popover'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/RangePickerWithSlot.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/RangePickerWithSlot.vue'],
|
||||||
|
},
|
||||||
ScrollAreaDemo: {
|
ScrollAreaDemo: {
|
||||||
name: 'ScrollAreaDemo',
|
name: 'ScrollAreaDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1369,6 +1572,13 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/SliderDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/SliderDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/SliderDemo.vue'],
|
files: ['../src/lib/registry/new-york/example/SliderDemo.vue'],
|
||||||
},
|
},
|
||||||
|
SonnerDemo: {
|
||||||
|
name: 'SonnerDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['button'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/SonnerDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/SonnerDemo.vue'],
|
||||||
|
},
|
||||||
SwitchDemo: {
|
SwitchDemo: {
|
||||||
name: 'SwitchDemo',
|
name: 'SwitchDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
@ -1488,6 +1698,48 @@ export const Index = {
|
||||||
component: () => import('../src/lib/registry/new-york/example/ToggleDisabledDemo.vue').then(m => m.default),
|
component: () => import('../src/lib/registry/new-york/example/ToggleDisabledDemo.vue').then(m => m.default),
|
||||||
files: ['../src/lib/registry/new-york/example/ToggleDisabledDemo.vue'],
|
files: ['../src/lib/registry/new-york/example/ToggleDisabledDemo.vue'],
|
||||||
},
|
},
|
||||||
|
ToggleGroupDemo: {
|
||||||
|
name: 'ToggleGroupDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/ToggleGroupDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/ToggleGroupDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupDisabledDemo: {
|
||||||
|
name: 'ToggleGroupDisabledDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/ToggleGroupDisabledDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/ToggleGroupDisabledDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupLargeDemo: {
|
||||||
|
name: 'ToggleGroupLargeDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/ToggleGroupLargeDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/ToggleGroupLargeDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupOutlineDemo: {
|
||||||
|
name: 'ToggleGroupOutlineDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/ToggleGroupOutlineDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/ToggleGroupOutlineDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupSingleDemo: {
|
||||||
|
name: 'ToggleGroupSingleDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/ToggleGroupSingleDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/ToggleGroupSingleDemo.vue'],
|
||||||
|
},
|
||||||
|
ToggleGroupSmallDemo: {
|
||||||
|
name: 'ToggleGroupSmallDemo',
|
||||||
|
type: 'components:example',
|
||||||
|
registryDependencies: ['toggle-group'],
|
||||||
|
component: () => import('../src/lib/registry/new-york/example/ToggleGroupSmallDemo.vue').then(m => m.default),
|
||||||
|
files: ['../src/lib/registry/new-york/example/ToggleGroupSmallDemo.vue'],
|
||||||
|
},
|
||||||
ToggleItalicDemo: {
|
ToggleItalicDemo: {
|
||||||
name: 'ToggleItalicDemo',
|
name: 'ToggleItalicDemo',
|
||||||
type: 'components:example',
|
type: 'components:example',
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "www",
|
"name": "www",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.8.4",
|
"version": "0.9.0",
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
|
|
@ -9,30 +9,35 @@
|
||||||
"dev": "vitepress dev",
|
"dev": "vitepress dev",
|
||||||
"build": "vitepress build",
|
"build": "vitepress build",
|
||||||
"preview": "vitepress preview",
|
"preview": "vitepress preview",
|
||||||
"typecheck": "vue-tsc --noEmit",
|
"typecheck": "vue-tsc",
|
||||||
"typecheck:registry": "vue-tsc --noEmit -p tsconfig.registry.json",
|
"typecheck:registry": "vue-tsc -p tsconfig.registry.json",
|
||||||
"build:registry": "pnpm typecheck:registry && tsx ./scripts/build-registry.ts"
|
"build:registry": "tsx ./scripts/build-registry.ts",
|
||||||
|
"build:registry-strict": "pnpm typecheck:registry && tsx ./scripts/build-registry.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.8.0",
|
"@formkit/auto-animate": "^0.8.1",
|
||||||
"@morev/vue-transitions": "^2.3.6",
|
"@morev/vue-transitions": "^2.3.6",
|
||||||
"@radix-icons/vue": "^1.0.0",
|
"@radix-icons/vue": "^1.0.0",
|
||||||
"@stackblitz/sdk": "^1.9.0",
|
"@stackblitz/sdk": "^1.9.0",
|
||||||
"@tanstack/vue-table": "^8.10.7",
|
"@tanstack/vue-table": "^8.11.8",
|
||||||
"@unovis/ts": "^1.2.1",
|
"@unovis/ts": "^1.3.3",
|
||||||
"@unovis/vue": "1.3.0",
|
"@unovis/vue": "^1.3.3",
|
||||||
"@vee-validate/zod": "^4.11.8",
|
"@vee-validate/zod": "^4.12.5",
|
||||||
"@vueuse/core": "^10.5.0",
|
"@vueuse/core": "^10.7.2",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.1.0",
|
||||||
"codesandbox": "^2.2.3",
|
"codesandbox": "^2.2.3",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
|
"embla-carousel": "^8.0.0-rc22",
|
||||||
|
"embla-carousel-autoplay": "^8.0.0-rc22",
|
||||||
|
"embla-carousel-vue": "^8.0.0-rc22",
|
||||||
"lucide-vue-next": "^0.276.0",
|
"lucide-vue-next": "^0.276.0",
|
||||||
"radix-vue": "^1.2.3",
|
"radix-vue": "^1.4.1",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"v-calendar": "^3.1.2",
|
"v-calendar": "^3.1.2",
|
||||||
"vee-validate": "4.11.8",
|
"vee-validate": "4.12.5",
|
||||||
"vue": "^3.3.7",
|
"vue": "^3.4.15",
|
||||||
|
"vue-sonner": "^1.0.3",
|
||||||
"vue-wrap-balancer": "^1.1.3",
|
"vue-wrap-balancer": "^1.1.3",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
},
|
},
|
||||||
|
|
@ -41,24 +46,27 @@
|
||||||
"@iconify-json/tabler": "^1.1.89",
|
"@iconify-json/tabler": "^1.1.89",
|
||||||
"@iconify/json": "^2.2.108",
|
"@iconify/json": "^2.2.108",
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
|
"@shikijs/transformers": "^1.0.0-beta.3",
|
||||||
"@types/lodash.template": "^4.5.2",
|
"@types/lodash.template": "^4.5.2",
|
||||||
"@types/node": "^20.8.10",
|
"@types/node": "^20.8.10",
|
||||||
"@vitejs/plugin-vue": "^4.4.0",
|
"@vitejs/plugin-vue": "^5.0.3",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.0.2",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"@vue/compiler-core": "^3.3.7",
|
"@vue/compiler-core": "^3.4.15",
|
||||||
"@vue/compiler-dom": "^3.3.7",
|
"@vue/compiler-dom": "^3.4.15",
|
||||||
"@vue/tsconfig": "^0.4.0",
|
"@vue/tsconfig": "^0.5.1",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.17",
|
||||||
"lodash.template": "^4.5.0",
|
"lodash.template": "^4.5.0",
|
||||||
"pathe": "^1.1.1",
|
"oxc-parser": "^0.2.0",
|
||||||
|
"pathe": "^1.1.2",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"tailwind-merge": "^2.0.0",
|
"shiki": "^1.0.0-beta.3",
|
||||||
"tailwindcss": "^3.3.5",
|
"tailwind-merge": "^2.2.1",
|
||||||
"tsx": "^3.14.0",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5.2.2",
|
"tsx": "^4.7.0",
|
||||||
"unplugin-icons": "^0.17.1",
|
"typescript": "^5.3.3",
|
||||||
"vite": "^4.5.0",
|
"unplugin-icons": "^0.18.3",
|
||||||
"vitepress": "^1.0.0-rc.24",
|
"vite": "^5.0.12",
|
||||||
"vue-tsc": "^1.8.22"
|
"vitepress": "^1.0.0-rc.41",
|
||||||
|
"vue-tsc": "^1.8.27"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ fs.writeFileSync(path.join(process.cwd(), '__registry__/index.ts'), index)
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Build registry/styles/[style]/[name].json.
|
// Build registry/styles/[style]/[name].json.
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
const newLine = '\n'
|
||||||
|
|
||||||
for (const style of styles) {
|
for (const style of styles) {
|
||||||
const targetPath = path.join(REGISTRY_PATH, 'styles', style.name)
|
const targetPath = path.join(REGISTRY_PATH, 'styles', style.name)
|
||||||
|
|
||||||
|
|
@ -78,11 +80,14 @@ for (const style of styles) {
|
||||||
continue
|
continue
|
||||||
|
|
||||||
const files = item.files?.map((file) => {
|
const files = item.files?.map((file) => {
|
||||||
const content = fs.readFileSync(
|
let content = fs.readFileSync(
|
||||||
path.join(process.cwd(), 'src/lib/registry', style.name, file),
|
path.join(process.cwd(), 'src/lib/registry', style.name, file),
|
||||||
'utf8',
|
'utf8',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Replace Windows-style newlines with Unix-style newlines
|
||||||
|
content = content.replace(/\r\n/g, newLine)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: basename(file),
|
name: basename(file),
|
||||||
content,
|
content,
|
||||||
|
|
@ -94,9 +99,11 @@ for (const style of styles) {
|
||||||
files,
|
files,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const payloadStr = JSON.stringify(payload, null, 2).replace(/\r\n/g, newLine)
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(targetPath, `${item.name}.json`),
|
path.join(targetPath, `${item.name}.json`),
|
||||||
JSON.stringify(payload, null, 2),
|
payloadStr,
|
||||||
'utf8',
|
'utf8',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ description: Powered by amazing open source projects.
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
[shadcn-vue](https://shadcn-vuee.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 [radix-vue](https://github.com/radix-vue).
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
|
@ -17,4 +17,4 @@ description: Powered by amazing open source projects.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT © [shadcn](https://shadcn.com) & [radix-vue](https://github.com/radix-vue)
|
MIT © [shadcn](https://shadcn.com) & [radix-vue](https://github.com/radix-vue)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
title: Calendar
|
title: Calendar
|
||||||
description: A date field component that allows users to enter and edit date.
|
description: A date field component that allows users to enter and edit date.
|
||||||
|
source: apps/www/src/lib/registry/default/ui/calendar
|
||||||
|
primitive: https://vcalendar.io/
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -54,5 +56,40 @@ import { Calendar } from '@/components/ui/calendar'
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [VCalendar](https://vcalendar.io/getting-started/installation.html) documentation for more information.
|
The API is essentially the same, i.e. props and slots. See the [VCalendar](https://vcalendar.io/getting-started/installation.html) documentation for more information.
|
||||||
|
|
||||||
|
### Slots
|
||||||
|
|
||||||
|
The slots available are [those currently supported](https://github.com/nathanreyes/v-calendar/blob/v3.1.2/src/components/Calendar/CalendarSlot.vue#L16-L28) by VCalendar, namely :
|
||||||
|
|
||||||
|
- `day-content`
|
||||||
|
- `day-popover`
|
||||||
|
- `dp-footer`
|
||||||
|
- `footer`
|
||||||
|
- `header-title-wrapper`
|
||||||
|
- `header-title`
|
||||||
|
- `header-prev-button`
|
||||||
|
- `header-next-button`
|
||||||
|
- `nav`
|
||||||
|
- `nav-prev-button`
|
||||||
|
- `nav-next-button`
|
||||||
|
- `page`
|
||||||
|
- `time-header`
|
||||||
|
|
||||||
|
Example using the `day-content` slot:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Calendar } from '@/components/ui/calendar'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Calendar>
|
||||||
|
<template #day-content="{ day, dayProps, dayEvents }">
|
||||||
|
<div v-bind="dayProps" v-on="dayEvents">
|
||||||
|
{{ day.label }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Calendar>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
282
apps/www/src/content/docs/components/carousel.md
Normal file
282
apps/www/src/content/docs/components/carousel.md
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
---
|
||||||
|
title: Carousel
|
||||||
|
description: A carousel with motion and swipe built using Embla.
|
||||||
|
source: apps/www/src/lib/registry/default/ui/carousel
|
||||||
|
primitive: https://www.embla-carousel.com/api
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
<ComponentPreview name="CarouselDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
The carousel component is built using the [Embla Carousel](https://www.embla-carousel.com/) library.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx shadcn-vue@latest add carousel
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
Carousel,
|
||||||
|
CarouselContent,
|
||||||
|
CarouselItem,
|
||||||
|
CarouselNext,
|
||||||
|
CarouselPrevious,
|
||||||
|
} from '@/components/ui/carousel'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel>
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem>...</CarouselItem>
|
||||||
|
<CarouselItem>...</CarouselItem>
|
||||||
|
<CarouselItem>...</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Sizes
|
||||||
|
|
||||||
|
To set the size of the items, you can use the `basis` utility class on the `<CarouselItem />`.
|
||||||
|
|
||||||
|
<ComponentPreview name="CarouselSize" />
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
```vue:line-numbers title="Example" {4-6}
|
||||||
|
// 33% of the carousel width.
|
||||||
|
<Carousel>
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem class="basis-1/3">...</CarouselItem>
|
||||||
|
<CarouselItem class="basis-1/3">...</CarouselItem>
|
||||||
|
<CarouselItem class="basis-1/3">...</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
</Carousel>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Responsive
|
||||||
|
|
||||||
|
```vue:line-numbers title="Responsive" {4-6}
|
||||||
|
// 50% on small screens and 33% on larger screens.
|
||||||
|
<Carousel>
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem class="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
|
||||||
|
<CarouselItem class="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
|
||||||
|
<CarouselItem class="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
</Carousel>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spacing
|
||||||
|
|
||||||
|
To set the spacing between the items, we use a `pl-[VALUE]` utility on the `<CarouselItem />` and a negative `-ml-[VALUE]` on the `<CarouselContent />`.
|
||||||
|
|
||||||
|
<Callout class="mt-6">
|
||||||
|
|
||||||
|
**Why:** I tried to use the `gap` property or a `grid` layout on the `
|
||||||
|
CarouselContent` but it required a lot of math and mental effort to get the
|
||||||
|
spacing right. I found `pl-[VALUE]` and `-ml-[VALUE]` utilities much easier to
|
||||||
|
use.
|
||||||
|
<br/><br/>
|
||||||
|
You can always adjust this in your own project if you need to.
|
||||||
|
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
<ComponentPreview name="CarouselSpacing" />
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
```vue:line-numbers /-ml-4/ /pl-4/
|
||||||
|
<template>
|
||||||
|
<Carousel>
|
||||||
|
<CarouselContent class="-ml-4">
|
||||||
|
<CarouselItem class="pl-4">
|
||||||
|
...
|
||||||
|
</CarouselItem>
|
||||||
|
<CarouselItem class="pl-4">
|
||||||
|
...
|
||||||
|
</CarouselItem>
|
||||||
|
<CarouselItem class="pl-4">
|
||||||
|
...
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
Responsive
|
||||||
|
|
||||||
|
```vue:line-numbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
|
||||||
|
<template>
|
||||||
|
<Carousel>
|
||||||
|
<CarouselContent class="-ml-2 md:-ml-4">
|
||||||
|
<CarouselItem class="pl-2 md:pl-4">
|
||||||
|
...
|
||||||
|
</CarouselItem>
|
||||||
|
<CarouselItem class="pl-2 md:pl-4">
|
||||||
|
...
|
||||||
|
</CarouselItem>
|
||||||
|
<CarouselItem class="pl-2 md:pl-4">
|
||||||
|
...
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Orientation
|
||||||
|
|
||||||
|
Use the `orientation` prop to set the orientation of the carousel.
|
||||||
|
|
||||||
|
<ComponentPreview name="CarouselOrientation" />
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<Carousel orientation="vertical | horizontal">
|
||||||
|
...
|
||||||
|
</Carousel>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
You can pass options to the carousel using the `opts` prop. See the [Embla Carousel docs](https://www.embla-carousel.com/api/options/) for more information.
|
||||||
|
|
||||||
|
```vue:line-numbers {3-6}
|
||||||
|
<template>
|
||||||
|
<Carousel
|
||||||
|
:opts="{
|
||||||
|
align: 'start',
|
||||||
|
loop: true,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem>...</CarouselItem>
|
||||||
|
<CarouselItem>...</CarouselItem>
|
||||||
|
<CarouselItem>...</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Method 1
|
||||||
|
|
||||||
|
Use the `@init-api` emit method on `<Carousel />` component to set the instance of the API.
|
||||||
|
|
||||||
|
<ComponentPreview name="CarouselApi" />
|
||||||
|
|
||||||
|
### Method 2
|
||||||
|
|
||||||
|
You can access it through setting a template ref on the `<Carousel />` component.
|
||||||
|
|
||||||
|
```vue:line-numbers {2,5,9}
|
||||||
|
<script setup>
|
||||||
|
const carouselContainerRef = ref<InstanceType<typeof Carousel> | null>(null)
|
||||||
|
|
||||||
|
function accessApi() {
|
||||||
|
carouselContainerRef.value?.carouselApi.on('select', () => {})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel ref="carouselContainerRef">
|
||||||
|
...
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
You can listen to events using the API. To get the API instance use the `@init-api` emit method on the `<Carousel />` component
|
||||||
|
|
||||||
|
```vue:line-numbers {5,7-9,25}
|
||||||
|
<script setup>
|
||||||
|
import { nextTick, ref, watch } from 'vue'
|
||||||
|
import { useCarousel } from '@/components/ui/carousel'
|
||||||
|
|
||||||
|
const api = ref<CarouselApi>()
|
||||||
|
|
||||||
|
function setApi(val: CarouselApi) {
|
||||||
|
api.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
const stop = watch(api, (api) => {
|
||||||
|
if (!api)
|
||||||
|
return
|
||||||
|
|
||||||
|
// Watch only once or use watchOnce() in @vueuse/core
|
||||||
|
nextTick(() => stop())
|
||||||
|
|
||||||
|
api.on('select', () => {
|
||||||
|
// Do something on select.
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel @init-api="setApi">
|
||||||
|
...
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [Embla Carousel docs](https://www.embla-carousel.com/api/events/) for more information on using events.
|
||||||
|
|
||||||
|
## Slot Props
|
||||||
|
|
||||||
|
You can get the reactive slot props like `carouselRef, canScrollNext..Prev, scrollNext..Prev` using the `v-slot` directive in the `<Carousel v-slot="slotProps" />` component to extend the functionality.
|
||||||
|
|
||||||
|
```vue:line-numbers {2}
|
||||||
|
<template>
|
||||||
|
<Carousel v-slot="{ canScrollNext, canScrollPrev }">
|
||||||
|
...
|
||||||
|
<CarouselPrevious v-if="canScrollPrev" />
|
||||||
|
<CarouselNext v-if="canScrollNext" />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
You can use the `plugins` prop to add plugins to the carousel.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i embla-carousel-autoplay
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```vue:line-numbers {2,8-10}
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Autoplay from 'embla-carousel-autoplay'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel
|
||||||
|
class="w-full max-w-xs"
|
||||||
|
:plugins="[Autoplay({
|
||||||
|
delay: 2000,
|
||||||
|
})]"
|
||||||
|
>
|
||||||
|
...
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
<ComponentPreview name="CarouselPlugin" />
|
||||||
|
|
||||||
|
See the [Embla Carousel docs](https://www.embla-carousel.com/api/plugins/) for more information on using plugins.
|
||||||
|
|
@ -40,6 +40,8 @@ import { Checkbox } from '@/components/ui/checkbox'
|
||||||
|
|
||||||
### Form
|
### Form
|
||||||
|
|
||||||
|
Please first read `vee-validate` section for [Checkbox and Radio Inputs](https://vee-validate.logaretm.com/v4/examples/checkboxes-and-radio/)
|
||||||
|
|
||||||
<ComponentPreview name="CheckboxFormSingle" />
|
<ComponentPreview name="CheckboxFormSingle" />
|
||||||
|
|
||||||
<ComponentPreview name="CheckboxFormMultiple" />
|
<ComponentPreview name="CheckboxFormMultiple" />
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Combobox
|
title: Combobox
|
||||||
description: Autocomplete input and command palette with a list of suggestions.
|
description: Autocomplete input and command palette with a list of suggestions.
|
||||||
component: true
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<ComponentPreview name="ComboboxDemo" />
|
<ComponentPreview name="ComboboxDemo" />
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
---
|
---
|
||||||
title: Data Table
|
title: Data Table
|
||||||
description: Powerful table and datagrids built using TanStack Table.
|
description: Powerful table and datagrids built using TanStack Table.
|
||||||
|
primitive: https://tanstack.com/table/v8/docs/guide/introduction
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
<ComponentPreview name="DataTableDemo" />
|
<ComponentPreview name="DataTableDemo" />
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
|
@ -22,9 +23,9 @@ We'll start with the basic `<Table />` component and build a complex data table
|
||||||
|
|
||||||
</Callout>
|
</Callout>
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
This guide will show you how to use [TanStack Table](https://tanstack.com/table/v8) and the <Table /> component to build your own custom data table. We'll cover the following topics:
|
This guide will show you how to use [TanStack Table](https://tanstack.com/table/v8) and the `<Table />` component to build your own custom data table. We'll cover the following topics:
|
||||||
|
|
||||||
- [Basic Table](#basic-table)
|
- [Basic Table](#basic-table)
|
||||||
- [Row Actions](#row-actions)
|
- [Row Actions](#row-actions)
|
||||||
|
|
@ -49,6 +50,13 @@ npx shadcn-vue@latest add table
|
||||||
npm install @tanstack/vue-table
|
npm install @tanstack/vue-table
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Column Pinning
|
||||||
|
|
||||||
|
<ComponentPreview name="DataTableColumnPinningDemo" />
|
||||||
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
We are going to build a table to show recent payments. Here's what our data looks like:
|
We are going to build a table to show recent payments. Here's what our data looks like:
|
||||||
|
|
@ -108,31 +116,23 @@ Let's start by building a basic table.
|
||||||
|
|
||||||
First, we'll define our columns in the `columns.ts` file.
|
First, we'll define our columns in the `columns.ts` file.
|
||||||
|
|
||||||
```ts:line-numbers title="components/payments/columns.ts" {1,12-27}
|
```ts:line-numbers {1,12-27}
|
||||||
import type { ColumnDef } from '@tanstack/vue-table'
|
import { h } from 'vue'
|
||||||
|
|
||||||
// This type is used to define the shape of our data.
|
|
||||||
// You can use a Zod schema here if you want.
|
|
||||||
export interface Payment {
|
|
||||||
id: string
|
|
||||||
amount: number
|
|
||||||
status: 'pending' | 'processing' | 'success' | 'failed'
|
|
||||||
email: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const columns: ColumnDef<Payment>[] = [
|
export const columns: ColumnDef<Payment>[] = [
|
||||||
{
|
|
||||||
accessorKey: 'status',
|
|
||||||
header: 'Status',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
accessorKey: 'email',
|
|
||||||
header: 'Email',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessorKey: 'amount',
|
accessorKey: 'amount',
|
||||||
header: 'Amount',
|
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
||||||
},
|
cell: ({ row }) => {
|
||||||
|
const amount = Number.parseFloat(row.getValue('amount'))
|
||||||
|
const formatted = new Intl.NumberFormat('en-US', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'USD',
|
||||||
|
}).format(amount)
|
||||||
|
|
||||||
|
return h('div', { class: 'text-right font-medium' }, formatted)
|
||||||
|
},
|
||||||
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -148,7 +148,7 @@ formatted, sorted and filtered.
|
||||||
|
|
||||||
Next, we'll create a `<DataTable />` component to render our table.
|
Next, we'll create a `<DataTable />` component to render our table.
|
||||||
|
|
||||||
```ts:line-numbers
|
```vue:line-numbers
|
||||||
<script setup lang="ts" generic="TData, TValue">
|
<script setup lang="ts" generic="TData, TValue">
|
||||||
import type { ColumnDef } from '@tanstack/vue-table'
|
import type { ColumnDef } from '@tanstack/vue-table'
|
||||||
import {
|
import {
|
||||||
|
|
@ -172,8 +172,8 @@ const props = defineProps<{
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -224,7 +224,7 @@ const table = useVueTable({
|
||||||
|
|
||||||
Finally, we'll render our table in our index component.
|
Finally, we'll render our table in our index component.
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{28}
|
```vue:line-numbers {28}
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { columns } from "./components/columns"
|
import { columns } from "./components/columns"
|
||||||
|
|
@ -271,7 +271,7 @@ Let's format the amount cell to display the dollar amount. We'll also align the
|
||||||
Update the `header` and `cell` definitions for amount as follows:
|
Update the `header` and `cell` definitions for amount as follows:
|
||||||
|
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers title="components/payments/columns.ts" {5-17}
|
```ts:line-numbers title="components/payments/columns.ts" {5-17}
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
|
|
||||||
export const columns: ColumnDef<Payment>[] = [
|
export const columns: ColumnDef<Payment>[] = [
|
||||||
|
|
@ -301,7 +301,7 @@ Let's add row actions to our table. We'll use a `<Dropdown />` component for thi
|
||||||
|
|
||||||
### Add the following into your `DataTableDropDown.vue` component:
|
### Add the following into your `DataTableDropDown.vue` component:
|
||||||
|
|
||||||
```ts:line-numbers
|
```vue:line-numbers
|
||||||
// DataTableDropDown.vue
|
// DataTableDropDown.vue
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { MoreHorizontal } from 'lucide-vue-next'
|
import { MoreHorizontal } from 'lucide-vue-next'
|
||||||
|
|
@ -379,7 +379,7 @@ Next, we'll add pagination to our table.
|
||||||
|
|
||||||
### Update `<DataTable>`
|
### Update `<DataTable>`
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{4,12}
|
```ts:line-numbers {4,12}
|
||||||
import {
|
import {
|
||||||
FlexRender,
|
FlexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
|
@ -388,8 +388,8 @@ import {
|
||||||
} from "@tanstack/vue-table"
|
} from "@tanstack/vue-table"
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
})
|
})
|
||||||
|
|
@ -401,14 +401,13 @@ This will automatically paginate your rows into pages of 10. See the [pagination
|
||||||
|
|
||||||
We can add pagination controls to our table using the `<Button />` component and the `table.previousPage()`, `table.nextPage()` API methods.
|
We can add pagination controls to our table using the `<Button />` component and the `table.previousPage()`, `table.nextPage()` API methods.
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{3,15,21-39}
|
```vue:line-numbers {3,15,21-39}
|
||||||
// components/payments/DataTable.vue
|
|
||||||
<script lang="ts" generic="TData, TValue">
|
<script lang="ts" generic="TData, TValue">
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
})
|
})
|
||||||
|
|
@ -457,7 +456,7 @@ Let's make the email column sortable.
|
||||||
|
|
||||||
### Add the following into your `utils` file:
|
### Add the following into your `utils` file:
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{5,6,12-17}
|
```ts:line-numbers {5,6,12-17}
|
||||||
import { type ClassValue, clsx } from 'clsx'
|
import { type ClassValue, clsx } from 'clsx'
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
import { camelize, getCurrentInstance, toHandlerKey } from 'vue'
|
import { camelize, getCurrentInstance, toHandlerKey } from 'vue'
|
||||||
|
|
@ -481,7 +480,7 @@ The `valueUpdater` function updates a Vue `ref` object's value. It handles both
|
||||||
|
|
||||||
### Update `<DataTable>`
|
### Update `<DataTable>`
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{4,7,16,34,41-44}
|
```vue:line-numbers {4,7,16,34,41-44}
|
||||||
<script setup lang="ts" generic="TData, TValue">
|
<script setup lang="ts" generic="TData, TValue">
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
|
|
@ -518,8 +517,8 @@ const props = defineProps<{
|
||||||
const sorting = ref<SortingState>([])
|
const sorting = ref<SortingState>([])
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
|
@ -544,7 +543,7 @@ const table = useVueTable({
|
||||||
|
|
||||||
We can now update the `email` header cell to add sorting controls.
|
We can now update the `email` header cell to add sorting controls.
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{5,10-17}
|
```ts:line-numbers {5,10-17}
|
||||||
// components/payments/columns.ts
|
// components/payments/columns.ts
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
|
|
@ -578,7 +577,7 @@ Let's add a search input to filter emails in our table.
|
||||||
|
|
||||||
### Update `<DataTable>`
|
### Update `<DataTable>`
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{4,11,19,39,48-49,52,60-64}
|
```vue:line-numbers {4,11,19,39,48-49,52,60-64}
|
||||||
<script setup lang="ts" generic="TData, TValue">
|
<script setup lang="ts" generic="TData, TValue">
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
|
|
@ -620,8 +619,8 @@ const sorting = ref<SortingState>([])
|
||||||
const columnFilters = ref<ColumnFiltersState>([])
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
|
@ -663,7 +662,7 @@ Adding column visibility is fairly simple using `@tanstack/vue-table` visibility
|
||||||
|
|
||||||
### Update `<DataTable>`
|
### Update `<DataTable>`
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{6,9-14,48,59,63,75-91}
|
```vue:line-numbers {6,9-14,48,59,63,75-91}
|
||||||
<script setup lang="ts" generic="TData, TValue">
|
<script setup lang="ts" generic="TData, TValue">
|
||||||
import type {
|
import type {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
|
|
@ -714,11 +713,11 @@ const columnFilters = ref<ColumnFiltersState>([])
|
||||||
const columnVisibility = ref<VisibilityState>({})
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
|
|
@ -802,7 +801,7 @@ Next, we're going to add row selection to our table.
|
||||||
|
|
||||||
### Update column definitions
|
### Update column definitions
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{3,6-20}
|
```ts:line-numbers {3,6-20}
|
||||||
import type { ColumnDef } from '@tanstack/vue-table'
|
import type { ColumnDef } from '@tanstack/vue-table'
|
||||||
|
|
||||||
import { Checkbox } from '@/components/ui/checkbox'
|
import { Checkbox } from '@/components/ui/checkbox'
|
||||||
|
|
@ -828,7 +827,7 @@ export const columns: ColumnDef<Payment>[] = [
|
||||||
|
|
||||||
### Update `<DataTable>`
|
### Update `<DataTable>`
|
||||||
|
|
||||||
```ts:line-numbers showLineNumbers{10,22,27}
|
```vue:line-numbers {10,22,27}
|
||||||
<script setup lang="ts" generic="TData, TValue">
|
<script setup lang="ts" generic="TData, TValue">
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
columns: ColumnDef<TData, TValue>[]
|
columns: ColumnDef<TData, TValue>[]
|
||||||
|
|
@ -841,11 +840,11 @@ const columnVisibility = ref<VisibilityState>({})
|
||||||
const rowSelection = ref({})
|
const rowSelection = ref({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
|
|
@ -894,7 +893,7 @@ Here are some components you can use to build your data tables. This is from the
|
||||||
|
|
||||||
Make any column header sortable and hideable.
|
Make any column header sortable and hideable.
|
||||||
|
|
||||||
```ts:line-numbers
|
```vue:line-numbers
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Column } from '@tanstack/vue-table'
|
import type { Column } from '@tanstack/vue-table'
|
||||||
import { type Task } from '../data/schema'
|
import { type Task } from '../data/schema'
|
||||||
|
|
@ -987,7 +986,7 @@ export const columns = [
|
||||||
|
|
||||||
Add pagination controls to your table including page size and selection count.
|
Add pagination controls to your table including page size and selection count.
|
||||||
|
|
||||||
```ts:line-numbers
|
```vue:line-numbers
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type Table } from '@tanstack/vue-table'
|
import { type Table } from '@tanstack/vue-table'
|
||||||
import { type Task } from '../data/schema'
|
import { type Task } from '../data/schema'
|
||||||
|
|
@ -1092,8 +1091,7 @@ defineProps<DataTablePaginationProps>()
|
||||||
|
|
||||||
A component to toggle column visibility.
|
A component to toggle column visibility.
|
||||||
|
|
||||||
```ts:line-numbers
|
```vue:line-numbers
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Table } from '@tanstack/vue-table'
|
import type { Table } from '@tanstack/vue-table'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,18 @@ const date = ref<Date>()
|
||||||
|
|
||||||
<ComponentPreview name="DatePickerWithRange" />
|
<ComponentPreview name="DatePickerWithRange" />
|
||||||
|
|
||||||
|
### Date Time Picker
|
||||||
|
|
||||||
|
<ComponentPreview name="DateTimePickerDemo" />
|
||||||
|
|
||||||
### With Presets
|
### With Presets
|
||||||
|
|
||||||
<ComponentPreview name="DatePickerWithPresets" />
|
<ComponentPreview name="DatePickerWithPresets" />
|
||||||
|
|
||||||
|
### With Slot
|
||||||
|
|
||||||
|
<ComponentPreview name="RangePickerWithSlot" />
|
||||||
|
|
||||||
### Form
|
### Form
|
||||||
|
|
||||||
<ComponentPreview name="DatePickerForm" />
|
<ComponentPreview name="DatePickerForm" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
title: VeeValidate
|
title: VeeValidate
|
||||||
description: Building forms with VeeValidate and Zod.
|
description: Building forms with VeeValidate and Zod.
|
||||||
|
primitive: https://vee-validate.logaretm.com/v4/guide/overview/
|
||||||
---
|
---
|
||||||
|
|
||||||
Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex.
|
Forms are tricky. They are one of the most common things you'll build in a web application, but also one of the most complex.
|
||||||
|
|
@ -158,7 +159,7 @@ Use `@vee-validate/zod` to integrate Zod schema validation with `vee-validate`
|
||||||
|
|
||||||
`toTypedSchema` also makes the form values and submitted values typed automatically and caters for both input and output types of that schema.
|
`toTypedSchema` also makes the form values and submitted values typed automatically and caters for both input and output types of that schema.
|
||||||
|
|
||||||
```vue showLineNumbers {2-3,5-7}
|
```vue:line-numbers {2-3,5-7}
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import * as z from 'zod'
|
import * as z from 'zod'
|
||||||
|
|
@ -172,13 +173,13 @@ const formSchema = toTypedSchema(z.object({
|
||||||
|
|
||||||
### Define a form
|
### Define a form
|
||||||
|
|
||||||
Use the `useForm` composable from `vee-validate` or use `<Form />` component to create a from.
|
Use the `useForm` composable from `vee-validate` or use `<Form />` component to create a form.
|
||||||
|
|
||||||
|
|
||||||
<TabPreview name="Composition" :names="['Composition', 'Component']">
|
<TabPreview name="Composition" :names="['Composition', 'Component']">
|
||||||
<template #Composition>
|
<template #Composition>
|
||||||
|
|
||||||
```vue showLineNumbers {2,19-21}
|
```vue:line-numbers {2,19-21}
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
|
@ -217,7 +218,7 @@ const onSubmit = form.handleSubmit((values) => {
|
||||||
|
|
||||||
<template #Component>
|
<template #Component>
|
||||||
|
|
||||||
```vue showLineNumbers {5,24-26}
|
```vue:line-numbers {5,24-26}
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
import * as z from 'zod'
|
import * as z from 'zod'
|
||||||
|
|
@ -255,7 +256,7 @@ function onSubmit(values) {
|
||||||
Based on last step we can either use `<Form />` component or `useForm` composable
|
Based on last step we can either use `<Form />` component or `useForm` composable
|
||||||
`useForm` is recommended cause values are typed automatically
|
`useForm` is recommended cause values are typed automatically
|
||||||
|
|
||||||
```vue showLineNumbers {2}
|
```vue:line-numbers {2}
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useForm } from 'vee-validate'
|
import { useForm } from 'vee-validate'
|
||||||
import { toTypedSchema } from '@vee-validate/zod'
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ import {
|
||||||
|
|
||||||
### Link Component
|
### Link Component
|
||||||
|
|
||||||
When using the Nuxt.js <NuxtLink /> component, you can use `navigationMenuTriggerStyle()` to apply the correct styles to the trigger.
|
When using the Nuxt.js `<NuxtLink />` component, you can use `navigationMenuTriggerStyle()` to apply the correct styles to the trigger.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { navigationMenuTriggerStyle } from '@/components/ui/navigation-menu'
|
import { navigationMenuTriggerStyle } from '@/components/ui/navigation-menu'
|
||||||
|
|
|
||||||
21
apps/www/src/content/docs/components/pin-input.md
Normal file
21
apps/www/src/content/docs/components/pin-input.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: PIN Input
|
||||||
|
description: Allows users to input a sequence of one-character alphanumeric inputs.
|
||||||
|
source: apps/www/src/lib/registry/default/ui/pin-input
|
||||||
|
primitive: https://www.radix-vue.com/components/pin-input.html
|
||||||
|
---
|
||||||
|
|
||||||
|
<ComponentPreview name="PinInputDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx shadcn-vue@latest add pin-input
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Form
|
||||||
|
|
||||||
|
<ComponentPreview name="PinInputFormDemo" />
|
||||||
|
|
@ -40,4 +40,6 @@ import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
||||||
|
|
||||||
### Form
|
### Form
|
||||||
|
|
||||||
|
Please first read `vee-validate` section for [Checkbox and Radio Inputs](https://vee-validate.logaretm.com/v4/examples/checkboxes-and-radio/)
|
||||||
|
|
||||||
<ComponentPreview name="RadioGroupForm" />
|
<ComponentPreview name="RadioGroupForm" />
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Sheet
|
title: Sheet
|
||||||
description: Extends the Dialog component to display content that complements the main content of the screen.
|
description: Extends the Dialog component to display content that complements the main content of the screen.
|
||||||
source: apps/www/src/lib/registry/default/ui/dialog
|
source: apps/www/src/lib/registry/default/ui/sheet
|
||||||
primitive: https://www.radix-vue.com/components/dialog.html
|
primitive: https://www.radix-vue.com/components/dialog.html
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ Use the `side` property to `<SheetContent />` to indicate the edge of the screen
|
||||||
|
|
||||||
You can adjust the size of the sheet using CSS classes:
|
You can adjust the size of the sheet using CSS classes:
|
||||||
|
|
||||||
```vue:line-numbers showLineNumbers{4}
|
```vue:line-numbers {4}
|
||||||
<template>
|
<template>
|
||||||
<Sheet>
|
<Sheet>
|
||||||
<SheetTrigger>Open</SheetTrigger>
|
<SheetTrigger>Open</SheetTrigger>
|
||||||
|
|
@ -72,4 +72,4 @@ You can adjust the size of the sheet using CSS classes:
|
||||||
</SheetContent>
|
</SheetContent>
|
||||||
</Sheet>
|
</Sheet>
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,6 @@ import { Skeleton } from '@/components/ui/skeleton'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Skeleton class="w-[100px] h-[20px] rounded-full" />
|
<Skeleton class="w-[100px] h-5 rounded-full" />
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
|
|
|
||||||
63
apps/www/src/content/docs/components/sonner.md
Normal file
63
apps/www/src/content/docs/components/sonner.md
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
---
|
||||||
|
title: Sonner
|
||||||
|
description: An opinionated toast component for Vue.
|
||||||
|
docs: https://vue-sonner.vercel.app
|
||||||
|
source: apps/www/src/lib/registry/default/ui/sonner
|
||||||
|
---
|
||||||
|
|
||||||
|
<ComponentPreview name="SonnerDemo" />
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
The Sonner component is provided by [vue-sonner](https://vue-sonner.vercel.app/), which is a Vue port of Sonner, originally created by [Emil Kowalski](https://twitter.com/emilkowalski_) for React.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
|
||||||
|
### Run the following command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx shadcn-vue@latest add sonner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add the Toaster component
|
||||||
|
|
||||||
|
Add the following `Toaster` component to your `App.vue` file:
|
||||||
|
|
||||||
|
```vue title="App.vue" {2,6}
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Toaster } from '@/components/ui/sonner'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Toaster />
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { toast } from 'vue-sonner'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
variant="outline" @click="() => {
|
||||||
|
toast('Event has been created', {
|
||||||
|
description: 'Sunday, December 03, 2023 at 9:00 AM',
|
||||||
|
action: {
|
||||||
|
label: 'Undo',
|
||||||
|
onClick: () => console.log('Undo'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
Add to calander
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
93
apps/www/src/content/docs/components/toggle-group.md
Normal file
93
apps/www/src/content/docs/components/toggle-group.md
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
title: Toggle Group
|
||||||
|
description: A set of two-state buttons that can be toggled on or off.
|
||||||
|
source: apps/www/src/lib/registry/default/ui/toggle-group
|
||||||
|
primitive: https://www.radix-vue.com/components/toggle-group.html
|
||||||
|
---
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupDemo" />
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
<TabPreview name="CLI">
|
||||||
|
<template #CLI>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx shadcn-vue@latest add toggle-group
|
||||||
|
```
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #Manual>
|
||||||
|
|
||||||
|
<Steps>
|
||||||
|
|
||||||
|
### Install the following dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install radix-vue
|
||||||
|
```
|
||||||
|
|
||||||
|
### Copy and paste the following code into your project
|
||||||
|
|
||||||
|
<<< @/lib/registry/default/ui/toggle-group/ToggleGroup.vue
|
||||||
|
|
||||||
|
</Steps>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</TabPreview>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="single">
|
||||||
|
<ToggleGroupItem value="a">
|
||||||
|
A
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="b">
|
||||||
|
B
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="c">
|
||||||
|
C
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Default
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
### Outline
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupOutlineDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
### Single
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupSingleDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
### Small
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupSmallDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
### Large
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupLargeDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
### Disabled
|
||||||
|
|
||||||
|
<ComponentPreview name="ToggleGroupDisabledDemo" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ npm create astro@latest
|
||||||
|
|
||||||
You will be asked a few questions to configure your project:
|
You will be asked a few questions to configure your project:
|
||||||
|
|
||||||
```txt showLineNumbers
|
```txt:line-numbers
|
||||||
- Where should we create your new project?
|
- Where should we create your new project?
|
||||||
./your-app-name
|
./your-app-name
|
||||||
- How would you like to start your new project?
|
- How would you like to start your new project?
|
||||||
|
|
@ -76,7 +76,7 @@ This will install `tailwindcss` and `@astrojs/tailwind` as dependencies and set
|
||||||
|
|
||||||
Add the code below to the tsconfig.json file to resolve paths:
|
Add the code below to the tsconfig.json file to resolve paths:
|
||||||
|
|
||||||
```json {2-7} showLineNumbers
|
```json:line-numbers {2-7}
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
|
@ -99,7 +99,7 @@ npx shadcn-vue@latest init
|
||||||
|
|
||||||
You will be asked a few questions to configure `components.json`:
|
You will be asked a few questions to configure `components.json`:
|
||||||
|
|
||||||
```txt showLineNumbers
|
```txt:line-numbers
|
||||||
Would you like to use TypeScript (recommended)? no / yes
|
Would you like to use TypeScript (recommended)? no / yes
|
||||||
Which framework are you using? Astro
|
Which framework are you using? Astro
|
||||||
Which style would you like to use? › Default
|
Which style would you like to use? › Default
|
||||||
|
|
@ -116,15 +116,17 @@ Write configuration to components.json. Proceed? > Y/n
|
||||||
|
|
||||||
Import the `globals.css` file in the `src/index.astro` file:
|
Import the `globals.css` file in the `src/index.astro` file:
|
||||||
|
|
||||||
```ts {2} showLineNumbers
|
```ts:line-numbers {2}
|
||||||
|
---
|
||||||
import '@/styles/globals.css'
|
import '@/styles/globals.css'
|
||||||
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update astro tailwind config
|
### Update astro tailwind config
|
||||||
|
|
||||||
To prevent serving the Tailwind base styles twice, we need to tell Astro not to apply the base styles, since we already include them in our own `globals.css` file. To do this, set the `applyBaseStyles` config option for the tailwind plugin in `astro.config.mjs` to `false`.
|
To prevent serving the Tailwind base styles twice, we need to tell Astro not to apply the base styles, since we already include them in our own `globals.css` file. To do this, set the `applyBaseStyles` config option for the tailwind plugin in `astro.config.mjs` to `false`.
|
||||||
|
|
||||||
```ts {3-5} showLineNumbers
|
```ts:line-numbers {3-5}
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [
|
integrations: [
|
||||||
tailwind({
|
tailwind({
|
||||||
|
|
@ -144,7 +146,7 @@ npx shadcn-vue@latest add button
|
||||||
|
|
||||||
The command above will add the `Button` component to your project. You can then import it like this:
|
The command above will add the `Button` component to your project. You can then import it like this:
|
||||||
|
|
||||||
```astro {2,10} showLineNumbers
|
```astro:line-numbers {2,10}
|
||||||
---
|
---
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ npx shadcn-vue@latest init
|
||||||
|
|
||||||
You will be asked a few questions to configure `components.json`:
|
You will be asked a few questions to configure `components.json`:
|
||||||
|
|
||||||
```txt showLineNumbers
|
```txt:line-numbers
|
||||||
Would you like to use TypeScript (recommended)? no / yes
|
Would you like to use TypeScript (recommended)? no / yes
|
||||||
Which framework are you using? Vite / Nuxt / Laravel
|
Which framework are you using? Vite / Nuxt / Laravel
|
||||||
Which style would you like to use? › Default
|
Which style would you like to use? › Default
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ description: Install and configure Nuxt.
|
||||||
|
|
||||||
### Create project
|
### Create project
|
||||||
|
|
||||||
Start by creating a new Nuxt project using `create-next-app`:
|
Start by creating a new Nuxt project using `create-nuxt-app`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx nuxi@latest init my-app
|
npx nuxi@latest init my-app
|
||||||
|
|
@ -26,12 +26,128 @@ npm install -D typescript
|
||||||
npm install -D @nuxtjs/tailwindcss
|
npm install -D @nuxtjs/tailwindcss
|
||||||
```
|
```
|
||||||
|
|
||||||
### Install `shadcn-nuxt` module (New ✨)
|
### Add `Nuxt` module
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<TabsMarkdown>
|
||||||
|
<TabMarkdown title="shadcn-nuxt">
|
||||||
|
|
||||||
|
Install the package below.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -D shadcn-nuxt
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabMarkdown>
|
||||||
|
|
||||||
|
|
||||||
|
<TabMarkdown title="manual">
|
||||||
|
|
||||||
|
Add the following code to `modules/shadcn.ts`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install -D shadcn-nuxt
|
import {
|
||||||
|
defineNuxtModule,
|
||||||
|
addComponent,
|
||||||
|
addComponentsDir,
|
||||||
|
tryResolveModule,
|
||||||
|
} from 'nuxt/kit';
|
||||||
|
|
||||||
|
export interface ShadcnVueOptions {
|
||||||
|
/**
|
||||||
|
* Prefix for all the imported component
|
||||||
|
*/
|
||||||
|
prefix: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory that the component lives in.
|
||||||
|
* @default "~/components/ui"
|
||||||
|
*/
|
||||||
|
componentDir: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineNuxtModule<ShadcnVueOptions>({
|
||||||
|
defaults: {
|
||||||
|
prefix: 'Ui',
|
||||||
|
componentDir: '~/components/ui',
|
||||||
|
},
|
||||||
|
meta: {
|
||||||
|
name: 'ShadcnVue',
|
||||||
|
configKey: 'shadcn',
|
||||||
|
version: '0.0.1',
|
||||||
|
compatibility: {
|
||||||
|
nuxt: '^3.9.0',
|
||||||
|
bridge: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async setup({ componentDir, prefix }) {
|
||||||
|
const isVeeValidateExist = await tryResolveModule('vee-validate');
|
||||||
|
|
||||||
|
addComponentsDir(
|
||||||
|
{
|
||||||
|
path: componentDir,
|
||||||
|
extensions: ['.vue'],
|
||||||
|
prefix,
|
||||||
|
pathPrefix: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prepend: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isVeeValidateExist !== undefined) {
|
||||||
|
addComponent({
|
||||||
|
filePath: 'vee-validate',
|
||||||
|
export: 'Form',
|
||||||
|
name: `${prefix}Form`,
|
||||||
|
priority: 999,
|
||||||
|
});
|
||||||
|
|
||||||
|
addComponent({
|
||||||
|
filePath: 'vee-validate',
|
||||||
|
export: 'Field',
|
||||||
|
name: `${prefix}FormField`,
|
||||||
|
priority: 999,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addComponent({
|
||||||
|
filePath: 'radix-vue',
|
||||||
|
export: 'PaginationRoot',
|
||||||
|
name: `${prefix}Pagination`,
|
||||||
|
priority: 999,
|
||||||
|
});
|
||||||
|
|
||||||
|
addComponent({
|
||||||
|
filePath: 'radix-vue',
|
||||||
|
export: 'PaginationList',
|
||||||
|
name: `${prefix}PaginationList`,
|
||||||
|
priority: 999,
|
||||||
|
});
|
||||||
|
|
||||||
|
addComponent({
|
||||||
|
filePath: 'radix-vue',
|
||||||
|
export: 'PaginationListItem',
|
||||||
|
name: `${prefix}PaginationListItem`,
|
||||||
|
priority: 999,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
declare module '@nuxt/schema' {
|
||||||
|
interface NuxtConfig {
|
||||||
|
shadcn?: ShadcnVueOptions;
|
||||||
|
}
|
||||||
|
interface NuxtOptions {
|
||||||
|
shadcn?: ShadcnVueOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</TabMarkdown>
|
||||||
|
</TabsMarkdown>
|
||||||
|
|
||||||
|
|
||||||
### Configure `nuxt.config.ts`
|
### Configure `nuxt.config.ts`
|
||||||
|
|
||||||
|
|
@ -64,7 +180,7 @@ npx shadcn-vue@latest init
|
||||||
|
|
||||||
You will be asked a few questions to configure `components.json`:
|
You will be asked a few questions to configure `components.json`:
|
||||||
|
|
||||||
```txt showLineNumbers
|
```txt:line-numbers
|
||||||
Would you like to use TypeScript (recommended)? no / yes
|
Would you like to use TypeScript (recommended)? no / yes
|
||||||
Which framework are you using? Vite / Nuxt / Laravel
|
Which framework are you using? Vite / Nuxt / Laravel
|
||||||
Which style would you like to use? › Default
|
Which style would you like to use? › Default
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,63 @@ npm create vite@latest my-vue-app -- --template vue-ts
|
||||||
|
|
||||||
### Add Tailwind and its configuration
|
### Add Tailwind and its configuration
|
||||||
|
|
||||||
Install `tailwindcss` and its peer dependencies, then generate your `tailwind.config.js` and `postcss.config.js` files:
|
Install `tailwindcss` and its peer dependencies, then generate your `tailwind.config.js` and configure `postcss` plugins
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -D tailwindcss postcss autoprefixer
|
|
||||||
|
|
||||||
npx tailwindcss init -p
|
|
||||||
```
|
<TabsMarkdown>
|
||||||
|
<TabMarkdown title="vite.config.ts">
|
||||||
|
|
||||||
|
Vite already has [`postcss`](https://github.com/vitejs/vite/blob/main/packages/vite/package.json#L78) dependency so you don't have to install it again in your package.json
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -D tailwindcss autoprefixer
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `vite.config`
|
||||||
|
|
||||||
|
```typescript {5,6,10-14}
|
||||||
|
import path from "path"
|
||||||
|
import { defineConfig } from "vite"
|
||||||
|
import vue from "@vitejs/plugin-vue"
|
||||||
|
|
||||||
|
import tailwind from "tailwindcss"
|
||||||
|
import autoprefixer from "autoprefixer"
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [tailwind(), autoprefixer()],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolve: {...}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabMarkdown>
|
||||||
|
|
||||||
|
|
||||||
|
<TabMarkdown title="postcss.config.js">
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -D tailwindcss autoprefixer postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `postcss.config.js`
|
||||||
|
|
||||||
|
```js
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</TabMarkdown>
|
||||||
|
</TabsMarkdown>
|
||||||
|
|
||||||
|
|
||||||
### Edit tsconfig.json
|
### Edit tsconfig.json
|
||||||
|
|
||||||
|
|
@ -42,6 +92,11 @@ Add the code below to the compilerOptions of your tsconfig.json so your app can
|
||||||
|
|
||||||
Add the code below to the vite.config.ts so your app can resolve paths without error
|
Add the code below to the vite.config.ts so your app can resolve paths without error
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# (so you can import "path" without error)
|
||||||
|
npm i -D @types/node
|
||||||
|
```
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import vue from "@vitejs/plugin-vue"
|
import vue from "@vitejs/plugin-vue"
|
||||||
|
|
@ -69,7 +124,7 @@ npx shadcn-vue@latest init
|
||||||
|
|
||||||
You will be asked a few questions to configure `components.json`:
|
You will be asked a few questions to configure `components.json`:
|
||||||
|
|
||||||
```txt showLineNumbers
|
```txt:line-numbers
|
||||||
Would you like to use TypeScript (recommended)? no / yes
|
Would you like to use TypeScript (recommended)? no / yes
|
||||||
Which framework are you using? Vite / Nuxt / Laravel
|
Which framework are you using? Vite / Nuxt / Laravel
|
||||||
Which style would you like to use? › Default
|
Which style would you like to use? › Default
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader class="grid grid-cols-[1fr_110px] items-start gap-4 space-y-0">
|
<CardHeader class="grid grid-cols-[minmax(0,1fr)_110px] items-start gap-4 space-y-0">
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<CardTitle>shadcn/ui</CardTitle>
|
<CardTitle>shadcn/ui</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
|
|
@ -39,7 +39,7 @@ import { Separator } from '@/lib/registry/new-york/ui/separator'
|
||||||
<StarIcon class="mr-2 h-4 w-4" />
|
<StarIcon class="mr-2 h-4 w-4" />
|
||||||
Star
|
Star
|
||||||
</Button>
|
</Button>
|
||||||
<Separator orientation="vertical" class="h-[20px]" />
|
<Separator orientation="vertical" class="h-5" />
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<Button variant="secondary" class="px-2 shadow-none">
|
<Button variant="secondary" class="px-2 shadow-none">
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ const date = ref({
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent class="w-auto p-0" :align="'end'" :avoid-collisions="true">
|
<PopoverContent class="w-auto p-0" :align="'end'">
|
||||||
<Calendar
|
<Calendar
|
||||||
v-model.range="date"
|
v-model.range="date"
|
||||||
:columns="2"
|
:columns="2"
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ async function onSubmit(values: any) {
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<FormField v-slot="{ componentField, value }" name="dob">
|
<FormField v-slot="{ componentField, value }" name="dob">
|
||||||
<FormItem>
|
<FormItem class="flex flex-col">
|
||||||
<FormLabel>Date of birth</FormLabel>
|
<FormLabel>Date of birth</FormLabel>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger as-child>
|
<PopoverTrigger as-child>
|
||||||
|
|
@ -123,7 +123,7 @@ async function onSubmit(values: any) {
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<FormField v-slot="{ value }" name="language">
|
<FormField v-slot="{ value }" name="language">
|
||||||
<FormItem>
|
<FormItem class="flex flex-col">
|
||||||
<FormLabel>Language</FormLabel>
|
<FormLabel>Language</FormLabel>
|
||||||
|
|
||||||
<Popover v-model:open="open">
|
<Popover v-model:open="open">
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ const onSubmit = handleSubmit((values) => {
|
||||||
<div class="items-center rounded-md border-2 border-muted p-1 hover:border-accent">
|
<div class="items-center rounded-md border-2 border-muted p-1 hover:border-accent">
|
||||||
<div class="space-y-2 rounded-sm bg-[#ecedef] p-2">
|
<div class="space-y-2 rounded-sm bg-[#ecedef] p-2">
|
||||||
<div class="space-y-2 rounded-md bg-white p-2 shadow-sm">
|
<div class="space-y-2 rounded-md bg-white p-2 shadow-sm">
|
||||||
<div class="h-2 w-[80px] rounded-lg bg-[#ecedef]" />
|
<div class="h-2 w-20 rounded-lg bg-[#ecedef]" />
|
||||||
<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
|
<div class="h-2 w-[100px] rounded-lg bg-[#ecedef]" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
|
<div class="flex items-center space-x-2 rounded-md bg-white p-2 shadow-sm">
|
||||||
|
|
@ -127,7 +127,7 @@ const onSubmit = handleSubmit((values) => {
|
||||||
<div class="items-center rounded-md border-2 border-muted bg-popover p-1 hover:bg-accent hover:text-accent-foreground">
|
<div class="items-center rounded-md border-2 border-muted bg-popover p-1 hover:bg-accent hover:text-accent-foreground">
|
||||||
<div class="space-y-2 rounded-sm bg-slate-950 p-2">
|
<div class="space-y-2 rounded-sm bg-slate-950 p-2">
|
||||||
<div class="space-y-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
<div class="space-y-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
||||||
<div class="h-2 w-[80px] rounded-lg bg-slate-400" />
|
<div class="h-2 w-20 rounded-lg bg-slate-400" />
|
||||||
<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
|
<div class="h-2 w-[100px] rounded-lg bg-slate-400" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
<div class="flex items-center space-x-2 rounded-md bg-slate-800 p-2 shadow-sm">
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ import CounterClockwiseClockIcon from '~icons/radix-icons/counter-clockwise-cloc
|
||||||
<Separator />
|
<Separator />
|
||||||
<Tabs default-value="complete" class="flex-1">
|
<Tabs default-value="complete" class="flex-1">
|
||||||
<div class="container h-full py-6">
|
<div class="container h-full py-6">
|
||||||
<div class="grid h-full items-stretch gap-6 md:grid-cols-[1fr_200px]">
|
<div class="grid h-full items-stretch gap-6 md:grid-cols-[minmax(0,1fr)_200px]">
|
||||||
<div class="hidden flex-col space-y-4 sm:flex md:order-2">
|
<div class="hidden flex-col space-y-4 sm:flex md:order-2">
|
||||||
<div class="grid gap-2">
|
<div class="grid gap-2">
|
||||||
<HoverCard :open-delay="200">
|
<HoverCard :open-delay="200">
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ const columnVisibility = ref<VisibilityState>({})
|
||||||
const rowSelection = ref({})
|
const rowSelection = ref({})
|
||||||
|
|
||||||
const table = useVueTable({
|
const table = useVueTable({
|
||||||
data: props.data,
|
get data() { return props.data },
|
||||||
columns: props.columns,
|
get columns() { return props.columns },
|
||||||
state: {
|
state: {
|
||||||
get sorting() { return sorting.value },
|
get sorting() { return sorting.value },
|
||||||
get columnFilters() { return columnFilters.value },
|
get columnFilters() { return columnFilters.value },
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,16 @@ export const columns: ColumnDef<Task>[] = [
|
||||||
{
|
{
|
||||||
id: 'select',
|
id: 'select',
|
||||||
header: ({ table }) => h(Checkbox,
|
header: ({ table }) => h(Checkbox,
|
||||||
{ 'checked': table.getIsAllPageRowsSelected(), 'onUpdate:checked': value => table.toggleAllPageRowsSelected(!!value), 'ariaLabel': 'Select all', 'class': 'translate-y-[2px]' }),
|
{ 'checked': table.getIsAllPageRowsSelected(), 'onUpdate:checked': value => table.toggleAllPageRowsSelected(!!value), 'ariaLabel': 'Select all', 'class': 'translate-y-0.5' }),
|
||||||
cell: ({ row }) => h(Checkbox,
|
cell: ({ row }) => h(Checkbox,
|
||||||
{ 'checked': row.getIsSelected(), 'onUpdate:checked': value => row.toggleSelected(!!value), 'ariaLabel': 'Select row', 'class': 'translate-y-[2px]' }),
|
{ 'checked': row.getIsSelected(), 'onUpdate:checked': value => row.toggleSelected(!!value), 'ariaLabel': 'Select row', 'class': 'translate-y-0.5' }),
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'id',
|
accessorKey: 'id',
|
||||||
header: ({ column }) => h(DataTableColumnHeader, { column, title: 'Task' }),
|
header: ({ column }) => h(DataTableColumnHeader, { column, title: 'Task' }),
|
||||||
cell: ({ row }) => h('div', { class: 'w-[80px]' }, row.getValue('id')),
|
cell: ({ row }) => h('div', { class: 'w-20' }, row.getValue('id')),
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
enableHiding: false,
|
enableHiding: false,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Button as-child>
|
<Button as-child>
|
||||||
<NuxtLink to="/login">
|
<a href="/login">
|
||||||
Login
|
Login
|
||||||
</NuxtLink>
|
</a>
|
||||||
</Button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ const notifications = [
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
v-for="(notification, index) in notifications" :key="index"
|
v-for="(notification, index) in notifications" :key="index"
|
||||||
class="mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0"
|
class="mb-4 grid grid-cols-[25px_minmax(0,1fr)] items-start pb-4 last:mb-0 last:pb-0"
|
||||||
>
|
>
|
||||||
<span class="flex h-2 w-2 translate-y-1 rounded-full bg-sky-500" />
|
<span class="flex h-2 w-2 translate-y-1 rounded-full bg-sky-500" />
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/lib/registry/default/ui/card'
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from '@/lib/registry/default/ui/card'
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
|
|
@ -22,11 +29,11 @@ import { Button } from '@/lib/registry/default/ui/button'
|
||||||
<form>
|
<form>
|
||||||
<div class="grid items-center w-full gap-4">
|
<div class="grid items-center w-full gap-4">
|
||||||
<div class="flex flex-col space-y-1.5">
|
<div class="flex flex-col space-y-1.5">
|
||||||
<Label html-for="name">Name</Label>
|
<Label for="name">Name</Label>
|
||||||
<Input id="name" placeholder="Name of your project" />
|
<Input id="name" placeholder="Name of your project" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col space-y-1.5">
|
<div class="flex flex-col space-y-1.5">
|
||||||
<Label html-for="framework">Framework</Label>
|
<Label for="framework">Framework</Label>
|
||||||
<Select>
|
<Select>
|
||||||
<SelectTrigger id="framework">
|
<SelectTrigger id="framework">
|
||||||
<SelectValue placeholder="Select" />
|
<SelectValue placeholder="Select" />
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ const lineY = (d: Data) => d.revenue
|
||||||
+20.1% from last month
|
+20.1% from last month
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="h-[80px]">
|
<div class="h-20">
|
||||||
<VisXYContainer
|
<VisXYContainer
|
||||||
height="80px"
|
height="80px"
|
||||||
:data="data" :margin="{
|
:data="data" :margin="{
|
||||||
|
|
@ -74,7 +74,7 @@ const lineY = (d: Data) => d.revenue
|
||||||
+54.8% from last month
|
+54.8% from last month
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="mt-4 h-[80px]">
|
<div class="mt-4 h-20">
|
||||||
<VisXYContainer
|
<VisXYContainer
|
||||||
height="80px" :data="data" :style="{
|
height="80px" :data="data" :style="{
|
||||||
'--theme-primary': `hsl(${
|
'--theme-primary': `hsl(${
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import {
|
||||||
useVueTable,
|
useVueTable,
|
||||||
} from '@tanstack/vue-table'
|
} from '@tanstack/vue-table'
|
||||||
import { h, ref } from 'vue'
|
import { h, ref } from 'vue'
|
||||||
import { CaretSortIcon, ChevronDownIcon } from '@radix-icons/vue'
|
import { ChevronDown, ChevronsUpDown } from 'lucide-vue-next'
|
||||||
import DropdownAction from '../DataTableDemoColumn.vue'
|
import DropdownAction from '../DataTableDemoColumn.vue'
|
||||||
|
|
||||||
import { Button } from '@/lib/registry/default/ui/button'
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
|
@ -104,7 +104,7 @@ const columns: ColumnDef<Payment>[] = [
|
||||||
return h(Button, {
|
return h(Button, {
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'),
|
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'),
|
||||||
}, ['Email', h(CaretSortIcon, { class: 'ml-2 h-4 w-4' })])
|
}, ['Email', h(ChevronsUpDown, { class: 'ml-2 h-4 w-4' })])
|
||||||
},
|
},
|
||||||
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
||||||
},
|
},
|
||||||
|
|
@ -179,7 +179,7 @@ const table = useVueTable({
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<Button variant="outline" class="ml-auto">
|
<Button variant="outline" class="ml-auto">
|
||||||
Columns <ChevronDownIcon class="ml-2 h-4 w-4" />
|
Columns <ChevronDown class="ml-2 h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
|
|
|
||||||
51
apps/www/src/lib/registry/default/example/CarouselApi.vue
Normal file
51
apps/www/src/lib/registry/default/example/CarouselApi.vue
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { watchOnce } from '@vueuse/core'
|
||||||
|
import type { CarouselApi } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Card, CardContent } from '@/lib/registry/default/ui/card'
|
||||||
|
|
||||||
|
const api = ref<CarouselApi>()
|
||||||
|
const totalCount = ref(0)
|
||||||
|
const current = ref(0)
|
||||||
|
|
||||||
|
function setApi(val: CarouselApi) {
|
||||||
|
api.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
watchOnce(api, (api) => {
|
||||||
|
if (!api)
|
||||||
|
return
|
||||||
|
|
||||||
|
totalCount.value = api.scrollSnapList().length
|
||||||
|
current.value = api.selectedScrollSnap() + 1
|
||||||
|
|
||||||
|
api.on('select', () => {
|
||||||
|
current.value = api.selectedScrollSnap() + 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full sm:w-auto">
|
||||||
|
<Carousel class="relative w-full max-w-xs" @init-api="setApi">
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem v-for="(_, index) in 5" :key="index">
|
||||||
|
<div class="p-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent class="flex aspect-square items-center justify-center p-6">
|
||||||
|
<span class="text-4xl font-semibold">{{ index + 1 }}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
|
||||||
|
<div class="py-2 text-center text-sm text-muted-foreground">
|
||||||
|
Slide {{ current }} of {{ totalCount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
22
apps/www/src/lib/registry/default/example/CarouselDemo.vue
Normal file
22
apps/www/src/lib/registry/default/example/CarouselDemo.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Card, CardContent } from '@/lib/registry/default/ui/card'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel class="relative w-full max-w-xs">
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem v-for="(_, index) in 5" :key="index">
|
||||||
|
<div class="p-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent class="flex aspect-square items-center justify-center p-6">
|
||||||
|
<span class="text-4xl font-semibold">{{ index + 1 }}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Card, CardContent } from '@/lib/registry/default/ui/card'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel
|
||||||
|
orientation="vertical"
|
||||||
|
class="relative w-full max-w-xsw-full max-w-xs"
|
||||||
|
:opts="{
|
||||||
|
align: 'start',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<CarouselContent class="-mt-1 h-[200px]">
|
||||||
|
<CarouselItem v-for="(_, index) in 5" :key="index" class="p-1 md:basis-1/2">
|
||||||
|
<div class="p-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent class="flex items-center justify-center p-6">
|
||||||
|
<span class="text-3xl font-semibold">{{ index + 1 }}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
34
apps/www/src/lib/registry/default/example/CarouselPlugin.vue
Normal file
34
apps/www/src/lib/registry/default/example/CarouselPlugin.vue
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Autoplay from 'embla-carousel-autoplay'
|
||||||
|
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Card, CardContent } from '@/lib/registry/default/ui/card'
|
||||||
|
|
||||||
|
const plugin = Autoplay({
|
||||||
|
delay: 2000,
|
||||||
|
stopOnMouseEnter: true,
|
||||||
|
stopOnInteraction: false,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel
|
||||||
|
class="relative w-full max-w-xs"
|
||||||
|
:plugins="[plugin]"
|
||||||
|
@mouseenter="plugin.stop"
|
||||||
|
@mouseleave="[plugin.reset(), plugin.play(), console.log('Runing')];"
|
||||||
|
>
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem v-for="(_, index) in 5" :key="index">
|
||||||
|
<div class="p-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent class="flex aspect-square items-center justify-center p-6">
|
||||||
|
<span class="text-4xl font-semibold">{{ index + 1 }}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
27
apps/www/src/lib/registry/default/example/CarouselSize.vue
Normal file
27
apps/www/src/lib/registry/default/example/CarouselSize.vue
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Card, CardContent } from '@/lib/registry/default/ui/card'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel
|
||||||
|
class="relative w-full max-w-sm"
|
||||||
|
:opts="{
|
||||||
|
align: 'start',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<CarouselContent>
|
||||||
|
<CarouselItem v-for="(_, index) in 5" :key="index" class="md:basis-1/2 lg:basis-1/3">
|
||||||
|
<div class="p-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent class="flex aspect-square items-center justify-center p-6">
|
||||||
|
<span class="text-3xl font-semibold">{{ index + 1 }}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/lib/registry/default/ui/carousel'
|
||||||
|
import { Card, CardContent } from '@/lib/registry/default/ui/card'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Carousel
|
||||||
|
class="relative w-full max-w-sm"
|
||||||
|
:opts="{
|
||||||
|
align: 'start',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<CarouselContent class="-ml-1">
|
||||||
|
<CarouselItem v-for="(_, index) in 5" :key="index" class="pl-1 md:basis-1/2 lg:basis-1/3">
|
||||||
|
<div class="p-1">
|
||||||
|
<Card>
|
||||||
|
<CardContent class="flex aspect-square items-center justify-center p-6">
|
||||||
|
<span class="text-2xl font-semibold">{{ index + 1 }}</span>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CarouselItem>
|
||||||
|
</CarouselContent>
|
||||||
|
<CarouselPrevious />
|
||||||
|
<CarouselNext />
|
||||||
|
</Carousel>
|
||||||
|
</template>
|
||||||
|
|
@ -77,16 +77,12 @@ const onSubmit = handleSubmit((values) => {
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormField v-for="item in items" v-slot="{ value, handleChange }" :key="item.id" name="items">
|
<FormField v-for="item in items" v-slot="{ value, handleChange }" :key="item.id" type="checkbox" :value="item.id" :unchecked-value="false" name="items">
|
||||||
<FormItem :key="item.id" class="flex flex-row items-start space-x-3 space-y-0">
|
<FormItem class="flex flex-row items-start space-x-3 space-y-0">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
:checked="value.includes(item.id)"
|
:checked="value.includes(item.id)"
|
||||||
@update:checked="(checked) => {
|
@update:checked="handleChange"
|
||||||
if (Array.isArray(value)) {
|
|
||||||
handleChange(checked ? [...value, item.id] : value.filter(id => id !== item.id))
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormLabel class="font-normal">
|
<FormLabel class="font-normal">
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ const onSubmit = handleSubmit((values) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form class="space-y-6" @submit="onSubmit">
|
<form class="space-y-6" @submit="onSubmit">
|
||||||
<FormField v-slot="{ value, handleChange }" name="mobile">
|
<FormField v-slot="{ value, handleChange }" type="checkbox" name="mobile">
|
||||||
<FormItem class="flex flex-row items-start gap-x-3 space-y-0 rounded-md border p-4">
|
<FormItem class="flex flex-row items-start gap-x-3 space-y-0 rounded-md border p-4">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Checkbox :checked="value" @update:checked="handleChange" />
|
<Checkbox :checked="value" @update:checked="handleChange" />
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import { Check, ChevronsUpDown } from 'lucide-vue-next'
|
import { Check, ChevronsUpDown } from 'lucide-vue-next'
|
||||||
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { Button } from '@/lib/registry/default/ui/button'
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
import {
|
import {
|
||||||
|
|
@ -27,9 +27,9 @@ const frameworks = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const open = ref(false)
|
const open = ref(false)
|
||||||
const value = ref<typeof frameworks[number]>()
|
const value = ref<string>('')
|
||||||
|
|
||||||
const filterFunction = (list: typeof frameworks, search: string) => list.filter(i => i.value.toLowerCase().includes(search.toLowerCase()))
|
// const filterFunction = (list: typeof frameworks, search: string) => list.filter(i => i.value.toLowerCase().includes(search.toLowerCase()))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -41,33 +41,36 @@ const filterFunction = (list: typeof frameworks, search: string) => list.filter(
|
||||||
:aria-expanded="open"
|
:aria-expanded="open"
|
||||||
class="w-[200px] justify-between"
|
class="w-[200px] justify-between"
|
||||||
>
|
>
|
||||||
{{ value ? value.label : 'Select framework...' }}
|
{{ value
|
||||||
|
? frameworks.find((framework) => framework.value === value)?.label
|
||||||
|
: "Select framework..." }}
|
||||||
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent class="w-[200px] p-0">
|
<PopoverContent class="w-[200px] p-0">
|
||||||
<Command :filter-function="filterFunction">
|
<Command>
|
||||||
<CommandInput placeholder="Search framework..." />
|
<CommandInput class="h-9" placeholder="Search framework..." />
|
||||||
<CommandEmpty>No framework found.</CommandEmpty>
|
<CommandEmpty>No framework found.</CommandEmpty>
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
<CommandItem
|
<CommandItem
|
||||||
v-for="framework in frameworks"
|
v-for="framework in frameworks"
|
||||||
:key="framework.value"
|
:key="framework.value"
|
||||||
:value="framework"
|
:value="framework.value"
|
||||||
@select="(ev) => {
|
@select="(ev) => {
|
||||||
value = ev.detail.value
|
if (typeof ev.detail.value === 'string') {
|
||||||
console.log(ev)
|
value = ev.detail.value
|
||||||
|
}
|
||||||
open = false
|
open = false
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
{{ framework.label }}
|
||||||
<Check
|
<Check
|
||||||
:class="cn(
|
:class="cn(
|
||||||
'mr-2 h-4 w-4',
|
'ml-auto h-4 w-4',
|
||||||
value?.value === framework.value ? 'opacity-100' : 'opacity-0',
|
value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||||
)"
|
)"
|
||||||
/>
|
/>
|
||||||
{{ framework.label }}
|
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
</CommandList>
|
</CommandList>
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,22 @@ import {
|
||||||
|
|
||||||
const open = ref(false)
|
const open = ref(false)
|
||||||
|
|
||||||
const keys = useMagicKeys()
|
const { Meta_J, Ctrl_J } = useMagicKeys({
|
||||||
const CmdJ = keys['Cmd+J']
|
passive: false,
|
||||||
|
onEventFired(e) {
|
||||||
|
if (e.key === 'j' && (e.metaKey || e.ctrlKey))
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
watch([Meta_J, Ctrl_J], (v) => {
|
||||||
|
if (v[0] || v[1])
|
||||||
|
handleOpenChange()
|
||||||
|
})
|
||||||
|
|
||||||
function handleOpenChange() {
|
function handleOpenChange() {
|
||||||
open.value = !open.value
|
open.value = !open.value
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(CmdJ, (v) => {
|
|
||||||
if (v)
|
|
||||||
handleOpenChange()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -37,7 +42,7 @@ watch(CmdJ, (v) => {
|
||||||
<span class="text-xs">⌘</span>J
|
<span class="text-xs">⌘</span>J
|
||||||
</kbd>
|
</kbd>
|
||||||
</p>
|
</p>
|
||||||
<CommandDialog :open="open" :on-open-change="handleOpenChange">
|
<CommandDialog v-model:open="open">
|
||||||
<CommandInput placeholder="Type a command or search..." />
|
<CommandInput placeholder="Type a command or search..." />
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>No results found.</CommandEmpty>
|
<CommandEmpty>No results found.</CommandEmpty>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type {
|
||||||
|
ColumnDef,
|
||||||
|
ColumnFiltersState,
|
||||||
|
SortingState,
|
||||||
|
VisibilityState,
|
||||||
|
} from '@tanstack/vue-table'
|
||||||
|
import {
|
||||||
|
FlexRender,
|
||||||
|
createColumnHelper,
|
||||||
|
getCoreRowModel,
|
||||||
|
getFilteredRowModel,
|
||||||
|
getPaginationRowModel,
|
||||||
|
getSortedRowModel,
|
||||||
|
|
||||||
|
useVueTable,
|
||||||
|
} from '@tanstack/vue-table'
|
||||||
|
import { ArrowUpDown, ChevronDown } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { h, ref } from 'vue'
|
||||||
|
import DropdownAction from './DataTableDemoColumn.vue'
|
||||||
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
import { Checkbox } from '@/lib/registry/default/ui/checkbox'
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/lib/registry/default/ui/dropdown-menu'
|
||||||
|
import { Input } from '@/lib/registry/default/ui/input'
|
||||||
|
import {
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableHead,
|
||||||
|
TableHeader,
|
||||||
|
TableRow,
|
||||||
|
} from '@/lib/registry/default/ui/table'
|
||||||
|
import { cn, valueUpdater } from '@/lib/utils'
|
||||||
|
|
||||||
|
export interface Payment {
|
||||||
|
id: string
|
||||||
|
amount: number
|
||||||
|
status: 'pending' | 'processing' | 'success' | 'failed'
|
||||||
|
email: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: Payment[] = [
|
||||||
|
{
|
||||||
|
id: 'm5gr84i9',
|
||||||
|
amount: 316,
|
||||||
|
status: 'success',
|
||||||
|
email: 'ken99@yahoo.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3u1reuv4',
|
||||||
|
amount: 242,
|
||||||
|
status: 'success',
|
||||||
|
email: 'Abe45@gmail.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'derv1ws0',
|
||||||
|
amount: 837,
|
||||||
|
status: 'processing',
|
||||||
|
email: 'Monserrat44@gmail.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5kma53ae',
|
||||||
|
amount: 874,
|
||||||
|
status: 'success',
|
||||||
|
email: 'Silas22@gmail.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'bhqecj4p',
|
||||||
|
amount: 721,
|
||||||
|
status: 'failed',
|
||||||
|
email: 'carmella@hotmail.com',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const columnHelper = createColumnHelper<Payment>()
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
columnHelper.display({
|
||||||
|
id: 'select',
|
||||||
|
header: ({ table }) => h(Checkbox, {
|
||||||
|
'checked': table.getIsAllPageRowsSelected(),
|
||||||
|
'onUpdate:checked': value => table.toggleAllPageRowsSelected(!!value),
|
||||||
|
'ariaLabel': 'Select all',
|
||||||
|
}),
|
||||||
|
cell: ({ row, column }) => {
|
||||||
|
return h(Checkbox, {
|
||||||
|
'checked': row.getIsSelected(),
|
||||||
|
'onUpdate:checked': value => row.toggleSelected(!!value),
|
||||||
|
'ariaLabel': 'Select row',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
enableSorting: false,
|
||||||
|
enableHiding: false,
|
||||||
|
}),
|
||||||
|
columnHelper.accessor('status', {
|
||||||
|
enablePinning: true,
|
||||||
|
header: 'Status',
|
||||||
|
cell: ({ row }) => h('div', { class: 'capitalize' }, row.getValue('status')),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor('email', {
|
||||||
|
header: ({ column }) => {
|
||||||
|
return h(Button, {
|
||||||
|
variant: 'ghost',
|
||||||
|
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'),
|
||||||
|
}, () => ['Email', h(ArrowUpDown, { class: 'ml-2 h-4 w-4' })])
|
||||||
|
},
|
||||||
|
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')),
|
||||||
|
}),
|
||||||
|
columnHelper.accessor('amount', {
|
||||||
|
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const amount = Number.parseFloat(row.getValue('amount'))
|
||||||
|
|
||||||
|
// Format the amount as a dollar amount
|
||||||
|
const formatted = new Intl.NumberFormat('en-US', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'USD',
|
||||||
|
}).format(amount)
|
||||||
|
|
||||||
|
return h('div', { class: 'text-right font-medium' }, formatted)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
columnHelper.display({
|
||||||
|
id: 'actions',
|
||||||
|
enableHiding: false,
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const payment = row.original
|
||||||
|
|
||||||
|
return h('div', { class: 'relative' }, h(DropdownAction, {
|
||||||
|
payment,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
|
const sorting = ref<SortingState>([])
|
||||||
|
const columnFilters = ref<ColumnFiltersState>([])
|
||||||
|
const columnVisibility = ref<VisibilityState>({})
|
||||||
|
const rowSelection = ref({})
|
||||||
|
|
||||||
|
const table = useVueTable({
|
||||||
|
data,
|
||||||
|
columns,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
getSortedRowModel: getSortedRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sorting),
|
||||||
|
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFilters),
|
||||||
|
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibility),
|
||||||
|
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelection),
|
||||||
|
state: {
|
||||||
|
get sorting() { return sorting.value },
|
||||||
|
get columnFilters() { return columnFilters.value },
|
||||||
|
get columnVisibility() { return columnVisibility.value },
|
||||||
|
get rowSelection() { return rowSelection.value },
|
||||||
|
columnPinning: {
|
||||||
|
left: ['status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const getState = table.getState()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full">
|
||||||
|
<div class="flex gap-2 items-center py-4">
|
||||||
|
<Input
|
||||||
|
class="max-w-sm"
|
||||||
|
placeholder="Filter emails..."
|
||||||
|
:model-value="table.getColumn('email')?.getFilterValue() as string"
|
||||||
|
@update:model-value=" table.getColumn('email')?.setFilterValue($event)"
|
||||||
|
/>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger as-child>
|
||||||
|
<Button variant="outline" class="ml-auto">
|
||||||
|
Columns <ChevronDown class="ml-2 h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<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) => {
|
||||||
|
column.toggleVisibility(!!value)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ column.id }}
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
<div class="rounded-md border">
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow v-for="headerGroup in table.getHeaderGroups()" :key="headerGroup.id">
|
||||||
|
<TableHead
|
||||||
|
v-for="header in headerGroup.headers" :key="header.id" :data-pinned="header.column.getIsPinned()"
|
||||||
|
:class="cn(
|
||||||
|
{ 'sticky bg-background/95': header.column.getIsPinned() },
|
||||||
|
header.column.getIsPinned() === 'left' ? 'left-0' : 'right-0',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
|
||||||
|
</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
<template v-if="table.getRowModel().rows?.length">
|
||||||
|
<TableRow
|
||||||
|
v-for="row in table.getRowModel().rows"
|
||||||
|
:key="row.id"
|
||||||
|
:data-state="row.getIsSelected() && 'selected'"
|
||||||
|
>
|
||||||
|
<TableCell
|
||||||
|
v-for="cell in row.getVisibleCells()" :key="cell.id" :data-pinned="cell.column.getIsPinned()"
|
||||||
|
:class="cn(
|
||||||
|
{ 'sticky bg-background/95': cell.column.getIsPinned() },
|
||||||
|
cell.column.getIsPinned() === 'left' ? 'left-0' : 'right-0',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<TableRow v-else>
|
||||||
|
<TableCell
|
||||||
|
col-span="{columns.length}"
|
||||||
|
class="h-24 text-center"
|
||||||
|
>
|
||||||
|
No results.
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center justify-end space-x-2 py-4">
|
||||||
|
<div class="flex-1 text-sm text-muted-foreground">
|
||||||
|
{{ table.getFilteredSelectedRowModel().rows.length }} of
|
||||||
|
{{ table.getFilteredRowModel().rows.length }} row(s) selected.
|
||||||
|
</div>
|
||||||
|
<div class="space-x-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
:disabled="!table.getCanPreviousPage()"
|
||||||
|
@click="table.previousPage()"
|
||||||
|
>
|
||||||
|
Previous
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
:disabled="!table.getCanNextPage()"
|
||||||
|
@click="table.nextPage()"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -40,7 +40,7 @@ const date = ref({
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent class="w-auto p-0" align="start" :avoid-collisions="true">
|
<PopoverContent class="w-auto p-0" align="start">
|
||||||
<Calendar
|
<Calendar
|
||||||
v-model.range="date"
|
v-model.range="date"
|
||||||
:columns="2"
|
:columns="2"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
import { Calendar as CalendarIcon } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
import { Calendar } from '@/lib/registry/default/ui/calendar'
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from '@/lib/registry/default/ui/popover'
|
||||||
|
|
||||||
|
const date = ref<Date>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger as-child>
|
||||||
|
<Button
|
||||||
|
:variant="'outline'"
|
||||||
|
:class="cn(
|
||||||
|
'w-[280px] justify-start text-left font-normal',
|
||||||
|
!date && 'text-muted-foreground',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||||
|
<span>{{ date ? format(date, 'PPP - hh:mm') : "Pick a date" }}</span>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent class="w-auto p-0">
|
||||||
|
<Calendar v-model="date" mode="datetime" />
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</template>
|
||||||
|
|
@ -31,7 +31,7 @@ import { Label } from '@/lib/registry/default/ui/label'
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<div class="grid flex-1 gap-2">
|
<div class="grid flex-1 gap-2">
|
||||||
<Label html-for="link" class="sr-only">
|
<Label for="link" class="sr-only">
|
||||||
Link
|
Link
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ const components: { title: string; href: string; description: string }[] = [
|
||||||
<NavigationMenuItem>
|
<NavigationMenuItem>
|
||||||
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
|
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
|
||||||
<NavigationMenuContent>
|
<NavigationMenuContent>
|
||||||
<ul class="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
|
<ul class="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[minmax(0,.75fr)_minmax(0,1fr)]">
|
||||||
<li class="row-span-3">
|
<li class="row-span-3">
|
||||||
<NavigationMenuLink as-child>
|
<NavigationMenuLink as-child>
|
||||||
<a
|
<a
|
||||||
|
|
|
||||||
28
apps/www/src/lib/registry/default/example/PinInputDemo.vue
Normal file
28
apps/www/src/lib/registry/default/example/PinInputDemo.vue
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import {
|
||||||
|
PinInput,
|
||||||
|
PinInputInput,
|
||||||
|
} from '@/lib/registry/default/ui/pin-input'
|
||||||
|
|
||||||
|
const value = ref<string[]>([])
|
||||||
|
const handleComplete = (e: string[]) => alert(e.join(''))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<PinInput
|
||||||
|
id="pin-input"
|
||||||
|
v-model="value"
|
||||||
|
placeholder="○"
|
||||||
|
class="flex gap-2 items-center mt-1"
|
||||||
|
@complete="handleComplete"
|
||||||
|
>
|
||||||
|
<PinInputInput
|
||||||
|
v-for="(id, index) in 5"
|
||||||
|
:key="id"
|
||||||
|
:index="index"
|
||||||
|
/>
|
||||||
|
</PinInput>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { h } from 'vue'
|
||||||
|
import { useForm } from 'vee-validate'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import * as z from 'zod'
|
||||||
|
import {
|
||||||
|
PinInput,
|
||||||
|
PinInputInput,
|
||||||
|
} from '@/lib/registry/new-york/ui/pin-input'
|
||||||
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from '@/lib/registry/default/ui/form'
|
||||||
|
import { toast } from '@/lib/registry/default/ui/toast'
|
||||||
|
|
||||||
|
const formSchema = toTypedSchema(z.object({
|
||||||
|
pin: z.array(z.coerce.string()).length(5, { message: 'Invalid input' }),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { handleSubmit, setValues } = useForm({
|
||||||
|
validationSchema: formSchema,
|
||||||
|
initialValues: {
|
||||||
|
pin: [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSubmit = handleSubmit(({ pin }) => {
|
||||||
|
toast({
|
||||||
|
title: 'You submitted the following values:',
|
||||||
|
description: h('pre', { class: 'mt-2 w-[340px] rounded-md bg-slate-950 p-4' }, h('code', { class: 'text-white' }, JSON.stringify(pin.join(''), null, 2))),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleComplete = (e: string[]) => console.log(e.join(''))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form class="w-2/3 space-y-6 mx-auto" @submit="onSubmit">
|
||||||
|
<FormField v-slot="{ componentField }" name="pin">
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>OTP</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<PinInput
|
||||||
|
id="pin-input"
|
||||||
|
placeholder="○"
|
||||||
|
class="flex gap-2 items-center mt-1"
|
||||||
|
otp
|
||||||
|
type="number"
|
||||||
|
:name="componentField.name"
|
||||||
|
@complete="handleComplete"
|
||||||
|
@update:model-value="(arrStr) => {
|
||||||
|
setValues({
|
||||||
|
pin: arrStr.filter(Boolean),
|
||||||
|
})
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<PinInputInput
|
||||||
|
v-for="(id, index) in 5"
|
||||||
|
:key="id"
|
||||||
|
:index="index"
|
||||||
|
/>
|
||||||
|
</PinInput>
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
Allows users to input a sequence of one-character alphanumeric inputs.
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
|
||||||
|
<Button>Submit</Button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
@ -11,5 +11,5 @@ watchEffect((cleanupFn) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Progress v-model="progress" class="w-[60%]" />
|
<Progress v-model="progress" class="w-3/5" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ const onSubmit = handleSubmit((values) => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form class="w-2/3 space-y-6" @submit="onSubmit">
|
<form class="w-2/3 space-y-6" @submit="onSubmit">
|
||||||
<FormField v-slot="{ componentField }" name="type">
|
<FormField v-slot="{ componentField }" type="radio" name="type">
|
||||||
<FormItem class="space-y-3">
|
<FormItem class="space-y-3">
|
||||||
<FormLabel>Notify me about...</FormLabel>
|
<FormLabel>Notify me about...</FormLabel>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { addDays, format } from 'date-fns'
|
||||||
|
import { Calendar as CalendarIcon } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
import { Calendar } from '@/lib/registry/default/ui/calendar'
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from '@/lib/registry/default/ui/popover'
|
||||||
|
|
||||||
|
const date = ref({
|
||||||
|
start: new Date(2022, 0, 20),
|
||||||
|
end: addDays(new Date(2022, 0, 20), 20),
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('grid gap-2', $attrs.class ?? '')">
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger as-child>
|
||||||
|
<Button
|
||||||
|
id="date"
|
||||||
|
:variant="'outline'"
|
||||||
|
:class="cn(
|
||||||
|
'w-[300px] justify-start text-left font-normal',
|
||||||
|
!date && 'text-muted-foreground',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<CalendarIcon class="mr-2 h-4 w-4" />
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{ date.start ? (
|
||||||
|
date.end ? `${format(date.start, 'LLL dd, y')} - ${format(date.end, 'LLL dd, y')}`
|
||||||
|
: format(date.start, 'LLL dd, y')
|
||||||
|
) : 'Pick a date' }}
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent class="w-auto p-0" align="start">
|
||||||
|
<Calendar
|
||||||
|
v-model.range="date"
|
||||||
|
mode="date"
|
||||||
|
:columns="2"
|
||||||
|
>
|
||||||
|
<template #footer>
|
||||||
|
<div class="w-full px-3 pb-3">
|
||||||
|
Entry time
|
||||||
|
<Calendar
|
||||||
|
v-model="date.start"
|
||||||
|
mode="time"
|
||||||
|
hide-time-header
|
||||||
|
/>
|
||||||
|
Exit time
|
||||||
|
<Calendar
|
||||||
|
v-model="date.end"
|
||||||
|
mode="time"
|
||||||
|
hide-time-header
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Calendar>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -11,6 +11,6 @@ const modelValue = ref([50])
|
||||||
v-model="modelValue"
|
v-model="modelValue"
|
||||||
:max="100"
|
:max="100"
|
||||||
:step="1"
|
:step="1"
|
||||||
:class="cn('w-[60%]', $attrs.class ?? '')"
|
:class="cn('w-3/5', $attrs.class ?? '')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
20
apps/www/src/lib/registry/default/example/SonnerDemo.vue
Normal file
20
apps/www/src/lib/registry/default/example/SonnerDemo.vue
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { toast } from 'vue-sonner'
|
||||||
|
import { Button } from '@/lib/registry/default/ui/button'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Button
|
||||||
|
variant="outline" @click="() => {
|
||||||
|
toast('Event has been created', {
|
||||||
|
description: 'Sunday, December 03, 2023 at 9:00 AM',
|
||||||
|
action: {
|
||||||
|
label: 'Undo',
|
||||||
|
onClick: () => console.log('Undo'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
Add to calander
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Bold, Italic, Underline } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/default/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="multiple">
|
||||||
|
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||||
|
<Bold class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||||
|
<Italic class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||||
|
<Underline class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Bold, Italic, Underline } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/default/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="multiple" disabled>
|
||||||
|
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||||
|
<Bold class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||||
|
<Italic class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||||
|
<Underline class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Bold, Italic, Underline } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/default/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="multiple" size="lg">
|
||||||
|
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||||
|
<Bold class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||||
|
<Italic class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||||
|
<Underline class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Bold, Italic, Underline } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/default/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="multiple" variant="outline">
|
||||||
|
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||||
|
<Bold class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||||
|
<Italic class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||||
|
<Underline class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Bold, Italic, Underline } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/default/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="single">
|
||||||
|
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||||
|
<Bold class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||||
|
<Italic class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||||
|
<Underline class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Bold, Italic, Underline } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
import { ToggleGroup, ToggleGroupItem } from '@/lib/registry/default/ui/toggle-group'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ToggleGroup type="multiple" size="sm">
|
||||||
|
<ToggleGroupItem value="bold" aria-label="Toggle bold">
|
||||||
|
<Bold class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="italic" aria-label="Toggle italic">
|
||||||
|
<Italic class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
<ToggleGroupItem value="underline" aria-label="Toggle underline">
|
||||||
|
<Underline class="h-4 w-4" />
|
||||||
|
</ToggleGroupItem>
|
||||||
|
</ToggleGroup>
|
||||||
|
</template>
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { default as AccordionDemo } from './AccordionDemo.vue'
|
|
||||||
|
|
@ -3,15 +3,17 @@ import {
|
||||||
AccordionRoot,
|
AccordionRoot,
|
||||||
type AccordionRootEmits,
|
type AccordionRootEmits,
|
||||||
type AccordionRootProps,
|
type AccordionRootProps,
|
||||||
useEmitAsProps,
|
useForwardPropsEmits,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
|
|
||||||
const props = defineProps<AccordionRootProps>()
|
const props = defineProps<AccordionRootProps>()
|
||||||
const emits = defineEmits<AccordionRootEmits>()
|
const emits = defineEmits<AccordionRootEmits>()
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(props, emits)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AccordionRoot v-bind="{ ...props, ...useEmitAsProps(emits) }">
|
<AccordionRoot v-bind="forwarded">
|
||||||
<slot />
|
<slot />
|
||||||
</AccordionRoot>
|
</AccordionRoot>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,23 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import { AccordionContent, type AccordionContentProps } from 'radix-vue'
|
import { AccordionContent, type AccordionContentProps } from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<AccordionContentProps & { class?: string }>()
|
const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AccordionContent
|
<AccordionContent
|
||||||
v-bind="props"
|
v-bind="delegatedProps"
|
||||||
:class="
|
class="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||||
cn(
|
|
||||||
'overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
|
|
||||||
props.class,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<div class="pb-4 pt-0">
|
<div :class="cn('pb-4 pt-0', props.class)">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,23 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AccordionItem, type AccordionItemProps } from 'radix-vue'
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
|
import { AccordionItem, type AccordionItemProps, useForwardProps } from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<AccordionItemProps & { class?: string }>()
|
const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
|
|
||||||
|
const forwardedProps = useForwardProps(delegatedProps)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AccordionItem
|
<AccordionItem
|
||||||
v-bind="props"
|
v-bind="forwardedProps"
|
||||||
:class="cn('border-b', props.class ?? '')"
|
:class="cn('border-b', props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import {
|
import {
|
||||||
AccordionHeader,
|
AccordionHeader,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
|
|
@ -7,13 +8,19 @@ import {
|
||||||
import { ChevronDown } from 'lucide-vue-next'
|
import { ChevronDown } from 'lucide-vue-next'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<AccordionTriggerProps & { class?: string }>()
|
const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AccordionHeader class="flex" as="div">
|
<AccordionHeader class="flex">
|
||||||
<AccordionTrigger
|
<AccordionTrigger
|
||||||
v-bind="props"
|
v-bind="delegatedProps"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
||||||
|
|
@ -22,9 +29,11 @@ const props = defineProps<AccordionTriggerProps & { class?: string }>()
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
<ChevronDown
|
<slot name="icon">
|
||||||
class="h-4 w-4 shrink-0 transition-transform duration-200"
|
<ChevronDown
|
||||||
/>
|
class="h-4 w-4 shrink-0 transition-transform duration-200"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
</AccordionHeader>
|
</AccordionHeader>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue'
|
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
||||||
|
|
||||||
const props = defineProps<AlertDialogActionProps>()
|
const props = defineProps<AlertDialogActionProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AlertDialogAction v-bind="props" :class="cn(buttonVariants(), $attrs.class ?? '')">
|
<AlertDialogAction v-bind="delegatedProps" :class="cn(buttonVariants(), props.class)">
|
||||||
<slot />
|
<slot />
|
||||||
</AlertDialogAction>
|
</AlertDialogAction>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue'
|
import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
||||||
|
|
||||||
const props = defineProps<AlertDialogCancelProps>()
|
const props = defineProps<AlertDialogCancelProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AlertDialogCancel v-bind="props" :class="cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', $attrs.class ?? '')">
|
<AlertDialogCancel v-bind="delegatedProps" :class="cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', props.class)">
|
||||||
<slot />
|
<slot />
|
||||||
</AlertDialogCancel>
|
</AlertDialogCancel>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,37 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import {
|
import {
|
||||||
AlertDialogContent,
|
AlertDialogContent,
|
||||||
type AlertDialogContentEmits,
|
type AlertDialogContentEmits,
|
||||||
type AlertDialogContentProps,
|
type AlertDialogContentProps,
|
||||||
AlertDialogOverlay,
|
AlertDialogOverlay,
|
||||||
AlertDialogPortal,
|
AlertDialogPortal,
|
||||||
useEmitAsProps,
|
useForwardPropsEmits,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<AlertDialogContentProps & { class?: string }>()
|
const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes['class'] }>()
|
||||||
const emits = defineEmits<AlertDialogContentEmits>()
|
const emits = defineEmits<AlertDialogContentEmits>()
|
||||||
|
|
||||||
const emitsAsProps = useEmitAsProps(emits)
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AlertDialogPortal>
|
<AlertDialogPortal>
|
||||||
<AlertDialogOverlay
|
<AlertDialogOverlay
|
||||||
class="fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
|
||||||
/>
|
/>
|
||||||
<AlertDialogContent
|
<AlertDialogContent
|
||||||
v-bind="{ ...props, ...emitsAsProps }"
|
v-bind="forwarded"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full',
|
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import {
|
import {
|
||||||
AlertDialogDescription,
|
AlertDialogDescription,
|
||||||
type AlertDialogDescriptionProps,
|
type AlertDialogDescriptionProps,
|
||||||
} from 'radix-vue'
|
} from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<AlertDialogDescriptionProps & { class?: string }>()
|
const props = defineProps<AlertDialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AlertDialogDescription
|
<AlertDialogDescription
|
||||||
:class="cn('text-muted-foreground text-sm', props.class)"
|
v-bind="delegatedProps"
|
||||||
:as-child="props.asChild"
|
:class="cn('text-sm text-muted-foreground', props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</AlertDialogDescription>
|
</AlertDialogDescription>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps<{
|
||||||
class: {
|
class?: HTMLAttributes['class']
|
||||||
type: String,
|
}>()
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'flex flex-col space-y-2 sm:space-y-0 mt-3.5 sm:flex-row sm:justify-end sm:space-x-2',
|
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { HTMLAttributes } from 'vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps<{
|
||||||
class: {
|
class?: HTMLAttributes['class']
|
||||||
type: String,
|
}>()
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="cn('flex flex-col space-y-2 text-center sm:text-left', props.class)"
|
:class="cn('flex flex-col gap-y-2 text-center sm:text-left', props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,21 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { type HTMLAttributes, computed } from 'vue'
|
||||||
import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue'
|
import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const props = defineProps<AlertDialogTitleProps & { class?: string }>()
|
const props = defineProps<AlertDialogTitleProps & { class?: HTMLAttributes['class'] }>()
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props
|
||||||
|
|
||||||
|
return delegated
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AlertDialogTitle
|
<AlertDialogTitle
|
||||||
:as-child="props.asChild"
|
v-bind="delegatedProps"
|
||||||
:class="cn('text-lg text-foreground font-semibold', props.class)"
|
:class="cn('text-lg font-semibold', props.class)"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</AlertDialogTitle>
|
</AlertDialogTitle>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { alertVariants } from '.'
|
import type { HTMLAttributes } from 'vue'
|
||||||
|
import { type AlertVariants, alertVariants } from '.'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
interface Props {
|
const props = defineProps<{
|
||||||
variant?: NonNullable<Parameters<typeof alertVariants>[0]>['variant']
|
class?: HTMLAttributes['class']
|
||||||
class?: string
|
variant?: AlertVariants['variant']
|
||||||
}
|
}>()
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="cn(alertVariants({ variant }), props.class ?? '')">
|
<div :class="cn(alertVariants({ variant }), props.class)" role="alert">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user