feat: templates #4

Merged
ange merged 4 commits from devel into prod 2024-12-21 11:19:27 +00:00
14 changed files with 126 additions and 108 deletions

View File

@ -6,8 +6,10 @@ COPY src/ .
RUN CGO_ENABLED=0 go build -o /app
FROM scratch
COPY --from=build /app /app
COPY static/ /static/
COPY html/ /html/
COPY --from=build /app .
COPY html/ html/
COPY css/ css/
COPY static/ static/
COPY tmpl/ tmpl/
EXPOSE 3000
CMD ["/app"]
CMD ["./app"]

View File

@ -8,9 +8,15 @@ services:
watch:
- action: rebuild
path: src/
- action: sync+restart
path: tmpl/
target: tmpl/
- action: sync+restart
path: html/
target: html
target: html/
- action: sync
path: css/
target: css/
- action: sync
path: static/
target: static
target: static/

11
css/resume.css Normal file
View File

@ -0,0 +1,11 @@
@media print {
@page {
size: A4;
size: portrait;
margin: 5mm;
}
#menu, #credits {
display: none;
}
}

View File

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ange DUHAYON</title>
<link rel="stylesheet" href="style.css"/>
</head>
<body>
<div id="header">
<a id="headerLink" href="/">Ange DUHAYON</a>
<span id="headerSubtitle">DevOps Engineer</span>
<span class="right" style="font-size: .4em;">Website heavily inspired from <a href="//suckless.org/" target="_blank" rel="noreferrer noopener">suckless.org</a></span>
</div>
<div id="menu">
<a href="/">contact</a>
<a href="/resume">resume</a>
<a href="/about"><b>about me</b></a>
<span class="right">
<a href="//git.gmoker.com/yw5n/" target="_blank" rel="noreferrer noopener">source</a>
</span>
</div>
<div id="content">
<!--
<div id="nav">
<ul>
</ul>
</div>
-->
<div id="main">
</div>
</div>
</body>
</html>

View File

@ -1,41 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ange DUHAYON</title>
<link rel="stylesheet" href="style.css"/>
<script>
function copyElem(id, r='') {
navigator.clipboard.writeText(
document.getElementById(id).innerText.replaceAll(r, ''),
);
}
function copyFile(id) {
fetch(document.getElementById(id).childNodes[0].href).then(f => {
f.text().then(t => {
navigator.clipboard.writeText(t);
})
})
}
</script>
{{template "head.tmpl" .}}
<script src="static/copy.js"></script>
</head>
<body>
<div id="header">
<a id="headerLink" href="/">Ange DUHAYON</a>
<span id="headerSubtitle">DevOps Engineer</span>
<span class="right" style="font-size: .4em;">Website heavily inspired from <a href="//suckless.org/" target="_blank" rel="noreferrer noopener">suckless.org</a></span>
</div>
<div id="menu">
<a href="/"><b>contact</b></a>
<a href="/resume">resume</a>
<!--
<a href="/about">about me</a>
-->
<span class="right">
<a href="//git.gmoker.com/yw5n/" target="_blank" rel="noreferrer noopener">source</a>
</span>
</div>
{{template "header.tmpl" .}}
<div id="content">
<!--
<div id="nav">
@ -76,6 +46,11 @@
<td id="wa"><a href="//wa.me/6285333559453" target="_blank" rel="noreferrer noopener">+62 853-3355-9453</a></td>
<td><button onclick="copyElem('wa', /[ |-]/g)">Copy</button></td>
</tr>
<tr>
<td>LinkedIn</td>
<td id="in"><a href="https://www.linkedin.com/in/angedhn" target="_blank" rel="noreferrer noopener">www.linkedin.com/in/angedhn</a></td>
<td><button onclick="copyElem('in')">Copy</button></td>
</tr>
<tr>
<td>PGP</td>
<td id="pgp"><a href="/static/pgp.asc" target="_blank" rel="noreferrer noopener">pgp.asc</a></td>

View File

@ -1,26 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ange DUHAYON</title>
<link rel="stylesheet" href="style.css"/>
{{template "head.tmpl" .}}
<link rel="stylesheet" href="resume.css"/>
</head>
<body>
<div id="header">
<a id="headerLink" href="/">Ange DUHAYON</a>
<span id="headerSubtitle">DevOps Engineer</span>
<span class="right" style="font-size: .4em;">Website heavily inspired from <a href="//suckless.org/" target="_blank" rel="noreferrer noopener">suckless.org</a></span>
</div>
<div id="menu">
<a href="/">contact</a>
<a href="/resume"><b>resume</b></a>
<!--
<a href="/about">about me</a>
-->
<span class="right">
<a href="//git.gmoker.com/yw5n/" target="_blank" rel="noreferrer noopener">source</a>
</span>
</div>
{{template "header.tmpl" .}}
<div id="content">
<div id="nav">
<!--
@ -46,20 +31,21 @@
<h3><b>Freelance</b> - DevOps</h3>
SEPTEMBER 2023 - TODAY
<ul>
<li>Server setup (Debian, Docker/K8s, web server, customer application)</li>
<li>Server setup (Debian, Docker/K8S, web server, customer application)</li>
<li>CI/CD, real-time monitoring</li>
</ul>
<h3><b>Selfhost</b> - DevOps</h3>
JANUARY 2022 - TODAY
<ul>
<li>Debian + K8S + Gitea CI/CD + Nextcloud + Matrix.org + Jellyfin + SearXNG</li>
<li>Debian, K8S, Gitea CI/CD</li>
<li>Nextcloud, Matrix.org, Jellyfin, SearXNG</li>
</ul>
<h3><b>EPITECH CodingClub association, Toulouse</b> - Cobra</h3>
JANUARY 2021 - JUNE 2024
<ul>
<li>Coding workshops for high school students</li>
</ul>
<h3><b>Predicloud, Toulouse</b> - DevOps / Site Reliability Manager</h3>
<h3><b>Predicloud, Toulouse</b> - DevOps SRE</h3>
JUNE 2022 - JULY 2023
<ul>
<li>CI/CD, K8S monitoring</li>
@ -75,7 +61,7 @@
<tr><td>Python</td> <td>Git</td></tr>
<tr><td>Bash</td> <td>Vim</td></tr>
<tr><td>Go</td> <td>Docker</td></tr>
<tr><td>JavaScript</td><td>K8S</td></tr>
<tr><td>JS</td> <td>K8S</td></tr>
</table>
</div>

View File

@ -7,9 +7,8 @@ import (
func main() {
http.HandleFunc("/", route)
err := http.ListenAndServe(":3000", nil)
if err != nil {
generateTmpl()
if err := http.ListenAndServe(":3000", nil); err != nil {
log.Fatal(err)
}
}

View File

@ -16,15 +16,19 @@ var routes = []struct {
handler http.HandlerFunc
}{
{[]string{"GET"}, url(""), index},
{[]string{"GET"}, url("/style\\.css"), style},
{[]string{"GET"}, url("/static/.+"), static},
{[]string{"GET"}, url("/[^/]+"), html},
{[]string{"GET"}, url("/(.+\\.css)"), css},
{[]string{"GET"}, url("/([^/]+)"), html},
}
func url(s string) *regexp.Regexp {
return regexp.MustCompile("^" + s + "/?$")
}
func getParam(r *http.Request, i int) string {
return r.Context().Value(URLParam{}).([]string)[i]
}
func route(w http.ResponseWriter, r *http.Request) {
for _, rt := range routes {
matches := rt.regex.FindStringSubmatch(r.URL.Path)
@ -34,8 +38,9 @@ func route(w http.ResponseWriter, r *http.Request) {
http.Error(
w, "405 method not allowed", http.StatusMethodNotAllowed,
)
fmt.Println(r.Method, r.URL.Path)
return
}
fmt.Println(r.Method, r.URL.Path)
rt.handler(w, r.WithContext(
context.WithValue(r.Context(), URLParam{}, matches[1:])),
)

31
src/tmpl.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
"bytes"
"html/template"
"path/filepath"
"regexp"
)
var TMPL map[string][]byte
func generateTmpl() {
files, _ := filepath.Glob("html/*.html")
re := regexp.MustCompile("html/(.+).html")
names := make([]string, len(files))
for i, f := range files {
names[i] = re.FindStringSubmatch(f)[1]
}
TMPL = make(map[string][]byte, len(files))
for i, f := range files {
b := new(bytes.Buffer)
t, _ := template.ParseFiles(f)
t.ParseGlob("tmpl/*.tmpl")
t.Execute(b, map[string]any{
"name": names[i],
"names": names,
})
TMPL[names[i]] = b.Bytes()
}
}

View File

@ -1,22 +1,28 @@
package main
import (
"net/http"
"path/filepath"
"net/http"
"fmt"
)
func index(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join("html", "index.html"))
}
func style(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "/html/style.css")
http.Redirect(w, r, "/contact", http.StatusMovedPermanently)
}
func static(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, r.URL.Path)
}
func html(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filepath.Join("html", r.URL.Path + ".html"))
func css(w http.ResponseWriter, r *http.Request) {
fmt.Println(filepath.Join("css", getParam(r, 0)))
http.ServeFile(w, r, filepath.Join("css", getParam(r, 0)))
}
func html(w http.ResponseWriter, r *http.Request) {
if t, found := TMPL[getParam(r, 0)]; found {
w.Write(t)
} else {
http.NotFound(w, r)
}
}

13
static/copy.js Normal file
View File

@ -0,0 +1,13 @@
function copyElem(id, r='') {
navigator.clipboard.writeText(
document.getElementById(id).innerText.replaceAll(r, ''),
);
}
function copyFile(id) {
fetch(document.getElementById(id).childNodes[0].href).then(f => {
f.text().then(t => {
navigator.clipboard.writeText(t);
})
})
}

3
tmpl/head.tmpl Normal file
View File

@ -0,0 +1,3 @@
<meta charset="UTF-8">
<title>Ange DUHAYON</title>
<link rel="stylesheet" href="style.css"/>

14
tmpl/header.tmpl Normal file
View File

@ -0,0 +1,14 @@
<div id="header">
<a id="headerLink" href="/">Ange DUHAYON</a>
<span id="headerSubtitle">DevOps Engineer</span>
<span id="credits" class="right" style="font-size: .4em;">Website heavily inspired from <a href="//suckless.org/" target="_blank" rel="noreferrer noopener">suckless.org</a></span>
</div>
<div id="menu">
{{$name := .name}}
{{range .names}}
<a href="/{{.}}">{{if eq $name .}}<b>{{.}}</b>{{else}}{{.}}{{end}}</a>
{{end}}
<span class="right">
<a href="//git.gmoker.com/yw5n" target="_blank" rel="noreferrer noopener">source</a>
</span>
</div>