primitives

Avatar

Avatar — базовый примитив RevueUI (Reka UI + shadcn-совместимый API).

Загрузка превью…

src/ui/avatar/Avatar.vue

<!-- Radix `Avatar` → Reka UI `AvatarRoot`/`AvatarImage`/`AvatarFallback`, тот же примитив. -->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import { AvatarRoot, type AvatarRootProps } from "reka-ui"
import { cn } from "@/lib/utils"

const props = withDefaults(
  defineProps<
    AvatarRootProps & {
      /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
      class?: HTMLAttributes["class"]
      size?: "default" | "sm" | "lg"
    }
  >(),
  {
    size: "default",
  }
)

const delegatedProps = computed(() => {
  const { class: _class, size: _size, ...delegated } = props
  return delegated
})
</script>

<template>
  <AvatarRoot
    data-slot="avatar"
    :data-size="props.size"
    v-bind="delegatedProps"
    :class="
      cn(
        'cn-avatar group/avatar relative flex shrink-0 select-none after:absolute after:inset-0 after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten',
        props.class
      )
    "
  >
    <slot />
  </AvatarRoot>
</template>

src/ui/avatar/AvatarBadge.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <span
    data-slot="avatar-badge"
    :class="
      cn(
        'cn-avatar-badge absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-blend-color ring-2 select-none',
        'group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden',
        'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2',
        'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2',
        props.class
      )
    "
  >
    <slot />
  </span>
</template>

src/ui/avatar/AvatarFallback.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import { AvatarFallback as AvatarFallbackPrimitive, type AvatarFallbackProps } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<
  AvatarFallbackProps & {
    /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
    class?: HTMLAttributes["class"]
  }
>()

const delegatedProps = computed(() => {
  const { class: _class, ...delegated } = props
  return delegated
})
</script>

<template>
  <AvatarFallbackPrimitive
    data-slot="avatar-fallback"
    v-bind="delegatedProps"
    :class="
      cn(
        'cn-avatar-fallback flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs',
        props.class
      )
    "
  >
    <slot />
  </AvatarFallbackPrimitive>
</template>

src/ui/avatar/AvatarGroup.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    data-slot="avatar-group"
    :class="
      cn(
        'cn-avatar-group group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>

src/ui/avatar/AvatarGroupCount.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div
    data-slot="avatar-group-count"
    :class="
      cn(
        'cn-avatar-group-count relative flex shrink-0 items-center justify-center ring-2 ring-background',
        '',
        props.class
      )
    "
  >
    <slot />
  </div>
</template>

src/ui/avatar/AvatarImage.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import {
  AvatarImage as AvatarImagePrimitive,
  type AvatarImageEmits,
  type AvatarImageProps,
  useForwardPropsEmits,
} from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<
  AvatarImageProps & {
    /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
    class?: HTMLAttributes["class"]
  }
>()
const emits = defineEmits<AvatarImageEmits>()

const delegatedProps = computed(() => {
  const { class: _class, ...delegated } = props
  return delegated
})

const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
  <AvatarImagePrimitive
    data-slot="avatar-image"
    v-bind="forwarded"
    :class="cn('cn-avatar-image aspect-square size-full object-cover', props.class)"
  />
</template>

src/ui/avatar/index.ts

export { default as Avatar } from "./Avatar.vue"
export { default as AvatarImage } from "./AvatarImage.vue"
export { default as AvatarFallback } from "./AvatarFallback.vue"
export { default as AvatarGroup } from "./AvatarGroup.vue"
export { default as AvatarGroupCount } from "./AvatarGroupCount.vue"
export { default as AvatarBadge } from "./AvatarBadge.vue"

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/avatar.json

Зависимости реестра

npm-зависимости

  • reka-ui

Источник: порт из ReUI (Keenthemes, MIT)