chore: remove CV builder code from repository
The code is now managed in the cv-builder repository in apollo.
This commit is contained in:
parent
95cf8dbcd6
commit
86215c2e57
14 changed files with 0 additions and 621 deletions
|
@ -1,5 +0,0 @@
|
||||||
*
|
|
||||||
!magefile.go
|
|
||||||
!helpers/*
|
|
||||||
!go.mod
|
|
||||||
!go.sum
|
|
|
@ -1,2 +0,0 @@
|
||||||
ignored:
|
|
||||||
- DL3015
|
|
21
LICENSE
21
LICENSE
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Dan Anglin
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
96
README.md
96
README.md
|
@ -1,96 +0,0 @@
|
||||||
# My CV Project
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
- [Overview](#overview)
|
|
||||||
- [Dependencies](#dependencies)
|
|
||||||
- [Using Docker as an alternative](#using-docker-as-an-alternative)
|
|
||||||
- [Generating the PDF Document](#generating-the-pdf-document)
|
|
||||||
- [Inspirations](#inspirations)
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This project parses my [CV](./data/cv.json) that is written as
|
|
||||||
a JSON document and generates a PDF document.
|
|
||||||
This project contains a Go application and uses the ConTeXt document processor
|
|
||||||
which are used to parse and generate a PDF document from the CV.
|
|
||||||
I chose to use ConTeXt as the document processor because it gives me more
|
|
||||||
control to edit page layouts, configure fonts,
|
|
||||||
perform additional formatting and add custom functionality.
|
|
||||||
|
|
||||||
Support for other formats such as HTML will be available soon.
|
|
||||||
|
|
||||||
### View/Download the CV
|
|
||||||
|
|
||||||
The latest build of the generated PDF document can be downloaded from the [release](https://gitlab.com/dananglin/cv/-/releases) page of the project in GitLab.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
If you are interested in generating the PDF document on your own machines
|
|
||||||
or want to use the project to generate your own CV, then below is a list
|
|
||||||
of dependencies that you'll need to install:
|
|
||||||
|
|
||||||
- **Go** - Please go [here](https://golang.org/dl/) to download the latest version of the Go programming language.
|
|
||||||
- **ConTeXt** - I recommend installing version 1.02 or higher. Please go [here](https://wiki.contextgarden.net/ConTeXt_Standalone) for installation instructions for your distribution.
|
|
||||||
- **The Carlito font (ttf-carlito)** - In prevous iterations of my CV I used the Calibri font. Carlito is the free, metric compatible alternative to this and is specified in the TEX template.
|
|
||||||
- For Ubuntu/Debian installation you can use `apt`:
|
|
||||||
```bash
|
|
||||||
$ apt-get install font-crosextra-carlito
|
|
||||||
```
|
|
||||||
- For Arch Linux you can use `pacman`:
|
|
||||||
```bash
|
|
||||||
$ pacman -S ttf-carlito
|
|
||||||
```
|
|
||||||
- Alternatively you can download the font from https://fontlibrary.org/en/font/carlito
|
|
||||||
- Once this font is installed you'll need to update ConTeXt so it can find the font when generating the PDF:
|
|
||||||
```bash
|
|
||||||
$ OSFONTDIR=/usr/share/fonts
|
|
||||||
$ mtxrun --script fonts --reload
|
|
||||||
```
|
|
||||||
|
|
||||||
Once the dependencies are installed you can follow the
|
|
||||||
[Generating the PDF Document](#generating-the-pdf-document) section below.
|
|
||||||
|
|
||||||
## Using Docker as an alternative
|
|
||||||
|
|
||||||
If you prefer not to install the dependencies above,
|
|
||||||
I have created a Docker image installed with the above dependencies.
|
|
||||||
This image is used to build and publish the CV via the GitLab CI pipleines.
|
|
||||||
The image is built using this [Dockerfile](./docker/Dockerfile) and is
|
|
||||||
pullable from [GitLab's container registry](https://gitlab.com/dananglin/cv/container_registry).
|
|
||||||
|
|
||||||
To use the image follow the steps below:
|
|
||||||
|
|
||||||
1. Make sure you've clone this project to your workspace:
|
|
||||||
```bash
|
|
||||||
$ git clone https://gitlab.com/dananglin/cv.git
|
|
||||||
$ cd cv
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create the docker container and mount the current directory to the /project directory inside the container:
|
|
||||||
```bash
|
|
||||||
$ docker run --rm -it -v ${PWD}:/project registry.gitlab.com/dananglin/cv/cv-builder:master-44f2a31c bash
|
|
||||||
|
|
||||||
# Once inside the docker container
|
|
||||||
$ cd /project
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Follow the [Generating the PDF Document](#generating-the-pdf-document) section below.
|
|
||||||
|
|
||||||
## Generating the PDF Document
|
|
||||||
|
|
||||||
The PDF document can be generated by running the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go run mage.go pdf
|
|
||||||
```
|
|
||||||
|
|
||||||
The PDF generation is completed in two steps:
|
|
||||||
|
|
||||||
1. The Go application will generate a TEX file using the JSON document and the TEX template files located in the [template](./template) directory.
|
|
||||||
2. ConTeXt is then used to generate the PDF document from the generated TEX file.
|
|
||||||
|
|
||||||
## Inspirations
|
|
||||||
|
|
||||||
- [The Markdown Resume](https://mszep.github.io/pandoc_resume/) - This project uses ConTeXt and pandoc to convert Markdown based CVs into multiple formats including PDF, HTML and DOCX. This is where I discovered ConTeXt.
|
|
||||||
- [melkir/resume](https://github.com/melkir/resume) - This project generates CVs using Go and LaTeX.
|
|
|
@ -1,47 +0,0 @@
|
||||||
FROM golang:1.19-buster AS builder
|
|
||||||
|
|
||||||
RUN git clone https://github.com/magefile/mage "${GOPATH}/src/mage"
|
|
||||||
|
|
||||||
WORKDIR ${GOPATH}/src/mage
|
|
||||||
|
|
||||||
RUN go run bootstrap.go
|
|
||||||
|
|
||||||
COPY go.mod ${GOPATH}/cv-builder/
|
|
||||||
COPY go.sum ${GOPATH}/cv-builder/
|
|
||||||
COPY magefile.go ${GOPATH}/cv-builder/
|
|
||||||
COPY helpers ${GOPATH}/cv-builder/helpers
|
|
||||||
|
|
||||||
WORKDIR ${GOPATH}/cv-builder
|
|
||||||
|
|
||||||
RUN mage -compile /usr/local/bin/cv-make
|
|
||||||
|
|
||||||
FROM debian:buster
|
|
||||||
|
|
||||||
COPY --from=builder /usr/local/bin/cv-make /usr/local/bin
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN \
|
|
||||||
apt-get update \
|
|
||||||
&& apt-get install -y \
|
|
||||||
fonts-crosextra-carlito \
|
|
||||||
rsync \
|
|
||||||
curl= \
|
|
||||||
aspell \
|
|
||||||
aspell-en \
|
|
||||||
&& apt-get clean autoclean \
|
|
||||||
&& apt-get autoremove -y \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* /tmp/* \
|
|
||||||
&& mkdir /opt/context
|
|
||||||
|
|
||||||
WORKDIR /opt/context
|
|
||||||
|
|
||||||
# Install ConTeXt standalone
|
|
||||||
RUN \
|
|
||||||
curl -LO http://minimals.contextgarden.net/setup/first-setup.sh \
|
|
||||||
&& sh first-setup.sh --context=current --engine=luatex \
|
|
||||||
&& rm -rf /opt/context/tex/texmf-context/doc
|
|
||||||
|
|
||||||
ENV PATH=${PATH}:/opt/context/tex/texmf-linux-64/bin \
|
|
||||||
OSFONTDIR=/usr/share/fonts
|
|
||||||
|
|
||||||
RUN mtxrun --script fonts --reload
|
|
5
go.mod
5
go.mod
|
@ -1,5 +0,0 @@
|
||||||
module gitlab.com/dananglin/cv
|
|
||||||
|
|
||||||
go 1.19
|
|
||||||
|
|
||||||
require github.com/magefile/mage v1.14.0
|
|
2
go.sum
2
go.sum
|
@ -1,2 +0,0 @@
|
||||||
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
|
|
||||||
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
|
|
@ -1,53 +0,0 @@
|
||||||
//go:build mage
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
type Cv struct {
|
|
||||||
FirstName string `json:"firstName"`
|
|
||||||
LastName string `json:"lastName"`
|
|
||||||
JobTitle string `json:"jobTitle"`
|
|
||||||
Contact Contact `json:"contact"`
|
|
||||||
Links Links `json:"links"`
|
|
||||||
Summary []string `json:"summary"`
|
|
||||||
Technologies []Technologies `json:"technologies"`
|
|
||||||
Employment []Experience `json:"employment"`
|
|
||||||
Education []Experience `json:"education"`
|
|
||||||
Interests []string `json:"interests"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Contact struct {
|
|
||||||
Email string `json:"email"`
|
|
||||||
Phone string `json:"phone"`
|
|
||||||
Location string `json:"location"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Links struct {
|
|
||||||
LinkedIn string `json:"linkedin"`
|
|
||||||
GitHub string `json:"github"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Technologies struct {
|
|
||||||
Category string `json:"category"`
|
|
||||||
Values []string `json:"values"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Experience struct {
|
|
||||||
Company string `json:"company,omitempty"`
|
|
||||||
School string `json:"school,omitempty"`
|
|
||||||
Location string `json:"location"`
|
|
||||||
JobTitle string `json:"jobTitle,omitempty"`
|
|
||||||
Qualification string `json:"qualification,omitempty"`
|
|
||||||
Duration Duration `json:"duration"`
|
|
||||||
Details []string `json:"details"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Duration struct {
|
|
||||||
Start Date `json:"start"`
|
|
||||||
End Date `json:"end"`
|
|
||||||
Present string `json:"present"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Date struct {
|
|
||||||
Year string `json:"year"`
|
|
||||||
Month string `json:"month"`
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
//go:build mage
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
aspellLang string = "en_GB"
|
|
||||||
defaultImageName string = "cv-builder"
|
|
||||||
defaultImageTag string = "latest"
|
|
||||||
)
|
|
||||||
|
|
||||||
// imageName generates the docker image name from the environment
|
|
||||||
// variables IMAGE_NAME and IMAGE_TAG. Default vaules will be used
|
|
||||||
// if these variables are not set or empty.
|
|
||||||
func imageName() string {
|
|
||||||
name := os.Getenv("IMAGE_NAME")
|
|
||||||
if len(name) == 0 {
|
|
||||||
name = defaultImageName
|
|
||||||
}
|
|
||||||
|
|
||||||
tag := os.Getenv("IMAGE_TAG")
|
|
||||||
if len(tag) == 0 {
|
|
||||||
tag = defaultImageTag
|
|
||||||
}
|
|
||||||
|
|
||||||
return name + ":" + tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// createCVTex generates the CV docuemnt as a Tex file.
|
|
||||||
func createCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName string) error {
|
|
||||||
fmt.Printf("INFO: Attempting to read data from %s...\n", cvJsonDataFile)
|
|
||||||
|
|
||||||
data, err := os.ReadFile(cvJsonDataFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to read data from file. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("INFO: Successfully read data.")
|
|
||||||
|
|
||||||
fmt.Println("INFO: Attempting to unmarshal JSON data...")
|
|
||||||
|
|
||||||
var cv Cv
|
|
||||||
if err = json.Unmarshal(data, &cv); err != nil {
|
|
||||||
return fmt.Errorf("unable to unmarshal JSON data; %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("INFO: JSON unmarshalling was successful.")
|
|
||||||
|
|
||||||
// if CV_CONTACT_PHONE is set then add it to the CV
|
|
||||||
phone := os.Getenv("CV_CONTACT_PHONE")
|
|
||||||
if len(phone) > 0 {
|
|
||||||
cv.Contact.Phone = phone
|
|
||||||
}
|
|
||||||
|
|
||||||
cvOutputPath := cvOutputDir + "/" + cvOutputFileName
|
|
||||||
fmt.Printf("INFO: Attempting to create output file %s...\n", cvOutputPath)
|
|
||||||
|
|
||||||
if err = os.MkdirAll(cvOutputDir, 0750); err != nil {
|
|
||||||
return fmt.Errorf("unable to create output directory %s; %w", cvOutputDir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err := os.Create(cvOutputPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to create output file %s; %w", cvOutputPath, err)
|
|
||||||
}
|
|
||||||
fmt.Printf("INFO: Successfully created output file %s.\n", cvOutputPath)
|
|
||||||
defer output.Close()
|
|
||||||
|
|
||||||
fmt.Println("INFO: Attempting template execution...")
|
|
||||||
fmap := template.FuncMap{
|
|
||||||
"notLastElement": notLastElement,
|
|
||||||
"join": join,
|
|
||||||
"durationToString": durationToString,
|
|
||||||
}
|
|
||||||
|
|
||||||
t := template.Must(template.New("cv.tmpl.tex").Funcs(fmap).Delims("<<", ">>").ParseGlob(cvTemplateDir + "*.tmpl.tex"))
|
|
||||||
|
|
||||||
if err = t.Execute(output, cv); err != nil {
|
|
||||||
return fmt.Errorf("unable to execute the CV template. %w", err)
|
|
||||||
}
|
|
||||||
fmt.Println("INFO: Template execution successful.")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func spellCheck(dataFile, aspellPersonalWordlist string) error {
|
|
||||||
fmt.Printf("INFO: Reading data from %s...\n", dataFile)
|
|
||||||
|
|
||||||
data, err := os.ReadFile(dataFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to read data from %s, %s", dataFile, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// declare the aspell command and its standard input pipe.
|
|
||||||
cmd := exec.Command("aspell", "-d", aspellLang, "-p", aspellPersonalWordlist, "list")
|
|
||||||
stdin, err := cmd.StdinPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the CV data to standard input for piping.
|
|
||||||
go func() {
|
|
||||||
defer stdin.Close()
|
|
||||||
io.WriteString(stdin, string(data))
|
|
||||||
}()
|
|
||||||
|
|
||||||
// run aspell and get the list of mispelt words (if any).
|
|
||||||
// (the output is a string.)
|
|
||||||
fmt.Println("Running aspell...")
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
list := strings.Split(string(out), "\n")
|
|
||||||
if list[len(list)-1] == "" {
|
|
||||||
list = list[:len(list)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(list) > 0 {
|
|
||||||
var b strings.Builder
|
|
||||||
errMsg := fmt.Sprintf("the following spelling errors were found in %s:", dataFile)
|
|
||||||
b.WriteString(errMsg)
|
|
||||||
|
|
||||||
for _, v := range list {
|
|
||||||
s := "\n- " + v
|
|
||||||
b.WriteString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf(b.String())
|
|
||||||
} else {
|
|
||||||
fmt.Println("No spelling errors were found.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
//go:build mage
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/magefile/mage/mg"
|
|
||||||
"github.com/magefile/mage/sh"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
aspellPersonalWordlist string = "./.aspell/.aspell.en.pws"
|
|
||||||
cvJsonDataFile string = "./data/cv.json"
|
|
||||||
cvOutputDir string = "./__output"
|
|
||||||
cvTemplateDir string = "./template/tex/"
|
|
||||||
cvOutputFileName string = "cv.tex"
|
|
||||||
dockerfile string = "./docker/Dockerfile"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Default sets the default target.
|
|
||||||
var Default = Pdf
|
|
||||||
|
|
||||||
// SpellCheck checks the CV JSON file for spelling errors. If there are any
|
|
||||||
// misspelt words found the function returns a list of those words in an error.
|
|
||||||
// Any error found while gathering the list is returned.
|
|
||||||
// This function depends on the aspell program.
|
|
||||||
func SpellCheck() error {
|
|
||||||
return spellCheck(cvJsonDataFile, aspellPersonalWordlist)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tex takes the CV data file and generates the output tex file from
|
|
||||||
// template.
|
|
||||||
func Tex() error {
|
|
||||||
fmt.Println("Generating the tex file...")
|
|
||||||
|
|
||||||
mg.Deps(Clean)
|
|
||||||
|
|
||||||
return createCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pdf takes the output tex file generated by the Tex target and
|
|
||||||
// generates the output PDF file.
|
|
||||||
func Pdf() error {
|
|
||||||
mg.Deps(Tex)
|
|
||||||
|
|
||||||
pathArg := "--path=" + cvOutputDir
|
|
||||||
|
|
||||||
fmt.Println("Generating the PDF file...")
|
|
||||||
return sh.Run("mtxrun", pathArg, "--script", "context", "cv.tex")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Image builds the CV builder docker image.
|
|
||||||
func Image() error {
|
|
||||||
image := imageName()
|
|
||||||
|
|
||||||
return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublishImage publishes the CV builder docker image
|
|
||||||
// to the docker registry.
|
|
||||||
func PublishImage() error {
|
|
||||||
mg.Deps(Image)
|
|
||||||
|
|
||||||
image := imageName()
|
|
||||||
return sh.Run("docker", "push", image)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean removes the directory where the output files
|
|
||||||
// are generated.
|
|
||||||
func Clean() error {
|
|
||||||
if err := sh.Rm(cvOutputDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
//go:build mage
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// notLastElement returns true if an element of an array
|
|
||||||
// or a slice is not the last.
|
|
||||||
func notLastElement(pos, length int) bool {
|
|
||||||
return pos < length-1
|
|
||||||
}
|
|
||||||
|
|
||||||
// join uses strings.Join to join all string elements into
|
|
||||||
// a single string.
|
|
||||||
func join(s []string) string {
|
|
||||||
return strings.Join(s, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// durationToString outputs the employment/education
|
|
||||||
// duration as a formatted string.
|
|
||||||
func durationToString(d Duration) string {
|
|
||||||
start := fmt.Sprintf("%s, %s", d.Start.Month, d.Start.Year)
|
|
||||||
present := strings.ToLower(d.Present)
|
|
||||||
end := ""
|
|
||||||
|
|
||||||
if present == "yes" || present == "true" {
|
|
||||||
end = "Present"
|
|
||||||
} else {
|
|
||||||
end = fmt.Sprintf("%s, %s", d.End.Month, d.End.Year)
|
|
||||||
}
|
|
||||||
|
|
||||||
return start + " - " + end
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
<<- /* Prepend the setup area */ ->>
|
|
||||||
<< template "cv_setup.tmpl.tex" .>>
|
|
||||||
|
|
||||||
\starttext
|
|
||||||
\starttitleAndContact
|
|
||||||
\cvtitle{<<.FirstName>> <<.LastName>>}{<<.JobTitle>>}
|
|
||||||
\titleAndContact
|
|
||||||
{\bf Email:} <<.Contact.Email>>\blank[none]
|
|
||||||
<<if .Contact.Phone>>{\bf Phone:} <<.Contact.Phone>>\blank[none]<<end>>
|
|
||||||
{\bf Location:} <<.Contact.Location>>\blank[medium]
|
|
||||||
|
|
||||||
<<if .Links.LinkedIn>>{\bf LinkedIn:} <<.Links.LinkedIn>>\blank[none]<<end>>
|
|
||||||
<<if .Links.GitHub>>{\bf GitHub:} <<.Links.GitHub>>\blank[none]<<end>>
|
|
||||||
\stoptitleAndContact
|
|
||||||
|
|
||||||
\section{SUMMARY}
|
|
||||||
<<join .Summary>>
|
|
||||||
|
|
||||||
\section{SKILLS SUMMARY}
|
|
||||||
\starttabulate[|w(0.3\textwidth)lB|lp(0.7\textwidth)|]
|
|
||||||
<<$lenTech := len .Technologies>>
|
|
||||||
<<range $i, $tech := .Technologies>>
|
|
||||||
<<$lenValues := len $tech.Values>>
|
|
||||||
\NC <<$tech.Category>> \NC <<range $j, $val := $tech.Values>><<$val>><<if notLastElement $j $lenValues>>, <<end>><<end>>\NC\NR
|
|
||||||
<<if notLastElement $i $lenTech>>\TB[1mm]<<end>>
|
|
||||||
<<end>>
|
|
||||||
\stoptabulate
|
|
||||||
|
|
||||||
\section{EXPERIENCE}
|
|
||||||
<<- range .Employment>>
|
|
||||||
\jobsection{<<.Company>>}{<<.Location>>}{<<.JobTitle>>}{<<durationToString .Duration>>}
|
|
||||||
\startitemize
|
|
||||||
<<range .Details>>
|
|
||||||
\item <<.>>
|
|
||||||
<<end>>
|
|
||||||
\stopitemize
|
|
||||||
<<end>>
|
|
||||||
|
|
||||||
\section{EDUCATION}
|
|
||||||
<<range .Education ->>
|
|
||||||
\jobsection{<<.School>>}{<<.Location>>}{<<.Qualification>>}{<<durationToString .Duration>>}
|
|
||||||
\startitemize
|
|
||||||
<<range .Details>>
|
|
||||||
\item <<.>>
|
|
||||||
<<end>>
|
|
||||||
\stopitemize
|
|
||||||
<<end>>
|
|
||||||
|
|
||||||
\section{INTERESTS AND HOBBIES}
|
|
||||||
<<join .Interests>>
|
|
||||||
|
|
||||||
\section{REFERENCES}
|
|
||||||
References are available upon request.
|
|
||||||
\stoptext
|
|
|
@ -1,78 +0,0 @@
|
||||||
\version [final]
|
|
||||||
|
|
||||||
% set main language to English
|
|
||||||
\mainlanguage [en]
|
|
||||||
|
|
||||||
% set paper size to A4
|
|
||||||
\setuppapersize [A4]
|
|
||||||
|
|
||||||
% define the page layout
|
|
||||||
\setuplayout
|
|
||||||
[backspace=20mm,
|
|
||||||
bottomspace=20mm,
|
|
||||||
cutspace=0mm,
|
|
||||||
footer=0mm,
|
|
||||||
header=0mm,
|
|
||||||
height=middle,
|
|
||||||
topspace=10mm,
|
|
||||||
width=middle]
|
|
||||||
% \showframe
|
|
||||||
|
|
||||||
% remove page numbers by setting an empty location
|
|
||||||
\setuppagenumbering[location=]
|
|
||||||
|
|
||||||
% Colour definitions for headings
|
|
||||||
\definecolor [bluetheme][h=1155cc]
|
|
||||||
\definecolor [greytheme][h=434343]
|
|
||||||
|
|
||||||
% Font setup
|
|
||||||
% https://wiki.contextgarden.net/Simplefonts
|
|
||||||
\definefontfamily [cvfontfamily][rm][LiberationSerif]
|
|
||||||
\definefontfamily [cvfontfamily][ss][Carlito]
|
|
||||||
\definefontfamily [cvfontfamily][tt][LiberationMono]
|
|
||||||
\definefontfamily [cvfontfamily][mm][LibertinusMath]
|
|
||||||
\setupbodyfont [cvfontfamily,ss,10pt]
|
|
||||||
|
|
||||||
% define the font scaling when using commands such as \tfa, \tfb, etc
|
|
||||||
\definebodyfontenvironment [10pt][a=11pt,b=20pt,c=32pt]
|
|
||||||
|
|
||||||
% cvtitle outputs the title of the CV
|
|
||||||
% arguments:
|
|
||||||
% #1 - name: name of the individual
|
|
||||||
% #2 - role: job role of the individual
|
|
||||||
\define[2]\cvtitle{
|
|
||||||
{\bfc#1}\blank[small]{\tfb#2}
|
|
||||||
}
|
|
||||||
|
|
||||||
% jobsection outputs the summary of a work experience
|
|
||||||
% arguments:
|
|
||||||
% #1 - company: the company where the work experience took place
|
|
||||||
% #2 - location: the location of the work experience
|
|
||||||
% #3 - role: the role of the work experience
|
|
||||||
% #4 - duration: the duration of the work experience (e.g. March, 2017 - April, 2018)
|
|
||||||
\define[4]\jobsection{
|
|
||||||
{\bfa#1,} {\tfa#2} — {\tfa\em#3}\blank[small]\color[greytheme]{#4}\blank[line]
|
|
||||||
}
|
|
||||||
\definehead [skillssection][subsection]
|
|
||||||
|
|
||||||
\setuphead [section][color=bluetheme]
|
|
||||||
\setuphead [skillssection][color=black]
|
|
||||||
\setuphead [section, skillssection][number=no, align=right, style=\bfa]
|
|
||||||
|
|
||||||
% setup the format of items (bullet points)
|
|
||||||
\setupitemize
|
|
||||||
[1]
|
|
||||||
[packed]
|
|
||||||
[align=right,
|
|
||||||
symbol=1,
|
|
||||||
margin=no,
|
|
||||||
distance=1mm]
|
|
||||||
|
|
||||||
% defineparagraphs and setupparagraphs allows us to create custom
|
|
||||||
% columns. Here we define and configure a paragraph environment for the CV title
|
|
||||||
% and contact columns.
|
|
||||||
% https://wiki.contextgarden.net/Command/defineparagraphs
|
|
||||||
% https://wiki.contextgarden.net/Command/setupparagraphs
|
|
||||||
\defineparagraphs[titleAndContact][n=2,after={\blank}]
|
|
||||||
\setupparagraphs [titleAndContact][1][width=0.5\textwidth]
|
|
||||||
\setupparagraphs [titleAndContact][2][width=0.5\textwidth]
|
|
Loading…
Reference in a new issue