hover-card

Hover card with paginated release notes

Hover card with paginated release notes

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

src/hover-card/c-hover-card-8.vue

<!--
  Порт c-hover-card-8 ("Hover card with release notes carousel") —
  .agent-tmp/reui-upstream/registry-reui/bases/radix/components/hover-card/c-hover-card-8.tsx

  `IconPlaceholder` (стрелки prev/next, внутри `HoverCardContent`, не
  смонтирован закрытым) заменена инлайновым `<svg>` (lucide-react v0.545.0
  "arrow-left"/"arrow-right"). Состояние карусели (`current`) зафиксировано
  на 0 (docs/PORTING.md §3 задачи, popover/content всё равно не рендерится
  закрытым) — `handleNext`/`handlePrev` перенесены по смыслу, но кнопки не
  нажимаются на статичном скриншоте.
-->
<script setup lang="ts">
import { computed, ref } from "vue"
import { Badge } from "@/components/reui/badge"
import { Button } from "@/components/ui/button"
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@/components/ui/hover-card"

const releases = [
  {
    version: "v3.2.0",
    date: "Feb 5, 2026",
    tag: "Latest",
    tagVariant: "success" as const,
    description:
      "Added real-time collaboration cursors, improved markdown editor performance, and fixed PDF export layout issues.",
  },
  {
    version: "v3.1.4",
    date: "Jan 22, 2026",
    tag: "Patch",
    tagVariant: "destructive" as const,
    description:
      "Resolved a memory leak in the dashboard widgets, patched a security vulnerability in file uploads.",
  },
  {
    version: "v3.1.0",
    date: "Jan 10, 2026",
    tag: "Minor",
    tagVariant: "info" as const,
    description:
      "Introduced API rate limiting dashboard, added webhook retry configuration, and new audit log filters.",
  },
  {
    version: "v3.0.0",
    date: "Dec 15, 2025",
    tag: "Major",
    tagVariant: "warning" as const,
    description:
      "Complete UI redesign with new component library, migrated to edge runtime, and added multi-tenant workspace support.",
  },
]

const current = ref(0)

function handleNext() {
  if (current.value < releases.length - 1) current.value += 1
}
function handlePrev() {
  if (current.value > 0) current.value -= 1
}

const isFirst = computed(() => current.value === 0)
const isLast = computed(() => current.value === releases.length - 1)
const release = computed(() => releases[current.value]!)
</script>

<template>
  <div class="flex min-h-[100px] items-center justify-center">
    <HoverCard :open-delay="100" :close-delay="200">
      <HoverCardTrigger class="text-primary cursor-default text-sm font-medium underline decoration-dashed decoration-1 underline-offset-4">What&apos;s new?</HoverCardTrigger>
      <HoverCardContent class="w-72 space-y-1 px-3 pt-3 pb-2">
        <div class="flex items-center justify-between">
          <div class="flex items-center gap-2">
            <span class="font-semibold">{{ release.version }}</span>
            <Badge :variant="release.tagVariant" size="xs">{{ release.tag }}</Badge>
          </div>
          <span class="text-muted-foreground">{{ release.date }}</span>
        </div>
        <p class="text-muted-foreground leading-relaxed">{{ release.description }}</p>
        <div class="flex items-center justify-between">
          <div class="flex gap-1">
            <span
              v-for="(_, i) in releases"
              :key="i"
              :class="`size-1.5 rounded-full transition-colors ${i === current ? 'bg-primary' : 'bg-muted-foreground/30'}`"
            />
          </div>
          <div class="flex gap-0.5">
            <Button
              aria-label="Previous release"
              class="size-6"
              :disabled="isFirst"
              size="icon"
              variant="ghost"
              @click="handlePrev"
            >
              <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"
                class="size-3.5"
                aria-hidden="true"
              >
                <path d="m12 19-7-7 7-7" />
                <path d="M19 12H5" />
              </svg>
            </Button>
            <Button
              aria-label="Next release"
              class="size-6"
              :disabled="isLast"
              size="icon"
              variant="ghost"
              @click="handleNext"
            >
              <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"
                class="size-3.5"
                aria-hidden="true"
              >
                <path d="M5 12h14" />
                <path d="m12 5 7 7-7 7" />
              </svg>
            </Button>
          </div>
        </div>
      </HoverCardContent>
    </HoverCard>
  </div>
</template>

Установка

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

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

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