add custom fonts support

This commit is contained in:
Sina Atalay 2023-10-08 15:41:20 +02:00
parent 3bf176f689
commit 8790097351
11 changed files with 76 additions and 45 deletions

View File

@ -13,6 +13,7 @@ import re
import logging import logging
from functools import cached_property from functools import cached_property
import urllib.request import urllib.request
import os
from pydantic import ( from pydantic import (
BaseModel, BaseModel,
@ -409,12 +410,48 @@ class Design(BaseModel):
title="Theme name", title="Theme name",
description='The only option is "Classic" for now.', description='The only option is "Classic" for now.',
) )
font: Literal["SourceSans3", "Roboto"] = Field(
default="SourceSans3",
title="Font",
description="The font of the CV.",
examples=["SourceSans3", "Roboto"],
)
font_size: Literal["10pt", "11pt", "12pt"] = Field(
default="10pt",
title="Font Size",
description="The font size of the CV. It can be 10pt, 11pt, or 12pt.",
examples=["10pt", "11pt", "12pt"],
)
options: ClassicThemeOptions = Field( options: ClassicThemeOptions = Field(
default=ClassicThemeOptions(), default=ClassicThemeOptions(),
title="Theme Options", title="Theme Options",
description="The options of the theme.", description="The options of the theme.",
) )
@field_validator("font")
@classmethod
def check_font(cls, font: str) -> str:
# Go to fonts directory and check if the font exists:
fonts_directory = os.path.join(os.path.dirname(__file__), "templates", "fonts")
if font not in os.listdir(fonts_directory):
raise ValueError(
f'The font "{font}" is not found in the "fonts" directory! To add a new'
" font, please see TO BE ADDED."
)
else:
font_directory = os.path.join(fonts_directory, font)
required_files = [
f"{font}-Bold.ttf",
f"{font}-BoldItalic.ttf",
f"{font}-Italic.ttf",
f"{font}-Regular.ttf",
]
for file in required_files:
if file not in os.listdir(font_directory):
raise ValueError(f"{file} is not found in the {font} directory!")
return font
# ====================================================================================== # ======================================================================================
# ====================================================================================== # ======================================================================================

View File

@ -202,13 +202,13 @@ def print_today() -> str:
return today.strftime("%B %d, %Y") return today.strftime("%B %d, %Y")
def get_path_to_fonts_directory() -> str: def get_path_to_font_directory(font_name: str) -> str:
"""Return the path to the fonts directory. """Return the path to the fonts directory.
Returns: Returns:
str: The path to the fonts directory. str: The path to the fonts directory.
""" """
return os.path.join(os.path.dirname(__file__), "templates", "fonts") return os.path.join(os.path.dirname(__file__), "templates", "fonts", font_name)
def render_template(data): def render_template(data):
@ -252,10 +252,10 @@ def render_template(data):
environment.filters["make_it_italic"] = make_it_italic environment.filters["make_it_italic"] = make_it_italic
output_latex_file = template.render( output_latex_file = template.render(
design=data.design.options,
cv=data.cv, cv=data.cv,
design=data.design,
theme_options=data.design.options,
today=print_today(), today=print_today(),
fonts_directory=get_path_to_fonts_directory(),
) )
# Create an output file and write the rendered LaTeX code to it: # Create an output file and write the rendered LaTeX code to it:
@ -265,19 +265,13 @@ def render_template(data):
file.write(output_latex_file) file.write(output_latex_file)
# Copy the fonts directory to the output directory: # Copy the fonts directory to the output directory:
fonts_directory = get_path_to_fonts_directory() font_directory = get_path_to_font_directory(data.design.font)
output_fonts_directory = os.path.join(os.path.dirname(output_file_path), "fonts") output_fonts_directory = os.path.join(os.path.dirname(output_file_path), "fonts")
os.makedirs(output_fonts_directory, exist_ok=True) shutil.copytree(
for directory in os.listdir(fonts_directory): font_directory,
if directory == "SourceSans3": output_fonts_directory,
# copy the SourceSans3 fonts: dirs_exist_ok=True,
source_directory = os.path.join(fonts_directory, directory) )
shutil.copytree(
source_directory,
output_fonts_directory,
dirs_exist_ok=True,
)
return output_file_path return output_file_path

View File

@ -2,15 +2,15 @@
((* from "components/classic/section_contents.tex.j2" import section_contents with context *)) ((* from "components/classic/section_contents.tex.j2" import section_contents with context *))
((* from "components/classic/header.tex.j2" import header with context *)) ((* from "components/classic/header.tex.j2" import header with context *))
\documentclass[10pt, a4paper]{article} \documentclass[<<design.font_size>>, a4paper]{article}
% Packages: % Packages:
\usepackage[ \usepackage[
ignoreheadfoot, % set margins without considering header and footer ignoreheadfoot, % set margins without considering header and footer
top=<<design.margins.page.top>>, % seperation between body and page edge from the top top=<<theme_options.margins.page.top>>, % seperation between body and page edge from the top
bottom=<<design.margins.page.bottom>>, % seperation between body and page edge from the bottom bottom=<<theme_options.margins.page.bottom>>, % seperation between body and page edge from the bottom
left=<<design.margins.page.left>>, % seperation between body and page edge from the left left=<<theme_options.margins.page.left>>, % seperation between body and page edge from the left
right=<<design.margins.page.right>>, % seperation between body and page edge from the right right=<<theme_options.margins.page.right>>, % seperation between body and page edge from the right
% showframe % for debugging % showframe % for debugging
]{geometry} % for adjusting page geometry ]{geometry} % for adjusting page geometry
\usepackage{fontspec} % for loading fonts \usepackage{fontspec} % for loading fonts
@ -18,7 +18,7 @@
\usepackage{tabularx} % for making tables with fixed width columns \usepackage{tabularx} % for making tables with fixed width columns
\usepackage{array} % tabularx requires this \usepackage{array} % tabularx requires this
\usepackage[dvipsnames]{xcolor} % for coloring text \usepackage[dvipsnames]{xcolor} % for coloring text
\definecolor{primaryColor}{RGB}{<<design.primary_color.as_rgb_tuple()|join(", ")>>} % define primary color \definecolor{primaryColor}{RGB}{<<theme_options.primary_color.as_rgb_tuple()|join(", ")>>} % define primary color
\usepackage{enumitem} % for customizing lists \usepackage{enumitem} % for customizing lists
\usepackage{fontawesome5} % for using icons \usepackage{fontawesome5} % for using icons
\usepackage[ \usepackage[
@ -38,7 +38,7 @@
\pagenumbering{gobble} % no page numbering \pagenumbering{gobble} % no page numbering
\setmainfont{SourceSans3}[ \setmainfont{<<design.font>>}[
Path= fonts/, Path= fonts/,
Extension = .ttf, Extension = .ttf,
UprightFont = *-Regular, UprightFont = *-Regular,
@ -63,10 +63,10 @@
0pt 0pt
}{ }{
% top space: % top space:
<<design.margins.section_title.top>> <<theme_options.margins.section_title.top>>
}{ }{
% bottom space: % bottom space:
<<design.margins.section_title.bottom>> <<theme_options.margins.section_title.bottom>>
} % section title spacing } % section title spacing
\newcolumntype{L}[1]{ \newcolumntype{L}[1]{
@ -82,11 +82,11 @@
\newenvironment{highlights}{ \newenvironment{highlights}{
\begin{itemize}[ \begin{itemize}[
topsep=0pt, topsep=0pt,
parsep=<<design.margins.highlights_area.vertical_between_bullet_points>>, parsep=<<theme_options.margins.highlights_area.vertical_between_bullet_points>>,
partopsep=0pt, partopsep=0pt,
itemsep=0pt, itemsep=0pt,
after=\vspace*{-1\baselineskip}, after=\vspace*{-1\baselineskip},
leftmargin=<<design.margins.highlights_area.left>> + 3pt leftmargin=<<theme_options.margins.highlights_area.left>> + 3pt
] ]
}{ }{
\end{itemize} \end{itemize}
@ -108,7 +108,7 @@
\newcommand{\hrefExternal}[2]{\href{#1}{#2\, \raisebox{.1ex}{\footnotesize \faExternalLink*}}} % new command for external links \newcommand{\hrefExternal}[2]{\href{#1}{#2\, \raisebox{.1ex}{\footnotesize \faExternalLink*}}} % new command for external links
\begin{document} \begin{document}
((* if design.show_last_updated_date *)) ((* if theme_options.show_last_updated_date *))
\placelastupdatedtext \placelastupdatedtext
((* endif *)) ((* endif *))

View File

@ -1,9 +1,9 @@
((* macro date_and_location_strings(date_and_location_strings) *)) ((* macro date_and_location_strings(date_and_location_strings) *))
((* for item in date_and_location_strings *)) ((* for item in date_and_location_strings *))
((* if loop.last *)) ((* if loop.last *))
<<item>> \hspace*{-0.2cm + <<design.margins.entry_area.right>>} <<item>> \hspace*{-0.2cm + <<theme_options.margins.entry_area.right>>}
((* else *)) ((* else *))
<<item>> \hspace*{-0.2cm + <<design.margins.entry_area.right>>} \newline <<item>> \hspace*{-0.2cm + <<theme_options.margins.entry_area.right>>} \newline
((* endif *)) ((* endif *))
((* endfor *)) ((* endfor *))
((* endmacro *)) ((* endmacro *))

View File

@ -6,9 +6,9 @@
((# width: \textwidth #)) ((# width: \textwidth #))
((# preamble: first column, second column, third column #)) ((# preamble: first column, second column, third column #))
((# first column: p{0.55cm}; constant width, ragged left column #)) ((# first column: p{0.55cm}; constant width, ragged left column #))
((# second column: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #)) ((# second column: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
((# third column: R{<<design.date_and_location_width>>}; constant widthm ragged right column #)) ((# third column: R{<<theme_options.date_and_location_width>>}; constant widthm ragged right column #))
\begin{tabularx}{\textwidth}{p{0.55cm} K{<<design.margins.entry_area.left>>} R{<<design.date_and_location_width>>}} \begin{tabularx}{\textwidth}{p{0.55cm} K{<<theme_options.margins.entry_area.left>>} R{<<theme_options.date_and_location_width>>}}
\textbf{<<study_type if study_type is not none>>} \textbf{<<study_type if study_type is not none>>}
& &
\textbf{<<institution>>}, <<area>> \textbf{<<institution>>}, <<area>>
@ -22,9 +22,9 @@
((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #)) ((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #))
((# width: \textwidth #)) ((# width: \textwidth #))
((# preamble: first column, second column #)) ((# preamble: first column, second column #))
((# first column:: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #)) ((# first column:: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
((# second column: R{<<design.date_and_location_width>>}; constant width ragged right column #)) ((# second column: R{<<theme_options.date_and_location_width>>}; constant width ragged right column #))
\begin{tabularx}{\textwidth}{K{<<design.margins.entry_area.left>>} R{<<design.date_and_location_width>>}} \begin{tabularx}{\textwidth}{K{<<theme_options.margins.entry_area.left>>} R{<<theme_options.date_and_location_width>>}}
\textbf{<<company>>}, <<position>> \textbf{<<company>>}, <<position>>
<<print_higlights(highlights)|indent(4)->> <<print_higlights(highlights)|indent(4)->>
& &
@ -36,9 +36,9 @@
((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #)) ((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #))
((# width: \textwidth #)) ((# width: \textwidth #))
((# preamble: first column, second column #)) ((# preamble: first column, second column #))
((# first column:: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #)) ((# first column:: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
((# second column: R{<<design.date_and_location_width>>}; constant width ragged right column #)) ((# second column: R{<<theme_options.date_and_location_width>>}; constant width ragged right column #))
\begin{tabularx}{\textwidth}{K{<<design.margins.entry_area.left>>} R{<<design.date_and_location_width>>}} \begin{tabularx}{\textwidth}{K{<<theme_options.margins.entry_area.left>>} R{<<theme_options.date_and_location_width>>}}
((* if markdown_url is not none *)) ((* if markdown_url is not none *))
((* if link_text is not none *)) ((* if link_text is not none *))
((* set markdown_url = "["+link_text+"]("+ markdown_url|markdown_url_to_url +")" *)) ((* set markdown_url = "["+link_text+"]("+ markdown_url|markdown_url_to_url +")" *))
@ -59,9 +59,9 @@
((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #)) ((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #))
((# width: \textwidth #)) ((# width: \textwidth #))
((# preamble: first column, second column #)) ((# preamble: first column, second column #))
((# first column:: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #)) ((# first column:: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
((# second column: R{<<design.date_and_location_width>>}; constant width ragged right column #)) ((# second column: R{<<theme_options.date_and_location_width>>}; constant width ragged right column #))
\begin{tabularx}{\textwidth}{K{<<design.margins.entry_area.left>>} R{2 cm}} \begin{tabularx}{\textwidth}{K{<<theme_options.margins.entry_area.left>>} R{2 cm}}
\textbf{<<title>>} \textbf{<<title>>}
<<authors|join(", ")|make_it_italic(cv.name)>> <<authors|join(", ")|make_it_italic(cv.name)>>

View File

@ -1,5 +1,5 @@
((* macro highlights(highlights) *)) ((* macro highlights(highlights) *))
\vspace*{<<design.margins.highlights_area.top>>} \vspace*{<<theme_options.margins.highlights_area.top>>}
((* for item in highlights *)) ((* for item in highlights *))
((* if loop.first *)) ((* if loop.first *))
\begin{highlights} \begin{highlights}

View File

@ -12,7 +12,7 @@
date_and_location_strings=date_and_location_strings date_and_location_strings=date_and_location_strings
)|indent(4)>> )|indent(4)>>
((* elif entry_type == "ExperienceEntry" *)) ((* elif entry_type == "ExperienceEntry" *))
((* if design.show_timespan_in_experience_entries *)) ((* if theme_options.show_timespan_in_experience_entries *))
((* set date_and_location_strings = value.date_and_location_strings_with_timespan *)) ((* set date_and_location_strings = value.date_and_location_strings_with_timespan *))
((* endif *)) ((* endif *))
<<entry["experience"]( <<entry["experience"](
@ -47,7 +47,7 @@
)|indent(4)>> )|indent(4)>>
((* endif *)) ((* endif *))
((* if not loop.last *)) ((* if not loop.last *))
\vspace*{<<design.margins.entry_area.vertical_between>>} \vspace*{<<theme_options.margins.entry_area.vertical_between>>}
((* endif *)) ((* endif *))
((* endfor *)) ((* endfor *))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.