Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Jarno Rankinen | 9d5033f51d | |
Jarno Rankinen | 4d393d6d8b | |
Jarno Rankinen | c47776b92c | |
Jarno Rankinen | b33f6fcd78 | |
Jarno Rankinen | c405556e9c | |
Jarno Rankinen | e861a2ff85 |
|
@ -0,0 +1,152 @@
|
||||||
|
## YAML Configuration
|
||||||
|
|
||||||
|
The configuration file is read for each request, there's no need to stop the server
|
||||||
|
to make edits.
|
||||||
|
|
||||||
|
### `basepath`
|
||||||
|
Defaults to empty, set if you want to serve under a subpath
|
||||||
|
```YAML
|
||||||
|
basepath: "/cv"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `theme`
|
||||||
|
Sets the default theme that is loaded when people visit your CV
|
||||||
|
```YAML
|
||||||
|
theme: "dark"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `meta` section
|
||||||
|
These values correspond to tags in the `<head> section.
|
||||||
|
- `meta.title` sets the `<title>` meta tag content
|
||||||
|
- `meta.github-corner` enables/disables the GitHub link to this repo in the top-right corner
|
||||||
|
- `meta.favicon` is still WIP, will point to a local or remote favicon assett
|
||||||
|
- `meta.language` sets the language for the headings in the document (e.g. SUMMARY), also the `<meta name="language">` tag
|
||||||
|
- Only English and Finnish translations for now, but adding new ones is simple (not much to translate)
|
||||||
|
- Others correspond to `<meta name="tag name">`
|
||||||
|
```YAML
|
||||||
|
meta:
|
||||||
|
robots: "index, follow"
|
||||||
|
language: "en-EN"
|
||||||
|
author: "Mickey Mouse"
|
||||||
|
theme-color: "#bd93f9"
|
||||||
|
title: ""
|
||||||
|
description: ""
|
||||||
|
favicon: ""
|
||||||
|
github-corner: false
|
||||||
|
```
|
||||||
|
|
||||||
|
## `profile` (the main content definitions)
|
||||||
|
### Main info fields
|
||||||
|
Other info fields are quite self-explanatory, except
|
||||||
|
- `profile.photo`
|
||||||
|
- Can be a local file. In this case the path is relative
|
||||||
|
to the photo to use, meaning `./data/photo/`, `data/photo/`
|
||||||
|
and `/data/photo/` all mean a folder under the directory the
|
||||||
|
binary is in. **NOT AN ABSOLUTE OS PATH**
|
||||||
|
- Can be a URL to a remote asset
|
||||||
|
- `profile.summary` Can be written on multiple lines by using the
|
||||||
|
standard YAML `>`, `|` etc selectors, and can additionally
|
||||||
|
contain HTML. For example multiple paragraphs using `<p></p>`
|
||||||
|
```YAML
|
||||||
|
profile:
|
||||||
|
name: "Mickey Mouse"
|
||||||
|
title: "Professional job applicant"
|
||||||
|
city: "City, Country"
|
||||||
|
phone: "+358 xx xxx xxxx"
|
||||||
|
email: "your@email.com"
|
||||||
|
photo: "./data/photo/Mickey_Mouse_Steamboat_Willie.jpg"
|
||||||
|
summary: >-
|
||||||
|
Insert summary here. Multiple
|
||||||
|
lines can be used, but line breaks are determined
|
||||||
|
by the renderer
|
||||||
|
```
|
||||||
|
|
||||||
|
### `profile.experience`
|
||||||
|
A YAML List of previous jobs. Noteworthy is the description,
|
||||||
|
which is also a list of items, corresponding to e.g. different
|
||||||
|
tasks or responsibilities
|
||||||
|
```YAML
|
||||||
|
profile:
|
||||||
|
experience:
|
||||||
|
- company: Company 1
|
||||||
|
location: City, country
|
||||||
|
title: Professional employee
|
||||||
|
period: "03/2023 - "
|
||||||
|
description:
|
||||||
|
- Each item in this list
|
||||||
|
- Will be a new item
|
||||||
|
- In the CV
|
||||||
|
- company: Company 2
|
||||||
|
location: City, country
|
||||||
|
title: Professional employee
|
||||||
|
period: "03/2022 - 03/2023"
|
||||||
|
description:
|
||||||
|
- Each item in this list
|
||||||
|
- Will be a new item
|
||||||
|
- In the CV
|
||||||
|
- company: Company 3
|
||||||
|
location: City, country
|
||||||
|
title: Professional employee
|
||||||
|
period: "03/2021 - 03/2022"
|
||||||
|
description:
|
||||||
|
- Each item in this list
|
||||||
|
- Will be a new item
|
||||||
|
- In the CV
|
||||||
|
```
|
||||||
|
|
||||||
|
### `profile.education`
|
||||||
|
A YAML list of prior education history items. These may not fit
|
||||||
|
every imaginable education, but the fields are not named in the
|
||||||
|
resulting CV, so they can be used a bit creatively.
|
||||||
|
- `profile.education.degree` is the main title
|
||||||
|
- `profile.education.name` is the subtitle
|
||||||
|
```YAML
|
||||||
|
profile:
|
||||||
|
education:
|
||||||
|
- degree: B.S. in Job interviews
|
||||||
|
name: Job interviewee
|
||||||
|
faculty: School for Job applicants
|
||||||
|
city: City, Country
|
||||||
|
period: 1/1996 - 12/1996
|
||||||
|
- degree: Undergraduate of CV Authoring
|
||||||
|
name: Technical writer
|
||||||
|
faculty: School for Job applicants
|
||||||
|
city: City, Country
|
||||||
|
period: 1/1995 - 12/1995
|
||||||
|
```
|
||||||
|
|
||||||
|
### `profile.skills`, `profile.languages`
|
||||||
|
- name and the amount of starts to give each (1-5)
|
||||||
|
```YAML
|
||||||
|
profile:
|
||||||
|
skills:
|
||||||
|
- name: Skill 1
|
||||||
|
level: 1
|
||||||
|
- name: Skill 2
|
||||||
|
level: 2
|
||||||
|
- name: Skill 3
|
||||||
|
level: 3
|
||||||
|
- name: Skill 4
|
||||||
|
level: 4
|
||||||
|
- name: Skill 5
|
||||||
|
level: 5
|
||||||
|
languages:
|
||||||
|
- name: Language 1
|
||||||
|
level: 5
|
||||||
|
- name: Language 2
|
||||||
|
level: 4
|
||||||
|
- name: Language 1
|
||||||
|
level: 3
|
||||||
|
- name: Language 2
|
||||||
|
level: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### `profile.certificates`
|
||||||
|
Other mentionable courses, etc that don't quite fit the others, for example
|
||||||
|
driver's license, any certificate like CKAD
|
||||||
|
```YAML
|
||||||
|
profile:
|
||||||
|
certificates:
|
||||||
|
- name: Certified Kubernetes Application Developer
|
||||||
|
- name: Driver's License (commercial)
|
||||||
|
```
|
79
README.md
79
README.md
|
@ -1,8 +1,77 @@
|
||||||
# Go-resume
|
# Go-resume ![Static Badge](https://img.shields.io/badge/WIP-yellow)
|
||||||
|
|
||||||
## Work in progress
|
A dynamic resume site server using [Bulma CSS](https://github.com/jgthms/bulma) written in Go.
|
||||||
|
|
||||||
A dynamic resume site using [Bulma CSS](https://github.com/jgthms/bulma) written in Go.
|
|
||||||
Get up and running easily by defining the content in a single YAML file.
|
Get up and running easily by defining the content in a single YAML file.
|
||||||
|
|
||||||
Shamelessly copied from [mazipan's](https://github.com/mazipan) [bulma-resume-template](https://github.com/mazipan/bulma-resume-template).
|
If you have a public server, can serve the website on port 3000 (configurable). Or run locally only to
|
||||||
|
generate a PDF.
|
||||||
|
|
||||||
|
### Live example: [https://oranki.net/cv](https://oranki.net/cv)
|
||||||
|
|
||||||
|
### Screenshots:
|
||||||
|
#### Desktop
|
||||||
|
![kuva](https://github.com/0ranki/go-resume/assets/50285623/4d918f31-a922-45d7-b2e6-67d4a44ebedb)
|
||||||
|
|
||||||
|
#### Mobile:
|
||||||
|
![kuva](https://github.com/0ranki/go-resume/assets/50285623/3d0252c2-2450-47b2-b2c4-bcf448db9f75)
|
||||||
|
|
||||||
|
|
||||||
|
### PDF
|
||||||
|
The resume can be exported fairly well to PDF by using your browser's built-in printing function.
|
||||||
|
Just configure your resume.yaml, run the server locally, open the page in your browser and press
|
||||||
|
"Print to PDF". Feedback is welcome, the result is not perfect, but subjectively as good as most
|
||||||
|
of the free Word templates I've come across.
|
||||||
|
|
||||||
|
**Note:** Printing the dark version doesn't quite work yet
|
||||||
|
|
||||||
|
## Usage (see [CONFIGURATION.md](CONFIGURATION.md))
|
||||||
|
- Download one of the pre-built binaries from releases or build yourself
|
||||||
|
- Update YAML (see separate document for details)
|
||||||
|
- Start the server
|
||||||
|
- The content is updated live, so you can make edits while the server is
|
||||||
|
running
|
||||||
|
- If you want to use a different port, start the binary with the
|
||||||
|
`--port <port>` flag
|
||||||
|
|
||||||
|
### Reverse proxy
|
||||||
|
Running behind a reverse proxy is simple, e.g. for NGINX:
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name my-cv.example.com;
|
||||||
|
location / {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
server_name my-cv.example.com;
|
||||||
|
ssl_certificate "/path/to/cert";
|
||||||
|
ssl_certificate_key "/path/to/key";
|
||||||
|
location / {
|
||||||
|
proxy_set_header X-Forwarded-For $real_ip; # Not really necessary
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
If you want to run under a subpath, set `basepath` in the config YAML and change the
|
||||||
|
location block to the same, e.g. `basepath: "/cv"` in YAML, and
|
||||||
|
```
|
||||||
|
...
|
||||||
|
location /cv {
|
||||||
|
proxy_pass http://localhost:3000;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Planned, but still missing features:
|
||||||
|
- Socials list
|
||||||
|
- Contact / contact info so it won't cause a spam wave
|
||||||
|
- Setting the highlight color via configuration file
|
||||||
|
- Dark theme print to PDF
|
||||||
|
|
||||||
|
|
||||||
|
## Special thanks
|
||||||
|
Shamelessly adapted to Go from [mazipan's](https://github.com/mazipan) [bulma-resume-template](https://github.com/mazipan/bulma-resume-template).
|
||||||
|
|
|
@ -83,6 +83,9 @@ profile:
|
||||||
level: 3
|
level: 3
|
||||||
- name: Language 2
|
- name: Language 2
|
||||||
level: 2
|
level: 2
|
||||||
|
certificates:
|
||||||
|
- name: Boat license
|
||||||
|
- name: CKA
|
||||||
|
|
||||||
## Not implemented yet
|
## Not implemented yet
|
||||||
socials: []
|
socials: []
|
7
main.go
7
main.go
|
@ -23,6 +23,7 @@ var strs map[string]map[string]string
|
||||||
func main() {
|
func main() {
|
||||||
loadStrings()
|
loadStrings()
|
||||||
cfgFile := flag.String("config", "./data/resume.yaml", "Path to the configuration YAML")
|
cfgFile := flag.String("config", "./data/resume.yaml", "Path to the configuration YAML")
|
||||||
|
port := flag.Int("port", 3000, "Listening port")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
cfg, err := readConfig(*cfgFile)
|
cfg, err := readConfig(*cfgFile)
|
||||||
|
@ -48,13 +49,13 @@ func main() {
|
||||||
dir, relDir := getPhotoPaths(cfg)
|
dir, relDir := getPhotoPaths(cfg)
|
||||||
mux.Handle(dir, http.StripPrefix(dir, http.FileServer(http.Dir(relDir))))
|
mux.Handle(dir, http.StripPrefix(dir, http.FileServer(http.Dir(relDir))))
|
||||||
}
|
}
|
||||||
slog.Info("Starting go-resume server, listening on port 3000")
|
slog.Info(fmt.Sprintf("Starting go-resume server, listening on port %d", *port))
|
||||||
err = http.ListenAndServe("0.0.0.0:3000", mux)
|
err = http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", *port), mux)
|
||||||
slog.Error(err.Error())
|
slog.Error(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func home(w http.ResponseWriter, r *http.Request) {
|
func home(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Println("Client: " + r.Header.Get("X-Forwarded-For") + " Request: " + r.URL.Path)
|
slog.Info(fmt.Sprintf("Client: %s Request: %s ", r.Header.Get("X-Forwarded-For"), r.URL.Path))
|
||||||
acceptedPages := []string{basePath, basePath + "light", basePath + "dark"}
|
acceptedPages := []string{basePath, basePath + "light", basePath + "dark"}
|
||||||
if !slices.Contains(acceptedPages, r.URL.Path) {
|
if !slices.Contains(acceptedPages, r.URL.Path) {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
|
|
|
@ -86,4 +86,6 @@ body {
|
||||||
.item {
|
.item {
|
||||||
page-break-inside: avoid; }
|
page-break-inside: avoid; }
|
||||||
html {
|
html {
|
||||||
color-adjust: exact; } }
|
color-adjust: exact; }
|
||||||
|
footer {
|
||||||
|
display: none; } }
|
||||||
|
|
|
@ -113,4 +113,7 @@ body {
|
||||||
html {
|
html {
|
||||||
color-adjust: exact;
|
color-adjust: exact;
|
||||||
}
|
}
|
||||||
|
footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,9 @@ body {
|
||||||
.item {
|
.item {
|
||||||
page-break-inside: avoid; }
|
page-break-inside: avoid; }
|
||||||
html {
|
html {
|
||||||
color-adjust: exact; } }
|
color-adjust: exact; }
|
||||||
|
footer {
|
||||||
|
display: none; } }
|
||||||
|
|
||||||
.tag:not(body).is-success {
|
.tag:not(body).is-success {
|
||||||
background-color: var(--section-title-color); }
|
background-color: var(--section-title-color); }
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<script>function printPage() {
|
<script>function printPage() {
|
||||||
if ("{{ .Theme }}" == "dark") {
|
if ("{{ .Theme }}" == "dark") {
|
||||||
alert("{{ translate "print_dark" $lang }}")
|
alert("{{ translate "print_dark" $lang }}")
|
||||||
window.location.replace("/light")
|
window.location.replace("{{ .Basepath }}/light")
|
||||||
} else {
|
} else {
|
||||||
window.print();
|
window.print();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue