Merge branch 'dev' into feature/command-custom-filter
This commit is contained in:
commit
f9c7e15dfe
|
|
@ -1,19 +0,0 @@
|
|||
// const process = require('node:process')
|
||||
// process.env.ESLINT_TSCONFIG = 'tsconfig.json'
|
||||
|
||||
module.exports = {
|
||||
extends: '@antfu',
|
||||
|
||||
rules: {
|
||||
'vue/one-component-per-file': 'off',
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
'vue/no-useless-v-bind': 'off',
|
||||
'symbol-description': 'off',
|
||||
'no-console': 'warn',
|
||||
'no-tabs': 'off',
|
||||
'no-invalid-character': 'off',
|
||||
'import/first': 'off',
|
||||
'@stylistic/js/no-tabs': 'off',
|
||||
'n/prefer-global/process': 'off',
|
||||
},
|
||||
}
|
||||
77
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
77
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
|
|
@ -6,62 +6,27 @@ body:
|
|||
- type: markdown
|
||||
attributes:
|
||||
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
|
||||
or are unsure if this is really a bug, make sure to:
|
||||
|
||||
- Read the [docs](https://radix-vue.com/)
|
||||
- Ask on [Discord Chat](https://chat.radix-vue.com/)
|
||||
- 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
|
||||
id: reproduction-link
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Link to minimal reproduction
|
||||
label: Reproduction
|
||||
description: |
|
||||
Please provide a link to a minimal reproduction of the bug.
|
||||
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
|
||||
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)
|
||||
|
||||
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.
|
||||
placeholder: Reproduction Link
|
||||
validations:
|
||||
required: true
|
||||
- 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
|
||||
or use template presets
|
||||
https://vite.new
|
||||
https://nuxt.new
|
||||
placeholder: Reproduction
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
|
@ -73,14 +38,18 @@ body:
|
|||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
id: system-info
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
label: System Info
|
||||
description: Output of `npx envinfo --system --npmPackages vue,@vueuse/core,radix-vue,nuxt,shadcn-vue,shadcn-nuxt,unplugin-auto-import --binaries --browsers`
|
||||
render: bash
|
||||
placeholder: System, Binaries, Browsers
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: contributes
|
||||
attributes:
|
||||
label: Conext & Screenshots (if applicable)
|
||||
description: |
|
||||
If applicable, provide any additional context or screenshots of the bug.
|
||||
You can drag and drop images here to add them to the issue.
|
||||
label: Contributes
|
||||
options:
|
||||
- label: I am willing to submit a PR to fix this issue
|
||||
- label: I am willing to submit a PR with failing tests
|
||||
|
|
|
|||
5
.github/workflows/publish.yaml
vendored
5
.github/workflows/publish.yaml
vendored
|
|
@ -17,8 +17,6 @@ on:
|
|||
- opened
|
||||
# When a labeled '🚀request-deploy' pull request from forked repo, it will be deploy to Cloudflare Pages
|
||||
- labeled
|
||||
paths:
|
||||
- 'apps/www/**'
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
# eslint-disable-next-line yml/no-empty-mapping-value
|
||||
workflow_dispatch:
|
||||
|
|
@ -52,9 +50,6 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
# Run a build step here
|
||||
- name: Setup Node.js environment
|
||||
|
|
|
|||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
|
|
@ -1,11 +1,23 @@
|
|||
{
|
||||
"eslint.experimental.useFlatConfig": true,
|
||||
"prettier.enable": false,
|
||||
"editor.formatOnSave": false,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "never"
|
||||
},
|
||||
|
||||
"eslint.rules.customizations": [
|
||||
{ "rule": "style/*", "severity": "off" },
|
||||
{ "rule": "format/*", "severity": "off" },
|
||||
{ "rule": "*-indent", "severity": "off" },
|
||||
{ "rule": "*-spacing", "severity": "off" },
|
||||
{ "rule": "*-spaces", "severity": "off" },
|
||||
{ "rule": "*-order", "severity": "off" },
|
||||
{ "rule": "*-dangle", "severity": "off" },
|
||||
{ "rule": "*-newline", "severity": "off" },
|
||||
{ "rule": "*quotes", "severity": "off" },
|
||||
{ "rule": "*semi", "severity": "off" }
|
||||
],
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@ import { defineConfig } from 'vitepress'
|
|||
import Icons from 'unplugin-icons/vite'
|
||||
import tailwind from 'tailwindcss'
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import { createCssVariablesTheme } from 'shikiji'
|
||||
import { createCssVariablesTheme } from 'shiki'
|
||||
|
||||
// import { transformerMetaWordHighlight, transformerNotationWordHighlight } from '@shikijs/transformers'
|
||||
import { siteConfig } from './theme/config/site'
|
||||
import ComponentPreviewPlugin from './theme/plugins/previewer'
|
||||
|
||||
const cssVariables = createCssVariablesTheme({
|
||||
name: 'css-variables',
|
||||
variablePrefix: '--shiki-',
|
||||
variableDefaults: {},
|
||||
fontStyle: true,
|
||||
})
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
|
|
@ -59,6 +59,10 @@ export default defineConfig({
|
|||
srcDir: path.resolve(__dirname, '../src'),
|
||||
markdown: {
|
||||
theme: cssVariables,
|
||||
codeTransformers: [
|
||||
// transformerMetaWordHighlight(),
|
||||
// transformerNotationWordHighlight(),
|
||||
],
|
||||
config(md) {
|
||||
md.use(ComponentPreviewPlugin)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ const kbdClass = computed(() => {
|
|||
{
|
||||
variants: {
|
||||
size: {
|
||||
xs: 'min-h-[16px] text-[10px] h-4 px-1',
|
||||
sm: 'min-h-[20px] text-[11px] h-5 px-1',
|
||||
md: 'min-h-[24px] text-[12px] h-6 px-1.5',
|
||||
xs: 'min-h-4 text-[10px] h-4 px-1',
|
||||
sm: 'min-h-5 text-[11px] h-5 px-1',
|
||||
md: 'min-h-6 text-[12px] h-6 px-1.5',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import PageHeader from '../components/PageHeader.vue'
|
||||
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
||||
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
||||
import PageAction from '../components/PageAction.vue'
|
||||
import ExamplesNav from '../components/ExamplesNav.vue'
|
||||
import { announcementConfig } from '../config/site'
|
||||
import GitHubIcon from '~icons/radix-icons/github-logo'
|
||||
|
|
@ -31,7 +32,7 @@ import DashboardExample from '@/examples/dashboard/Example.vue'
|
|||
apps. Accessible. Customizable. Open Source.
|
||||
</PageHeaderDescription>
|
||||
|
||||
<section class="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
|
||||
<PageAction>
|
||||
<a
|
||||
href="/docs/introduction"
|
||||
:class="cn(buttonVariants(), 'rounded-[6px]')"
|
||||
|
|
@ -49,7 +50,7 @@ import DashboardExample from '@/examples/dashboard/Example.vue'
|
|||
<GitHubIcon class="mr-2 h-4 w-4" />
|
||||
GitHub
|
||||
</a>
|
||||
</section>
|
||||
</PageAction>
|
||||
</PageHeader>
|
||||
<ExamplesNav />
|
||||
<section class="space-y-8 overflow-hidden rounded-lg border-2 border-primary dark:border-muted md:hidden">
|
||||
|
|
|
|||
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>
|
||||
<section
|
||||
: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 ?? '',
|
||||
)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { cn } from '@/lib/utils'
|
|||
</script>
|
||||
|
||||
<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 />
|
||||
</WrapBalancer>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { cn } from '@/lib/utils'
|
|||
<template>
|
||||
<h1
|
||||
: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 ?? '',
|
||||
)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -254,6 +254,12 @@ export const docsConfig: DocsConfig = {
|
|||
href: '/docs/components/pagination',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Pin Input',
|
||||
href: '/docs/components/pin-input',
|
||||
label: 'New',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Popover',
|
||||
href: '/docs/components/popover',
|
||||
|
|
@ -299,6 +305,12 @@ export const docsConfig: DocsConfig = {
|
|||
href: '/docs/components/slider',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Sonner',
|
||||
href: '/docs/components/sonner',
|
||||
label: 'New',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Switch',
|
||||
href: '/docs/components/switch',
|
||||
|
|
@ -314,6 +326,12 @@ export const docsConfig: DocsConfig = {
|
|||
href: '/docs/components/tabs',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Tags Input',
|
||||
href: '/docs/components/tags-input',
|
||||
label: 'New',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: 'Textarea',
|
||||
href: '/docs/components/textarea',
|
||||
|
|
@ -322,7 +340,6 @@ export const docsConfig: DocsConfig = {
|
|||
{
|
||||
title: 'Toast',
|
||||
href: '/docs/components/toast',
|
||||
label: 'New',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ export const siteConfig = {
|
|||
|
||||
export const announcementConfig = {
|
||||
icon: '✨',
|
||||
title: 'VSCode extension',
|
||||
link: '/docs/installation.html#vscode-extension',
|
||||
title: 'New components!',
|
||||
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 { Badge } from '@/lib/registry/default/ui/badge'
|
||||
import RadixIconsCode from '~icons/radix-icons/code'
|
||||
import RadixIconsExternalLink from '~icons/radix-icons/external-link'
|
||||
import ChevronRightIcon from '~icons/lucide/chevron-right'
|
||||
|
||||
const $route = useRoute()
|
||||
|
|
@ -20,7 +21,7 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
|
|||
<aside
|
||||
class="fixed top-14 z-30 -ml-2 hidden h-[calc(100vh-3.5rem)] w-full shrink-0 md:sticky md:block overflow-y-auto"
|
||||
>
|
||||
<ScrollArea orientation="vertical" class="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 v-for="docsGroup in docsConfig.sidebarNav" :key="docsGroup.title" class="pb-4">
|
||||
<h4
|
||||
|
|
@ -45,9 +46,9 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
|
|||
>
|
||||
{{ doc.title }}
|
||||
|
||||
<Badge v-if="doc.label" class="ml-2" :variant="'secondary'">
|
||||
<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 }}
|
||||
</Badge>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -81,6 +82,10 @@ const sourceLink = 'https://github.com/radix-vue/shadcn-vue/tree/dev/'
|
|||
</div>
|
||||
|
||||
<div class="flex items-center space-x-2 pt-4">
|
||||
<a v-if="frontmatter.docs" :href="frontmatter.docs" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
|
||||
<RadixIconsExternalLink class="mr-1" />
|
||||
Docs
|
||||
</a>
|
||||
<a v-if="frontmatter.source" :href="sourceLink + frontmatter.source" target="_blank" class="inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 select-none border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80">
|
||||
<RadixIconsCode class="mr-1" />
|
||||
Component Source
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import PageHeader from '../components/PageHeader.vue'
|
||||
import PageHeaderHeading from '../components/PageHeaderHeading.vue'
|
||||
import PageHeaderDescription from '../components/PageHeaderDescription.vue'
|
||||
import PageAction from '../components/PageAction.vue'
|
||||
import ExamplesNav from '../components/ExamplesNav.vue'
|
||||
import { announcementConfig } from '../config/site'
|
||||
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.
|
||||
</PageHeaderDescription>
|
||||
|
||||
<section class="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
|
||||
<PageAction>
|
||||
<a
|
||||
href="/docs/introduction"
|
||||
:class="cn(buttonVariants(), 'rounded-[6px]')"
|
||||
|
|
@ -52,7 +53,7 @@ import { cn } from '@/lib/utils'
|
|||
>
|
||||
Components
|
||||
</a>
|
||||
</section>
|
||||
</PageAction>
|
||||
</PageHeader>
|
||||
<section>
|
||||
<ExamplesNav />
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import RadixIconsSun from '~icons/radix-icons/sun'
|
|||
import { useConfigStore } from '@/stores/config'
|
||||
import { Dialog, DialogContent } from '@/lib/registry/default/ui/dialog'
|
||||
import { Toaster as DefaultToaster } from '@/lib/registry/default/ui/toast'
|
||||
import { Toaster as NewYorkSonner } from '@/lib/registry/new-york/ui/sonner'
|
||||
import { Toaster as NewYorkToaster } from '@/lib/registry/new-york/ui/toast'
|
||||
|
||||
import File from '~icons/radix-icons/file'
|
||||
|
|
@ -86,7 +87,7 @@ watch(() => $route.path, (n) => {
|
|||
<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">
|
||||
<div
|
||||
class="container flex justify-between h-14 items-center"
|
||||
class="container flex justify-between h-14 max-w-screen-2xl items-center"
|
||||
>
|
||||
<MobileNav />
|
||||
|
||||
|
|
@ -134,9 +135,10 @@ watch(() => $route.path, (n) => {
|
|||
:href="link.href" target="_blank"
|
||||
:variant="'ghost'" :size="'icon'"
|
||||
>
|
||||
<component :is="link.icon" class="w-[20px] h-[20px]" />
|
||||
<component :is="link.icon" class="w-[20px] h-5" />
|
||||
</Button>
|
||||
|
||||
<ClientOnly>
|
||||
<Button
|
||||
class="flex items-center justify-center"
|
||||
aria-label="Toggle dark mode"
|
||||
|
|
@ -145,9 +147,10 @@ watch(() => $route.path, (n) => {
|
|||
>
|
||||
<component
|
||||
:is="isDark ? RadixIconsSun : RadixIconsMoon"
|
||||
class="w-[20px] h-[20px] text-foreground"
|
||||
class="w-[20px] h-5 text-foreground"
|
||||
/>
|
||||
</Button>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -287,6 +290,9 @@ watch(() => $route.path, (n) => {
|
|||
</DialogContent>
|
||||
</Dialog>
|
||||
<DefaultToaster />
|
||||
<ClientOnly>
|
||||
<NewYorkSonner :theme="isDark ? 'dark' : 'light'" />
|
||||
</ClientOnly>
|
||||
<NewYorkToaster />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap");
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--font-geist-sans: "geist-sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
|
|
@ -19,7 +21,7 @@
|
|||
--muted-foreground: 240 3.8% 46.1%;
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive: 0 72.22% 50.59%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
|
|
@ -68,6 +70,16 @@
|
|||
-webkit-tap-highlight-color: rgba(128, 128, 128, 0.5);
|
||||
}
|
||||
|
||||
/* Font face Geist font */
|
||||
|
||||
@font-face {
|
||||
font-family: "geist-sans";
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("/fonts/Geist/GeistVariableVF.woff2") format("woff2");
|
||||
}
|
||||
|
||||
/* === Scrollbars === */
|
||||
|
||||
::-webkit-scrollbar {
|
||||
|
|
@ -116,7 +128,7 @@
|
|||
|
||||
.step:before {
|
||||
@apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background;
|
||||
@apply ml-[-50px] mt-[-4px];
|
||||
@apply -ml-[50px] -mt-1;
|
||||
content: counter(step);
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +151,7 @@ pre code {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
:root {
|
||||
--shiki-foreground: #EEEEEE;
|
||||
--shiki-foreground: #FFF8;
|
||||
--shiki-color-background: #ffffff;
|
||||
--shiki-token-constant: #ffffff;
|
||||
--shiki-token-string: #ffffff88;
|
||||
|
|
@ -7,7 +7,14 @@
|
|||
--shiki-token-keyword: #ffffff88;
|
||||
--shiki-token-parameter: #AA0000;
|
||||
--shiki-token-function: #ffffff;
|
||||
--shiki-token-string-expression: #ffffff88;
|
||||
--shiki-token-string-expression: #ebebeb;
|
||||
--shiki-token-punctuation: #ffffff;
|
||||
--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-code-bg: hsl(var(--muted));
|
||||
--vp-c-divider: hsl(var(--muted));
|
||||
--vp-code-block-color: #fff
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -414,7 +415,7 @@
|
|||
|
||||
.vp-doc div[class*='language-'].line-numbers-mode {
|
||||
/*rtl:ignore*/
|
||||
padding-left: 32px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.vp-doc .line-numbers-wrapper {
|
||||
|
|
@ -567,3 +568,11 @@
|
|||
.vp-external-link-icon::after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.vp-doc [class*=language-] code {
|
||||
color: var(--vp-code-block-color);
|
||||
}
|
||||
|
||||
.line-numbers-mode pre code .line {
|
||||
padding-left: 3rem !important;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
// This file is autogenerated by scripts/build-registry.ts
|
||||
// Do not edit this file directly.
|
||||
export const Index = {
|
||||
|
|
@ -324,6 +325,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/ContextMenuDemo.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'DataTableDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -387,6 +395,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/DialogDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/DialogDemo.vue'],
|
||||
},
|
||||
DialogScrollBodyDemo: {
|
||||
name: 'DialogScrollBodyDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'dialog'],
|
||||
component: () => import('../src/lib/registry/default/example/DialogScrollBodyDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/DialogScrollBodyDemo.vue'],
|
||||
},
|
||||
DialogScrollOverlayDemo: {
|
||||
name: 'DialogScrollOverlayDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'dialog'],
|
||||
component: () => import('../src/lib/registry/default/example/DialogScrollOverlayDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/DialogScrollOverlayDemo.vue'],
|
||||
},
|
||||
DropdownMenuDemo: {
|
||||
name: 'DropdownMenuDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -443,6 +465,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/InputWithButton.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/InputWithButton.vue'],
|
||||
},
|
||||
InputWithIcon: {
|
||||
name: 'InputWithIcon',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['input'],
|
||||
component: () => import('../src/lib/registry/default/example/InputWithIcon.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/InputWithIcon.vue'],
|
||||
},
|
||||
InputWithLabel: {
|
||||
name: 'InputWithLabel',
|
||||
type: 'components:example',
|
||||
|
|
@ -485,6 +514,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/PaginationDemo.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'PopoverDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -513,6 +556,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/RadioGroupForm.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'ScrollAreaDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -576,6 +626,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/SliderDemo.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'SwitchDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -604,6 +661,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/default/example/TabsDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TabsDemo.vue'],
|
||||
},
|
||||
TagsInputComboboxDemo: {
|
||||
name: 'TagsInputComboboxDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['command', 'tags-input'],
|
||||
component: () => import('../src/lib/registry/default/example/TagsInputComboboxDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TagsInputComboboxDemo.vue'],
|
||||
},
|
||||
TagsInputDemo: {
|
||||
name: 'TagsInputDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['tags-input'],
|
||||
component: () => import('../src/lib/registry/default/example/TagsInputDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TagsInputDemo.vue'],
|
||||
},
|
||||
TextareaDemo: {
|
||||
name: 'TextareaDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -776,96 +847,96 @@ export const Index = {
|
|||
name: 'TypographyBlockquote',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyBlockquote.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyBlockquote.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyBlockquote.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyBlockquote.vue"],
|
||||
},
|
||||
TypographyDemo: {
|
||||
name: 'TypographyDemo',
|
||||
type: 'components:example',
|
||||
"TypographyDemo": {
|
||||
name: "TypographyDemo",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyDemo.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyDemo.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyDemo.vue"],
|
||||
},
|
||||
TypographyH1: {
|
||||
name: 'TypographyH1',
|
||||
type: 'components:example',
|
||||
"TypographyH1": {
|
||||
name: "TypographyH1",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH1.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH1.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyH1.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyH1.vue"],
|
||||
},
|
||||
TypographyH2: {
|
||||
name: 'TypographyH2',
|
||||
type: 'components:example',
|
||||
"TypographyH2": {
|
||||
name: "TypographyH2",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH2.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH2.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyH2.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyH2.vue"],
|
||||
},
|
||||
TypographyH3: {
|
||||
name: 'TypographyH3',
|
||||
type: 'components:example',
|
||||
"TypographyH3": {
|
||||
name: "TypographyH3",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH3.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH3.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyH3.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyH3.vue"],
|
||||
},
|
||||
TypographyH4: {
|
||||
name: 'TypographyH4',
|
||||
type: 'components:example',
|
||||
"TypographyH4": {
|
||||
name: "TypographyH4",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyH4.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyH4.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyH4.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyH4.vue"],
|
||||
},
|
||||
TypographyInlineCode: {
|
||||
name: 'TypographyInlineCode',
|
||||
type: 'components:example',
|
||||
"TypographyInlineCode": {
|
||||
name: "TypographyInlineCode",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyInlineCode.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyInlineCode.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyInlineCode.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyInlineCode.vue"],
|
||||
},
|
||||
TypographyLarge: {
|
||||
name: 'TypographyLarge',
|
||||
type: 'components:example',
|
||||
"TypographyLarge": {
|
||||
name: "TypographyLarge",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyLarge.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyLarge.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyLarge.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyLarge.vue"],
|
||||
},
|
||||
TypographyLead: {
|
||||
name: 'TypographyLead',
|
||||
type: 'components:example',
|
||||
"TypographyLead": {
|
||||
name: "TypographyLead",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyLead.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyLead.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyLead.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyLead.vue"],
|
||||
},
|
||||
TypographyList: {
|
||||
name: 'TypographyList',
|
||||
type: 'components:example',
|
||||
"TypographyList": {
|
||||
name: "TypographyList",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyList.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyList.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyList.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyList.vue"],
|
||||
},
|
||||
TypographyMuted: {
|
||||
name: 'TypographyMuted',
|
||||
type: 'components:example',
|
||||
"TypographyMuted": {
|
||||
name: "TypographyMuted",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyMuted.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyMuted.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyMuted.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyMuted.vue"],
|
||||
},
|
||||
TypographyP: {
|
||||
name: 'TypographyP',
|
||||
type: 'components:example',
|
||||
"TypographyP": {
|
||||
name: "TypographyP",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyP.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyP.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographyP.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographyP.vue"],
|
||||
},
|
||||
TypographySmall: {
|
||||
name: 'TypographySmall',
|
||||
type: 'components:example',
|
||||
"TypographySmall": {
|
||||
name: "TypographySmall",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographySmall.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographySmall.vue'],
|
||||
component: () => import("../src/lib/registry/default/example/TypographySmall.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/default/example/TypographySmall.vue"],
|
||||
},
|
||||
TypographyTable: {
|
||||
name: 'TypographyTable',
|
||||
type: 'components:example',
|
||||
"TypographyTable": {
|
||||
name: "TypographyTable",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/default/example/TypographyTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/default/example/TypographyTable.vue'],
|
||||
|
|
@ -1215,6 +1286,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/ContextMenuDemo.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'DataTableDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -1278,6 +1356,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/DialogDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/DialogDemo.vue'],
|
||||
},
|
||||
DialogScrollBodyDemo: {
|
||||
name: 'DialogScrollBodyDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'dialog'],
|
||||
component: () => import('../src/lib/registry/new-york/example/DialogScrollBodyDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/DialogScrollBodyDemo.vue'],
|
||||
},
|
||||
DialogScrollOverlayDemo: {
|
||||
name: 'DialogScrollOverlayDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'dialog'],
|
||||
component: () => import('../src/lib/registry/new-york/example/DialogScrollOverlayDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/DialogScrollOverlayDemo.vue'],
|
||||
},
|
||||
DropdownMenuDemo: {
|
||||
name: 'DropdownMenuDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -1334,6 +1426,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/InputWithButton.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/InputWithButton.vue'],
|
||||
},
|
||||
InputWithIcon: {
|
||||
name: 'InputWithIcon',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['input'],
|
||||
component: () => import('../src/lib/registry/new-york/example/InputWithIcon.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/InputWithIcon.vue'],
|
||||
},
|
||||
InputWithLabel: {
|
||||
name: 'InputWithLabel',
|
||||
type: 'components:example',
|
||||
|
|
@ -1376,6 +1475,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/PaginationDemo.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'PopoverDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -1404,6 +1517,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/RadioGroupForm.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'ScrollAreaDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -1467,6 +1587,13 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/SliderDemo.vue').then(m => m.default),
|
||||
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: {
|
||||
name: 'SwitchDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -1495,6 +1622,20 @@ export const Index = {
|
|||
component: () => import('../src/lib/registry/new-york/example/TabsDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TabsDemo.vue'],
|
||||
},
|
||||
TagsInputComboboxDemo: {
|
||||
name: 'TagsInputComboboxDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['command', 'tags-input'],
|
||||
component: () => import('../src/lib/registry/new-york/example/TagsInputComboboxDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TagsInputComboboxDemo.vue'],
|
||||
},
|
||||
TagsInputDemo: {
|
||||
name: 'TagsInputDemo',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['tags-input'],
|
||||
component: () => import('../src/lib/registry/new-york/example/TagsInputDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TagsInputDemo.vue'],
|
||||
},
|
||||
TextareaDemo: {
|
||||
name: 'TextareaDemo',
|
||||
type: 'components:example',
|
||||
|
|
@ -1667,120 +1808,120 @@ export const Index = {
|
|||
name: 'TypographyBlockquote',
|
||||
type: 'components:example',
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyBlockquote.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyBlockquote.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyBlockquote.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyBlockquote.vue"],
|
||||
},
|
||||
TypographyDemo: {
|
||||
name: 'TypographyDemo',
|
||||
type: 'components:example',
|
||||
"TypographyDemo": {
|
||||
name: "TypographyDemo",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyDemo.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyDemo.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyDemo.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyDemo.vue"],
|
||||
},
|
||||
TypographyH1: {
|
||||
name: 'TypographyH1',
|
||||
type: 'components:example',
|
||||
"TypographyH1": {
|
||||
name: "TypographyH1",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH1.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH1.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyH1.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyH1.vue"],
|
||||
},
|
||||
TypographyH2: {
|
||||
name: 'TypographyH2',
|
||||
type: 'components:example',
|
||||
"TypographyH2": {
|
||||
name: "TypographyH2",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH2.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH2.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyH2.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyH2.vue"],
|
||||
},
|
||||
TypographyH3: {
|
||||
name: 'TypographyH3',
|
||||
type: 'components:example',
|
||||
"TypographyH3": {
|
||||
name: "TypographyH3",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH3.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH3.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyH3.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyH3.vue"],
|
||||
},
|
||||
TypographyH4: {
|
||||
name: 'TypographyH4',
|
||||
type: 'components:example',
|
||||
"TypographyH4": {
|
||||
name: "TypographyH4",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyH4.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyH4.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyH4.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyH4.vue"],
|
||||
},
|
||||
TypographyInlineCode: {
|
||||
name: 'TypographyInlineCode',
|
||||
type: 'components:example',
|
||||
"TypographyInlineCode": {
|
||||
name: "TypographyInlineCode",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyInlineCode.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyInlineCode.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyInlineCode.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyInlineCode.vue"],
|
||||
},
|
||||
TypographyLarge: {
|
||||
name: 'TypographyLarge',
|
||||
type: 'components:example',
|
||||
"TypographyLarge": {
|
||||
name: "TypographyLarge",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyLarge.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyLarge.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyLarge.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyLarge.vue"],
|
||||
},
|
||||
TypographyLead: {
|
||||
name: 'TypographyLead',
|
||||
type: 'components:example',
|
||||
"TypographyLead": {
|
||||
name: "TypographyLead",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyLead.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyLead.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyLead.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyLead.vue"],
|
||||
},
|
||||
TypographyList: {
|
||||
name: 'TypographyList',
|
||||
type: 'components:example',
|
||||
"TypographyList": {
|
||||
name: "TypographyList",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyList.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyList.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyList.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyList.vue"],
|
||||
},
|
||||
TypographyMuted: {
|
||||
name: 'TypographyMuted',
|
||||
type: 'components:example',
|
||||
"TypographyMuted": {
|
||||
name: "TypographyMuted",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyMuted.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyMuted.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyMuted.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyMuted.vue"],
|
||||
},
|
||||
TypographyP: {
|
||||
name: 'TypographyP',
|
||||
type: 'components:example',
|
||||
"TypographyP": {
|
||||
name: "TypographyP",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyP.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyP.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyP.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyP.vue"],
|
||||
},
|
||||
TypographySmall: {
|
||||
name: 'TypographySmall',
|
||||
type: 'components:example',
|
||||
"TypographySmall": {
|
||||
name: "TypographySmall",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographySmall.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographySmall.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographySmall.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographySmall.vue"],
|
||||
},
|
||||
TypographyTable: {
|
||||
name: 'TypographyTable',
|
||||
type: 'components:example',
|
||||
"TypographyTable": {
|
||||
name: "TypographyTable",
|
||||
type: "components:example",
|
||||
registryDependencies: [],
|
||||
component: () => import('../src/lib/registry/new-york/example/TypographyTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/TypographyTable.vue'],
|
||||
component: () => import("../src/lib/registry/new-york/example/TypographyTable.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/TypographyTable.vue"],
|
||||
},
|
||||
ActivityGoal: {
|
||||
name: 'ActivityGoal',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'card', 'themes', 'config'],
|
||||
component: () => import('../src/lib/registry/new-york/example/Cards/ActivityGoal.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/Cards/ActivityGoal.vue'],
|
||||
"ActivityGoal": {
|
||||
name: "ActivityGoal",
|
||||
type: "components:example",
|
||||
registryDependencies: ["button","card","themes","config"],
|
||||
component: () => import("../src/lib/registry/new-york/example/Cards/ActivityGoal.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/Cards/ActivityGoal.vue"],
|
||||
},
|
||||
DataTable: {
|
||||
name: 'DataTable',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['button', 'checkbox', 'dropdown-menu', 'input', 'table', 'card', 'utils'],
|
||||
component: () => import('../src/lib/registry/new-york/example/Cards/DataTable.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/Cards/DataTable.vue'],
|
||||
"DataTable": {
|
||||
name: "DataTable",
|
||||
type: "components:example",
|
||||
registryDependencies: ["button","checkbox","dropdown-menu","input","table","card","utils"],
|
||||
component: () => import("../src/lib/registry/new-york/example/Cards/DataTable.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/Cards/DataTable.vue"],
|
||||
},
|
||||
Metric: {
|
||||
name: 'Metric',
|
||||
type: 'components:example',
|
||||
registryDependencies: ['card', 'config'],
|
||||
component: () => import('../src/lib/registry/new-york/example/Cards/Metric.vue').then(m => m.default),
|
||||
files: ['../src/lib/registry/new-york/example/Cards/Metric.vue'],
|
||||
"Metric": {
|
||||
name: "Metric",
|
||||
type: "components:example",
|
||||
registryDependencies: ["card","config"],
|
||||
component: () => import("../src/lib/registry/new-york/example/Cards/Metric.vue").then((m) => m.default),
|
||||
files: ["../src/lib/registry/new-york/example/Cards/Metric.vue"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "www",
|
||||
"type": "module",
|
||||
"version": "0.8.7",
|
||||
"version": "0.9.0",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
|
|
@ -19,26 +19,26 @@
|
|||
"@morev/vue-transitions": "^2.3.6",
|
||||
"@radix-icons/vue": "^1.0.0",
|
||||
"@stackblitz/sdk": "^1.9.0",
|
||||
"@tanstack/vue-table": "^8.11.6",
|
||||
"@unovis/ts": "^1.3.1",
|
||||
"@unovis/vue": "^1.3.1",
|
||||
"@vee-validate/zod": "^4.12.4",
|
||||
"@tanstack/vue-table": "^8.11.8",
|
||||
"@unovis/ts": "^1.3.3",
|
||||
"@unovis/vue": "^1.3.3",
|
||||
"@vee-validate/zod": "^4.12.5",
|
||||
"@vueuse/core": "^10.7.2",
|
||||
"@vueuse/integrations": "^10.7.2",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"codesandbox": "^2.2.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"embla-carousel": "8.0.0-rc19",
|
||||
"embla-carousel-autoplay": "8.0.0-rc19",
|
||||
"embla-carousel-vue": "8.0.0-rc19",
|
||||
"fuse.js": "^7.0.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",
|
||||
"radix-vue": "^1.3.2",
|
||||
"radix-vue": "^1.4.6",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"v-calendar": "^3.1.2",
|
||||
"vee-validate": "4.12.4",
|
||||
"vue": "^3.4.14",
|
||||
"vee-validate": "4.12.5",
|
||||
"vue": "^3.4.15",
|
||||
"vue-sonner": "^1.0.3",
|
||||
"vue-wrap-balancer": "^1.1.3",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
|
|
@ -47,25 +47,27 @@
|
|||
"@iconify-json/tabler": "^1.1.89",
|
||||
"@iconify/json": "^2.2.108",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@shikijs/transformers": "^1.0.0-beta.3",
|
||||
"@types/lodash.template": "^4.5.2",
|
||||
"@types/node": "^20.8.10",
|
||||
"@vitejs/plugin-vue": "^5.0.3",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/compiler-core": "^3.4.14",
|
||||
"@vue/compiler-dom": "^3.4.14",
|
||||
"@vue/compiler-core": "^3.4.15",
|
||||
"@vue/compiler-dom": "^3.4.15",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"lodash.template": "^4.5.0",
|
||||
"oxc-parser": "^0.2.0",
|
||||
"pathe": "^1.1.2",
|
||||
"rimraf": "^5.0.5",
|
||||
"shikiji": "^0.10.0-beta.2",
|
||||
"tailwind-merge": "^2.2.0",
|
||||
"shiki": "^1.0.0-beta.3",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tsx": "^4.7.0",
|
||||
"typescript": "^5.3.3",
|
||||
"unplugin-icons": "^0.17.1",
|
||||
"vite": "^5.0.11",
|
||||
"vitepress": "^1.0.0-rc.37",
|
||||
"unplugin-icons": "^0.18.3",
|
||||
"vite": "^5.0.12",
|
||||
"vitepress": "^1.0.0-rc.41",
|
||||
"vue-tsc": "^1.8.27"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,5 +56,40 @@ import { Calendar } from '@/components/ui/calendar'
|
|||
</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>
|
||||
```
|
||||
|
|
@ -57,7 +57,7 @@ To set the size of the items, you can use the `basis` utility class on the `<Car
|
|||
|
||||
Example
|
||||
|
||||
```vue title="Example" showLineNumbers {4-6}
|
||||
```vue:line-numbers title="Example" {4-6}
|
||||
// 33% of the carousel width.
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
|
|
@ -71,7 +71,7 @@ Example
|
|||
|
||||
Responsive
|
||||
|
||||
```vue title="Responsive" showLineNumbers {4-6}
|
||||
```vue:line-numbers title="Responsive" {4-6}
|
||||
// 50% on small screens and 33% on larger screens.
|
||||
<Carousel>
|
||||
<CarouselContent>
|
||||
|
|
@ -101,7 +101,7 @@ You can always adjust this in your own project if you need to.
|
|||
|
||||
Example
|
||||
|
||||
```vue showLineNumbers /-ml-4/ /pl-4/
|
||||
```vue:line-numbers /-ml-4/ /pl-4/
|
||||
<template>
|
||||
<Carousel>
|
||||
<CarouselContent class="-ml-4">
|
||||
|
|
@ -121,7 +121,7 @@ Example
|
|||
|
||||
Responsive
|
||||
|
||||
```vue showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
|
||||
```vue:line-numbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
|
||||
<template>
|
||||
<Carousel>
|
||||
<CarouselContent class="-ml-2 md:-ml-4">
|
||||
|
|
@ -155,7 +155,7 @@ Use the `orientation` prop to set the orientation of the carousel.
|
|||
|
||||
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 showLineNumbers {3-6}
|
||||
```vue:line-numbers {3-6}
|
||||
<template>
|
||||
<Carousel
|
||||
:opts="{
|
||||
|
|
@ -184,7 +184,7 @@ Use the `@init-api` emit method on `<Carousel />` component to set the instance
|
|||
|
||||
You can access it through setting a template ref on the `<Carousel />` component.
|
||||
|
||||
```vue showLineNumbers {2,5,9}
|
||||
```vue:line-numbers {2,5,9}
|
||||
<script setup>
|
||||
const carouselContainerRef = ref<InstanceType<typeof Carousel> | null>(null)
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ function accessApi() {
|
|||
|
||||
You can listen to events using the API. To get the API instance use the `@init-api` emit method on the `<Carousel />` component
|
||||
|
||||
```vue showLineNumbers {5,7-9,25}
|
||||
```vue:line-numbers {5,7-9,25}
|
||||
<script setup>
|
||||
import { nextTick, ref, watch } from 'vue'
|
||||
import { useCarousel } from '@/components/ui/carousel'
|
||||
|
|
@ -241,7 +241,7 @@ See the [Embla Carousel docs](https://www.embla-carousel.com/api/events/) for mo
|
|||
|
||||
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 showLineNumbers {2}
|
||||
```vue:line-numbers {2}
|
||||
<template>
|
||||
<Carousel v-slot="{ canScrollNext, canScrollPrev }">
|
||||
...
|
||||
|
|
@ -260,7 +260,7 @@ npm i embla-carousel-autoplay
|
|||
```
|
||||
|
||||
|
||||
```vue showLineNumbers {2,8-10}
|
||||
```vue:line-numbers {2,8-10}
|
||||
<script setup lang="ts">
|
||||
import Autoplay from 'embla-carousel-autoplay'
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ We'll start with the basic `<Table />` component and build a complex data table
|
|||
|
||||
## 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)
|
||||
- [Row Actions](#row-actions)
|
||||
|
|
@ -50,6 +50,13 @@ npx shadcn-vue@latest add table
|
|||
npm install @tanstack/vue-table
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Column Pinning
|
||||
|
||||
<ComponentPreview name="DataTableColumnPinningDemo" />
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
We are going to build a table to show recent payments. Here's what our data looks like:
|
||||
|
|
@ -109,31 +116,23 @@ Let's start by building a basic table.
|
|||
|
||||
First, we'll define our columns in the `columns.ts` file.
|
||||
|
||||
```ts:line-numbers title="components/payments/columns.ts" {1,12-27}
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
|
||||
// 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
|
||||
}
|
||||
```ts:line-numbers {1,12-27}
|
||||
import { h } from 'vue'
|
||||
|
||||
export const columns: ColumnDef<Payment>[] = [
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: 'Status',
|
||||
},
|
||||
{
|
||||
accessorKey: 'email',
|
||||
header: 'Email',
|
||||
},
|
||||
{
|
||||
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)
|
||||
},
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
|
@ -149,7 +148,7 @@ formatted, sorted and filtered.
|
|||
|
||||
Next, we'll create a `<DataTable />` component to render our table.
|
||||
|
||||
```ts:line-numbers
|
||||
```vue:line-numbers
|
||||
<script setup lang="ts" generic="TData, TValue">
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
import {
|
||||
|
|
@ -225,7 +224,7 @@ const table = useVueTable({
|
|||
|
||||
Finally, we'll render our table in our index component.
|
||||
|
||||
```ts:line-numbers showLineNumbers{28}
|
||||
```vue:line-numbers {28}
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { columns } from "./components/columns"
|
||||
|
|
@ -272,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:
|
||||
|
||||
|
||||
```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'
|
||||
|
||||
export const columns: ColumnDef<Payment>[] = [
|
||||
|
|
@ -302,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:
|
||||
|
||||
```ts:line-numbers
|
||||
```vue:line-numbers
|
||||
// DataTableDropDown.vue
|
||||
<script setup lang="ts">
|
||||
import { MoreHorizontal } from 'lucide-vue-next'
|
||||
|
|
@ -380,7 +379,7 @@ Next, we'll add pagination to our table.
|
|||
|
||||
### Update `<DataTable>`
|
||||
|
||||
```ts:line-numbers showLineNumbers{4,12}
|
||||
```ts:line-numbers {4,12}
|
||||
import {
|
||||
FlexRender,
|
||||
getCoreRowModel,
|
||||
|
|
@ -402,8 +401,7 @@ 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.
|
||||
|
||||
```ts:line-numbers showLineNumbers{3,15,21-39}
|
||||
// components/payments/DataTable.vue
|
||||
```vue:line-numbers {3,15,21-39}
|
||||
<script lang="ts" generic="TData, TValue">
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
|
|
@ -458,7 +456,7 @@ Let's make the email column sortable.
|
|||
|
||||
### 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 { twMerge } from 'tailwind-merge'
|
||||
import { camelize, getCurrentInstance, toHandlerKey } from 'vue'
|
||||
|
|
@ -482,7 +480,7 @@ The `valueUpdater` function updates a Vue `ref` object's value. It handles both
|
|||
|
||||
### 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">
|
||||
import type {
|
||||
ColumnDef,
|
||||
|
|
@ -545,7 +543,7 @@ const table = useVueTable({
|
|||
|
||||
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
|
||||
import type {
|
||||
ColumnDef,
|
||||
|
|
@ -579,7 +577,7 @@ Let's add a search input to filter emails in our table.
|
|||
|
||||
### 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">
|
||||
import type {
|
||||
ColumnDef,
|
||||
|
|
@ -664,7 +662,7 @@ Adding column visibility is fairly simple using `@tanstack/vue-table` visibility
|
|||
|
||||
### 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">
|
||||
import type {
|
||||
ColumnDef,
|
||||
|
|
@ -803,7 +801,7 @@ Next, we're going to add row selection to our table.
|
|||
|
||||
### Update column definitions
|
||||
|
||||
```ts:line-numbers showLineNumbers{3,6-20}
|
||||
```ts:line-numbers {3,6-20}
|
||||
import type { ColumnDef } from '@tanstack/vue-table'
|
||||
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
|
|
@ -829,7 +827,7 @@ export const columns: ColumnDef<Payment>[] = [
|
|||
|
||||
### Update `<DataTable>`
|
||||
|
||||
```ts:line-numbers showLineNumbers{10,22,27}
|
||||
```vue:line-numbers {10,22,27}
|
||||
<script setup lang="ts" generic="TData, TValue">
|
||||
const props = defineProps<{
|
||||
columns: ColumnDef<TData, TValue>[]
|
||||
|
|
@ -895,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.
|
||||
|
||||
```ts:line-numbers
|
||||
```vue:line-numbers
|
||||
<script setup lang="ts">
|
||||
import type { Column } from '@tanstack/vue-table'
|
||||
import { type Task } from '../data/schema'
|
||||
|
|
@ -988,7 +986,7 @@ export const columns = [
|
|||
|
||||
Add pagination controls to your table including page size and selection count.
|
||||
|
||||
```ts:line-numbers
|
||||
```vue:line-numbers
|
||||
<script setup lang="ts">
|
||||
import { type Table } from '@tanstack/vue-table'
|
||||
import { type Task } from '../data/schema'
|
||||
|
|
@ -1093,8 +1091,7 @@ defineProps<DataTablePaginationProps>()
|
|||
|
||||
A component to toggle column visibility.
|
||||
|
||||
```ts:line-numbers
|
||||
|
||||
```vue:line-numbers
|
||||
<script setup lang="ts">
|
||||
import type { Table } from '@tanstack/vue-table'
|
||||
import { computed } from 'vue'
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ const date = ref<Date>()
|
|||
|
||||
<ComponentPreview name="DatePickerWithPresets" />
|
||||
|
||||
### With Slot
|
||||
|
||||
<ComponentPreview name="RangePickerWithSlot" />
|
||||
|
||||
### Form
|
||||
|
||||
<ComponentPreview name="DatePickerForm" />
|
||||
|
|
|
|||
|
|
@ -55,6 +55,14 @@ import {
|
|||
|
||||
<ComponentPreview name="DialogCustomCloseButton" />
|
||||
|
||||
### Scroll body
|
||||
|
||||
<ComponentPreview name="DialogScrollBodyDemo" />
|
||||
|
||||
### Scroll overlay
|
||||
|
||||
<ComponentPreview name="DialogScrollOverlayDemo" />
|
||||
|
||||
## Notes
|
||||
|
||||
To activate the `Dialog` component from within a `Context Menu` or `Dropdown Menu`, you must encase the `Context Menu` or `Dropdown Menu` component in the `Dialog` component. For more information, refer to the linked issue [here](https://github.com/radix-ui/primitives/issues/1836).
|
||||
|
|
|
|||
|
|
@ -159,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.
|
||||
|
||||
```vue showLineNumbers {2-3,5-7}
|
||||
```vue:line-numbers {2-3,5-7}
|
||||
<script setup lang="ts">
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import * as z from 'zod'
|
||||
|
|
@ -179,7 +179,7 @@ Use the `useForm` composable from `vee-validate` or use `<Form />` component to
|
|||
<TabPreview name="Composition" :names="['Composition', 'Component']">
|
||||
<template #Composition>
|
||||
|
||||
```vue showLineNumbers {2,19-21}
|
||||
```vue:line-numbers {2,19-21}
|
||||
<script setup lang="ts">
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
|
|
@ -218,7 +218,7 @@ const onSubmit = form.handleSubmit((values) => {
|
|||
|
||||
<template #Component>
|
||||
|
||||
```vue showLineNumbers {5,24-26}
|
||||
```vue:line-numbers {5,24-26}
|
||||
<script setup lang="ts">
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import * as z from 'zod'
|
||||
|
|
@ -256,7 +256,7 @@ function onSubmit(values) {
|
|||
Based on last step we can either use `<Form />` component or `useForm` composable
|
||||
`useForm` is recommended cause values are typed automatically
|
||||
|
||||
```vue showLineNumbers {2}
|
||||
```vue:line-numbers {2}
|
||||
<script setup lang="ts">
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ import { Input } from '@/components/ui/input'
|
|||
|
||||
<ComponentPreview name="InputWithButton" class="max-w-xs" />
|
||||
|
||||
### With Icon
|
||||
|
||||
<ComponentPreview name="InputWithIcon" class="max-w-xs" />
|
||||
|
||||
### Form
|
||||
|
||||
<ComponentPreview name="InputForm" />
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ import {
|
|||
|
||||
### 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
|
||||
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" />
|
||||
|
|
@ -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:
|
||||
|
||||
```vue:line-numbers showLineNumbers{4}
|
||||
```vue:line-numbers {4}
|
||||
<template>
|
||||
<Sheet>
|
||||
<SheetTrigger>Open</SheetTrigger>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,6 @@ import { Skeleton } from '@/components/ui/skeleton'
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Skeleton class="w-[100px] h-[20px] rounded-full" />
|
||||
<Skeleton class="w-[100px] h-5 rounded-full" />
|
||||
</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 calendar
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
21
apps/www/src/content/docs/components/tags-input.md
Normal file
21
apps/www/src/content/docs/components/tags-input.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
title: Tags Input
|
||||
description: Tag inputs render tags inside an input, followed by an actual text input.
|
||||
source: apps/www/src/lib/registry/default/ui/tags-input
|
||||
primitive: https://www.radix-vue.com/components/tags-input.html
|
||||
---
|
||||
|
||||
<ComponentPreview name="TagsInputDemo" />
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx shadcn-vue@latest add tags-input
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Tags with Combobox
|
||||
|
||||
<ComponentPreview name="TagsInputComboboxDemo" />
|
||||
|
|
@ -61,7 +61,7 @@ const { toast } = useToast()
|
|||
});
|
||||
}"
|
||||
>
|
||||
Add to calander
|
||||
Add to calendar
|
||||
</Button>
|
||||
</template>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ npm create astro@latest
|
|||
|
||||
You will be asked a few questions to configure your project:
|
||||
|
||||
```txt showLineNumbers
|
||||
```txt:line-numbers
|
||||
- Where should we create your new project?
|
||||
./your-app-name
|
||||
- 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:
|
||||
|
||||
```json {2-7} showLineNumbers
|
||||
```json:line-numbers {2-7}
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
|
|
@ -99,7 +99,7 @@ npx shadcn-vue@latest init
|
|||
|
||||
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
|
||||
Which framework are you using? Astro
|
||||
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:
|
||||
|
||||
```ts {2} showLineNumbers
|
||||
```ts:line-numbers {2}
|
||||
---
|
||||
import '@/styles/globals.css'
|
||||
---
|
||||
```
|
||||
|
||||
### 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`.
|
||||
|
||||
```ts {3-5} showLineNumbers
|
||||
```ts:line-numbers {3-5}
|
||||
export default defineConfig({
|
||||
integrations: [
|
||||
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:
|
||||
|
||||
```astro {2,10} showLineNumbers
|
||||
```astro:line-numbers {2,10}
|
||||
---
|
||||
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`:
|
||||
|
||||
```txt showLineNumbers
|
||||
```txt:line-numbers
|
||||
Would you like to use TypeScript (recommended)? no / yes
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ npx shadcn-vue@latest init
|
|||
|
||||
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
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
|
|
|
|||
|
|
@ -19,22 +19,82 @@ npm create vite@latest my-vue-app -- --template vue-ts
|
|||
|
||||
### 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">
|
||||
|
||||
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,9-13}
|
||||
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({
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [tailwind(), autoprefixer()],
|
||||
},
|
||||
},
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
</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
|
||||
|
||||
Add the code below to the compilerOptions of your tsconfig.json so your app can resolve paths without error
|
||||
|
||||
```typescript
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
```json {4-7}
|
||||
{
|
||||
"compilerOptions": {
|
||||
// ...
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -42,12 +102,22 @@ 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
|
||||
|
||||
```typescript
|
||||
```bash
|
||||
# (so you can import "path" without error)
|
||||
npm i -D @types/node
|
||||
```
|
||||
|
||||
```typescript {12-16}
|
||||
import path from "path"
|
||||
import vue from "@vitejs/plugin-vue"
|
||||
import { defineConfig } from "vite"
|
||||
|
||||
export default defineConfig({
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [tailwind(), autoprefixer()],
|
||||
},
|
||||
},
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
@ -69,7 +139,7 @@ npx shadcn-vue@latest init
|
|||
|
||||
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
|
||||
Which framework are you using? Vite / Nuxt / Laravel
|
||||
Which style would you like to use? › Default
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { Separator } from '@/lib/registry/new-york/ui/separator'
|
|||
|
||||
<template>
|
||||
<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">
|
||||
<CardTitle>shadcn/ui</CardTitle>
|
||||
<CardDescription>
|
||||
|
|
@ -39,7 +39,7 @@ import { Separator } from '@/lib/registry/new-york/ui/separator'
|
|||
<StarIcon class="mr-2 h-4 w-4" />
|
||||
Star
|
||||
</Button>
|
||||
<Separator orientation="vertical" class="h-[20px]" />
|
||||
<Separator orientation="vertical" class="h-5" />
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="secondary" class="px-2 shadow-none">
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const date = ref({
|
|||
</span>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0" :align="'end'" :avoid-collisions="true">
|
||||
<PopoverContent class="w-auto p-0" :align="'end'">
|
||||
<Calendar
|
||||
v-model.range="date"
|
||||
:columns="2"
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ async function onSubmit(values: any) {
|
|||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField, value }" name="dob">
|
||||
<FormItem>
|
||||
<FormItem class="flex flex-col">
|
||||
<FormLabel>Date of birth</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger as-child>
|
||||
|
|
@ -123,7 +123,7 @@ async function onSubmit(values: any) {
|
|||
</FormField>
|
||||
|
||||
<FormField v-slot="{ value }" name="language">
|
||||
<FormItem>
|
||||
<FormItem class="flex flex-col">
|
||||
<FormLabel>Language</FormLabel>
|
||||
|
||||
<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="space-y-2 rounded-sm bg-[#ecedef] p-2">
|
||||
<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>
|
||||
<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="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="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>
|
||||
<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 />
|
||||
<Tabs default-value="complete" class="flex-1">
|
||||
<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="grid gap-2">
|
||||
<HoverCard :open-delay="200">
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import type { Column } from '@tanstack/vue-table'
|
||||
import type { Component } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { type Task } from '../data/schema'
|
||||
import type { Task } from '../data/schema'
|
||||
import PlusCircledIcon from '~icons/radix-icons/plus-circled'
|
||||
import CheckIcon from '~icons/radix-icons/check'
|
||||
|
||||
|
|
@ -84,7 +84,8 @@ const selectedValues = computed(() => new Set(props.column?.getFilterValue() as
|
|||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:value="option"
|
||||
@select="() => {
|
||||
@select="(e) => {
|
||||
console.log(e.detail.value)
|
||||
const isSelected = selectedValues.has(option.value)
|
||||
if (isSelected) {
|
||||
selectedValues.delete(option.value)
|
||||
|
|
|
|||
|
|
@ -12,16 +12,16 @@ export const columns: ColumnDef<Task>[] = [
|
|||
{
|
||||
id: 'select',
|
||||
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,
|
||||
{ '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,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: 'id',
|
||||
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,
|
||||
enableHiding: false,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const notifications = [
|
|||
<div>
|
||||
<div
|
||||
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" />
|
||||
<div class="space-y-1">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
<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 {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const lineY = (d: Data) => d.revenue
|
|||
+20.1% from last month
|
||||
</p>
|
||||
|
||||
<div class="h-[80px]">
|
||||
<div class="h-20">
|
||||
<VisXYContainer
|
||||
height="80px"
|
||||
:data="data" :margin="{
|
||||
|
|
@ -79,7 +79,7 @@ const lineY = (d: Data) => d.revenue
|
|||
+54.8% from last month
|
||||
</p>
|
||||
|
||||
<div class="mt-4 h-[80px]">
|
||||
<div class="mt-4 h-20">
|
||||
<VisXYContainer
|
||||
height="80px" :data="data" :style="{
|
||||
'--theme-primary': `hsl(${
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
useVueTable,
|
||||
} from '@tanstack/vue-table'
|
||||
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 { Button } from '@/lib/registry/default/ui/button'
|
||||
|
|
@ -104,7 +104,7 @@ const columns: ColumnDef<Payment>[] = [
|
|||
return h(Button, {
|
||||
variant: 'ghost',
|
||||
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')),
|
||||
},
|
||||
|
|
@ -179,7 +179,7 @@ const table = useVueTable({
|
|||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<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>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { CaretSortIcon, CheckIcon } from '@radix-icons/vue'
|
||||
import { Check, ChevronsUpDown } from 'lucide-vue-next'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
|
|
@ -44,7 +44,7 @@ const value = ref<string>('')
|
|||
{{ value
|
||||
? frameworks.find((framework) => framework.value === value)?.label
|
||||
: "Select framework..." }}
|
||||
<CaretSortIcon class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<ChevronsUpDown class="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-[200px] p-0">
|
||||
|
|
@ -65,7 +65,7 @@ const value = ref<string>('')
|
|||
}"
|
||||
>
|
||||
{{ framework.label }}
|
||||
<CheckIcon
|
||||
<Check
|
||||
:class="cn(
|
||||
'ml-auto h-4 w-4',
|
||||
value === framework.value ? 'opacity-100' : 'opacity-0',
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent class="w-auto p-0" align="start" :avoid-collisions="true">
|
||||
<PopoverContent class="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
v-model.range="date"
|
||||
:columns="2"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<script setup lang="ts">
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/lib/registry/default/ui/dialog'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog>
|
||||
<DialogTrigger as-child>
|
||||
<Button variant="outline">
|
||||
Edit Profile
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent class="sm:max-w-[425px] grid-rows-[auto_minmax(0,1fr)_auto] p-0 max-h-[90dvh]">
|
||||
<DialogHeader class="p-6 pb-0">
|
||||
<DialogTitle>Edit profile</DialogTitle>
|
||||
<DialogDescription>
|
||||
Make changes to your profile here. Click save when you're done.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="grid gap-4 py-4 overflow-y-auto px-6">
|
||||
<div class="flex flex-col justify-between h-[300dvh]">
|
||||
<p>
|
||||
This is some placeholder content to show the scrolling behavior for modals. We use repeated line breaks to demonstrate how content can exceed minimum inner height, thereby showing inner scrolling. When content becomes longer than the predefined max-height of modal, content will be cropped and scrollable within the modal.
|
||||
</p>
|
||||
|
||||
<p>This content should appear at the bottom after you scroll.</p>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter class="p-6 pt-0">
|
||||
<Button type="submit">
|
||||
Save changes
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<script setup lang="ts">
|
||||
import { Button } from '@/lib/registry/default/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogScrollContent,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from '@/lib/registry/default/ui/dialog'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog>
|
||||
<DialogTrigger as-child>
|
||||
<Button variant="outline">
|
||||
Edit Profile
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogScrollContent class="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Modal title</DialogTitle>
|
||||
<DialogDescription>
|
||||
Here is modal with overlay scroll
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="grid gap-4 py-4 h-[300dvh]">
|
||||
<p>
|
||||
This is some placeholder content to show the scrolling behavior for modals. Instead of repeating the text in the modal, we use an inline style to set a minimum height, thereby extending the length of the overall modal and demonstrating the overflow scrolling. When content becomes longer than the height of the viewport, scrolling will move the modal as needed.
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button type="submit">
|
||||
Save changes
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogScrollContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
13
apps/www/src/lib/registry/default/example/InputWithIcon.vue
Normal file
13
apps/www/src/lib/registry/default/example/InputWithIcon.vue
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { MagnifyingGlassIcon } from '@radix-icons/vue'
|
||||
import { Input } from '@/lib/registry/default/ui/input'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative w-full max-w-sm items-center">
|
||||
<Input id="search" type="text" placeholder="Search..." class="pl-10" />
|
||||
<span class="absolute start-0 inset-y-0 flex items-center justify-center px-2">
|
||||
<MagnifyingGlassIcon class="size-6 text-muted-foreground" />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -55,7 +55,7 @@ const components: { title: string; href: string; description: string }[] = [
|
|||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
|
||||
<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">
|
||||
<NavigationMenuLink as-child>
|
||||
<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>
|
||||
|
||||
<template>
|
||||
<Progress v-model="progress" class="w-[60%]" />
|
||||
<Progress v-model="progress" class="w-3/5" />
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:class="cn('w-[60%]', $attrs.class ?? '')"
|
||||
:class="cn('w-3/5', $attrs.class ?? '')"
|
||||
/>
|
||||
</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 calendar
|
||||
</Button>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { ComboboxAnchor, ComboboxInput, ComboboxPortal, ComboboxRoot } from 'radix-vue'
|
||||
import { CommandEmpty, CommandGroup, CommandItem, CommandList } from '@/lib/registry/default/ui/command'
|
||||
import { TagsInput, TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInputItemText } from '@/lib/registry/default/ui/tags-input'
|
||||
|
||||
const frameworks = [
|
||||
{ value: 'next.js', label: 'Next.js' },
|
||||
{ value: 'sveltekit', label: 'SvelteKit' },
|
||||
{ value: 'nuxt.js', label: 'Nuxt.js' },
|
||||
{ value: 'remix', label: 'Remix' },
|
||||
{ value: 'astro', label: 'Astro' },
|
||||
]
|
||||
|
||||
const modelValue = ref<string[]>([])
|
||||
const open = ref(false)
|
||||
const searchTerm = ref('')
|
||||
|
||||
const filteredFrameworks = computed(() => frameworks.filter(i => !modelValue.value.includes(i.label)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TagsInput class="px-0 gap-0 w-80" :model-value="modelValue">
|
||||
<div class="flex gap-2 flex-wrap items-center px-3">
|
||||
<TagsInputItem v-for="item in modelValue" :key="item" :value="item">
|
||||
<TagsInputItemText />
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
</div>
|
||||
|
||||
<ComboboxRoot v-model="modelValue" v-model:open="open" v-model:searchTerm="searchTerm" class="w-full">
|
||||
<ComboboxAnchor as-child>
|
||||
<ComboboxInput placeholder="Framework..." as-child>
|
||||
<TagsInputInput class="w-full px-3" :class="modelValue.length > 0 ? 'mt-2' : ''" @keydown.enter.prevent />
|
||||
</ComboboxInput>
|
||||
</ComboboxAnchor>
|
||||
|
||||
<ComboboxPortal>
|
||||
<CommandList
|
||||
position="popper"
|
||||
class="w-[--radix-popper-anchor-width] rounded-md mt-2 border bg-popover text-popover-foreground shadow-md outline-none 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
|
||||
>
|
||||
<CommandEmpty />
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
v-for="framework in filteredFrameworks" :key="framework.value" :value="framework.label"
|
||||
@select.prevent="(ev) => {
|
||||
if (typeof ev.detail.value === 'string') {
|
||||
searchTerm = ''
|
||||
modelValue.push(ev.detail.value)
|
||||
}
|
||||
|
||||
if (filteredFrameworks.length === 0) {
|
||||
open = false
|
||||
}
|
||||
}"
|
||||
>
|
||||
{{ framework.label }}
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</ComboboxPortal>
|
||||
</ComboboxRoot>
|
||||
</TagsInput>
|
||||
</template>
|
||||
17
apps/www/src/lib/registry/default/example/TagsInputDemo.vue
Normal file
17
apps/www/src/lib/registry/default/example/TagsInputDemo.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { TagsInput, TagsInputInput, TagsInputItem, TagsInputItemDelete, TagsInputItemText } from '@/lib/registry/default/ui/tags-input'
|
||||
|
||||
const modelValue = ref(['Apple', 'Banana'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TagsInput v-model="modelValue">
|
||||
<TagsInputItem v-for="item in modelValue" :key="item" :value="item">
|
||||
<TagsInputItemText />
|
||||
<TagsInputItemDelete />
|
||||
</TagsInputItem>
|
||||
|
||||
<TagsInputInput placeholder="Fruits..." />
|
||||
</TagsInput>
|
||||
</template>
|
||||
|
|
@ -14,6 +14,6 @@ const { toast } = useToast()
|
|||
});
|
||||
}"
|
||||
>
|
||||
Add to calander
|
||||
Add to calendar
|
||||
</Button>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -3,15 +3,17 @@ import {
|
|||
AccordionRoot,
|
||||
type AccordionRootEmits,
|
||||
type AccordionRootProps,
|
||||
useEmitAsProps,
|
||||
useForwardPropsEmits,
|
||||
} from 'radix-vue'
|
||||
|
||||
const props = defineProps<AccordionRootProps>()
|
||||
const emits = defineEmits<AccordionRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AccordionRoot v-bind="{ ...props, ...useEmitAsProps(emits) }">
|
||||
<AccordionRoot v-bind="forwarded">
|
||||
<slot />
|
||||
</AccordionRoot>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import { AccordionContent, type AccordionContentProps } from 'radix-vue'
|
||||
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>
|
||||
|
||||
<template>
|
||||
<AccordionContent
|
||||
v-bind="props"
|
||||
:class="
|
||||
cn(
|
||||
'overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
v-bind="delegatedProps"
|
||||
class="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
||||
>
|
||||
<div class="pb-4 pt-0">
|
||||
<div :class="cn('pb-4 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</AccordionContent>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
<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'
|
||||
|
||||
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>
|
||||
|
||||
<template>
|
||||
<AccordionItem
|
||||
v-bind="props"
|
||||
:class="cn('border-b', props.class ?? '')"
|
||||
v-bind="forwardedProps"
|
||||
:class="cn('border-b', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</AccordionItem>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import {
|
||||
AccordionHeader,
|
||||
AccordionTrigger,
|
||||
|
|
@ -7,13 +8,19 @@ import {
|
|||
import { ChevronDown } from 'lucide-vue-next'
|
||||
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>
|
||||
|
||||
<template>
|
||||
<AccordionHeader class="flex" as="div">
|
||||
<AccordionHeader class="flex">
|
||||
<AccordionTrigger
|
||||
v-bind="props"
|
||||
v-bind="delegatedProps"
|
||||
:class="
|
||||
cn(
|
||||
'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 name="icon">
|
||||
<ChevronDown
|
||||
class="h-4 w-4 shrink-0 transition-transform duration-200"
|
||||
/>
|
||||
</slot>
|
||||
</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import { AlertDialogAction, type AlertDialogActionProps } from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
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>
|
||||
|
||||
<template>
|
||||
<AlertDialogAction v-bind="props" :class="cn(buttonVariants(), $attrs.class ?? '')">
|
||||
<AlertDialogAction v-bind="delegatedProps" :class="cn(buttonVariants(), props.class)">
|
||||
<slot />
|
||||
</AlertDialogAction>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import { AlertDialogCancel, type AlertDialogCancelProps } from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
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>
|
||||
|
||||
<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 />
|
||||
</AlertDialogCancel>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,30 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import {
|
||||
AlertDialogContent,
|
||||
type AlertDialogContentEmits,
|
||||
type AlertDialogContentProps,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogPortal,
|
||||
useEmitAsProps,
|
||||
useForwardPropsEmits,
|
||||
} from 'radix-vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<AlertDialogContentProps & { class?: string }>()
|
||||
const props = defineProps<AlertDialogContentProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<AlertDialogContentEmits>()
|
||||
|
||||
const emitsAsProps = useEmitAsProps(emits)
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AlertDialogPortal>
|
||||
<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
|
||||
v-bind="{ ...props, ...emitsAsProps }"
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
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,
|
||||
)
|
||||
"
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import {
|
||||
AlertDialogDescription,
|
||||
type AlertDialogDescriptionProps,
|
||||
} from 'radix-vue'
|
||||
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>
|
||||
|
||||
<template>
|
||||
<AlertDialogDescription
|
||||
:class="cn('text-muted-foreground text-sm', props.class)"
|
||||
:as-child="props.asChild"
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('text-sm text-muted-foreground', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogDescription>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="
|
||||
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,
|
||||
)
|
||||
"
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<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 />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import { AlertDialogTitle, type AlertDialogTitleProps } from 'radix-vue'
|
||||
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>
|
||||
|
||||
<template>
|
||||
<AlertDialogTitle
|
||||
:as-child="props.asChild"
|
||||
:class="cn('text-lg text-foreground font-semibold', props.class)"
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('text-lg font-semibold', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</AlertDialogTitle>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { alertVariants } from '.'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { type AlertVariants, alertVariants } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
variant?: NonNullable<Parameters<typeof alertVariants>[0]>['variant']
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
variant?: AlertVariants['variant']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn(alertVariants({ variant }), props.class ?? '')">
|
||||
<div :class="cn(alertVariants({ variant }), props.class)" role="alert">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: String,
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h5 :class="cn('mb-1 font-medium leading-none tracking-tight', $attrs.class ?? '')">
|
||||
<h5 :class="cn('mb-1 font-medium leading-none tracking-tight', props.class)">
|
||||
<slot />
|
||||
</h5>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { cva } from 'class-variance-authority'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Alert } from './Alert.vue'
|
||||
export { default as AlertTitle } from './AlertTitle.vue'
|
||||
|
|
@ -19,3 +19,5 @@ export const alertVariants = cva(
|
|||
},
|
||||
},
|
||||
)
|
||||
|
||||
export type AlertVariants = VariantProps<typeof alertVariants>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { AvatarRoot } from 'radix-vue'
|
||||
import { avatarVariant } from '.'
|
||||
import { type AvatarVariants, avatarVariant } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface Props {
|
||||
size?: NonNullable<Parameters<typeof avatarVariant>[0]>['size']
|
||||
shape?: NonNullable<Parameters<typeof avatarVariant>[0]>['shape']
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
const props = withDefaults(defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
size?: AvatarVariants['size']
|
||||
shape?: AvatarVariants['shape']
|
||||
}>(), {
|
||||
size: 'sm',
|
||||
shape: 'circle',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { cva } from 'class-variance-authority'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Avatar } from './Avatar.vue'
|
||||
export { default as AvatarImage } from './AvatarImage.vue'
|
||||
|
|
@ -20,3 +20,5 @@ export const avatarVariant = cva(
|
|||
},
|
||||
},
|
||||
)
|
||||
|
||||
export type AvatarVariants = VariantProps<typeof avatarVariant>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
import { badgeVariants } from '.'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { type BadgeVariants, badgeVariants } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface BadgeVariantProps extends VariantProps<typeof badgeVariants> {}
|
||||
|
||||
interface Props {
|
||||
variant?: BadgeVariantProps['variant']
|
||||
}
|
||||
defineProps<Props>()
|
||||
const props = defineProps<{
|
||||
variant?: BadgeVariants['variant']
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn(badgeVariants({ variant }), $attrs.class ?? '')">
|
||||
<div :class="cn(badgeVariants({ variant }), props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { cva } from 'class-variance-authority'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Badge } from './Badge.vue'
|
||||
|
||||
|
|
@ -21,3 +21,5 @@ export const badgeVariants = cva(
|
|||
},
|
||||
},
|
||||
)
|
||||
|
||||
export type BadgeVariants = VariantProps<typeof badgeVariants>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import type { VariantProps } from 'class-variance-authority'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { Primitive, type PrimitiveProps } from 'radix-vue'
|
||||
import { buttonVariants } from '.'
|
||||
import { type ButtonVariants, buttonVariants } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface ButtonVariantProps extends VariantProps<typeof buttonVariants> {}
|
||||
|
||||
interface Props extends PrimitiveProps {
|
||||
variant?: ButtonVariantProps['variant']
|
||||
size?: ButtonVariantProps['size']
|
||||
variant?: ButtonVariants['variant']
|
||||
size?: ButtonVariants['size']
|
||||
as?: string
|
||||
class?: HTMLAttributes['class']
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
as: 'button',
|
||||
})
|
||||
</script>
|
||||
|
|
@ -23,7 +20,7 @@ withDefaults(defineProps<Props>(), {
|
|||
<Primitive
|
||||
:as="as"
|
||||
:as-child="asChild"
|
||||
:class="cn(buttonVariants({ variant, size }), $attrs.class ?? '')"
|
||||
:class="cn(buttonVariants({ variant, size }), props.class)"
|
||||
>
|
||||
<slot />
|
||||
</Primitive>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { cva } from 'class-variance-authority'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Button } from './Button.vue'
|
||||
|
||||
export const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-md whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
@ -30,3 +30,5 @@ export const buttonVariants = cva(
|
|||
},
|
||||
},
|
||||
)
|
||||
|
||||
export type ButtonVariants = VariantProps<typeof buttonVariants>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-vue-next'
|
||||
import type { Calendar } from 'v-calendar'
|
||||
import { DatePicker } from 'v-calendar'
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-vue-next'
|
||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
||||
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
||||
import { computed, nextTick, onMounted, ref, useSlots } from 'vue'
|
||||
import { isVCalendarSlot } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { buttonVariants } from '@/lib/registry/default/ui/button'
|
||||
|
||||
/* Extracted from v-calendar */
|
||||
type DatePickerModel = DatePickerDate | DatePickerRangeObject
|
||||
|
|
@ -28,8 +29,7 @@ interface SimpleDateParts {
|
|||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
const props = withDefaults(defineProps< {
|
||||
modelValue?: string | number | Date | DatePickerModel
|
||||
modelModifiers?: object
|
||||
columns?: number
|
||||
|
|
@ -64,6 +64,16 @@ onMounted(async () => {
|
|||
if (modelValue.value instanceof Date && calendarRef.value)
|
||||
calendarRef.value.focusDate(modelValue.value)
|
||||
})
|
||||
|
||||
const $slots = useSlots()
|
||||
const vCalendarSlots = computed(() => {
|
||||
return Object.keys($slots)
|
||||
.filter(name => isVCalendarSlot(name))
|
||||
.reduce((obj: Record<string, any>, key: string) => {
|
||||
obj[key] = $slots[key]
|
||||
return obj
|
||||
}, {})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -79,18 +89,30 @@ onMounted(async () => {
|
|||
|
||||
<DatePicker
|
||||
ref="datePicker"
|
||||
v-model="modelValue"
|
||||
v-bind="$attrs"
|
||||
v-model="modelValue"
|
||||
:model-modifiers="modelModifiers"
|
||||
class="calendar"
|
||||
trim-weeks
|
||||
:transition="'none'"
|
||||
:columns="columns"
|
||||
/>
|
||||
>
|
||||
<template v-for="(_, slot) of vCalendarSlots" #[slot]="scope">
|
||||
<slot :name="slot" v-bind="scope" />
|
||||
</template>
|
||||
|
||||
<template #nav-prev-button>
|
||||
<ChevronLeft />
|
||||
</template>
|
||||
|
||||
<template #nav-next-button>
|
||||
<ChevronRight />
|
||||
</template>
|
||||
</DatePicker>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="postcss">
|
||||
<style lang="css">
|
||||
.calendar {
|
||||
@apply p-3 text-center;
|
||||
}
|
||||
|
|
@ -98,7 +120,25 @@ onMounted(async () => {
|
|||
@apply grid gap-4;
|
||||
}
|
||||
.calendar .vc-title {
|
||||
@apply text-sm font-medium pointer-events-none;
|
||||
@apply text-sm font-medium relative z-20;
|
||||
}
|
||||
.vc-popover-content-wrapper .vc-popover-content {
|
||||
@apply mt-3 rounded-md max-w-xs border bg-background;
|
||||
}
|
||||
.vc-popover-content-wrapper .vc-nav-header {
|
||||
@apply flex justify-between items-center p-2;
|
||||
}
|
||||
.vc-popover-content-wrapper .vc-nav-items {
|
||||
@apply grid grid-cols-4 gap-2 p-2;
|
||||
}
|
||||
.vc-popover-content-wrapper .vc-nav-items .vc-nav-item {
|
||||
@apply rounded-md px-2 py-1;
|
||||
}
|
||||
.vc-popover-content-wrapper .vc-nav-items .vc-nav-item:hover {
|
||||
@apply text-muted-foreground bg-muted;
|
||||
}
|
||||
.vc-popover-content-wrapper .vc-nav-items .vc-nav-item.is-active {
|
||||
@apply bg-primary text-primary-foreground;
|
||||
}
|
||||
.calendar .vc-pane-header-wrapper {
|
||||
@apply hidden;
|
||||
|
|
@ -107,19 +147,19 @@ onMounted(async () => {
|
|||
@apply mt-4;
|
||||
}
|
||||
.calendar .vc-weekdays {
|
||||
@apply flex;
|
||||
@apply justify-items-center;
|
||||
}
|
||||
.calendar .vc-weekday {
|
||||
@apply text-muted-foreground rounded-md w-9 font-normal text-[0.8rem];
|
||||
@apply text-muted-foreground rounded-md font-normal text-[0.8rem];
|
||||
}
|
||||
.calendar .vc-weeks {
|
||||
@apply w-full space-y-2 flex flex-col [&>_div]:grid [&>_div]:grid-cols-7;
|
||||
}
|
||||
.calendar .vc-day:has(.vc-highlights) {
|
||||
@apply bg-accent first:rounded-l-md last:rounded-r-md overflow-hidden;
|
||||
@apply first:rounded-l-md last:rounded-r-md;
|
||||
}
|
||||
.calendar .vc-day.is-today:not(:has(.vc-day-layer)) {
|
||||
@apply bg-secondary rounded-md;
|
||||
.calendar .vc-day.is-today:not(:has(.vc-day-layer)) .vc-day-content {
|
||||
@apply bg-secondary text-primary rounded-md;
|
||||
}
|
||||
.calendar .vc-day:has(.vc-highlight-base-start) {
|
||||
@apply rounded-l-md;
|
||||
|
|
@ -157,6 +197,7 @@ onMounted(async () => {
|
|||
--vc-slide-duration: 0.15s;
|
||||
--vc-slide-timing: ease;
|
||||
}
|
||||
|
||||
.calendar .vc-fade-enter-active,
|
||||
.calendar .vc-fade-leave-active,
|
||||
.calendar .vc-slide-left-enter-active,
|
||||
|
|
@ -183,6 +224,7 @@ onMounted(async () => {
|
|||
backface-visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.calendar .vc-none-leave-active,
|
||||
.calendar .vc-fade-leave-active,
|
||||
.calendar .vc-slide-left-leave-active,
|
||||
|
|
@ -192,6 +234,7 @@ onMounted(async () => {
|
|||
position: absolute !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.calendar .vc-none-enter-from,
|
||||
.calendar .vc-none-leave-to,
|
||||
.calendar .vc-fade-enter-from,
|
||||
|
|
@ -208,6 +251,7 @@ onMounted(async () => {
|
|||
.calendar .vc-slide-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.calendar .vc-slide-left-enter-from,
|
||||
.calendar .vc-slide-right-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-left,
|
||||
|
|
@ -215,6 +259,7 @@ onMounted(async () => {
|
|||
-webkit-transform: translateX(var(--vc-slide-translate));
|
||||
transform: translateX(var(--vc-slide-translate));
|
||||
}
|
||||
|
||||
.calendar .vc-slide-right-enter-from,
|
||||
.calendar .vc-slide-left-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-right,
|
||||
|
|
@ -222,6 +267,7 @@ onMounted(async () => {
|
|||
-webkit-transform: translateX(calc(-1 * var(--vc-slide-translate)));
|
||||
transform: translateX(calc(-1 * var(--vc-slide-translate)));
|
||||
}
|
||||
|
||||
.calendar .vc-slide-up-enter-from,
|
||||
.calendar .vc-slide-down-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-top,
|
||||
|
|
@ -229,6 +275,7 @@ onMounted(async () => {
|
|||
-webkit-transform: translateY(var(--vc-slide-translate));
|
||||
transform: translateY(var(--vc-slide-translate));
|
||||
}
|
||||
|
||||
.calendar .vc-slide-down-enter-from,
|
||||
.calendar .vc-slide-up-leave-to,
|
||||
.calendar .vc-slide-fade-enter-from.direction-bottom,
|
||||
|
|
|
|||
|
|
@ -1 +1,22 @@
|
|||
export { default as Calendar } from './Calendar.vue'
|
||||
import type { CalendarSlotName } from 'v-calendar/dist/types/src/components/Calendar/CalendarSlot.vue.d.ts'
|
||||
|
||||
export function isVCalendarSlot(slotName: string): slotName is CalendarSlotName {
|
||||
const validSlots: CalendarSlotName[] = [
|
||||
'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',
|
||||
]
|
||||
|
||||
return validSlots.includes(slotName as CalendarSlotName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('p-6 pt-0', props.class)">
|
||||
<div :class="cn('flex items-center p-6 pt-0', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('flex flex-col space-y-1.5 p-6', props.class)">
|
||||
<div :class="cn('flex flex-col gap-y-1.5 p-6', props.class)">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps({
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const props = defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3
|
||||
:class="
|
||||
cn('text-2xl font-semibold leading-none tracking-tighter', props.class)
|
||||
cn('text-2xl font-semibold leading-none tracking-tight', props.class)
|
||||
"
|
||||
>
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import emblaCarouselVue from 'embla-carousel-vue'
|
||||
import { useProvideCarousel } from './useCarousel'
|
||||
import type { CarouselEmits, CarouselProps, WithClassAsProps } from './interface'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { WithClassAsProps } from './interface'
|
||||
import { useCarousel } from './useCarousel'
|
||||
import type { WithClassAsProps } from './interface'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
defineOptions({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { WithClassAsProps } from './interface'
|
||||
import { useCarousel } from './useCarousel'
|
||||
import type { WithClassAsProps } from './interface'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<WithClassAsProps>()
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
<script setup lang="ts">
|
||||
import { type HTMLAttributes, computed } from 'vue'
|
||||
import type { CheckboxRootEmits, CheckboxRootProps } from 'radix-vue'
|
||||
import { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'radix-vue'
|
||||
import { Check } from 'lucide-vue-next'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = defineProps<CheckboxRootProps>()
|
||||
const props = defineProps<CheckboxRootProps & { class?: HTMLAttributes['class'] }>()
|
||||
const emits = defineEmits<CheckboxRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
const delegatedProps = computed(() => {
|
||||
const { class: _, ...delegated } = props
|
||||
|
||||
return delegated
|
||||
})
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -15,10 +22,12 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|||
v-bind="forwarded"
|
||||
:class="
|
||||
cn('peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
|
||||
$attrs.class ?? '')"
|
||||
props.class)"
|
||||
>
|
||||
<CheckboxIndicator class="flex h-full w-full items-center justify-center text-current">
|
||||
<slot>
|
||||
<Check class="h-4 w-4" />
|
||||
</slot>
|
||||
</CheckboxIndicator>
|
||||
</CheckboxRoot>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { CollapsibleRoot, useEmitAsProps } from 'radix-vue'
|
||||
import { CollapsibleRoot, useForwardPropsEmits } from 'radix-vue'
|
||||
import type { CollapsibleRootEmits, CollapsibleRootProps } from 'radix-vue'
|
||||
|
||||
const props = defineProps<CollapsibleRootProps>()
|
||||
const emits = defineEmits<CollapsibleRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CollapsibleRoot v-slot="{ open }" v-bind="{ ...props, ...useEmitAsProps(emits) }">
|
||||
<CollapsibleRoot v-slot="{ open }" v-bind="forwarded">
|
||||
<slot :open="open" />
|
||||
</CollapsibleRoot>
|
||||
</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