curriculum-vitae/frontend/src/lib/components/slideshow.svelte

233 lines
6.3 KiB
Svelte

<script>
import { swipe } from "svelte-gestures";
import SvgIcon from "@jamescoyle/svelte-icon";
import { mdiArrowRight, mdiArrowLeft, mdiRestore } from "@mdi/js";
import "$lib/css/slideshow.css";
import { onMount } from "svelte";
import {
createTimeLine,
updateTimeLine,
slideContainerCount,
slideTimelineCount,
slideStringCount,
} from "$lib/js/slideshow.js";
// Exported values
export let data = [];
export let type;
export let timeline = false;
export let reverse = false;
export let show_max_index = false;
if (reverse) {
data = data.reverse();
}
// Svelte bindings
let windowWidth = 0;
// Resizing variables
let resizing = false;
// Slideshow global variables
let slideshow_index = 0;
let slideshow_hidden = [];
let slideshowTimeline;
let slideshowElements;
let slideshowBubbles;
// Timeline global variables
let slideshow;
let bubbles = [];
onMount(() => {
/* Slideshow */
//global writer count
const currentSlideCount = $slideContainerCount;
// Sliced array from currentSlideCount to data.length
slideshowElements = Array.from(
document.querySelectorAll(".slide-container"),
).slice(currentSlideCount, currentSlideCount + data.length);
// Updating with the current length
slideContainerCount.update((value) => {
return value + data.length;
});
if (timeline) {
/* SlideTimeline */
//global writer count
const currentTimelineCount = $slideTimelineCount;
// Creating the string between the bubbles
slideshowBubbles = Array.from(
document.querySelectorAll(".slide-bubble"),
).slice(currentTimelineCount, currentTimelineCount + data.length);
// Creating strings
for (const element of slideshowBubbles) {
bubbles.push({
left: element.offsetLeft,
top: element.offsetTop,
});
}
createTimelineStrings();
}
});
function slideCards(advance) {
// Set or reset slideshow index, hidden array and timeling.
if (advance) {
if (slideshow_index >= data.length - 1) {
resetSlideCards();
} else {
slideshow_hidden.push(slideshow_index);
slideshow_index++;
}
} else {
slideshow_hidden.pop();
slideshow_index--;
}
// Incrementing the transformValue for each element
let transformValue = 0;
for (const id of slideshow_hidden) {
transformValue += slideshowElements[id].clientWidth;
}
// Translating elements
slideshowElements.forEach((element, id) => {
/* Slideshow translating*/
let newtransformValue = transformValue;
if (slideshow_hidden.includes(id)) {
// 1.1 because when in 'unactive' state, the scale is 0.9, adjusting the actual ratio
newtransformValue *= 1.1;
}
element.style.transform = `translateX(-${newtransformValue}px)`;
/* Slideshow Timeline translating */
if (timeline) {
if (slideshowTimeline[id] != undefined) {
slideshowTimeline[id].style.transform =
`translateX(-${transformValue}px)`;
}
}
});
}
function resetSlideCards() {
return new Promise((resolve) => {
slideshow_hidden = [];
slideshow_index = 0;
for (const element of slideshowElements) {
element.style.transform = "";
}
if (timeline) {
for (const timeline of slideshowTimeline) {
timeline.style.transform = "";
}
}
resolve();
});
}
function createTimelineStrings() {
const stringTimelineElements = createTimeLine(bubbles);
for (const div of stringTimelineElements) {
slideshow.appendChild(div);
}
// Updating with the current length
slideTimelineCount.update((value) => {
return value + data.length;
});
//global writer count
const currentStringCount = $slideStringCount;
/* Sliced array from currentTimelineCount to data.length
Everytime a slideshow created the slide string, the queryselector all will get all the elements
We do not want that and only want the slide-string we are interested in
Starting from the oldest count, finishing by our actual length */
slideshowTimeline = Array.from(
document.querySelectorAll(".slide-string"),
).slice(
currentStringCount,
currentStringCount + stringTimelineElements.length,
);
// Updating with the current length
slideStringCount.update((value) => {
return value + stringTimelineElements.length;
});
}
// Mobile swipe
function mobileSwipe(event) {
if (slideshow_index > 0 || event.detail.direction == "left")
slideCards(event.detail.direction == "left");
}
async function changeSize() {
if (timeline && !resizing) {
resizing = true;
await resetSlideCards();
await new Promise((resolve) => setTimeout(resolve, 400));
updateTimeLine(slideshowTimeline, slideshowBubbles);
resizing = false;
//global writer count
}
}
</script>
<svelte:window on:resize={changeSize} bind:innerWidth={windowWidth} />
<div
class="slideshow"
use:swipe={{ timeframe: 300, minSwipeDistance: 100, touchAction: "pan-y" }}
on:swipe={mobileSwipe}
bind:this={slideshow}
>
<button
class={slideshow_index >= 1
? "slideshow_btn"
: "slideshow_btn slideshow_btn_center"}
on:click={() => slideCards(true)}
>
<div>
<SvgIcon
size={windowWidth < 1000 ? "30" : "45"}
path={slideshow_index >= data.length - 1 ? mdiRestore : mdiArrowRight}
type="mdi"
/>
</div>
</button>
<button
class={slideshow_index >= 1
? "slideshow_btn slideshow_btn_low"
: "slideshow_btn slideshow_btn_low slideshow_btn_disabled"}
on:click={() => {
if (slideshow_index >= 1) slideCards(false);
}}
>
<SvgIcon
size={windowWidth < 1000 ? "30" : "45"}
path={mdiArrowLeft}
type="mdi"
/>
</button>
{#each data as selected_data, index (index)}
{#if show_max_index}
<svelte:component
this={type}
data={selected_data}
active={index == slideshow_index ? true : false}
max={data.length}
actualnum={index + 1}
/>
{:else}
<svelte:component
this={type}
data={selected_data}
active={index == slideshow_index ? true : false}
/>
{/if}
{/each}
</div>