feat: added product page

This commit is contained in:
Tobias Klemp
2025-11-29 22:27:37 +01:00
parent 90280fd436
commit 6d03984e21
85 changed files with 1869 additions and 436 deletions

View File

@@ -0,0 +1,98 @@
<script lang="ts">
import type { ImageCarouselItem } from '.'
import * as Carousel from '../carousel'
import ImgCarouselItem from './ImageCarouselItem.svelte'
import type { CarouselAPI } from '$lib/components/ui/carousel/context.js'
import { Button } from '../button'
import { ChevronLeftIcon, ChevronRightIcon } from '@lucide/svelte'
const {
items,
preview = false,
buttonPosition = 'default',
}: {
items: ImageCarouselItem[]
preview?: boolean
buttonPosition?: 'contained' | 'default' | 'hidden'
} = $props()
let api = $state<CarouselAPI>()
let currentImageIndex = $state(0)
$effect(() => {
if (!api) return
api.on('select', () => {
if (!api) return
currentImageIndex = api.selectedScrollSnap()
})
})
function onPreviewImageClick(toIndex: number) {
if (!api) return
api.scrollTo(toIndex, false)
}
function prevImage() {
if (!api) return
api.scrollPrev()
}
function nextImage() {
if (!api) return
api.scrollNext()
}
</script>
<div>
<Carousel.Root setApi={(emblaApi) => (api = emblaApi)}>
<Carousel.Content>
{#each items as item}
<ImgCarouselItem {item} />
{/each}
</Carousel.Content>
{#if buttonPosition === 'default'}
<Carousel.Next />
{:else if buttonPosition === 'contained'}
<Button
onclick={prevImage}
variant="outline"
size="icon"
class="absolute top-1/2 -translate-y-1/2 left-4 rounded-full"
><ChevronLeftIcon /></Button
>
{/if}
{#if buttonPosition === 'default'}
<Carousel.Previous />
{:else if buttonPosition === 'contained'}
<Button
onclick={nextImage}
variant="outline"
size="icon"
class="absolute top-1/2 -translate-y-1/2 right-4 rounded-full"
><ChevronRightIcon /></Button
>
{/if}
</Carousel.Root>
{#if preview}
<Carousel.Root
opts={{
align: 'start',
}}
class="hidden md:block"
>
<Carousel.Content>
{#each items as item, i}
<ImgCarouselItem
onclick={() => onPreviewImageClick(i)}
{item}
class="md:basis-1/3 lg:basis-1/4 mt-4"
isSelected={i === currentImageIndex}
/>
{/each}
</Carousel.Content>
</Carousel.Root>
{/if}
</div>