feat: some shit
This commit is contained in:
122
src/components/ImageSlider.svelte
Normal file
122
src/components/ImageSlider.svelte
Normal file
@@ -0,0 +1,122 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let slot: HTMLDivElement;
|
||||
let images: HTMLImageElement[];
|
||||
|
||||
export let title: string;
|
||||
|
||||
let altText: string;
|
||||
let height: number;
|
||||
let loaded = false;
|
||||
|
||||
function hide(img: HTMLImageElement) {
|
||||
img.classList.remove("active");
|
||||
}
|
||||
|
||||
function show(img: HTMLImageElement) {
|
||||
img.classList.add("active");
|
||||
if (img?.alt) altText = img.alt;
|
||||
else altText = "";
|
||||
height = img.getBoundingClientRect().height;
|
||||
setTimeout(() => {
|
||||
height = img.getBoundingClientRect().height;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
function setIndex(i: number) {
|
||||
if (i < 0) i = images.length - 1;
|
||||
if (i >= images.length) i = 0;
|
||||
hide(images[index]);
|
||||
index = i;
|
||||
show(images[index]);
|
||||
}
|
||||
|
||||
$: if (slot) {
|
||||
images = Array.from(slot.querySelectorAll("img"));
|
||||
if (images?.length) {
|
||||
images.forEach(hide);
|
||||
show(images[index]);
|
||||
images[index].onload = () => {
|
||||
loaded = true;
|
||||
height = images[index].getBoundingClientRect().height;
|
||||
};
|
||||
}
|
||||
setTimeout(() => {
|
||||
loaded = true;
|
||||
}, 100);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="wrapper grid overflow-hidden rounded-xl border border-light"
|
||||
class:title
|
||||
class:loaded
|
||||
style={`--height:${height}px`}
|
||||
>
|
||||
{#if title}
|
||||
<div class="flex items-center p-x-4 bg">
|
||||
<h3>{title}</h3>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="images" bind:this={slot}>
|
||||
<slot />
|
||||
</div>
|
||||
<div class="p-2 flex place-content-between bg">
|
||||
<p>{index + 1}/{images?.length}</p>
|
||||
{#if altText}
|
||||
<p class="text-right">{altText}</p>
|
||||
{/if}
|
||||
<div class="overflow-hidden rounded-md bg-light gap-2 flex p-1">
|
||||
<button
|
||||
class="flex-1 i-tabler-arrow-left"
|
||||
aria-label="previous image"
|
||||
on:click={() => setIndex(index - 1)}
|
||||
/>
|
||||
<button
|
||||
class="flex-1 i-tabler-arrow-right"
|
||||
aria-label="next image"
|
||||
on:click={() => setIndex(index + 1)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
grid-template-rows: 1fr 40px;
|
||||
transition: height 0.3s;
|
||||
}
|
||||
|
||||
.wrapper :global(.image-wrapper) {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.wrapper.title {
|
||||
grid-template-rows: 40px 1fr 40px;
|
||||
}
|
||||
|
||||
.loaded {
|
||||
height: calc(var(--height) + 40px);
|
||||
}
|
||||
|
||||
.wrapper.title.loaded {
|
||||
height: calc(var(--height) + 80px);
|
||||
}
|
||||
|
||||
.images :global(img) {
|
||||
border-radius: 0px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.images :global(.active) {
|
||||
position: relative;
|
||||
display: block !important;
|
||||
opacity: 1;
|
||||
transition:
|
||||
opacity 0.3s ease,
|
||||
display 0.3s 0.3s;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user