fix tailwind

This commit is contained in:
padreug 2025-03-11 01:52:56 +01:00
parent 00f4bfa583
commit f2a3f5e53e
63 changed files with 807 additions and 562 deletions

View file

@ -1,314 +1,146 @@
@import "tailwindcss"; @import 'tailwindcss';
@config "../../tailwind.config.js";
@plugin 'tailwindcss-animate';
@custom-variant dark (&:is(.dark *));
@theme {
--radius-lg: var(--radius);
--radius-md: calc(var(--radius) - 2px);
--radius-sm: calc(var(--radius) - 4px);
--color-background: oklch(var(--background));
--color-foreground: oklch(var(--foreground));
--color-card: oklch(var(--card));
--color-card-foreground: oklch(var(--card-foreground));
--color-popover: oklch(var(--popover));
--color-popover-foreground: oklch(var(--popover-foreground));
--color-primary: oklch(var(--primary));
--color-primary-foreground: oklch(var(--primary-foreground));
--color-secondary: oklch(var(--secondary));
--color-secondary-foreground: oklch(var(--secondary-foreground));
--color-muted: oklch(var(--muted));
--color-muted-foreground: oklch(var(--muted-foreground));
--color-accent: oklch(var(--accent));
--color-accent-foreground: oklch(var(--accent-foreground));
--color-destructive: oklch(var(--destructive));
--color-destructive-foreground: oklch(var(--destructive-foreground));
--color-border: oklch(var(--border));
--color-input: oklch(var(--input));
--color-ring: oklch(var(--ring));
--color-chart-1: oklch(var(--chart-1));
--color-chart-2: oklch(var(--chart-2));
--color-chart-3: oklch(var(--chart-3));
--color-chart-4: oklch(var(--chart-4));
--color-chart-5: oklch(var(--chart-5));
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--reka-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--reka-accordion-content-height);
}
to {
height: 0;
}
}
}
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
@layer base { @layer base {
:root { :root {
/* Light theme */ /* Catppuccin Latte */
--background: 0 0% 100%; --background: 0.97 0.005 235; /* base */
--background: oklch(0.97 0.02 250); --foreground: 0.30 0.02 235; /* text */
--foreground: 222.2 84% 4.9%; --card: 0.97 0.005 235;
--foreground: oklch(0.40 0.03 265); --card-foreground: 0.30 0.02 235;
--popover: 0.97 0.005 235;
--card: 0 0% 100%; --popover-foreground: 0.30 0.02 235;
--card: oklch(0.92 0.02 260); --primary: 0.55 0.15 250; /* lavender */
--card-foreground: 222.2 84% 4.9%; --primary-foreground: 0.97 0.005 235;
--card-foreground: oklch(0.40 0.03 265); --secondary: 0.90 0.03 235; /* surface1 */
--secondary-foreground: 0.30 0.02 235;
--popover: 0 0% 100%; --muted: 0.93 0.02 235; /* surface0 */
--popover: oklch(0.92 0.02 260); --muted-foreground: 0.50 0.02 235; /* subtext0 */
--popover-foreground: 222.2 84% 4.9%; --accent: 0.65 0.15 290; /* mauve */
--popover-foreground: oklch(0.40 0.03 265); --accent-foreground: 0.30 0.02 235;
--destructive: 0.65 0.25 0; /* red */
--primary: 222.2 47.4% 11.2%; --destructive-foreground: 0.97 0.005 235;
--primary: oklch(0.60 0.20 260); --border: 0.90 0.03 235; /* surface1 */
--primary-foreground: 210 40% 98%; --input: 0.90 0.03 235;
--primary-foreground: oklch(0.97 0.02 250); --ring: 0.55 0.15 250; /* lavender */
--chart-1: 0.65 0.25 0; /* red */
--secondary: 210 40% 96.1%; --chart-2: 0.75 0.20 30; /* peach */
--secondary: oklch(0.87 0.03 255); --chart-3: 0.80 0.15 90; /* yellow */
--secondary-foreground: 222.2 47.4% 11.2%; --chart-4: 0.70 0.15 150; /* green */
--secondary-foreground: oklch(0.40 0.03 265); --chart-5: 0.60 0.15 180; /* blue */
--muted: 210 40% 96.1%;
--muted: oklch(0.87 0.03 255);
--muted-foreground: 215.4 16.3% 46.9%;
--muted-foreground: oklch(0.55 0.03 265);
--accent: 210 40% 96.1%;
--accent: oklch(0.70 0.15 30);
--accent-foreground: 222.2 47.4% 11.2%;
--accent-foreground: oklch(0.97 0.02 250);
--destructive: 0 84.2% 60.2%;
--destructive: oklch(0.50 0.28 15);
--destructive-foreground: 210 40% 98%;
--destructive-foreground: oklch(0.97 0.02 250);
--border: 214.3 31.8% 91.4%;
--border: oklch(0.83 0.02 265);
--input: 214.3 31.8% 91.4%;
--input: oklch(0.83 0.02 265);
--ring: 222.2 84% 4.9%;
--ring: oklch(0.60 0.20 260);
--radius: 0.5rem; --radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
} }
.dark { .dark {
/* Dark theme */ /* Catppuccin Mocha */
--background: 222.2 84% 4.9%; --background: 0.20 0.02 235; /* base */
--background: oklch(0.25 0.05 265); --foreground: 0.90 0.02 235; /* text */
--foreground: 210 40% 98%; --card: 0.20 0.02 235;
--foreground: oklch(0.90 0.03 260); --card-foreground: 0.90 0.02 235;
--popover: 0.20 0.02 235;
--card: 222.2 84% 4.9%; --popover-foreground: 0.90 0.02 235;
--card: oklch(0.20 0.05 265); --primary: 0.55 0.15 250; /* lavender */
--card-foreground: 210 40% 98%; --primary-foreground: 0.20 0.02 235;
--card-foreground: oklch(0.90 0.03 260); --secondary: 0.25 0.02 235; /* surface1 */
--secondary-foreground: 0.90 0.02 235;
--popover: 222.2 84% 4.9%; --muted: 0.23 0.02 235; /* surface0 */
--popover: oklch(0.20 0.05 265); --muted-foreground: 0.70 0.02 235; /* subtext0 */
--popover-foreground: 210 40% 98%; --accent: 0.65 0.15 290; /* mauve */
--popover-foreground: oklch(0.90 0.03 260); --accent-foreground: 0.90 0.02 235;
--destructive: 0.65 0.25 0; /* red */
--primary: 210 40% 98%; --destructive-foreground: 0.90 0.02 235;
--primary: oklch(0.75 0.15 260); --border: 0.25 0.02 235; /* surface1 */
--primary-foreground: 222.2 47.4% 11.2%; --input: 0.25 0.02 235;
--primary-foreground: oklch(0.25 0.05 265); --ring: 0.55 0.15 250; /* lavender */
--chart-1: 0.65 0.25 0; /* red */
--secondary: 217.2 32.6% 17.5%; --chart-2: 0.75 0.20 30; /* peach */
--secondary: oklch(0.30 0.06 265); --chart-3: 0.80 0.15 90; /* yellow */
--secondary-foreground: 210 40% 98%; --chart-4: 0.70 0.15 150; /* green */
--secondary-foreground: oklch(0.90 0.03 260); --chart-5: 0.60 0.15 180; /* blue */
--muted: 217.2 32.6% 17.5%;
--muted: oklch(0.30 0.06 265);
--muted-foreground: 215 20.2% 65.1%;
--muted-foreground: oklch(0.78 0.06 265);
--accent: 217.2 32.6% 17.5%;
--accent: oklch(0.83 0.12 30);
--accent-foreground: 210 40% 98%;
--accent-foreground: oklch(0.25 0.05 265);
--destructive: 0 62.8% 30.6%;
--destructive: oklch(0.75 0.18 15);
--destructive-foreground: 210 40% 98%;
--destructive-foreground: oklch(0.25 0.05 265);
--border: 217.2 32.6% 17.5%;
--border: oklch(0.30 0.06 265);
--input: 217.2 32.6% 17.5%;
--input: oklch(0.30 0.06 265);
--ring: 212.7 26.8% 83.9%;
--ring: oklch(0.75 0.15 260);
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
} }
} }
@layer base {
* {
@apply box-border;
}
body {
@apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
@layer utilities {
.bg-background {
background-color: var(--background);
}
.bg-foreground {
background-color: var(--foreground);
}
.bg-card {
background-color: var(--card);
}
.bg-card-foreground {
background-color: var(--card-foreground);
}
.bg-popover {
background-color: var(--popover);
}
.bg-popover-foreground {
background-color: var(--popover-foreground);
}
.bg-primary {
background-color: var(--primary);
}
.bg-primary-foreground {
background-color: var(--primary-foreground);
}
.bg-secondary {
background-color: var(--secondary);
}
.bg-secondary-foreground {
background-color: var(--secondary-foreground);
}
.bg-muted {
background-color: var(--muted);
}
.bg-muted-foreground {
background-color: var(--muted-foreground);
}
.bg-accent {
background-color: var(--accent);
}
.bg-accent-foreground {
background-color: var(--accent-foreground);
}
.bg-destructive {
background-color: var(--destructive);
}
.bg-destructive-foreground {
background-color: var(--destructive-foreground);
}
.text-background {
color: var(--background);
}
.text-foreground {
color: var(--foreground);
}
.text-card {
color: var(--card);
}
.text-card-foreground {
color: var(--card-foreground);
}
.text-popover {
color: var(--popover);
}
.text-popover-foreground {
color: var(--popover-foreground);
}
.text-primary {
color: var(--primary);
}
.text-primary-foreground {
color: var(--primary-foreground);
}
.text-secondary {
color: var(--secondary);
}
.text-secondary-foreground {
color: var(--secondary-foreground);
}
.text-muted {
color: var(--muted);
}
.text-muted-foreground {
color: var(--muted-foreground);
}
.text-accent {
color: var(--accent);
}
.text-accent-foreground {
color: var(--accent-foreground);
}
.text-destructive {
color: var(--destructive);
}
.text-destructive-foreground {
color: var(--destructive-foreground);
}
@supports not (backdrop-filter: blur(1px)) {
.select-content {
background-color: var(--background);
}
}
}
/* Add support for ring colors */
@layer utilities {
.ring-border {
--tw-ring-color: var(--border);
}
.ring-primary {
--tw-ring-color: var(--primary);
}
.ring-background {
--tw-ring-color: var(--background);
}
}
/* Add support for border colors */
@layer utilities {
.border {
border-color: var(--border);
}
.border-x {
border-left-color: var(--border);
border-right-color: var(--border);
}
.border-y {
border-top-color: var(--border);
border-bottom-color: var(--border);
}
.border-t {
border-top-color: var(--border);
}
.border-r {
border-right-color: var(--border);
}
.border-b {
border-bottom-color: var(--border);
}
.border-l {
border-left-color: var(--border);
}
.border-primary {
border-color: var(--primary);
}
.border-background {
border-color: var(--background);
}
.border-foreground {
border-color: var(--foreground);
}
.border-card {
border-color: var(--card);
}
.border-card-foreground {
border-color: var(--card-foreground);
}
.border-muted {
border-color: var(--muted);
}
.border-muted-foreground {
border-color: var(--muted-foreground);
}
.border-accent {
border-color: var(--accent);
}
.border-accent-foreground {
border-color: var(--accent-foreground);
}
.border-destructive {
border-color: var(--destructive);
}
.border-destructive-foreground {
border-color: var(--destructive-foreground);
}
}
@layer base { @layer base {
* { * {
@apply border-border; @apply border-border;

View file

@ -4,7 +4,7 @@ import {
type AccordionRootEmits, type AccordionRootEmits,
type AccordionRootProps, type AccordionRootProps,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'reka-ui'
const props = defineProps<AccordionRootProps>() const props = defineProps<AccordionRootProps>()
const emits = defineEmits<AccordionRootEmits>() const emits = defineEmits<AccordionRootEmits>()

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { AccordionContent, type AccordionContentProps } from 'radix-vue' import { AccordionContent, type AccordionContentProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AccordionContentProps & { class?: HTMLAttributes['class'] }>()
@ -15,7 +15,7 @@ const delegatedProps = computed(() => {
<template> <template>
<AccordionContent <AccordionContent
v-bind="delegatedProps" v-bind="delegatedProps"
class="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down" class="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
> >
<div :class="cn('pb-4 pt-0', props.class)"> <div :class="cn('pb-4 pt-0', props.class)">
<slot /> <slot />

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { AccordionItem, type AccordionItemProps, useForwardProps } from 'radix-vue' import { AccordionItem, type AccordionItemProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()

View file

@ -5,7 +5,7 @@ import {
AccordionHeader, AccordionHeader,
AccordionTrigger, AccordionTrigger,
type AccordionTriggerProps, type AccordionTriggerProps,
} from 'radix-vue' } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes['class'] }>()
@ -23,7 +23,7 @@ const delegatedProps = computed(() => {
v-bind="delegatedProps" v-bind="delegatedProps"
:class=" :class="
cn( cn(
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180', 'flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
props.class, props.class,
) )
" "
@ -31,7 +31,7 @@ const delegatedProps = computed(() => {
<slot /> <slot />
<slot name="icon"> <slot name="icon">
<ChevronDown <ChevronDown
class="h-4 w-4 shrink-0 transition-transform duration-200" class="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200"
/> />
</slot> </slot>
</AccordionTrigger> </AccordionTrigger>

View file

@ -1,16 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { AvatarRoot } from 'reka-ui'
import { avatarVariant, type AvatarVariants } from '.'
const props = defineProps<{ const props = withDefaults(defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes['class']
}>() size?: AvatarVariants['size']
shape?: AvatarVariants['shape']
}>(), {
size: 'sm',
shape: 'circle',
})
</script> </script>
<template> <template>
<div <AvatarRoot :class="cn(avatarVariant({ size, shape }), props.class)">
:class="cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', props.class)"
>
<slot /> <slot />
</div> </AvatarRoot>
</template> </template>

View file

@ -1,16 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import { AvatarFallback, type AvatarFallbackProps } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<{ const props = defineProps<AvatarFallbackProps>()
class?: HTMLAttributes['class']
}>()
</script> </script>
<template> <template>
<div <AvatarFallback v-bind="props">
:class="cn('flex h-full w-full items-center justify-center rounded-full bg-muted', props.class)"
>
<slot /> <slot />
</div> </AvatarFallback>
</template> </template>

View file

@ -1,18 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { AvatarImageProps } from 'reka-ui'
import { cn } from '@/lib/utils' import { AvatarImage } from 'reka-ui'
const props = defineProps<{ const props = defineProps<AvatarImageProps>()
src?: string
alt?: string
class?: HTMLAttributes['class']
}>()
</script> </script>
<template> <template>
<img <AvatarImage v-bind="props" class="h-full w-full object-cover">
:src="src" <slot />
:alt="alt" </AvatarImage>
:class="cn('aspect-square h-full w-full', props.class)"
/>
</template> </template>

View file

@ -1,3 +1,24 @@
import { cva, type VariantProps } from 'class-variance-authority'
export { default as Avatar } from './Avatar.vue' export { default as Avatar } from './Avatar.vue'
export { default as AvatarImage } from './AvatarImage.vue'
export { default as AvatarFallback } from './AvatarFallback.vue' export { default as AvatarFallback } from './AvatarFallback.vue'
export { default as AvatarImage } from './AvatarImage.vue'
export const avatarVariant = cva(
'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden',
{
variants: {
size: {
sm: 'h-10 w-10 text-xs',
base: 'h-16 w-16 text-2xl',
lg: 'h-32 w-32 text-5xl',
},
shape: {
circle: 'rounded-full',
square: 'rounded-md',
},
},
},
)
export type AvatarVariants = VariantProps<typeof avatarVariant>

View file

@ -10,7 +10,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<span :class="cn(badgeVariants({ variant: props.variant }), props.class)"> <div :class="cn(badgeVariants({ variant }), props.class)">
<slot /> <slot />
</span> </div>
</template> </template>

View file

@ -3,21 +3,17 @@ import { cva, type VariantProps } from 'class-variance-authority'
export { default as Badge } from './Badge.vue' export { default as Badge } from './Badge.vue'
export const badgeVariants = cva( export const badgeVariants = cva(
'inline-flex items-center whitespace-nowrap rounded-full border px-1.5 py-0.5 text-[10px] font-medium transition-colors', 'inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2',
{ {
variants: { variants: {
variant: { variant: {
default: default:
'border-transparent bg-primary/10 text-primary hover:bg-primary/20', 'border-transparent bg-primary text-primary-foreground shadow-sm hover:bg-primary/80',
secondary: secondary:
'border-transparent bg-secondary/10 text-secondary-foreground hover:bg-secondary/20', 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
destructive: destructive:
'border-transparent bg-destructive/10 text-destructive hover:bg-destructive/20', 'border-transparent bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/80',
success: outline: 'text-foreground',
'border-transparent bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400',
warning:
'border-transparent bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400',
outline: 'border-border text-foreground hover:bg-accent hover:text-accent-foreground',
}, },
}, },
defaultVariants: { defaultVariants: {

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { Primitive, type PrimitiveProps } from 'radix-vue' import { Primitive, type PrimitiveProps } from 'reka-ui'
import { type ButtonVariants, buttonVariants } from '.' import { type ButtonVariants, buttonVariants } from '.'
interface Props extends PrimitiveProps { interface Props extends PrimitiveProps {
@ -16,7 +16,11 @@ const props = withDefaults(defineProps<Props>(), {
</script> </script>
<template> <template>
<Primitive :as="as" :as-child="asChild" :class="cn(buttonVariants({ variant, size }), props.class)"> <Primitive
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
>
<slot /> <slot />
</Primitive> </Primitive>
</template> </template>

View file

@ -3,23 +3,23 @@ import { cva, type VariantProps } from 'class-variance-authority'
export { default as Button } from './Button.vue' export { default as Button } from './Button.vue'
export const buttonVariants = cva( export const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 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 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{ {
variants: { variants: {
variant: { variant: {
default: default: 'bg-primary text-primary-foreground shadow-sm hover:bg-primary/90',
'bg-primary text-primary-foreground shadow hover:bg-primary/90',
destructive: destructive:
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', 'bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90',
outline: outline:
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', 'border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground',
secondary: secondary:
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground', ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline', link: 'text-primary underline-offset-4 hover:underline',
}, },
size: { size: {
default: 'h-9 px-4 py-2', default: 'h-9 px-4 py-2',
xs: 'h-7 rounded px-2',
sm: 'h-8 rounded-md px-3 text-xs', sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8', lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9', icon: 'h-9 w-9',

View file

@ -9,7 +9,12 @@ const props = defineProps<{
<template> <template>
<div <div
:class="cn('rounded-lg border bg-card text-card-foreground shadow-sm', props.class)" :class="
cn(
'rounded-xl border bg-card text-card-foreground shadow-sm',
props.class,
)
"
> >
<slot /> <slot />
</div> </div>

View file

@ -8,11 +8,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<div <div :class="cn('p-6 pt-0', props.class)">
:class="
cn('p-6 pt-0', props.class)
"
>
<slot /> <slot />
</div> </div>
</template> </template>

View file

@ -8,11 +8,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<p <p :class="cn('text-sm text-muted-foreground', props.class)">
:class="
cn('text-sm text-muted-foreground', props.class)
"
>
<slot /> <slot />
</p> </p>
</template> </template>

View file

@ -8,11 +8,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<div <div :class="cn('flex items-center p-6 pt-0', props.class)">
:class="
cn('flex items-center p-6 pt-0', props.class)
"
>
<slot /> <slot />
</div> </div>
</template> </template>

View file

@ -8,11 +8,7 @@ const props = defineProps<{
</script> </script>
<template> <template>
<div <div :class="cn('flex flex-col gap-y-1.5 p-6', props.class)">
:class="
cn('flex flex-col space-y-1.5 p-6', props.class)
"
>
<slot /> <slot />
</div> </div>
</template> </template>

View file

@ -10,7 +10,7 @@ const props = defineProps<{
<template> <template>
<h3 <h3
:class=" :class="
cn('text-2xl font-semibold leading-none tracking-tight', props.class) cn('font-semibold leading-none tracking-tight', props.class)
" "
> >
<slot /> <slot />

View file

@ -1,19 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogRoot } from 'radix-vue' import { DialogRoot, type DialogRootEmits, type DialogRootProps, useForwardPropsEmits } from 'reka-ui'
const props = defineProps<{ const props = defineProps<DialogRootProps>()
open?: boolean const emits = defineEmits<DialogRootEmits>()
defaultOpen?: boolean
modal?: boolean
}>()
const emits = defineEmits<{ const forwarded = useForwardPropsEmits(props, emits)
'update:open': [value: boolean]
}>()
</script> </script>
<template> <template>
<DialogRoot v-bind="props" @update:open="emits('update:open', $event)"> <DialogRoot v-bind="forwarded">
<slot /> <slot />
</DialogRoot> </DialogRoot>
</template> </template>

View file

@ -0,0 +1,11 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from 'reka-ui'
const props = defineProps<DialogCloseProps>()
</script>
<template>
<DialogClose v-bind="props">
<slot />
</DialogClose>
</template>

View file

@ -1,12 +1,27 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogPortal, DialogOverlay, DialogContent as DialogContentPrimitive, DialogClose } from 'radix-vue'
import { X } from 'lucide-vue-next'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import type { HTMLAttributes } from 'vue' import { X } from 'lucide-vue-next'
import {
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<{ const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
class?: HTMLAttributes['class'] const emits = defineEmits<DialogContentEmits>()
}>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script> </script>
<template> <template>
@ -14,19 +29,22 @@ const props = defineProps<{
<DialogOverlay <DialogOverlay
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" 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"
/> />
<DialogContentPrimitive <DialogContent
:class="cn( v-bind="forwarded"
'fixed left-[50%] top-[50%] z-50 grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] 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 mx-auto', :class="
props.class cn(
'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,
)" )"
> >
<slot /> <slot />
<DialogClose <DialogClose
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground" class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
> >
<X class="h-4 w-4" /> <X class="w-4 h-4" />
<span class="sr-only">Close</span> <span class="sr-only">Close</span>
</DialogClose> </DialogClose>
</DialogContentPrimitive> </DialogContent>
</DialogPortal> </DialogPortal>
</template> </template>

View file

@ -1,15 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogDescription as DialogDescriptionPrimitive } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import type { HTMLAttributes } from 'vue' import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<{ const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
class?: HTMLAttributes['class']
}>() const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script> </script>
<template> <template>
<DialogDescriptionPrimitive :class="cn('text-sm text-muted-foreground', props.class)"> <DialogDescription
v-bind="forwardedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
>
<slot /> <slot />
</DialogDescriptionPrimitive> </DialogDescription>
</template> </template>

View file

@ -1,14 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils'
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{ const props = defineProps<{ class?: HTMLAttributes['class'] }>()
class?: HTMLAttributes['class']
}>()
</script> </script>
<template> <template>
<div :class="cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', props.class)"> <div
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
props.class,
)
"
>
<slot /> <slot />
</div> </div>
</template> </template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils'
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{ const props = defineProps<{
class?: HTMLAttributes['class'] class?: HTMLAttributes['class']
@ -8,7 +8,9 @@ const props = defineProps<{
</script> </script>
<template> <template>
<div :class="cn('flex flex-col space-y-1.5 text-center sm:text-left', props.class)"> <div
:class="cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)"
>
<slot /> <slot />
</div> </div>
</template> </template>

View file

@ -0,0 +1,59 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { X } from 'lucide-vue-next'
import {
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DialogContentEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto 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"
>
<DialogContent
:class="
cn(
'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',
props.class,
)
"
v-bind="forwarded"
@pointer-down-outside="(event) => {
const originalEvent = event.detail.originalEvent;
const target = originalEvent.target as HTMLElement;
if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
event.preventDefault();
}
}"
>
<slot />
<DialogClose
class="absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary"
>
<X class="w-4 h-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogOverlay>
</DialogPortal>
</template>

View file

@ -1,15 +1,29 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogTitle as DialogTitlePrimitive } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import type { HTMLAttributes } from 'vue' import { DialogTitle, type DialogTitleProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<{ const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
class?: HTMLAttributes['class']
}>() const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script> </script>
<template> <template>
<DialogTitlePrimitive :class="cn('text-lg font-semibold leading-none tracking-tight', props.class)"> <DialogTitle
v-bind="forwardedProps"
:class="
cn(
'text-lg font-semibold leading-none tracking-tight',
props.class,
)
"
>
<slot /> <slot />
</DialogTitlePrimitive> </DialogTitle>
</template> </template>

View file

@ -1,16 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { DialogTrigger as DialogTriggerPrimitive } from 'radix-vue' import { DialogTrigger, type DialogTriggerProps } from 'reka-ui'
import { cn } from '@/lib/utils'
import type { HTMLAttributes } from 'vue'
const props = defineProps<{ const props = defineProps<DialogTriggerProps>()
class?: HTMLAttributes['class']
asChild?: boolean
}>()
</script> </script>
<template> <template>
<DialogTriggerPrimitive v-bind="props" :class="cn(props.class)"> <DialogTrigger v-bind="props">
<slot /> <slot />
</DialogTriggerPrimitive> </DialogTrigger>
</template> </template>

View file

@ -1,17 +1,9 @@
export { default as Dialog } from './Dialog.vue' export { default as Dialog } from './Dialog.vue'
export { default as DialogClose } from './DialogClose.vue'
export { default as DialogContent } from './DialogContent.vue' export { default as DialogContent } from './DialogContent.vue'
export { default as DialogDescription } from './DialogDescription.vue' export { default as DialogDescription } from './DialogDescription.vue'
export { default as DialogFooter } from './DialogFooter.vue' export { default as DialogFooter } from './DialogFooter.vue'
export { default as DialogHeader } from './DialogHeader.vue' export { default as DialogHeader } from './DialogHeader.vue'
export { default as DialogScrollContent } from './DialogScrollContent.vue'
export { default as DialogTitle } from './DialogTitle.vue' export { default as DialogTitle } from './DialogTitle.vue'
export { default as DialogTrigger } from './DialogTrigger.vue' export { default as DialogTrigger } from './DialogTrigger.vue'
export type {
DialogRootEmits,
DialogRootProps,
DialogOverlayProps,
DialogPortalProps,
DialogContentProps,
DialogTitleProps,
DialogTriggerProps,
} from 'radix-vue'

View file

@ -1,17 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenuRoot } from 'radix-vue' import { DropdownMenuRoot, type DropdownMenuRootEmits, type DropdownMenuRootProps, useForwardPropsEmits } from 'reka-ui'
defineOptions({ const props = defineProps<DropdownMenuRootProps>()
name: 'DropdownMenu' const emits = defineEmits<DropdownMenuRootEmits>()
})
defineSlots<{ const forwarded = useForwardPropsEmits(props, emits)
default?: (props: {}) => any
}>()
</script> </script>
<template> <template>
<DropdownMenuRoot v-bind="$attrs"> <DropdownMenuRoot v-bind="forwarded">
<slot /> <slot />
</DropdownMenuRoot> </DropdownMenuRoot>
</template> </template>

View file

@ -0,0 +1,40 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { Check } from 'lucide-vue-next'
import {
DropdownMenuCheckboxItem,
type DropdownMenuCheckboxItemEmits,
type DropdownMenuCheckboxItemProps,
DropdownMenuItemIndicator,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DropdownMenuCheckboxItemEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<DropdownMenuCheckboxItem
v-bind="forwarded"
:class=" cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
props.class,
)"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Check class="w-4 h-4" />
</DropdownMenuItemIndicator>
</span>
<slot />
</DropdownMenuCheckboxItem>
</template>

View file

@ -1,31 +1,38 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenuContent, type DropdownMenuContentProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import {
defineOptions({ DropdownMenuContent,
name: 'DropdownMenuContent' type DropdownMenuContentEmits,
}) type DropdownMenuContentProps,
DropdownMenuPortal,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = withDefaults( const props = withDefaults(
defineProps<DropdownMenuContentProps & { defineProps<DropdownMenuContentProps & { class?: HTMLAttributes['class'] }>(),
class?: string
}>(),
{ {
sideOffset: 4, sideOffset: 4,
align: 'start', },
class: ''
}
) )
const emits = defineEmits<DropdownMenuContentEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script> </script>
<template> <template>
<DropdownMenuPortal>
<DropdownMenuContent <DropdownMenuContent
:class="cn( v-bind="forwarded"
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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', :class="cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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', props.class)"
props.class
)"
v-bind="{ ...props, ...$attrs }"
> >
<slot /> <slot />
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenuPortal>
</template> </template>

View file

@ -0,0 +1,11 @@
<script setup lang="ts">
import { DropdownMenuGroup, type DropdownMenuGroupProps } from 'reka-ui'
const props = defineProps<DropdownMenuGroupProps>()
</script>
<template>
<DropdownMenuGroup v-bind="props">
<slot />
</DropdownMenuGroup>
</template>

View file

@ -1,33 +1,27 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenuItem, type DropdownMenuItemProps } from 'radix-vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { DropdownMenuItem, type DropdownMenuItemProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
defineOptions({ const props = defineProps<DropdownMenuItemProps & { class?: HTMLAttributes['class'], inset?: boolean }>()
name: 'DropdownMenuItem'
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
}) })
const props = withDefaults( const forwardedProps = useForwardProps(delegatedProps)
defineProps<
DropdownMenuItemProps & {
class?: string
inset?: boolean
}
>(),
{
class: '',
inset: false
}
)
</script> </script>
<template> <template>
<DropdownMenuItem <DropdownMenuItem
v-bind="forwardedProps"
:class="cn( :class="cn(
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', 'relative flex cursor-default select-none items-center rounded-sm gap-2 px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0',
inset && 'pl-8', inset && 'pl-8',
props.class props.class,
)" )"
v-bind="{ ...props, ...$attrs }"
> >
<slot /> <slot />
</DropdownMenuItem> </DropdownMenuItem>

View file

@ -0,0 +1,24 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { DropdownMenuLabel, type DropdownMenuLabelProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuLabelProps & { class?: HTMLAttributes['class'], inset?: boolean }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<DropdownMenuLabel
v-bind="forwardedProps"
:class="cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', props.class)"
>
<slot />
</DropdownMenuLabel>
</template>

View file

@ -0,0 +1,19 @@
<script setup lang="ts">
import {
DropdownMenuRadioGroup,
type DropdownMenuRadioGroupEmits,
type DropdownMenuRadioGroupProps,
useForwardPropsEmits,
} from 'reka-ui'
const props = defineProps<DropdownMenuRadioGroupProps>()
const emits = defineEmits<DropdownMenuRadioGroupEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<DropdownMenuRadioGroup v-bind="forwarded">
<slot />
</DropdownMenuRadioGroup>
</template>

View file

@ -0,0 +1,41 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { Circle } from 'lucide-vue-next'
import {
DropdownMenuItemIndicator,
DropdownMenuRadioItem,
type DropdownMenuRadioItemEmits,
type DropdownMenuRadioItemProps,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DropdownMenuRadioItemEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<DropdownMenuRadioItem
v-bind="forwarded"
:class="cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
props.class,
)"
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuItemIndicator>
<Circle class="h-4 w-4 fill-current" />
</DropdownMenuItemIndicator>
</span>
<slot />
</DropdownMenuRadioItem>
</template>

View file

@ -0,0 +1,22 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import {
DropdownMenuSeparator,
type DropdownMenuSeparatorProps,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuSeparatorProps & {
class?: HTMLAttributes['class']
}>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>
<template>
<DropdownMenuSeparator v-bind="delegatedProps" :class="cn('-mx-1 my-1 h-px bg-muted', props.class)" />
</template>

View file

@ -0,0 +1,14 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
</script>
<template>
<span :class="cn('ml-auto text-xs tracking-widest opacity-60', props.class)">
<slot />
</span>
</template>

View file

@ -0,0 +1,19 @@
<script setup lang="ts">
import {
DropdownMenuSub,
type DropdownMenuSubEmits,
type DropdownMenuSubProps,
useForwardPropsEmits,
} from 'reka-ui'
const props = defineProps<DropdownMenuSubProps>()
const emits = defineEmits<DropdownMenuSubEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<DropdownMenuSub v-bind="forwarded">
<slot />
</DropdownMenuSub>
</template>

View file

@ -0,0 +1,30 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import {
DropdownMenuSubContent,
type DropdownMenuSubContentEmits,
type DropdownMenuSubContentProps,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DropdownMenuSubContentEmits>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<DropdownMenuSubContent
v-bind="forwarded"
:class="cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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', props.class)"
>
<slot />
</DropdownMenuSubContent>
</template>

View file

@ -0,0 +1,33 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { ChevronRight } from 'lucide-vue-next'
import {
DropdownMenuSubTrigger,
type DropdownMenuSubTriggerProps,
useForwardProps,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DropdownMenuSubTriggerProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<DropdownMenuSubTrigger
v-bind="forwardedProps"
:class="cn(
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent data-[state=open]:bg-accent',
props.class,
)"
>
<slot />
<ChevronRight class="ml-auto h-4 w-4" />
</DropdownMenuSubTrigger>
</template>

View file

@ -1,22 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import { DropdownMenuTrigger } from 'radix-vue' import { DropdownMenuTrigger, type DropdownMenuTriggerProps, useForwardProps } from 'reka-ui'
defineOptions({ const props = defineProps<DropdownMenuTriggerProps>()
name: 'DropdownMenuTrigger'
})
const props = withDefaults( const forwardedProps = useForwardProps(props)
defineProps<{
asChild?: boolean
}>(),
{
asChild: false
}
)
</script> </script>
<template> <template>
<DropdownMenuTrigger v-bind="{ ...props, ...$attrs }"> <DropdownMenuTrigger class="outline-hidden" v-bind="forwardedProps">
<slot /> <slot />
</DropdownMenuTrigger> </DropdownMenuTrigger>
</template> </template>

View file

@ -1,4 +1,16 @@
export { default as DropdownMenu } from './DropdownMenu.vue' export { default as DropdownMenu } from './DropdownMenu.vue'
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
export { default as DropdownMenuCheckboxItem } from './DropdownMenuCheckboxItem.vue'
export { default as DropdownMenuContent } from './DropdownMenuContent.vue' export { default as DropdownMenuContent } from './DropdownMenuContent.vue'
export { default as DropdownMenuGroup } from './DropdownMenuGroup.vue'
export { default as DropdownMenuItem } from './DropdownMenuItem.vue' export { default as DropdownMenuItem } from './DropdownMenuItem.vue'
export { default as DropdownMenuLabel } from './DropdownMenuLabel.vue'
export { default as DropdownMenuRadioGroup } from './DropdownMenuRadioGroup.vue'
export { default as DropdownMenuRadioItem } from './DropdownMenuRadioItem.vue'
export { default as DropdownMenuSeparator } from './DropdownMenuSeparator.vue'
export { default as DropdownMenuShortcut } from './DropdownMenuShortcut.vue'
export { default as DropdownMenuSub } from './DropdownMenuSub.vue'
export { default as DropdownMenuSubContent } from './DropdownMenuSubContent.vue'
export { default as DropdownMenuSubTrigger } from './DropdownMenuSubTrigger.vue'
export { default as DropdownMenuTrigger } from './DropdownMenuTrigger.vue'
export { DropdownMenuPortal } from 'reka-ui'

View file

@ -20,5 +20,5 @@ const modelValue = useVModel(props, 'modelValue', emits, {
</script> </script>
<template> <template>
<input v-model="modelValue" :class="cn('flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', props.class)"> <input v-model="modelValue" :class="cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', props.class)">
</template> </template>

View file

@ -0,0 +1,27 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { Label, type LabelProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<LabelProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>
<template>
<Label
v-bind="delegatedProps"
:class="
cn(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
props.class,
)
"
>
<slot />
</Label>
</template>

View file

@ -1,8 +1 @@
import { Label as LabelPrimitive } from 'radix-vue' export { default as Label } from './Label.vue'
import { tv } from 'tailwind-variants'
export const labelVariants = tv({
base: 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
})
export const Label = LabelPrimitive.Root

View file

@ -5,7 +5,7 @@ import {
ScrollAreaRoot, ScrollAreaRoot,
type ScrollAreaRootProps, type ScrollAreaRootProps,
ScrollAreaViewport, ScrollAreaViewport,
} from 'radix-vue' } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
import ScrollBar from './ScrollBar.vue' import ScrollBar from './ScrollBar.vue'

View file

@ -1,17 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { import { ScrollAreaScrollbar, type ScrollAreaScrollbarProps, ScrollAreaThumb } from 'reka-ui'
ScrollAreaScrollbar,
ScrollAreaThumb,
type ScrollAreaScrollbarProps,
} from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps< const props = withDefaults(defineProps<ScrollAreaScrollbarProps & { class?: HTMLAttributes['class'] }>(), {
ScrollAreaScrollbarProps & { orientation: 'vertical',
class?: HTMLAttributes['class'] })
}
>()
const delegatedProps = computed(() => { const delegatedProps = computed(() => {
const { class: _, ...delegated } = props const { class: _, ...delegated } = props
@ -23,20 +17,14 @@ const delegatedProps = computed(() => {
<template> <template>
<ScrollAreaScrollbar <ScrollAreaScrollbar
v-bind="delegatedProps" v-bind="delegatedProps"
:class="cn( :class="
'flex touch-none select-none transition-colors', cn('flex touch-none select-none transition-colors',
props.orientation === 'vertical' && orientation === 'vertical'
'h-full w-2.5 border-l border-l-transparent p-[1px]', && 'h-full w-2.5 border-l border-l-transparent p-px',
props.orientation === 'horizontal' && orientation === 'horizontal'
'h-2.5 border-t border-t-transparent p-[1px]', && 'h-2.5 flex-col border-t border-t-transparent p-px',
props.class props.class)"
)"
> >
<ScrollAreaThumb <ScrollAreaThumb class="relative flex-1 rounded-full bg-border" />
:class="cn(
'relative rounded-full bg-border',
props.orientation === 'vertical' && 'flex-1'
)"
/>
</ScrollAreaScrollbar> </ScrollAreaScrollbar>
</template> </template>

View file

@ -1 +1,2 @@
export { default as ScrollArea } from './ScrollArea.vue' export { default as ScrollArea } from './ScrollArea.vue'
export { default as ScrollBar } from './ScrollBar.vue'

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectRootEmits, SelectRootProps } from 'radix-vue' import type { SelectRootEmits, SelectRootProps } from 'reka-ui'
import { SelectRoot, useForwardPropsEmits } from 'radix-vue' import { SelectRoot, useForwardPropsEmits } from 'reka-ui'
const props = defineProps<SelectRootProps>() const props = defineProps<SelectRootProps>()
const emits = defineEmits<SelectRootEmits>() const emits = defineEmits<SelectRootEmits>()

View file

@ -7,7 +7,7 @@ import {
SelectPortal, SelectPortal,
SelectViewport, SelectViewport,
useForwardPropsEmits, useForwardPropsEmits,
} from 'radix-vue' } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
import { SelectScrollDownButton, SelectScrollUpButton } from '.' import { SelectScrollDownButton, SelectScrollUpButton } from '.'
@ -37,9 +37,6 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
<SelectContent <SelectContent
v-bind="{ ...forwarded, ...$attrs }" :class="cn( v-bind="{ ...forwarded, ...$attrs }" :class="cn(
'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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', 'relative z-50 max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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',
'bg-background dark:bg-background',
'backdrop-blur-sm backdrop-saturate-150 bg-opacity-90 dark:bg-opacity-90',
'[&>div]:bg-background [&>div]:dark:bg-background',
position === 'popper' position === 'popper'
&& 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', && 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
props.class, props.class,
@ -47,7 +44,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
" "
> >
<SelectScrollUpButton /> <SelectScrollUpButton />
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[--radix-select-trigger-height] w-full min-w-[--radix-select-trigger-width]')"> <SelectViewport :class="cn('p-1', position === 'popper' && 'h-(--reka-select-trigger-height) w-full min-w-(--reka-select-trigger-width)')">
<slot /> <slot />
</SelectViewport> </SelectViewport>
<SelectScrollDownButton /> <SelectScrollDownButton />

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectGroup, type SelectGroupProps } from 'radix-vue' import { SelectGroup, type SelectGroupProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectGroupProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectGroupProps & { class?: HTMLAttributes['class'] }>()

View file

@ -7,7 +7,7 @@ import {
type SelectItemProps, type SelectItemProps,
SelectItemText, SelectItemText,
useForwardProps, useForwardProps,
} from 'radix-vue' } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectItemProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectItemProps & { class?: HTMLAttributes['class'] }>()
@ -26,14 +26,12 @@ const forwardedProps = useForwardProps(delegatedProps)
v-bind="forwardedProps" v-bind="forwardedProps"
:class=" :class="
cn( cn(
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', 'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
'hover:bg-accent/50',
'active:bg-accent/70',
props.class, props.class,
) )
" "
> >
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> <span class="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectItemIndicator> <SelectItemIndicator>
<Check class="h-4 w-4" /> <Check class="h-4 w-4" />
</SelectItemIndicator> </SelectItemIndicator>

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { SelectItemText, type SelectItemTextProps } from 'radix-vue' import { SelectItemText, type SelectItemTextProps } from 'reka-ui'
const props = defineProps<SelectItemTextProps>() const props = defineProps<SelectItemTextProps>()
</script> </script>

View file

@ -1,13 +1,13 @@
<script setup lang="ts"> <script setup lang="ts">
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectLabel, type SelectLabelProps } from 'radix-vue' import { SelectLabel, type SelectLabelProps } from 'reka-ui'
const props = defineProps<SelectLabelProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectLabelProps & { class?: HTMLAttributes['class'] }>()
</script> </script>
<template> <template>
<SelectLabel :class="cn('py-1.5 pl-8 pr-2 text-sm font-semibold', props.class)"> <SelectLabel :class="cn('px-2 py-1.5 text-sm font-semibold', props.class)">
<slot /> <slot />
</SelectLabel> </SelectLabel>
</template> </template>

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronDown } from 'lucide-vue-next' import { ChevronDown } from 'lucide-vue-next'
import { SelectScrollDownButton, type SelectScrollDownButtonProps, useForwardProps } from 'radix-vue' import { SelectScrollDownButton, type SelectScrollDownButtonProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes['class'] }>()
@ -18,7 +18,7 @@ const forwardedProps = useForwardProps(delegatedProps)
<template> <template>
<SelectScrollDownButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)"> <SelectScrollDownButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
<slot> <slot>
<ChevronDown class="h-4 w-4" /> <ChevronDown />
</slot> </slot>
</SelectScrollDownButton> </SelectScrollDownButton>
</template> </template>

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronUp } from 'lucide-vue-next' import { ChevronUp } from 'lucide-vue-next'
import { SelectScrollUpButton, type SelectScrollUpButtonProps, useForwardProps } from 'radix-vue' import { SelectScrollUpButton, type SelectScrollUpButtonProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes['class'] }>()
@ -18,7 +18,7 @@ const forwardedProps = useForwardProps(delegatedProps)
<template> <template>
<SelectScrollUpButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)"> <SelectScrollUpButton v-bind="forwardedProps" :class="cn('flex cursor-default items-center justify-center py-1', props.class)">
<slot> <slot>
<ChevronUp class="h-4 w-4" /> <ChevronUp />
</slot> </slot>
</SelectScrollUpButton> </SelectScrollUpButton>
</template> </template>

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectSeparator, type SelectSeparatorProps } from 'radix-vue' import { SelectSeparator, type SelectSeparatorProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes['class'] }>()

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { ChevronDown } from 'lucide-vue-next' import { ChevronDown } from 'lucide-vue-next'
import { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'radix-vue' import { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'] }>()
@ -19,7 +19,7 @@ const forwardedProps = useForwardProps(delegatedProps)
<SelectTrigger <SelectTrigger
v-bind="forwardedProps" v-bind="forwardedProps"
:class="cn( :class="cn(
'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start', 'flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs ring-offset-background data-placeholder:text-muted-foreground focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate text-start',
props.class, props.class,
)" )"
> >

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { SelectValue, type SelectValueProps } from 'radix-vue' import { SelectValue, type SelectValueProps } from 'reka-ui'
const props = defineProps<SelectValueProps>() const props = defineProps<SelectValueProps>()
</script> </script>

View file

@ -0,0 +1,22 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { TabsContent, type TabsContentProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<TabsContentProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
</script>
<template>
<TabsContent
:class="cn('mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', props.class)"
v-bind="delegatedProps"
>
<slot />
</TabsContent>
</template>

View file

@ -0,0 +1,29 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { TabsTrigger, type TabsTriggerProps, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<TabsTriggerProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<TabsTrigger
v-bind="forwardedProps"
:class="cn(
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
props.class,
)"
>
<span class="truncate">
<slot />
</span>
</TabsTrigger>
</template>