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 (
|
CREATE TABLE public.education (
|
||||||
id serial4 NOT NULL,
|
id serial4 NOT NULL,
|
||||||
start_year time NULL,
|
start_year date NULL,
|
||||||
end_year time NULL,
|
end_year date NULL,
|
||||||
school text NULL,
|
school text NULL,
|
||||||
speciality text NULL,
|
speciality text NULL,
|
||||||
school_location text NULL,
|
school_location text NULL,
|
||||||
school_options text NULL,
|
school_options text NULL,
|
||||||
|
picture_url text NULL,
|
||||||
CONSTRAINT education_pkey PRIMARY KEY (id)
|
CONSTRAINT education_pkey PRIMARY KEY (id)
|
||||||
);
|
);
|
|
@ -12,5 +12,6 @@ CREATE TABLE public.experience (
|
||||||
enterprise_location text NULL,
|
enterprise_location text NULL,
|
||||||
start_year date NULL,
|
start_year date NULL,
|
||||||
end_year date NULL,
|
end_year date NULL,
|
||||||
|
picture_url text NULL,
|
||||||
CONSTRAINT experience_pkey PRIMARY KEY (id)
|
CONSTRAINT experience_pkey PRIMARY KEY (id)
|
||||||
);
|
);
|
|
@ -33,6 +33,7 @@ pub struct Experience {
|
||||||
pub enterprise_location: Option<String>,
|
pub enterprise_location: Option<String>,
|
||||||
pub start_year: Option<NaiveDate>,
|
pub start_year: Option<NaiveDate>,
|
||||||
pub end_year: Option<NaiveDate>,
|
pub end_year: Option<NaiveDate>,
|
||||||
|
pub picture_url: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[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>>> {
|
async fn experience(State(pool): State<PgPool>) -> Result<Json<Vec<Experience>>> {
|
||||||
let datas = sqlx::query_as!(
|
let datas = sqlx::query_as!(
|
||||||
Experience,
|
Experience,
|
||||||
"SELECT id, job_position, job_description, enterprise, enterprise_location, start_year, end_year FROM public.experience"
|
"SELECT * FROM public.experience"
|
||||||
)
|
)
|
||||||
.fetch_all(&pool)
|
.fetch_all(&pool)
|
||||||
.await?;
|
.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
|
// Exported values
|
||||||
export let data = [];
|
export let data = [];
|
||||||
export let type;
|
export let type;
|
||||||
|
export let typename;
|
||||||
|
export let timeline = false;
|
||||||
|
|
||||||
// Slideshow global variables
|
// Slideshow global variables
|
||||||
let slideshow_index = 0;
|
let slideshow_index = 0;
|
||||||
|
@ -16,32 +18,37 @@
|
||||||
// Timeline global variables
|
// Timeline global variables
|
||||||
let slideshow;
|
let slideshow;
|
||||||
let bubbles = [];
|
let bubbles = [];
|
||||||
onMount(() => {
|
if (timeline) {
|
||||||
for (const element of document.getElementsByClassName(
|
onMount(() => {
|
||||||
"education-bubble"
|
for (const element of document.getElementsByClassName(
|
||||||
)) {
|
`${typename}-bubble`
|
||||||
bubbles.push({
|
)) {
|
||||||
left: element.offsetLeft,
|
bubbles.push({
|
||||||
top: element.offsetTop,
|
left: element.offsetLeft,
|
||||||
});
|
top: element.offsetTop,
|
||||||
}
|
});
|
||||||
for (const div of createTimeLine(bubbles)) {
|
}
|
||||||
slideshow.appendChild(div);
|
for (const div of createTimeLine(bubbles,typename)) {
|
||||||
}
|
slideshow.appendChild(div);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function slideEducation() {
|
function slideCards() {
|
||||||
const slideshowElements = document.querySelectorAll(
|
const slideshowElements = document.querySelectorAll(
|
||||||
".education-container"
|
`.${typename}-container`
|
||||||
);
|
);
|
||||||
const slideshowTimeline =
|
const slideshowTimeline =
|
||||||
document.querySelectorAll(".education-string");
|
document.querySelectorAll(`.${typename}-string`);
|
||||||
|
|
||||||
|
console.log(slideshowTimeline);
|
||||||
if (slideshow_index >= data.length - 1) {
|
if (slideshow_index >= data.length - 1) {
|
||||||
slideshow_hidden = [];
|
slideshow_hidden = [];
|
||||||
slideshow_index = 0;
|
slideshow_index = 0;
|
||||||
for(const timeline of slideshowTimeline) {
|
if (timeline) {
|
||||||
timeline.style.backgroundColor = '';
|
for (const timeline of slideshowTimeline) {
|
||||||
|
timeline.style.backgroundColor = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
slideshow_hidden.push(slideshow_index);
|
slideshow_hidden.push(slideshow_index);
|
||||||
|
@ -58,10 +65,13 @@
|
||||||
newtransformValue *= 1.1;
|
newtransformValue *= 1.1;
|
||||||
}
|
}
|
||||||
element.style.transform = `translateX(-${newtransformValue}px)`;
|
element.style.transform = `translateX(-${newtransformValue}px)`;
|
||||||
if(slideshowTimeline[id] != undefined) {
|
if (slideshowTimeline[id] != undefined) {
|
||||||
slideshowTimeline[id].style.transform = `translateX(-${transformValue}px)`;
|
slideshowTimeline[
|
||||||
|
id
|
||||||
|
].style.transform = `translateX(-${transformValue}px)`;
|
||||||
if (slideshow_hidden.includes(id)) {
|
if (slideshow_hidden.includes(id)) {
|
||||||
slideshowTimeline[id].style.backgroundColor = 'var(--color-background)';
|
slideshowTimeline[id].style.backgroundColor =
|
||||||
|
"var(--color-background)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -69,7 +79,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="slideshow" bind:this={slideshow}>
|
<div class="slideshow" bind:this={slideshow}>
|
||||||
<button class="slideshow_btn" on:click={slideEducation}>
|
<button class="slideshow_btn" on:click={slideCards}>
|
||||||
<div>
|
<div>
|
||||||
<SvgIcon
|
<SvgIcon
|
||||||
size="45"
|
size="45"
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
.education-img {
|
.education-img {
|
||||||
max-height: 15rem;
|
max-height: 15rem;
|
||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
|
max-width: 25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.education-text-container {
|
.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) {
|
export function processData(data) {
|
||||||
if (data.status === 0) {
|
if (data.status === 0) {
|
||||||
const info = data.info[0];
|
const info = data.info[0];
|
||||||
const experiences = data.experience;
|
const experiences = arrangeById(data.experience);
|
||||||
const education = arrangeById(data.education);
|
const education = arrangeById(data.education);
|
||||||
const skills = data.skills[1];
|
const skills = data.skills[1];
|
||||||
const projects = data.skills[0];
|
const projects = data.skills[0];
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
export function createTimeLine(positionsArray) {
|
export function createTimeLine(positionsArray,typename) {
|
||||||
let divArray = []
|
let divArray = []
|
||||||
console.log(positionsArray);
|
console.log(positionsArray);
|
||||||
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 = 'education-string';
|
newDiv.className = `${typename}-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;
|
||||||
|
|
|
@ -18,13 +18,15 @@
|
||||||
// Main
|
// Main
|
||||||
import Section from "$lib/components/section.svelte";
|
import Section from "$lib/components/section.svelte";
|
||||||
import Education from "$lib/components/education.svelte";
|
import Education from "$lib/components/education.svelte";
|
||||||
|
import Experience from "$lib/components/experience.svelte"
|
||||||
import SlideShow from "$lib/components/slideshow.svelte";
|
import SlideShow from "$lib/components/slideshow.svelte";
|
||||||
import { mdiSchool } from "@mdi/js";
|
import { mdiSchool,mdiBriefcase } from "@mdi/js";
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
const cv = data.status == 0 ? processData(data) : undefined;
|
const cv = data.status == 0 ? processData(data) : undefined;
|
||||||
const birth_year =
|
const birth_year =
|
||||||
data.status == 0 ? formatDate(cv.info.birth_year) : undefined;
|
data.status == 0 ? formatDate(cv.info.birth_year) : undefined;
|
||||||
|
console.log(cv.experience)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if data.status == 0}
|
{#if data.status == 0}
|
||||||
|
@ -63,7 +65,9 @@
|
||||||
<h1 class="name">{cv.info.full_name}</h1>
|
<h1 class="name">{cv.info.full_name}</h1>
|
||||||
<h2 class="name">Apprentice Engineer Automatic/Electronic</h2>
|
<h2 class="name">Apprentice Engineer Automatic/Electronic</h2>
|
||||||
<Section icon={mdiSchool} title="Education" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|
Loading…
Add table
Reference in a new issue