Coder Dad
Coder Dad

Reputation: 55

Svelte Carousel nav dots active colors aren't transitioning with slides

I'm working on a carousel component using schadcn-svelte and embla carousel. The initial click on dot 2 transitions from slide 1 to slide 2, and the active dot styles update perfectly. However after that initial reaction, the nav dots active state stop updating, and slide transitions lag. I'm really not sure how to resolve the issue because it seems to be working at first, then gets buggy. Any help is greatly appreciated. Current code:

<script lang="ts">
  import * as Card from "$lib/components/ui/card/index.js";
  import type { CarouselAPI } from "$lib/components/ui/carousel/context";
  import * as Carousel from "$lib/components/ui/carousel/index.js";
  import { projects } from "../data/slides";
  import { MoveRight } from "lucide-svelte";
  import emblaCarouselSvelte from "embla-carousel-svelte";

  // CAROUSEL

  let slideAxisOffset = -1000;
  let duration = 500;

  let carouselApi: CarouselAPI;
  let carouselWrapperWidth: number;

  let activeCarouselItemId = 0;
  function setActiveCarouselItem(index: number) {
    carouselApi.scrollTo(index);
    activeCarouselItemId = index;
  }

  let apiSet = false;

  let interval = setInterval((): any => {
    if (carouselApi) {
      carouselApi.on("scroll", (carouselApi) => {
        activeCarouselItemId = carouselApi.slidesInView()[1];
      });
      apiSet = true;
      clearInterval(interval);
    }
  });

  let carouselRootEl: HTMLElement;
</script>

<Carousel.Root
  opts={{
    // align: "center",
    loop: true,
  }}
  class="w-full bg-black"
  bind:api={carouselApi}
>
  <Carousel.Content class="">
    {#each projects as project}
      <Carousel.Item class="basis-1/2 hover:cursor-grab border-none">
        <div class="my-4 border-none">
          <Card.Root class="border-none">
            <Card.Content
              class="flex h-[60vh] p-6 rounded-lg border-none"
              style="background-image: url({project.image}); background-repeat: no-repeat; background-size: cover;"
            >
              <div class="absolute top-12 left-12 h-full text-white uppercase">
                <h2 class="text-2xl font-semibold">{project.title}</h2>
                <p class="text-xl font-normal">{project.description}</p>
                <button
                  class="flex items-center gap-2 absolute bottom-24 left-0 uppercase font-black text-xl tracking-wider border-2 rounded-full py-2 px-6 hover:bg-white/50 ease-in-out duration-300"
                  >Explore <MoveRight size="40" /></button
                >
              </div></Card.Content
            >
          </Card.Root>
        </div>
      </Carousel.Item>
    {/each}
  </Carousel.Content>
</Carousel.Root>
<!-- Progress circles -->
<div class="flex space-x-2 bg-black w-full items-center justify-center py-12">
  {#each projects as item, idx}
    <button
      on:click={() => {
        setActiveCarouselItem(idx);
      }}
      class="rounded-full aspect-square w-4 {idx === activeCarouselItemId
        ? 'bg-white'
        : 'bg-white/30'}"
    ></button>
  {/each}
</div>

I'm new to svelte and typescript, so any suggestions or insight is greatly appreciated!

Upvotes: 2

Views: 156

Answers (1)

SIKANDAR BHIDE
SIKANDAR BHIDE

Reputation: 9

Working Example

<script lang="ts">
  import * as Card from "$lib/components/ui/card/index";
  import * as Carousel from "$lib/components/ui/carousel/index";
  import type { CarouselAPI } from "$lib/components/ui/carousel/context";

  let carouselApi: CarouselAPI;
  let activeCarouselItemId = 0;
  function setActiveCarouselItem(index: number) {
    carouselApi.scrollTo(index);
    activeCarouselItemId = index;
  }
  $: {
    if (carouselApi) {
      carouselApi.on("select", (e) => {
        activeCarouselItemId = carouselApi.selectedScrollSnap();
      });
    }
  }
</script>

<div>
  <Carousel.Root
    opts={{
      loop: true,
    }}
    class="w-full max-w-xs"
    bind:api={carouselApi}
  >
    <Carousel.Content>
      {#each Array(5) as _, i (i)}
        <Carousel.Item>
          <div class="p-1">
            <Card.Root>
              <Card.Content
                class="flex aspect-square items-center justify-center p-6"
              >
                <span class="text-4xl font-semibold">{i + 1}</span>
              </Card.Content>
            </Card.Root>
          </div>
        </Carousel.Item>
      {/each}
    </Carousel.Content>
    <Carousel.Previous />
    <Carousel.Next />
    <div
      class="flex space-x-2 bg-black w-full items-center justify-center py-12"
    >
      {#each { length: 5 } as item, idx}
        <button
          on:click={() => {
            setActiveCarouselItem(idx);
          }}
          class="rounded-full aspect-square w-4 {idx === activeCarouselItemId
            ? 'bg-white'
            : 'bg-white/30'}"
        ></button>
      {/each}
    </div>
  </Carousel.Root>
</div>

Upvotes: 0

Related Questions