Frontend: Added 'Experience' component. Backend: Modified database.

This commit is contained in:
Yohan Boujon 2023-11-16 22:32:53 +01:00
parent 057d2c7955
commit a65045becb
11 changed files with 205 additions and 30 deletions

View file

@ -6,11 +6,12 @@
CREATE TABLE public.education (
id serial4 NOT NULL,
start_year time NULL,
end_year time NULL,
start_year date NULL,
end_year date NULL,
school text NULL,
speciality text NULL,
school_location text NULL,
school_options text NULL,
picture_url text NULL,
CONSTRAINT education_pkey PRIMARY KEY (id)
);

View file

@ -12,5 +12,6 @@ CREATE TABLE public.experience (
enterprise_location text NULL,
start_year date NULL,
end_year date NULL,
picture_url text NULL,
CONSTRAINT experience_pkey PRIMARY KEY (id)
);

View file

@ -33,6 +33,7 @@ pub struct Experience {
pub enterprise_location: Option<String>,
pub start_year: Option<NaiveDate>,
pub end_year: Option<NaiveDate>,
pub picture_url: Option<String>
}
#[derive(Deserialize, Serialize)]

View file

@ -61,7 +61,7 @@ async fn education(State(pool): State<PgPool>) -> Result<Json<Vec<Education>>> {
async fn experience(State(pool): State<PgPool>) -> Result<Json<Vec<Experience>>> {
let datas = sqlx::query_as!(
Experience,
"SELECT id, job_position, job_description, enterprise, enterprise_location, start_year, end_year FROM public.experience"
"SELECT * FROM public.experience"
)
.fetch_all(&pool)
.await?;

View file

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

View file

@ -8,6 +8,8 @@
// Exported values
export let data = [];
export let type;
export let typename;
export let timeline = false;
// Slideshow global variables
let slideshow_index = 0;
@ -16,32 +18,37 @@
// Timeline global variables
let slideshow;
let bubbles = [];
if (timeline) {
onMount(() => {
for (const element of document.getElementsByClassName(
"education-bubble"
`${typename}-bubble`
)) {
bubbles.push({
left: element.offsetLeft,
top: element.offsetTop,
});
}
for (const div of createTimeLine(bubbles)) {
for (const div of createTimeLine(bubbles,typename)) {
slideshow.appendChild(div);
}
});
}
function slideEducation() {
function slideCards() {
const slideshowElements = document.querySelectorAll(
".education-container"
`.${typename}-container`
);
const slideshowTimeline =
document.querySelectorAll(".education-string");
document.querySelectorAll(`.${typename}-string`);
console.log(slideshowTimeline);
if (slideshow_index >= data.length - 1) {
slideshow_hidden = [];
slideshow_index = 0;
if (timeline) {
for (const timeline of slideshowTimeline) {
timeline.style.backgroundColor = '';
timeline.style.backgroundColor = "";
}
}
} else {
slideshow_hidden.push(slideshow_index);
@ -59,9 +66,12 @@
}
element.style.transform = `translateX(-${newtransformValue}px)`;
if (slideshowTimeline[id] != undefined) {
slideshowTimeline[id].style.transform = `translateX(-${transformValue}px)`;
slideshowTimeline[
id
].style.transform = `translateX(-${transformValue}px)`;
if (slideshow_hidden.includes(id)) {
slideshowTimeline[id].style.backgroundColor = 'var(--color-background)';
slideshowTimeline[id].style.backgroundColor =
"var(--color-background)";
}
}
});
@ -69,7 +79,7 @@
</script>
<div class="slideshow" bind:this={slideshow}>
<button class="slideshow_btn" on:click={slideEducation}>
<button class="slideshow_btn" on:click={slideCards}>
<div>
<SvgIcon
size="45"

View file

@ -26,6 +26,7 @@
.education-img {
max-height: 15rem;
min-width: 20rem;
max-width: 25rem;
}
.education-text-container {

View file

@ -0,0 +1,103 @@
.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;
}
.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

@ -9,7 +9,7 @@ function arrangeById(array) {
export function processData(data) {
if (data.status === 0) {
const info = data.info[0];
const experiences = data.experience;
const experiences = arrangeById(data.experience);
const education = arrangeById(data.education);
const skills = data.skills[1];
const projects = data.skills[0];

View file

@ -1,10 +1,10 @@
export function createTimeLine(positionsArray) {
export function createTimeLine(positionsArray,typename) {
let divArray = []
console.log(positionsArray);
for(let i=0; i<positionsArray.length-1; i++)
{
var newDiv = document.createElement('div');
newDiv.className = 'education-string';
newDiv.className = `${typename}-string`;
const left = positionsArray[i].left + (2.5*16);
newDiv.style.left = `${left}px`;
const top = positionsArray[i].top + 16;

View file

@ -18,13 +18,15 @@
// Main
import Section from "$lib/components/section.svelte";
import Education from "$lib/components/education.svelte";
import Experience from "$lib/components/experience.svelte"
import SlideShow from "$lib/components/slideshow.svelte";
import { mdiSchool } from "@mdi/js";
import { mdiSchool,mdiBriefcase } from "@mdi/js";
export let data;
const cv = data.status == 0 ? processData(data) : undefined;
const birth_year =
data.status == 0 ? formatDate(cv.info.birth_year) : undefined;
console.log(cv.experience)
</script>
{#if data.status == 0}
@ -63,7 +65,9 @@
<h1 class="name">{cv.info.full_name}</h1>
<h2 class="name">Apprentice Engineer Automatic/Electronic</h2>
<Section icon={mdiSchool} title="Education" />
<SlideShow data={cv.education} type={Education} />
<SlideShow data={cv.education} type={Education} typename="education" timeline=true />
<Section icon={mdiBriefcase} title="Experience" />
<SlideShow data={cv.experiences} type={Experience} typename="experience" timeline=true />
</div>
</div>
{:else}