Frontend: Cleaning out slideshow and making it more usable and simplier. Deleted unused css. Added writables.

This commit is contained in:
Yohan Boujon 2023-11-18 00:11:36 +01:00
parent 4406c3a9a8
commit dc6d1af0d9
9 changed files with 192 additions and 308 deletions

View file

@ -1,7 +1,7 @@
<script> <script>
import SvgIcon from "@jamescoyle/svelte-icon"; import SvgIcon from "@jamescoyle/svelte-icon";
import { mdiMapMarker, mdiCog } from "@mdi/js"; import { mdiMapMarker, mdiCog } from "@mdi/js";
import "$lib/css/education.css"; import "$lib/css/slide.css";
import { formatYear } from "$lib/js/date.js" import { formatYear } from "$lib/js/date.js"
export let active = false; export let active = false;
@ -16,36 +16,36 @@
const start_year = data.start_year === null ? '' : (data.end_year === null ? formatYear(data.start_year) : '-'+formatYear(data.start_year)); const start_year = data.start_year === null ? '' : (data.end_year === null ? formatYear(data.start_year) : '-'+formatYear(data.start_year));
</script> </script>
<div class="education-container"> <div class="slide-container">
<div class="education-main {active ? '' : 'education-unactive'}"> <div class="slide-main {active ? '' : 'slide-unactive'}">
<div class="education-img-container"> <div class="slide-img-container">
<img class="education-img" src={picture} alt="Education" /> <img class="slide-img" src={picture} alt="Education" />
</div> </div>
<div class="education-text-container"> <div class="slide-text-container">
<h1 class="education-title">{title}</h1> <h1 class="slide-title">{title}</h1>
{#if location} {#if location}
<div class="education-subtitle-container"> <div class="slide-subtitle-container">
<SvgIcon size="35" path={mdiMapMarker} type="mdi" /> <SvgIcon size="35" path={mdiMapMarker} type="mdi" />
<p class="education-subtitle education-aftericon"> <p class="slide-subtitle slide-aftericon">
{location} {location}
</p> </p>
</div> </div>
{/if} {/if}
{#if speciality} {#if speciality}
<div class="education-subtitle-container"> <div class="slide-subtitle-container">
<SvgIcon size="35" path={mdiCog} type="mdi" /> <SvgIcon size="35" path={mdiCog} type="mdi" />
<p class="education-subtitle education-aftericon"> <p class="slide-subtitle slide-aftericon">
{speciality} {speciality}
</p> </p>
</div> </div>
{/if} {/if}
{#if option} {#if option}
<p class="education-subtitle">{option}</p> <p class="slide-subtitle">{option}</p>
{/if} {/if}
</div> </div>
</div> </div>
<div class="education-time"> <div class="slide-time">
<div class="education-bubble" /> <div class="slide-bubble" />
<h2 class="education-date">{`${end_year}${start_year}`}</h2> <h2 class="slide-date">{`${end_year}${start_year}`}</h2>
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
<script> <script>
import SvgIcon from "@jamescoyle/svelte-icon"; import SvgIcon from "@jamescoyle/svelte-icon";
import { mdiMapMarker, mdiCardText, mdiOfficeBuilding } from "@mdi/js"; import { mdiMapMarker, mdiOfficeBuilding } from "@mdi/js";
import "$lib/css/experience.css"; import "$lib/css/slide.css";
import { formatDate } from "$lib/js/date.js"; import { formatDate } from "$lib/js/date.js";
export let active = false; export let active = false;
@ -21,38 +21,38 @@
const picture = data.picture_url; const picture = data.picture_url;
</script> </script>
<div class="experience-container"> <div class="slide-container">
<div class="experience-main {active ? '' : 'experience-unactive'}"> <div class="slide-main {active ? '' : 'slide-unactive'}">
<div class="experience-img-container"> <div class="slide-img-container">
<img class="experience-img" src={picture} alt="Experience" /> <img class="slide-img" src={picture} alt="Experience" />
</div> </div>
<div class="experience-text-container"> <div class="slide-text-container">
<h1 class="experience-title">{position}</h1> <h1 class="slide-title">{position}</h1>
<div class="experience-subtitle-container"> <div class="slide-subtitle-container">
<SvgIcon size="35" path={mdiOfficeBuilding} type="mdi" /> <SvgIcon size="35" path={mdiOfficeBuilding} type="mdi" />
<p class="experience-subtitle experience-aftericon"> <p class="slide-subtitle slide-aftericon">
{enterprise} {enterprise}
</p> </p>
</div> </div>
{#if location} {#if location}
<div class="experience-subtitle-container"> <div class="slide-subtitle-container">
<SvgIcon size="35" path={mdiMapMarker} type="mdi" /> <SvgIcon size="35" path={mdiMapMarker} type="mdi" />
<p class="experience-subtitle experience-aftericon"> <p class="slide-subtitle slide-aftericon">
{location} {location}
</p> </p>
</div> </div>
{/if} {/if}
{#if description} {#if description}
<div class="experience-subtitle-container"> <div class="slide-subtitle-container">
<p class="experience-subtitle"> <p class="slide-subtitle">
{description} {description}
</p> </p>
</div> </div>
{/if} {/if}
</div> </div>
</div> </div>
<div class="experience-time"> <div class="slide-time">
<div class="experience-bubble" /> <div class="slide-bubble" />
<h2 class="experience-date">{`${end_year}${start_year}`}</h2> <h2 class="slide-date">{`${end_year}${start_year}`}</h2>
</div> </div>
</div> </div>

View file

@ -1,7 +1,7 @@
<script> <script>
import SvgIcon from "@jamescoyle/svelte-icon"; import SvgIcon from "@jamescoyle/svelte-icon";
import { mdiCalendarRange, mdiPlus } from "@mdi/js"; import { mdiCalendarRange, mdiPlus } from "@mdi/js";
import "$lib/css/projects.css"; import "$lib/css/slide.css";
export let active = false; export let active = false;
export let data; export let data;
@ -12,26 +12,26 @@
const picture = data.picture_url; const picture = data.picture_url;
</script> </script>
<div class="projects-container"> <div class="slide-container">
<div class="projects-main {active ? '' : 'projects-unactive'}"> <div class="slide-main {active ? '' : 'slide-unactive'}">
<div class="projects-img-container"> <div class="slide-img-container">
<img class="projects-img" src={picture} alt="projects" /> <img class="slide-img" src={picture} alt="projects" />
</div> </div>
<div class="projects-text-container"> <div class="slide-text-container">
<h1 class="projects-title">{title}</h1> <h1 class="slide-title">{title}</h1>
<div class="projects-subtitle-container"> <div class="slide-subtitle-container">
<SvgIcon size="35" path={mdiCalendarRange} type="mdi" /> <SvgIcon size="35" path={mdiCalendarRange} type="mdi" />
<p class="projects-subtitle projects-aftericon"> <p class="slide-subtitle slide-aftericon">
{issued_date} {issued_date}
</p> </p>
</div> </div>
<div class="projects-subtitle-container"> <div class="slide-subtitle-container">
<p class="projects-subtitle projects-text"> <p class="slide-subtitle slide-text">
{description} {description}
</p> </p>
</div> </div>
<div class="projects-button-container"> <div class="slide-button-container">
<button class="projects-more-button"> <button class="slide-button">
<SvgIcon size="20" path={mdiPlus} type="mdi" /> <SvgIcon size="20" path={mdiPlus} type="mdi" />
More</button More</button
> >

View file

@ -3,45 +3,84 @@
import { mdiArrowRight, mdiChevronLeft } from "@mdi/js"; import { mdiArrowRight, mdiChevronLeft } from "@mdi/js";
import "$lib/css/slideshow.css"; import "$lib/css/slideshow.css";
import { onMount } from "svelte"; import { onMount } from "svelte";
import { createTimeLine } from "$lib/js/timeline.js"; import {
createTimeLine,
slideContainerCount,
slideTimelineCount,
slideStringCount,
} from "$lib/js/slideshow.js";
// Exported values // Exported values
export let data = []; export let data = [];
export let type; export let type;
export let typename;
export let timeline = false; export let timeline = false;
// Slideshow global variables // Slideshow global variables
let slideshow_index = 0; let slideshow_index = 0;
let slideshow_hidden = []; let slideshow_hidden = [];
let slideshowTimeline;
let slideshowElements;
// Timeline global variables // Timeline global variables
let slideshow; let slideshow;
let bubbles = []; let bubbles = [];
if (timeline) {
onMount(() => { onMount(() => {
for (const element of document.getElementsByClassName( /* Slideshow */
`${typename}-bubble` //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
const slideshowBubbles = Array.from(
document.querySelectorAll(".slide-bubble")
).slice(currentTimelineCount, currentTimelineCount + data.length);
// Creating strings
for (const element of slideshowBubbles) {
bubbles.push({ bubbles.push({
left: element.offsetLeft, left: element.offsetLeft,
top: element.offsetTop, top: element.offsetTop,
}); });
} }
for (const div of createTimeLine(bubbles, typename)) { const stringTimelineElements = createTimeLine(bubbles);
for (const div of stringTimelineElements) {
slideshow.appendChild(div); 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
slideshowTimeline = Array.from(
document.querySelectorAll(".slide-string")
).slice(
currentStringCount,
currentStringCount + stringTimelineElements.length
);
// Updating with the current length
slideStringCount.update((value) => {
return value + stringTimelineElements.length;
}); });
} }
});
function slideCards() { function slideCards() {
const slideshowElements = document.querySelectorAll( // Set or reset slideshow index, hidden array and timeling.
`.${typename}-container`
);
const slideshowTimeline = document.querySelectorAll(
`.${typename}-string`
);
if (slideshow_index >= data.length - 1) { if (slideshow_index >= data.length - 1) {
slideshow_hidden = []; slideshow_hidden = [];
slideshow_index = 0; slideshow_index = 0;
@ -54,17 +93,26 @@
slideshow_hidden.push(slideshow_index); slideshow_hidden.push(slideshow_index);
slideshow_index++; slideshow_index++;
} }
// Incrementing the transformValue for each element
let transformValue = 0; let transformValue = 0;
for (const id of slideshow_hidden) { for (const id of slideshow_hidden) {
transformValue += slideshowElements[id].clientWidth; transformValue += slideshowElements[id].clientWidth;
} }
// Translating elements
console.log(slideshowTimeline)
slideshowElements.forEach((element, id) => { slideshowElements.forEach((element, id) => {
/* Slideshow translating*/
let newtransformValue = transformValue; let newtransformValue = transformValue;
if (slideshow_hidden.includes(id)) { if (slideshow_hidden.includes(id)) {
// 1.1 because when in 'unactive' state, the scale is 0.9, adjusting the actual ratio // 1.1 because when in 'unactive' state, the scale is 0.9, adjusting the actual ratio
newtransformValue *= 1.1; newtransformValue *= 1.1;
} }
element.style.transform = `translateX(-${newtransformValue}px)`; element.style.transform = `translateX(-${newtransformValue}px)`;
/* Slideshow Timeline trnaslating */
if (timeline) {
if (slideshowTimeline[id] != undefined) { if (slideshowTimeline[id] != undefined) {
slideshowTimeline[ slideshowTimeline[
id id
@ -74,10 +122,12 @@
"var(--color-background)"; "var(--color-background)";
} }
} }
}
}); });
} }
</script> </script>
{@debug slideContainerCount}
<div class="slideshow" bind:this={slideshow}> <div class="slideshow" bind:this={slideshow}>
<button class="slideshow_btn" on:click={slideCards}> <button class="slideshow_btn" on:click={slideCards}>
<div> <div>

View file

@ -1,103 +0,0 @@
.education-container {
display: flex;
flex-direction: column;
transition: all .3s ease 0s;
}
.education-main {
display: flex;
border-radius: 0.4rem;
box-shadow: 0px 20px 50px -10px rgba(0, 0, 0, 0.2);
background-color: var(--color-background);
height: 20rem;
margin-left: 2.5rem;
margin-right: 2.5rem;
z-index: 1;
transition: all .3s ease 0s;
}
.education-img-container{
display: flex;
margin: 1.5rem;
justify-content: center;
align-items: center;
}
.education-img {
max-height: 15rem;
min-width: 20rem;
max-width: 25rem;
}
.education-text-container {
margin: 1.5rem;
width: 25rem;
}
.education-title {
color: var(--color-text);
font-family: 'Gabarito', sans-serif;
font-weight: 600;
font-size: 2rem;
}
.education-subtitle-container {
display: flex;
flex-direction: row;
align-items: center;
}
.education-aftericon {
margin-left: 0.5rem;
}
.education-subtitle {
color: var(--color-text);
font-family: 'Gabarito', sans-serif;
font-weight: 500;
font-size: 1.5rem;
margin-top: 0.75rem;
margin-bottom: 0.75rem;
}
.education-unactive {
scale: 0.9;
margin-left: 2.25rem !important;
margin-right: 2.25rem !important;
box-shadow: 0 7px 30px -10px rgba(150,170,180,0.5) !important;
}
.education-time {
margin-top: 3rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.education-bubble {
z-index: 2;
width: 5rem;
height: 5rem;
background-color: var(--color-special);
box-shadow: 0px 2px 5px -1px rgba(0, 0, 0, 0.2);
border-radius: 50%;
transition: all .3s ease 0s;
display: flex;
justify-content: center;
align-items: center;
}
.education-date {
color: var(--color-special);
font-weight: 700;
}
.education-string {
z-index: -1;
position: absolute;
height: 3rem;
background-color: var(--color-special);
opacity: 0.5;
transition: all .3s ease 0s;
}

View file

@ -1,105 +0,0 @@
.experience-container {
display: flex;
flex-direction: column;
transition: all .3s ease 0s;
}
.experience-main {
display: flex;
border-radius: 0.4rem;
box-shadow: 0px 20px 50px -10px rgba(0, 0, 0, 0.2);
background-color: var(--color-background);
height: 22rem;
margin-left: 2.5rem;
margin-right: 2.5rem;
z-index: 1;
transition: all .3s ease 0s;
}
.experience-img-container{
display: flex;
margin: 1.5rem;
justify-content: center;
align-items: center;
}
.experience-img {
max-height: 15rem;
min-width: 20rem;
max-width: 25rem;
}
.experience-text-container {
margin: 1.5rem;
width: 25rem;
}
.experience-title {
color: var(--color-text);
font-family: 'Gabarito', sans-serif;
font-weight: 600;
font-size: 2rem;
}
.experience-subtitle-container {
display: flex;
flex-direction: row;
align-items: center;
}
.experience-aftericon {
margin-left: 0.5rem;
}
.experience-subtitle {
color: var(--color-text);
font-family: 'Gabarito', sans-serif;
font-weight: 500;
font-size: 1.5rem;
margin-top: 0.75rem;
margin-bottom: 0.75rem;
text-align:justify;
text-justify: auto;
}
.experience-unactive {
scale: 0.9;
margin-left: 2.25rem !important;
margin-right: 2.25rem !important;
box-shadow: 0 7px 30px -10px rgba(150,170,180,0.5) !important;
}
.experience-time {
margin-top: 3rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.experience-bubble {
z-index: 2;
width: 5rem;
height: 5rem;
background-color: var(--color-special);
box-shadow: 0px 2px 5px -1px rgba(0, 0, 0, 0.2);
border-radius: 50%;
transition: all .3s ease 0s;
display: flex;
justify-content: center;
align-items: center;
}
.experience-date {
color: var(--color-special);
font-weight: 700;
}
.experience-string {
z-index: -1;
position: absolute;
height: 3rem;
background-color: var(--color-special);
opacity: 0.5;
transition: all .3s ease 0s;
}

View file

@ -1,10 +1,10 @@
.projects-container { .slide-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
transition: all .3s ease 0s; transition: all .3s ease 0s;
} }
.projects-main { .slide-main {
display: flex; display: flex;
border-radius: 0.4rem; border-radius: 0.4rem;
box-shadow: 0px 20px 50px -10px rgba(0, 0, 0, 0.2); box-shadow: 0px 20px 50px -10px rgba(0, 0, 0, 0.2);
@ -16,42 +16,51 @@
transition: all .3s ease 0s; transition: all .3s ease 0s;
} }
.projects-img-container { .slide-unactive {
scale: 0.9;
margin-left: 2.25rem !important;
margin-right: 2.25rem !important;
box-shadow: 0 7px 30px -10px rgba(150,170,180,0.5) !important;
}
.slide-img-container{
display: flex; display: flex;
margin: 1.5rem; margin: 1.5rem;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.projects-img { .slide-img {
max-height: 15rem; max-height: 15rem;
min-width: 20rem; min-width: 20rem;
max-width: 25rem; max-width: 25rem;
} }
.projects-text-container { .slide-text-container {
margin: 1.5rem; margin: 1.5rem;
width: 25rem; width: 25rem;
} }
.projects-title { .slide-title {
color: var(--color-text); color: var(--color-text);
font-family: 'Gabarito', sans-serif; font-family: 'Gabarito', sans-serif;
font-weight: 600; font-weight: 600;
font-size: 2rem; font-size: 2rem;
} }
.projects-subtitle-container { .slide-subtitle-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
} }
.projects-aftericon { /* When an icon is put after a subtitle*/
.slide-aftericon {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
.projects-subtitle { /* Any Subtitle */
.slide-subtitle {
color: var(--color-text); color: var(--color-text);
font-family: 'Gabarito', sans-serif; font-family: 'Gabarito', sans-serif;
font-weight: 500; font-weight: 500;
@ -63,7 +72,8 @@
text-justify: auto; text-justify: auto;
} }
.projects-text { /* Add it to any text that may overflow. (long texts)*/
.slide-text {
font-size: 1.25rem !important; font-size: 1.25rem !important;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
@ -72,19 +82,14 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.projects-unactive { /* For button at the end of the container*/
scale: 0.9; .slide-button-container {
margin-left: 2.25rem !important;
margin-right: 2.25rem !important;
box-shadow: 0 7px 30px -10px rgba(150, 170, 180, 0.5) !important;
}
.projects-button-container {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
.projects-more-button { /* Every button are centered to the right side of the component */
.slide-button {
padding-right: 1rem; padding-right: 1rem;
padding-left: 1rem; padding-left: 1rem;
padding-top: 0.5rem; padding-top: 0.5rem;
@ -103,7 +108,7 @@
transition: all .3s ease 0s; transition: all .3s ease 0s;
} }
.projects-more-button:hover { .slide-button:hover {
color: var(--color-special); color: var(--color-special);
background-color: var(--color-background); background-color: var(--color-background);
box-shadow: 0 0.7px 3px -1px rgba(150,170,180,0.5); box-shadow: 0 0.7px 3px -1px rgba(150,170,180,0.5);
@ -111,7 +116,44 @@
border-color: var(--color-special); border-color: var(--color-special);
} }
.projects-more-button:active { .slide-button:active {
transform: translateY(0.25rem); transform: translateY(0.25rem);
background-color: var(--color-subtitle); background-color: var(--color-subtitle);
} }
/* Timeline stuff */
.slide-time {
margin-top: 3rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.slide-bubble {
z-index: 2;
width: 5rem;
height: 5rem;
background-color: var(--color-special);
box-shadow: 0px 2px 5px -1px rgba(0, 0, 0, 0.2);
border-radius: 50%;
transition: all .3s ease 0s;
display: flex;
justify-content: center;
align-items: center;
}
/* Date text */
.slide-date {
color: var(--color-special);
font-weight: 700;
}
.slide-string {
z-index: -1;
position: absolute;
height: 3rem;
background-color: var(--color-special);
opacity: 0.5;
transition: all .3s ease 0s;
}

View file

@ -1,8 +1,10 @@
export function createTimeLine(positionsArray, typename) { import { writable } from 'svelte/store';
export function createTimeLine(positionsArray) {
let divArray = []; let divArray = [];
for (let i = 0; i < positionsArray.length - 1; i++) { for (let i = 0; i < positionsArray.length - 1; i++) {
var newDiv = document.createElement('div'); var newDiv = document.createElement('div');
newDiv.className = `${typename}-string`; newDiv.className = "slide-string";
const left = positionsArray[i].left + (2.5 * 16); const left = positionsArray[i].left + (2.5 * 16);
newDiv.style.left = `${left}px`; newDiv.style.left = `${left}px`;
const top = positionsArray[i].top + 16; const top = positionsArray[i].top + 16;
@ -13,3 +15,7 @@ export function createTimeLine(positionsArray, typename) {
} }
return divArray; return divArray;
} }
export let slideContainerCount = writable(0);
export let slideTimelineCount = writable(0);
export let slideStringCount = writable(0);

View file

@ -34,10 +34,8 @@
let sidebar_height = 0; let sidebar_height = 0;
$: scrollY = 0; $: scrollY = 0;
$: innerHeight = 0; $: innerHeight = 0;
$: outerHeight = 0;
onMount(() => { onMount(() => {
sidebar_height = sidebar.offsetHeight; sidebar_height = sidebar.offsetHeight;
console.log(sidebar_height);
sidebarScrollingHandler(); sidebarScrollingHandler();
}); });
@ -53,7 +51,7 @@
} }
</script> </script>
<svelte:window bind:scrollY bind:innerHeight bind:outerHeight on:scroll={sidebarScrollingHandler} /> <svelte:window bind:scrollY bind:innerHeight on:scroll={sidebarScrollingHandler} />
{#if data.status == 0} {#if data.status == 0}
<div class="container-cv"> <div class="container-cv">
@ -95,22 +93,18 @@
<SlideShow <SlideShow
data={cv.education} data={cv.education}
type={Education} type={Education}
typename="education"
timeline="true" timeline="true"
/> />
<Section icon={mdiBriefcase} title="Experience" /> <Section icon={mdiBriefcase} title="Experience" />
<SlideShow <SlideShow
data={cv.experiences} data={cv.experiences}
type={Experience} type={Experience}
typename="experience"
timeline="true" timeline="true"
/> />
<Section icon={mdiWrench} title="Projects" /> <Section icon={mdiWrench} title="Projects" />
<SlideShow <SlideShow
data={cv.projects} data={cv.projects}
type={Projects} type={Projects}
typename="projects"
timeline="false"
/> />
<Section icon={mdiPencil} title="Skills" /> <Section icon={mdiPencil} title="Skills" />
</div> </div>