diff --git a/resources/cs-CZ/ovlach_pdf b/resources/cs-CZ/ovlach_pdf index 04dd624..f1229c6 100644 --- a/resources/cs-CZ/ovlach_pdf +++ b/resources/cs-CZ/ovlach_pdf @@ -18,4 +18,10 @@ phone = Telefon czech = Česky english = Anglicky skills-languages = Jazyky -skills-technology = Technologie/Frameworky \ No newline at end of file +skills-technology = Technologie/Frameworky +Master = expert +Expert = expert +Intermediate = pokročilá znalost +Beginer = malá znalost +tools = nástroje +operating-systems = operační systémy diff --git a/resources/en-US/ovlach_pdf b/resources/en-US/ovlach_pdf index d4aaaf6..6836786 100644 --- a/resources/en-US/ovlach_pdf +++ b/resources/en-US/ovlach_pdf @@ -1,6 +1,6 @@ devops-enginner-web-developer = DevOPS engineer/Backend web developer download-cv = Download CV -hire-me = Hire me +hire-me = Hire me about-me = About me professional-skills = Professional Skills education = Education @@ -18,4 +18,10 @@ phone = Phone czech = Czech english = English skills-languages = Languages -skills-technology = Technologies/Frameworks \ No newline at end of file +skills-technology = Technologies/Frameworks +Master = master +Expert = expert +Intermediate = intermediate +Beginer = beginer +tools = tools +operating-systems = operating systems diff --git a/src/routes/pdf.rs b/src/routes/pdf.rs index 9dc152f..f58e52b 100644 --- a/src/routes/pdf.rs +++ b/src/routes/pdf.rs @@ -9,7 +9,7 @@ use ::rocket::{State, http::Status}; use ::rocket::get; use tempfile::NamedTempFile; use tera::Context; -use tracing::{info_span, error, debug}; +use tracing::{info_span, error, debug, Instrument}; use crate::DefaultPerson; 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 { margin_right: Some(0.0), margin_top: Some(0.0), print_background: Some(true), - //paper_width: Some(29.7), - //paper_height: Some(21.0), + paper_width: Some(8.3), + paper_height: Some(11.7), + landscape: Some(false), ..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, cv_config: &State, language: RequestLanguage, browser: BrowserHolder, default_person: &State) -> Result { - let entered_span = tracing.0.enter(); - match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await { - Ok(cv_data) => { - let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap(); - render_template("two_column", &file, tera, cv_data, language.language); - let span = info_span!("render_pdf", username = username); - let pdf = span.in_scope(||{ - generate_pdf(browser.browser, &file) - }); - drop(entered_span); - Ok(PdfStream::new(pdf)) - }, - Err(e) => { - error!("Error fetching cv data: {:?}", e); - Err(Status::InternalServerError) + async move { + match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await { + Ok(cv_data) => { + let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap(); + render_template("two_column", &file, tera, cv_data, language.language); + let span = info_span!("render_pdf", username = username); + let pdf = span.in_scope(||{ + generate_pdf(browser.browser, &file) + }); + Ok(PdfStream::new(pdf)) + }, + Err(e) => { + error!("Error fetching cv data: {:?}", e); + Err(Status::InternalServerError) + } } - } + }.instrument(tracing.0).await } /// 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, cv_config: &State, language: RequestLanguage, default_person: &State) -> Result { - let _ = tracing.0.enter(); - match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await { - Ok(cv_data) => { - let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap(); - render_template("two_column", &file, tera, cv_data, language.language); - Ok(NamedFile::open(file.path()).await.unwrap()) - }, - Err(e) => { - error!("Error fetching cv data: {:?}", e); - Err(Status::InternalServerError) + async move { + match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.inner().default_person_name, &request_client.0).await { + Ok(cv_data) => { + let file = tempfile::Builder::new().suffix(".html").tempfile().unwrap(); + render_template("two_column", &file, tera, cv_data, language.language); + Ok(NamedFile::open(file.path()).await.unwrap()) + }, + Err(e) => { + error!("Error fetching cv data: {:?}", e); + Err(Status::InternalServerError) + } } - } + }.instrument(tracing.0).await } diff --git a/templates/two_column.css b/templates/two_column.css new file mode 100644 index 0000000..9d96960 --- /dev/null +++ b/templates/two_column.css @@ -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 %} diff --git a/templates/two_column.html.tera b/templates/two_column.html.tera index 73cfea5..f1ed2dd 100644 --- a/templates/two_column.html.tera +++ b/templates/two_column.html.tera @@ -1,3 +1,6 @@ +{% import "two_column.macros.tera" as macros %} +{% import "two_column.css" as css %} + @@ -6,205 +9,7 @@ @@ -229,14 +34,14 @@
{% for skill in cv.skills | filter(attribute="techtype",value="Language") %}
- {{ skill.name }}{%if skill.skill %} ({{ skill.skill | lower}}){%endif %} + {{ skill.name }}{%if skill.skill %} ({{ skill.skill | translate(lang=lang)}}){%endif %}
{% endfor %}
{% for skill in cv.skills | filter(attribute="techtype", value="Technology")%}
- {{ skill.name }}{%if skill.skill %} ({{ skill.skill | lower}}){%endif %} + {{ skill.name }}{%if skill.skill %} ({{ skill.skill | translate(lang=lang)}}){%endif %}
{% endfor %}
@@ -257,14 +62,14 @@
{% for skill in cv.skills | filter(attribute="techtype",value="Framework") %}
- {{ skill.name }}{%if skill.skill %} ({{ skill.skill | lower}}){%endif %} + {{ skill.name }}{%if skill.skill %} ({{ skill.skill | translate(lang=lang)}}){%endif %}
{% endfor %}
{% for skill in cv.skills | filter(attribute="techtype", value="Database")%}
- {{ skill.name }}{%if skill.skill %} ({{ skill.skill | lower}}){%endif %} + {{ skill.name }}{%if skill.skill %} ({{ skill.skill | translate(lang=lang)}}){%endif %}
{% endfor %}
@@ -273,39 +78,28 @@
{{"tools" | translate(lang=lang)}}: {% 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 %}, + {{ skill.name }}{% if skill.skill %} - {{skill.skill | ranslate(lang=lang)}}{% endif %}, {% endfor %} {{"operating-systems" | translate(lang=lang)}}: {% for skill in cv.skills | filter(attribute="techtype",value="OperatingSystem") | advanced_filter(attribute="skill", include_null="all") %} - {{ skill.name }}{% if skill.skill %} - {{skill.skill}}{% endif %}{% if not loop.last %},{% endif %} + {{ skill.name }}{% if skill.skill %} - {{skill.skill | translate(lang=lang)}}{% endif %}{% if not loop.last %},{% endif %} {% endfor %}

{{ "work-experience" | translate(lang=lang) }}

- {% for job in cv.jobs | filter(attribute="jobtype", value="Contract") %} -
-
-
-
{{ job.title }}
-
{{ job.languages }}
-

- {{ job.description | lang_entity(lang=lang) }} -

-
-
-
@{{ job.company }}
-
- {% if job.from | format_date(type="job") != job.from | format_date(type="job") %} -
{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}
- {% else %} -
{{ job.from | format_date(type="job") }}
- {% endif %} -
-
-
+ {% for job in cv.jobs | filter(attribute="jobtype", value="Contract") | slice(end=2) %} + {{macros::job_row(job_entity=job)}} + {% endfor %} +
+
 
+
+
+

{{ "work-experience" | translate(lang=lang) }}

+ {% for job in cv.jobs | filter(attribute="jobtype", value="Contract") | slice(start=2) %} + {{macros::job_row(job_entity=job)}} {% endfor %}
@@ -313,27 +107,7 @@

{{ "work-freelance" | translate(lang=lang) }}

{% for job in cv.jobs | filter(attribute="jobtype", value="Freelance") %} -
-
-
-
{{ job.title }}
-
{{ job.languages }}
-

- {{ job.description | lang_entity(lang=lang) }} -

-
-
-
@{{ job.company }}
-
- {% if job.from | format_date(type="job") != job.from | format_date(type="job") %} -
{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}
- {% else %} -
{{ job.from | format_date(type="job") }}
- {% endif %} -
-
-
-
+ {{macros::job_row(job_entity=job)}} {% endfor %}
@@ -370,9 +144,7 @@
-
- -
+ {% if cv.person.social.facebook %} {{ cv.person.social.facebook | strip_proto }} {% endif %} @@ -402,6 +174,8 @@ Phone +{{cv.person.phone | insert_space_every(times=3)}} +
{{ "about-me" | translate(lang=lang) }}
+
{{ cv.person.about | lang_entity(lang=lang) }}
diff --git a/templates/two_column.macros.tera b/templates/two_column.macros.tera new file mode 100644 index 0000000..4165073 --- /dev/null +++ b/templates/two_column.macros.tera @@ -0,0 +1,37 @@ +{% macro job_row(job_entity) %} +
+
+
+
{{ job_entity.title }}
+
+
+
@{{ job_entity.company }}
+
+
+
+
+
+ {% 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 %} +
+
+
+
+ {% if job_entity.from | format_date(type="job") != job_entity.to | format_date(type="job") %} +
{{ job_entity.from | format_date(type="job") }} - {{ job_entity.to | format_date(type="job") }}
+ {% else %} +
{{ job_entity.from | format_date(type="job") }}
+ {% endif %} +
+
+
+

+ {{ job_entity.description | lang_entity(lang=lang) }} +

+
+{% endmacro hello_world %}