working prototype
This commit is contained in:
parent
8a035affe3
commit
2fb24dda9b
@ -18,4 +18,10 @@ phone = Telefon
|
|||||||
czech = Česky
|
czech = Česky
|
||||||
english = Anglicky
|
english = Anglicky
|
||||||
skills-languages = Jazyky
|
skills-languages = Jazyky
|
||||||
skills-technology = Technologie/Frameworky
|
skills-technology = Technologie/Frameworky
|
||||||
|
Master = expert
|
||||||
|
Expert = expert
|
||||||
|
Intermediate = pokročilá znalost
|
||||||
|
Beginer = malá znalost
|
||||||
|
tools = nástroje
|
||||||
|
operating-systems = operační systémy
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
devops-enginner-web-developer = DevOPS engineer/Backend web developer
|
devops-enginner-web-developer = DevOPS engineer/Backend web developer
|
||||||
download-cv = Download CV
|
download-cv = Download CV
|
||||||
hire-me = Hire me
|
hire-me = Hire me
|
||||||
about-me = About me
|
about-me = About me
|
||||||
professional-skills = Professional Skills
|
professional-skills = Professional Skills
|
||||||
education = Education
|
education = Education
|
||||||
@ -18,4 +18,10 @@ phone = Phone
|
|||||||
czech = Czech
|
czech = Czech
|
||||||
english = English
|
english = English
|
||||||
skills-languages = Languages
|
skills-languages = Languages
|
||||||
skills-technology = Technologies/Frameworks
|
skills-technology = Technologies/Frameworks
|
||||||
|
Master = master
|
||||||
|
Expert = expert
|
||||||
|
Intermediate = intermediate
|
||||||
|
Beginer = beginer
|
||||||
|
tools = tools
|
||||||
|
operating-systems = operating systems
|
||||||
|
@ -9,7 +9,7 @@ use ::rocket::{State, http::Status};
|
|||||||
use ::rocket::get;
|
use ::rocket::get;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
use tracing::{info_span, error, debug};
|
use tracing::{info_span, error, debug, Instrument};
|
||||||
use crate::DefaultPerson;
|
use crate::DefaultPerson;
|
||||||
use crate::{chromium::rocket::BrowserHolder, tools::{tera::NanoTera, pdf::PdfStream, rocket::RequestLanguage}, services::cv::fetch_cv_data_from_backend, CVBackendConfig};
|
use crate::{chromium::rocket::BrowserHolder, tools::{tera::NanoTera, pdf::PdfStream, rocket::RequestLanguage}, services::cv::fetch_cv_data_from_backend, CVBackendConfig};
|
||||||
|
|
||||||
@ -28,8 +28,9 @@ fn generate_pdf(browser: Browser, file: &NamedTempFile) -> Vec<u8> {
|
|||||||
margin_right: Some(0.0),
|
margin_right: Some(0.0),
|
||||||
margin_top: Some(0.0),
|
margin_top: Some(0.0),
|
||||||
print_background: Some(true),
|
print_background: Some(true),
|
||||||
//paper_width: Some(29.7),
|
paper_width: Some(8.3),
|
||||||
//paper_height: Some(21.0),
|
paper_height: Some(11.7),
|
||||||
|
landscape: Some(false),
|
||||||
..PrintToPdfOptions::default()
|
..PrintToPdfOptions::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -63,23 +64,23 @@ fn render_template(template_name: &str, file: &NamedTempFile, tera: NanoTera, cv
|
|||||||
pub async fn render_pdf_cv(username: &str, tera: NanoTera, tracing: TracingSpan, request_client: OtelReqwestClient,
|
pub async fn render_pdf_cv(username: &str, tera: NanoTera, tracing: TracingSpan, request_client: OtelReqwestClient,
|
||||||
cv_config: &State<CVBackendConfig>, language: RequestLanguage, browser: BrowserHolder,
|
cv_config: &State<CVBackendConfig>, language: RequestLanguage, browser: BrowserHolder,
|
||||||
default_person: &State<DefaultPerson>) -> Result<PdfStream, Status> {
|
default_person: &State<DefaultPerson>) -> Result<PdfStream, Status> {
|
||||||
let entered_span = tracing.0.enter();
|
async move {
|
||||||
match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await {
|
match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await {
|
||||||
Ok(cv_data) => {
|
Ok(cv_data) => {
|
||||||
let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap();
|
let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap();
|
||||||
render_template("two_column", &file, tera, cv_data, language.language);
|
render_template("two_column", &file, tera, cv_data, language.language);
|
||||||
let span = info_span!("render_pdf", username = username);
|
let span = info_span!("render_pdf", username = username);
|
||||||
let pdf = span.in_scope(||{
|
let pdf = span.in_scope(||{
|
||||||
generate_pdf(browser.browser, &file)
|
generate_pdf(browser.browser, &file)
|
||||||
});
|
});
|
||||||
drop(entered_span);
|
Ok(PdfStream::new(pdf))
|
||||||
Ok(PdfStream::new(pdf))
|
},
|
||||||
},
|
Err(e) => {
|
||||||
Err(e) => {
|
error!("Error fetching cv data: {:?}", e);
|
||||||
error!("Error fetching cv data: {:?}", e);
|
Err(Status::InternalServerError)
|
||||||
Err(Status::InternalServerError)
|
}
|
||||||
}
|
}
|
||||||
}
|
}.instrument(tracing.0).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Route only for debuging
|
/// Route only for debuging
|
||||||
@ -87,17 +88,18 @@ pub async fn render_pdf_cv(username: &str, tera: NanoTera, tracing: TracingSpan,
|
|||||||
pub async fn render_html_cv(username: &str, tera: NanoTera, tracing: TracingSpan, request_client: OtelReqwestClient,
|
pub async fn render_html_cv(username: &str, tera: NanoTera, tracing: TracingSpan, request_client: OtelReqwestClient,
|
||||||
cv_config: &State<CVBackendConfig>, language: RequestLanguage,
|
cv_config: &State<CVBackendConfig>, language: RequestLanguage,
|
||||||
default_person: &State<DefaultPerson>) -> Result<NamedFile, Status> {
|
default_person: &State<DefaultPerson>) -> Result<NamedFile, Status> {
|
||||||
let _ = tracing.0.enter();
|
async move {
|
||||||
match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await {
|
match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await {
|
||||||
Ok(cv_data) => {
|
Ok(cv_data) => {
|
||||||
let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap();
|
let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap();
|
||||||
render_template("two_column", &file, tera, cv_data, language.language);
|
render_template("two_column", &file, tera, cv_data, language.language);
|
||||||
Ok(NamedFile::open(file.path()).await.unwrap())
|
Ok(NamedFile::open(file.path()).await.unwrap())
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error fetching cv data: {:?}", e);
|
error!("Error fetching cv data: {:?}", e);
|
||||||
Err(Status::InternalServerError)
|
Err(Status::InternalServerError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}.instrument(tracing.0).await
|
||||||
|
|
||||||
}
|
}
|
||||||
|
251
templates/two_column.css
Normal file
251
templates/two_column.css
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
{% macro css() %}
|
||||||
|
h1 {
|
||||||
|
/*font-weight: 800;*/
|
||||||
|
font-size: 3em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
margin-left: -0.1em;
|
||||||
|
/* text upper */
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.1em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body { min-height: 100vh; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Roboto' ;
|
||||||
|
min-height: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.about-me-small, .company {
|
||||||
|
color: #39c0ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-me-title {
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
.about-me {
|
||||||
|
font-size: 8pt;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part-content > * {
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part {
|
||||||
|
padding-top: 1em;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: normal;
|
||||||
|
align-content: normal;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 23.37in; /* TODO: jak udelam aby tenhle flex koncil s tistenou strankou? */
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items:nth-child(1) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
align-self: auto;
|
||||||
|
order: 0;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items:nth-child(2) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
align-self: auto;
|
||||||
|
order: 0;
|
||||||
|
width: 30%;
|
||||||
|
background-color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
width: 99%;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container-experience {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: normal;
|
||||||
|
align-items: normal;
|
||||||
|
align-content: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items-experience:nth-child(1) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
align-self: auto;
|
||||||
|
width: 70%;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items-experience:nth-child(2) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
text-align: right;
|
||||||
|
align-self: auto;
|
||||||
|
width: 30%;
|
||||||
|
margin-right: 1%;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container-experience-langdate {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: normal;
|
||||||
|
align-items: normal;
|
||||||
|
align-content: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items-experience-langdate:nth-child(1) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
align-self: auto;
|
||||||
|
width: 85%;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items-experience-langdate:nth-child(2) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
text-align: right;
|
||||||
|
align-self: auto;
|
||||||
|
width: 15%;
|
||||||
|
margin-right: 1%;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container-skills {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: normal;
|
||||||
|
align-items: normal;
|
||||||
|
align-content: normal;
|
||||||
|
width: 99%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header .flex-container-skills {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items-skills:nth-child(1) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
align-self: auto;
|
||||||
|
width: 50%;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-items-skills:nth-child(2) {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
text-align: left;
|
||||||
|
align-self: auto;
|
||||||
|
width: 50%;
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-name {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-level {
|
||||||
|
}
|
||||||
|
|
||||||
|
.job p {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.job:nth-child(n+3) {
|
||||||
|
padding-top: 10px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.contact-bar {
|
||||||
|
font-size: 11pt;
|
||||||
|
padding-left: 1em;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-bar i::after{
|
||||||
|
content: "\a";
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo {
|
||||||
|
padding-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-bar:first-child {
|
||||||
|
padding-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
height: 1em;
|
||||||
|
vertical-align:middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bolder {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.experience-desc {
|
||||||
|
max-width: 98%
|
||||||
|
}
|
||||||
|
|
||||||
|
.languages {
|
||||||
|
font-size: 8pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
{% endmacro css %}
|
@ -1,3 +1,6 @@
|
|||||||
|
{% import "two_column.macros.tera" as macros %}
|
||||||
|
{% import "two_column.css" as css %}
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@ -6,205 +9,7 @@
|
|||||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;800&family=Roboto&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;800&family=Roboto&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
{{css::css()}}
|
||||||
h1 {
|
|
||||||
/*font-weight: 800;*/
|
|
||||||
font-size: 3em;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: -0.1em;
|
|
||||||
/* text upper */
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.1em;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body { min-height: 100vh; }
|
|
||||||
|
|
||||||
body {
|
|
||||||
padding-left: 0.5em;
|
|
||||||
margin: 0;
|
|
||||||
font-family: 'Roboto' ;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about-me-small, .company {
|
|
||||||
color: #39c0ed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.part-content > * {
|
|
||||||
padding-bottom: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.part {
|
|
||||||
padding-top: 1em;
|
|
||||||
font-size: 10pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-container {
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: normal;
|
|
||||||
align-content: normal;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-items:nth-child(1) {
|
|
||||||
display: block;
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: auto;
|
|
||||||
align-self: auto;
|
|
||||||
order: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-items:nth-child(2) {
|
|
||||||
display: block;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: auto;
|
|
||||||
align-self: auto;
|
|
||||||
order: 0;
|
|
||||||
width: 30%;
|
|
||||||
background-color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
border-bottom: 1px solid gray;
|
|
||||||
width: 99%;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-container-experience {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: normal;
|
|
||||||
align-items: normal;
|
|
||||||
align-content: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-items-experience:nth-child(1) {
|
|
||||||
display: block;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: auto;
|
|
||||||
align-self: auto;
|
|
||||||
width: 70%;
|
|
||||||
order: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-items-experience:nth-child(2) {
|
|
||||||
display: block;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: auto;
|
|
||||||
text-align: right;
|
|
||||||
align-self: auto;
|
|
||||||
width: 30%;
|
|
||||||
margin-right: 1%;
|
|
||||||
order: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-container-skills {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: normal;
|
|
||||||
align-items: normal;
|
|
||||||
align-content: normal;
|
|
||||||
width: 99%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header .flex-container-skills {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-items-skills:nth-child(1) {
|
|
||||||
display: block;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: auto;
|
|
||||||
align-self: auto;
|
|
||||||
width: 50%;
|
|
||||||
order: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-items-skills:nth-child(2) {
|
|
||||||
display: block;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 1;
|
|
||||||
flex-basis: auto;
|
|
||||||
text-align: left;
|
|
||||||
align-self: auto;
|
|
||||||
width: 50%;
|
|
||||||
order: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-name {
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-level {
|
|
||||||
}
|
|
||||||
|
|
||||||
.job p {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.job:nth-child(n+3) {
|
|
||||||
padding-top: 10px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.contact-bar {
|
|
||||||
font-size: 11pt;
|
|
||||||
padding-left: 1em;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-bar i::after{
|
|
||||||
content: "\a";
|
|
||||||
white-space: pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
.photo {
|
|
||||||
padding-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact-bar:first-child {
|
|
||||||
padding-top: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.email{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
height: 1em;
|
|
||||||
vertical-align:middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bolder {
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-weight: 800;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -229,14 +34,14 @@
|
|||||||
<div class="flex-items-skills">
|
<div class="flex-items-skills">
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="Language") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="Language") %}
|
||||||
<div>
|
<div>
|
||||||
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | lower}}){%endif %}</span>
|
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | translate(lang=lang)}}){%endif %}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-items-skills">
|
<div class="flex-items-skills">
|
||||||
{% for skill in cv.skills | filter(attribute="techtype", value="Technology")%}
|
{% for skill in cv.skills | filter(attribute="techtype", value="Technology")%}
|
||||||
<div>
|
<div>
|
||||||
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | lower}}){%endif %}</span>
|
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | translate(lang=lang)}}){%endif %}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@ -257,14 +62,14 @@
|
|||||||
<div class="flex-items-skills">
|
<div class="flex-items-skills">
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="Framework") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="Framework") %}
|
||||||
<div>
|
<div>
|
||||||
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | lower}}){%endif %}</span>
|
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | translate(lang=lang)}}){%endif %}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-items-skills">
|
<div class="flex-items-skills">
|
||||||
{% for skill in cv.skills | filter(attribute="techtype", value="Database")%}
|
{% for skill in cv.skills | filter(attribute="techtype", value="Database")%}
|
||||||
<div>
|
<div>
|
||||||
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | lower}}){%endif %}</span>
|
<span class="tech-name">{{ skill.name }}</span>{%if skill.skill %}<span class="tech-level"> ({{ skill.skill | translate(lang=lang)}}){%endif %}</span>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@ -273,39 +78,28 @@
|
|||||||
<div class="part">
|
<div class="part">
|
||||||
<span class="bolder">{{"tools" | translate(lang=lang)}}:</span>
|
<span class="bolder">{{"tools" | translate(lang=lang)}}:</span>
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="Tool") | advanced_filter(attribute="skill", include_null="all") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="Tool") | advanced_filter(attribute="skill", include_null="all") %}
|
||||||
{{ skill.name }}{% if skill.skill %} - {{skill.skill}}{% endif %},<!-- TODO: fix-me (empty "," if operating system empty) %-->
|
{{ skill.name }}{% if skill.skill %} - {{skill.skill | ranslate(lang=lang)}}{% endif %},<!-- TODO: fix-me (empty "," if operating system empty) %-->
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<span class="bolder">{{"operating-systems" | translate(lang=lang)}}:</span>
|
<span class="bolder">{{"operating-systems" | translate(lang=lang)}}:</span>
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="OperatingSystem") | advanced_filter(attribute="skill", include_null="all") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="OperatingSystem") | advanced_filter(attribute="skill", include_null="all") %}
|
||||||
{{ skill.name }}</span>{% if skill.skill %} - {{skill.skill}}{% endif %}{% if not loop.last %},{% endif %}
|
{{ skill.name }}</span>{% if skill.skill %} - {{skill.skill | translate(lang=lang)}}{% endif %}{% if not loop.last %},{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="part">
|
<div class="part">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h2>{{ "work-experience" | translate(lang=lang) }}</h2>
|
<h2>{{ "work-experience" | translate(lang=lang) }}</h2>
|
||||||
</div>
|
</div>
|
||||||
{% for job in cv.jobs | filter(attribute="jobtype", value="Contract") %}
|
{% for job in cv.jobs | filter(attribute="jobtype", value="Contract") | slice(end=2) %}
|
||||||
<div class="job part-content">
|
{{macros::job_row(job_entity=job)}}
|
||||||
<div class="flex-container-experience">
|
{% endfor %}
|
||||||
<div class="flex-items-experience">
|
</div>
|
||||||
<div class="title">{{ job.title }}</div>
|
<div style="page-break-after: always;"> </div>
|
||||||
<div class="languages">{{ job.languages }}</div>
|
<div class="part">
|
||||||
<p>
|
<div class="section-header">
|
||||||
{{ job.description | lang_entity(lang=lang) }}
|
<h2>{{ "work-experience" | translate(lang=lang) }}</h2>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex-items-experience">
|
|
||||||
<div class="company">@{{ job.company }}</div>
|
|
||||||
<div class="dates">
|
|
||||||
{% if job.from | format_date(type="job") != job.from | format_date(type="job") %}
|
|
||||||
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
{% for job in cv.jobs | filter(attribute="jobtype", value="Contract") | slice(start=2) %}
|
||||||
|
{{macros::job_row(job_entity=job)}}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="part">
|
<div class="part">
|
||||||
@ -313,27 +107,7 @@
|
|||||||
<h2>{{ "work-freelance" | translate(lang=lang) }}</h2>
|
<h2>{{ "work-freelance" | translate(lang=lang) }}</h2>
|
||||||
</div>
|
</div>
|
||||||
{% for job in cv.jobs | filter(attribute="jobtype", value="Freelance") %}
|
{% for job in cv.jobs | filter(attribute="jobtype", value="Freelance") %}
|
||||||
<div class="job part-content">
|
{{macros::job_row(job_entity=job)}}
|
||||||
<div class="flex-container-experience">
|
|
||||||
<div class="flex-items-experience">
|
|
||||||
<div class="title">{{ job.title }}</div>
|
|
||||||
<div class="languages">{{ job.languages }}</div>
|
|
||||||
<p>
|
|
||||||
{{ job.description | lang_entity(lang=lang) }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="flex-items-experience">
|
|
||||||
<div class="company">@{{ job.company }}</div>
|
|
||||||
<div class="dates">
|
|
||||||
{% if job.from | format_date(type="job") != job.from | format_date(type="job") %}
|
|
||||||
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="part">
|
<div class="part">
|
||||||
@ -370,9 +144,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex-items">
|
<div class="flex-items">
|
||||||
<div class="contact-bar">
|
<div class="contact-bar">
|
||||||
<div class="photo">
|
|
||||||
<img class="img-thumbnail shadow-2-strong" src="{{ cv.person.email | gravatar_link }}" width="160" height="160"/>
|
|
||||||
</div>
|
|
||||||
{% if cv.person.social.facebook %}
|
{% if cv.person.social.facebook %}
|
||||||
<i class="fa-facebook"> {{ cv.person.social.facebook | strip_proto }}</i>
|
<i class="fa-facebook"> {{ cv.person.social.facebook | strip_proto }}</i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -402,6 +174,8 @@
|
|||||||
<img alt="Phone" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNNi4xNzYgMS4zMjJsMi44NDQtMS4zMjIgNC4wNDEgNy44OS0yLjcyNCAxLjM0MWMtLjUzOCAxLjI1OSAyLjE1OSA2LjI4OSAzLjI5NyA2LjM3Mi4wOS0uMDU4IDIuNjcxLTEuMzI4IDIuNjcxLTEuMzI4bDQuMTEgNy45MzJzLTIuNzY0IDEuMzU0LTIuODU0IDEuMzk2Yy03Ljg2MiAzLjU5MS0xOS4xMDMtMTguMjU4LTExLjM4NS0yMi4yODF6bTEuOTI5IDEuMjc0bC0xLjAyMy41MDRjLTUuMjk0IDIuNzYyIDQuMTc3IDIxLjE4NSA5LjY0OCAxOC42ODZsLjk3MS0uNDc0LTIuMjcxLTQuMzgzLTEuMDI2LjVjLTMuMTYzIDEuNTQ3LTguMjYyLTguMjE5LTUuMDU1LTkuOTM4bDEuMDA3LS40OTctMi4yNTEtNC4zOTh6Ii8+PC9zdmc+" class="icon">
|
<img alt="Phone" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNNi4xNzYgMS4zMjJsMi44NDQtMS4zMjIgNC4wNDEgNy44OS0yLjcyNCAxLjM0MWMtLjUzOCAxLjI1OSAyLjE1OSA2LjI4OSAzLjI5NyA2LjM3Mi4wOS0uMDU4IDIuNjcxLTEuMzI4IDIuNjcxLTEuMzI4bDQuMTEgNy45MzJzLTIuNzY0IDEuMzU0LTIuODU0IDEuMzk2Yy03Ljg2MiAzLjU5MS0xOS4xMDMtMTguMjU4LTExLjM4NS0yMi4yODF6bTEuOTI5IDEuMjc0bC0xLjAyMy41MDRjLTUuMjk0IDIuNzYyIDQuMTc3IDIxLjE4NSA5LjY0OCAxOC42ODZsLjk3MS0uNDc0LTIuMjcxLTQuMzgzLTEuMDI2LjVjLTMuMTYzIDEuNTQ3LTguMjYyLTguMjE5LTUuMDU1LTkuOTM4bDEuMDA3LS40OTctMi4yNTEtNC4zOTh6Ii8+PC9zdmc+" class="icon">
|
||||||
+{{cv.person.phone | insert_space_every(times=3)}}
|
+{{cv.person.phone | insert_space_every(times=3)}}
|
||||||
</i>
|
</i>
|
||||||
|
<div class="about-me-title">{{ "about-me" | translate(lang=lang) }}</div>
|
||||||
|
<div class="about-me">{{ cv.person.about | lang_entity(lang=lang) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
37
templates/two_column.macros.tera
Normal file
37
templates/two_column.macros.tera
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{% macro job_row(job_entity) %}
|
||||||
|
<div class="job part-content">
|
||||||
|
<div class="flex-container-experience">
|
||||||
|
<div class="flex-items-experience">
|
||||||
|
<div class="title">{{ job_entity.title }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-items-experience">
|
||||||
|
<div class="company">@{{ job_entity.company }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-container-experience-langdate">
|
||||||
|
<div class="flex-items-experience-langdate">
|
||||||
|
<div class="languages">
|
||||||
|
{% if job_entity.languages and job_entity.technologies %}
|
||||||
|
{{ job_entity.languages | concat(with=job_entity.technologies) }}
|
||||||
|
{% elif job_entity.languages %}
|
||||||
|
{{job_entity.languages}}
|
||||||
|
{% elif job_entity.technologies %}
|
||||||
|
{{job_entity.technologies}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-items-experience-langdate">
|
||||||
|
<div class="dates">
|
||||||
|
{% if job_entity.from | format_date(type="job") != job_entity.to | format_date(type="job") %}
|
||||||
|
<div class="text-muted text-small mb-3">{{ job_entity.from | format_date(type="job") }} - {{ job_entity.to | format_date(type="job") }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-muted text-small mb-3">{{ job_entity.from | format_date(type="job") }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="experience-desc">
|
||||||
|
{{ job_entity.description | lang_entity(lang=lang) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endmacro hello_world %}
|
Loading…
Reference in New Issue
Block a user