card

Card with dropdown menu

Card with dropdown menu

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

src/card/c-card-6.vue

<!--
  Расхождение с апстримом: `IconPlaceholder` заменена инлайновым `<svg>`
  (lucide-react v0.545.0 "more-horizontal"/"user"/"settings"/"external-link")
  — см. docs/PORTING.md §5. Аватар — `SiteAvatar*` (см. соседний файл):
  оригинал импортирует `Avatar`/`AvatarImage`/`AvatarFallback` из
  `@/components/ui/avatar`, недоступного в воркспейсе — тот же класс блокера.
-->
<script setup lang="ts">
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import SiteAvatar from "./SiteAvatar.vue"
import SiteAvatarFallback from "./SiteAvatarFallback.vue"
import SiteAvatarImage from "./SiteAvatarImage.vue"
</script>

<template>
  <Card class="w-full max-w-xs gap-2 pt-5">
    <CardHeader class="flex items-center justify-between">
      <CardTitle>Need a help in Claim?</CardTitle>
      <DropdownMenu>
        <DropdownMenuTrigger as-child>
          <Button variant="ghost" size="icon">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="24"
              height="24"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
              class="lucide lucide-more-horizontal"
            ><circle cx="12" cy="12" r="1" /><circle cx="19" cy="12" r="1" /><circle cx="5" cy="12" r="1" /></svg>
          </Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align="end" class="w-48">
          <DropdownMenuGroup>
            <DropdownMenuLabel>Team Settings</DropdownMenuLabel>
            <DropdownMenuSeparator />
            <DropdownMenuItem>
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="24"
                height="24"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                aria-hidden="true"
                class="lucide lucide-user"
              ><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" /></svg>
              <span>Manage members</span>
            </DropdownMenuItem>
            <DropdownMenuItem>
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="24"
                height="24"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                aria-hidden="true"
                class="lucide lucide-settings"
              ><path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /><circle cx="12" cy="12" r="3" /></svg>
              <span>Team preferences</span>
            </DropdownMenuItem>
          </DropdownMenuGroup>
          <DropdownMenuSeparator />
          <DropdownMenuItem>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="24"
              height="24"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
              class="lucide lucide-external-link"
            ><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
            <span>Open dashboard</span>
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </CardHeader>
    <CardContent class="mb-2">
      <p>
        Go to this step by step guideline process on how to certify for your
        weekly benefits:
      </p>
    </CardContent>
    <CardFooter>
      <Button size="sm">
        <SiteAvatar class="size-5">
          <SiteAvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
          <SiteAvatarFallback>CH</SiteAvatarFallback>
        </SiteAvatar>
        <span class="text-xs">@shadcn</span>
      </Button>
    </CardFooter>
  </Card>
</template>

src/card/SiteAvatar.vue

<!--
  Расхождение с апстримом: `c-card-6`/`c-card-10` в оригинале импортируют
  `Avatar`/`AvatarImage`/`AvatarFallback` из `@/components/ui/avatar` —
  сайтовую (не registry) обёртку сайта ReUI вокруг `@radix-ui/react-avatar`,
  которого нет в зависимостях воркспейса (тот же класс блокера, что у
  `IconPlaceholder`). Локальная копия на `reka-ui` (тот же примитив Radix
  Avatar) с Tailwind-строками `components/ui/avatar.tsx` перенесёнными
  дословно — деталь реализации двух блоков, не экспортируется из index.ts.
  См. docs/PORTING.md §5 и комментарий в `apps/proof/.../block-card/react.tsx`.
-->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { AvatarRoot } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>

<template>
  <AvatarRoot
    data-slot="avatar"
    :class="cn('site-rounded-full relative flex size-8 shrink-0 overflow-hidden', props.class)"
  >
    <slot />
  </AvatarRoot>
</template>

src/card/SiteAvatarFallback.vue

<!-- Деталь реализации `c-card-6`/`c-card-10`, см. SiteAvatar.vue. -->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { AvatarFallback } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>

<template>
  <AvatarFallback
    data-slot="avatar-fallback"
    :class="
      cn(
        'bg-site-muted text-site-foreground site-rounded-full flex size-full items-center justify-center font-medium',
        props.class
      )
    "
  >
    <slot />
  </AvatarFallback>
</template>

src/card/SiteAvatarImage.vue

<!-- Деталь реализации `c-card-6`/`c-card-10`, см. SiteAvatar.vue. -->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { AvatarImage } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{ class?: HTMLAttributes["class"]; src?: string; alt?: string }>()
</script>

<template>
  <AvatarImage
    data-slot="avatar-image"
    :src="props.src ?? ''"
    :alt="props.alt"
    :class="cn('aspect-square size-full', props.class)"
  />
</template>

Установка

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

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

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

  • reka-ui

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