Reputation: 55
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
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