Frontend: Added 'Experience' component. Backend: Modified database.
This commit is contained in:
parent
057d2c7955
commit
a65045becb
11 changed files with 205 additions and 30 deletions
|
@ -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)
|
||||
);
|
|
@ -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)
|
||||
);
|
|
@ -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)]
|
||||
|
|
|
@ -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?;
|
||||
|
|
54
frontend/src/lib/components/experience.svelte
Normal file
54
frontend/src/lib/components/experience.svelte
Normal 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>
|
|
@ -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;
|
||||
for(const timeline of slideshowTimeline) {
|
||||
timeline.style.backgroundColor = '';
|
||||
if (timeline) {
|
||||
for (const timeline of slideshowTimeline) {
|
||||
timeline.style.backgroundColor = "";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slideshow_hidden.push(slideshow_index);
|
||||
|
@ -58,10 +65,13 @@
|
|||
newtransformValue *= 1.1;
|
||||
}
|
||||
element.style.transform = `translateX(-${newtransformValue}px)`;
|
||||
if(slideshowTimeline[id] != undefined) {
|
||||
slideshowTimeline[id].style.transform = `translateX(-${transformValue}px)`;
|
||||
if (slideshowTimeline[id] != undefined) {
|
||||
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"
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
.education-img {
|
||||
max-height: 15rem;
|
||||
min-width: 20rem;
|
||||
max-width: 25rem;
|
||||
}
|
||||
|
||||
.education-text-container {
|
||||
|
|
103
frontend/src/lib/css/experience.css
Normal file
103
frontend/src/lib/css/experience.css
Normal 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;
|
||||
}
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Add table
Reference in a new issue