carousel

Carousel with dots navigation and content overlays

Carousel with dots navigation and content overlays

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

src/carousel/c-carousel-11.vue

<script setup lang="ts">
import { ref, watch } from "vue"
import type { EmblaCarouselType } from "embla-carousel"
import { Card } from "@/components/ui/card"
import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel"
import { cn } from "@/lib/utils"

const PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="
const slides = [0, 1, 2, 3, 4]

const api = ref<EmblaCarouselType>()
const current = ref(1)
const count = ref(0)

watch(
  api,
  (emblaApi) => {
    if (!emblaApi) return
    count.value = emblaApi.scrollSnapList().length
    current.value = emblaApi.selectedScrollSnap()
    emblaApi.on("select", () => {
      current.value = emblaApi.selectedScrollSnap()
    })
  },
  { immediate: true }
)
</script>

<template>
  <Carousel :set-api="(a) => (api = a)" :opts="{ startIndex: 1, duration: 0 }" class="w-full max-w-xs">
    <CarouselContent>
      <CarouselItem v-for="index in slides" :key="index">
        <div class="p-1">
          <Card class="group/card relative aspect-square overflow-hidden border-0 p-0">
            <img
              :src="PIXEL"
              :alt="`Slide ${index + 1}`"
              width="800"
              height="800"
              class="absolute inset-0 size-full scale-100 object-cover transition-transform duration-500 ease-in-out group-hover/card:scale-105"
            />
            <div class="absolute inset-x-0 bottom-0 h-1/2 bg-linear-to-t from-black/80 to-transparent" />
            <div class="absolute inset-0 top-auto flex flex-col justify-end bg-black/20 p-4">
              <h3 class="text-xl font-bold text-white">Slide {{ index + 1 }}</h3>
              <p class="text-sm text-white/90">Feature description for slide {{ index + 1 }}.</p>
            </div>
          </Card>
        </div>
      </CarouselItem>
    </CarouselContent>
    <div class="flex justify-center gap-2 py-3">
      <button
        v-for="index in count"
        :key="index - 1"
        :class="
          cn(
            'h-2 cursor-pointer rounded-full transition-all duration-500 ease-in-out',
            index - 1 === current ? 'bg-primary w-4 opacity-100' : 'bg-muted-foreground w-2 opacity-30 hover:opacity-50'
          )
        "
        :aria-label="`Go to slide ${index}`"
        @click="api?.scrollTo(index - 1)"
      />
    </div>
  </Carousel>
</template>

Установка

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

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

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

  • embla-carousel

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