mirror of https://github.com/eyhc1/rendercv.git
add custom fonts support
This commit is contained in:
parent
3bf176f689
commit
8790097351
|
@ -13,6 +13,7 @@ import re
|
|||
import logging
|
||||
from functools import cached_property
|
||||
import urllib.request
|
||||
import os
|
||||
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
|
@ -409,12 +410,48 @@ class Design(BaseModel):
|
|||
title="Theme name",
|
||||
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(
|
||||
default=ClassicThemeOptions(),
|
||||
title="Theme Options",
|
||||
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
|
||||
|
||||
|
||||
# ======================================================================================
|
||||
# ======================================================================================
|
||||
|
|
|
@ -202,13 +202,13 @@ def print_today() -> str:
|
|||
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.
|
||||
|
||||
Returns:
|
||||
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):
|
||||
|
@ -252,10 +252,10 @@ def render_template(data):
|
|||
environment.filters["make_it_italic"] = make_it_italic
|
||||
|
||||
output_latex_file = template.render(
|
||||
design=data.design.options,
|
||||
cv=data.cv,
|
||||
design=data.design,
|
||||
theme_options=data.design.options,
|
||||
today=print_today(),
|
||||
fonts_directory=get_path_to_fonts_directory(),
|
||||
)
|
||||
|
||||
# Create an output file and write the rendered LaTeX code to it:
|
||||
|
@ -265,16 +265,10 @@ def render_template(data):
|
|||
file.write(output_latex_file)
|
||||
|
||||
# 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")
|
||||
os.makedirs(output_fonts_directory, exist_ok=True)
|
||||
for directory in os.listdir(fonts_directory):
|
||||
if directory == "SourceSans3":
|
||||
# copy the SourceSans3 fonts:
|
||||
source_directory = os.path.join(fonts_directory, directory)
|
||||
|
||||
shutil.copytree(
|
||||
source_directory,
|
||||
font_directory,
|
||||
output_fonts_directory,
|
||||
dirs_exist_ok=True,
|
||||
)
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
((* from "components/classic/section_contents.tex.j2" import section_contents with context *))
|
||||
((* from "components/classic/header.tex.j2" import header with context *))
|
||||
|
||||
\documentclass[10pt, a4paper]{article}
|
||||
\documentclass[<<design.font_size>>, a4paper]{article}
|
||||
|
||||
% Packages:
|
||||
\usepackage[
|
||||
ignoreheadfoot, % set margins without considering header and footer
|
||||
top=<<design.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
|
||||
left=<<design.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
|
||||
top=<<theme_options.margins.page.top>>, % seperation between body and page edge from the top
|
||||
bottom=<<theme_options.margins.page.bottom>>, % seperation between body and page edge from the bottom
|
||||
left=<<theme_options.margins.page.left>>, % seperation between body and page edge from the left
|
||||
right=<<theme_options.margins.page.right>>, % seperation between body and page edge from the right
|
||||
% showframe % for debugging
|
||||
]{geometry} % for adjusting page geometry
|
||||
\usepackage{fontspec} % for loading fonts
|
||||
|
@ -18,7 +18,7 @@
|
|||
\usepackage{tabularx} % for making tables with fixed width columns
|
||||
\usepackage{array} % tabularx requires this
|
||||
\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{fontawesome5} % for using icons
|
||||
\usepackage[
|
||||
|
@ -38,7 +38,7 @@
|
|||
\pagenumbering{gobble} % no page numbering
|
||||
|
||||
|
||||
\setmainfont{SourceSans3}[
|
||||
\setmainfont{<<design.font>>}[
|
||||
Path= fonts/,
|
||||
Extension = .ttf,
|
||||
UprightFont = *-Regular,
|
||||
|
@ -63,10 +63,10 @@
|
|||
0pt
|
||||
}{
|
||||
% top space:
|
||||
<<design.margins.section_title.top>>
|
||||
<<theme_options.margins.section_title.top>>
|
||||
}{
|
||||
% bottom space:
|
||||
<<design.margins.section_title.bottom>>
|
||||
<<theme_options.margins.section_title.bottom>>
|
||||
} % section title spacing
|
||||
|
||||
\newcolumntype{L}[1]{
|
||||
|
@ -82,11 +82,11 @@
|
|||
\newenvironment{highlights}{
|
||||
\begin{itemize}[
|
||||
topsep=0pt,
|
||||
parsep=<<design.margins.highlights_area.vertical_between_bullet_points>>,
|
||||
parsep=<<theme_options.margins.highlights_area.vertical_between_bullet_points>>,
|
||||
partopsep=0pt,
|
||||
itemsep=0pt,
|
||||
after=\vspace*{-1\baselineskip},
|
||||
leftmargin=<<design.margins.highlights_area.left>> + 3pt
|
||||
leftmargin=<<theme_options.margins.highlights_area.left>> + 3pt
|
||||
]
|
||||
}{
|
||||
\end{itemize}
|
||||
|
@ -108,7 +108,7 @@
|
|||
\newcommand{\hrefExternal}[2]{\href{#1}{#2\, \raisebox{.1ex}{\footnotesize \faExternalLink*}}} % new command for external links
|
||||
|
||||
\begin{document}
|
||||
((* if design.show_last_updated_date *))
|
||||
((* if theme_options.show_last_updated_date *))
|
||||
\placelastupdatedtext
|
||||
((* endif *))
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
((* macro date_and_location_strings(date_and_location_strings) *))
|
||||
((* for item in date_and_location_strings *))
|
||||
((* if loop.last *))
|
||||
<<item>> \hspace*{-0.2cm + <<design.margins.entry_area.right>>}
|
||||
<<item>> \hspace*{-0.2cm + <<theme_options.margins.entry_area.right>>}
|
||||
((* else *))
|
||||
<<item>> \hspace*{-0.2cm + <<design.margins.entry_area.right>>} \newline
|
||||
<<item>> \hspace*{-0.2cm + <<theme_options.margins.entry_area.right>>} \newline
|
||||
((* endif *))
|
||||
((* endfor *))
|
||||
((* endmacro *))
|
|
@ -6,9 +6,9 @@
|
|||
((# width: \textwidth #))
|
||||
((# preamble: first column, second column, third column #))
|
||||
((# first column: p{0.55cm}; constant width, ragged left column #))
|
||||
((# second column: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# third column: R{<<design.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>>}}
|
||||
((# second column: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# third column: R{<<theme_options.date_and_location_width>>}; constant widthm ragged right column #))
|
||||
\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{<<institution>>}, <<area>>
|
||||
|
@ -22,9 +22,9 @@
|
|||
((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #))
|
||||
((# width: \textwidth #))
|
||||
((# preamble: first column, second column #))
|
||||
((# first column:: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# second column: R{<<design.date_and_location_width>>}; constant width ragged right column #))
|
||||
\begin{tabularx}{\textwidth}{K{<<design.margins.entry_area.left>>} R{<<design.date_and_location_width>>}}
|
||||
((# first column:: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# second column: R{<<theme_options.date_and_location_width>>}; constant width ragged right column #))
|
||||
\begin{tabularx}{\textwidth}{K{<<theme_options.margins.entry_area.left>>} R{<<theme_options.date_and_location_width>>}}
|
||||
\textbf{<<company>>}, <<position>>
|
||||
<<print_higlights(highlights)|indent(4)->>
|
||||
&
|
||||
|
@ -36,9 +36,9 @@
|
|||
((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #))
|
||||
((# width: \textwidth #))
|
||||
((# preamble: first column, second column #))
|
||||
((# first column:: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# second column: R{<<design.date_and_location_width>>}; constant width ragged right column #))
|
||||
\begin{tabularx}{\textwidth}{K{<<design.margins.entry_area.left>>} R{<<design.date_and_location_width>>}}
|
||||
((# first column:: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# second column: R{<<theme_options.date_and_location_width>>}; constant width ragged right column #))
|
||||
\begin{tabularx}{\textwidth}{K{<<theme_options.margins.entry_area.left>>} R{<<theme_options.date_and_location_width>>}}
|
||||
((* if markdown_url is not none *))
|
||||
((* if link_text is not none *))
|
||||
((* set markdown_url = "["+link_text+"]("+ markdown_url|markdown_url_to_url +")" *))
|
||||
|
@ -59,9 +59,9 @@
|
|||
((# \begin{tabularx}{⟨width⟩}[⟨pos⟩]{⟨preamble⟩} #))
|
||||
((# width: \textwidth #))
|
||||
((# preamble: first column, second column #))
|
||||
((# first column:: K{<<design.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# second column: R{<<design.date_and_location_width>>}; constant width ragged right column #))
|
||||
\begin{tabularx}{\textwidth}{K{<<design.margins.entry_area.left>>} R{2 cm}}
|
||||
((# first column:: K{<<theme_options.margins.entry_area.left>>}; variable width, ragged left column #))
|
||||
((# second column: R{<<theme_options.date_and_location_width>>}; constant width ragged right column #))
|
||||
\begin{tabularx}{\textwidth}{K{<<theme_options.margins.entry_area.left>>} R{2 cm}}
|
||||
\textbf{<<title>>}
|
||||
|
||||
<<authors|join(", ")|make_it_italic(cv.name)>>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
((* macro highlights(highlights) *))
|
||||
\vspace*{<<design.margins.highlights_area.top>>}
|
||||
\vspace*{<<theme_options.margins.highlights_area.top>>}
|
||||
((* for item in highlights *))
|
||||
((* if loop.first *))
|
||||
\begin{highlights}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
date_and_location_strings=date_and_location_strings
|
||||
)|indent(4)>>
|
||||
((* 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 *))
|
||||
((* endif *))
|
||||
<<entry["experience"](
|
||||
|
@ -47,7 +47,7 @@
|
|||
)|indent(4)>>
|
||||
((* endif *))
|
||||
((* if not loop.last *))
|
||||
\vspace*{<<design.margins.entry_area.vertical_between>>}
|
||||
\vspace*{<<theme_options.margins.entry_area.vertical_between>>}
|
||||
|
||||
((* endif *))
|
||||
((* endfor *))
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue