diff --git a/.gitignore b/.gitignore
index 4697f6a..7190c6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,12 +5,12 @@
# go webserver code
!cmd/
!internal/
-!vendor/
!static/
!.air.toml
!go.mod
!go.sum
!gomod2nix.toml
+static/js/
# blogs
!posts/
diff --git a/cmd/webserver/pages/cache.go b/cmd/webserver/cache/cache.go
similarity index 99%
rename from cmd/webserver/pages/cache.go
rename to cmd/webserver/cache/cache.go
index 587bd10..6cf0d40 100644
--- a/cmd/webserver/pages/cache.go
+++ b/cmd/webserver/cache/cache.go
@@ -1,4 +1,4 @@
-package pages
+package cache
import (
"fmt"
diff --git a/static/styles/components/ascii.css b/cmd/webserver/components/ascii/ascii.css
similarity index 60%
rename from static/styles/components/ascii.css
rename to cmd/webserver/components/ascii/ascii.css
index 81cf822..328fef4 100644
--- a/static/styles/components/ascii.css
+++ b/cmd/webserver/components/ascii/ascii.css
@@ -5,10 +5,10 @@
text-wrap: nowrap;
white-space-collapse: preserve;
text-align: center;
-}
-.ascii-char {
- display: inline-block;
- font-size: 5px;
- width: 3px;
+ & .ascii-char {
+ display: inline-block;
+ font-size: 5px;
+ width: 3px;
+ }
}
diff --git a/cmd/webserver/components/ascii/ascii.go b/cmd/webserver/components/ascii/ascii.go
new file mode 100644
index 0000000..ea67071
--- /dev/null
+++ b/cmd/webserver/components/ascii/ascii.go
@@ -0,0 +1,21 @@
+package components
+
+import (
+ "html/template"
+)
+
+type Props struct {
+ Ascii [][]string
+}
+
+func (props Props) Component(t *template.Template) error {
+ name := "ascii"
+
+ filepath := "cmd/webserver/components/" + name + "/" + name + ".tmpl"
+
+ if _, err := t.New(name + "-component").ParseFiles(filepath); err != nil {
+ return err
+ } else {
+ return nil
+ }
+}
diff --git a/cmd/webserver/components/ascii.tmpl b/cmd/webserver/components/ascii/ascii.tmpl
similarity index 100%
rename from cmd/webserver/components/ascii.tmpl
rename to cmd/webserver/components/ascii/ascii.tmpl
diff --git a/cmd/webserver/components/base.tmpl b/cmd/webserver/components/base.tmpl
deleted file mode 100644
index bdcf94c..0000000
--- a/cmd/webserver/components/base.tmpl
+++ /dev/null
@@ -1,13 +0,0 @@
-{{ define "base" }}
-
-
-{{ template "head" . }}
-
- {{ template "header" . }}
-
- {{ template "content" . }}
-
- {{ template "footer" . }}
-
-
-{{ end }}
diff --git a/static/styles/components/footer.css b/cmd/webserver/components/footer/footer.css
similarity index 100%
rename from static/styles/components/footer.css
rename to cmd/webserver/components/footer/footer.css
diff --git a/cmd/webserver/components/footer/footer.go b/cmd/webserver/components/footer/footer.go
new file mode 100644
index 0000000..b05e665
--- /dev/null
+++ b/cmd/webserver/components/footer/footer.go
@@ -0,0 +1,19 @@
+package components
+
+import (
+ "html/template"
+)
+
+type Props struct{}
+
+func (props Props) Component(t *template.Template) error {
+ name := "footer"
+
+ filepath := "cmd/webserver/components/" + name + "/" + name + ".tmpl"
+
+ if _, err := t.New(name + "-component").ParseFiles(filepath); err != nil {
+ return err
+ } else {
+ return nil
+ }
+}
diff --git a/cmd/webserver/components/footer.tmpl b/cmd/webserver/components/footer/footer.tmpl
similarity index 100%
rename from cmd/webserver/components/footer.tmpl
rename to cmd/webserver/components/footer/footer.tmpl
diff --git a/cmd/webserver/components/head.tmpl b/cmd/webserver/components/head.tmpl
deleted file mode 100644
index ee3de00..0000000
--- a/cmd/webserver/components/head.tmpl
+++ /dev/null
@@ -1,16 +0,0 @@
-{{ define "head" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{{ end }}
diff --git a/static/styles/components/header.css b/cmd/webserver/components/header/header.css
similarity index 86%
rename from static/styles/components/header.css
rename to cmd/webserver/components/header/header.css
index 11334ef..d9b1c3b 100644
--- a/static/styles/components/header.css
+++ b/cmd/webserver/components/header/header.css
@@ -30,4 +30,9 @@ header {
}
}
}
+
+ .divider {
+ border-block-start: var(--space-3xs) solid var(--clr-high);
+ width: 100%;
+ }
}
diff --git a/cmd/webserver/components/header/header.go b/cmd/webserver/components/header/header.go
new file mode 100644
index 0000000..c2f3b2e
--- /dev/null
+++ b/cmd/webserver/components/header/header.go
@@ -0,0 +1,39 @@
+package components
+
+import (
+ "html/template"
+
+ ascii "personal-website/cmd/webserver/components/ascii"
+ nav "personal-website/cmd/webserver/components/nav"
+)
+
+type Props struct {
+ Ascii [][]string
+ PageCurrent string
+ Pages []string
+}
+
+func (props Props) Component(t *template.Template) error {
+ name := "header"
+
+ filepath := "cmd/webserver/components/" + name + "/" + name + ".tmpl"
+
+ if err := (ascii.Props{
+ Ascii: props.Ascii,
+ }.Component(t)); err != nil {
+ return err
+ }
+
+ if err := (nav.Props{
+ PageCurrent: props.PageCurrent,
+ Pages: props.Pages,
+ }.Component(t)); err != nil {
+ return err
+ }
+
+ if _, err := t.New(name + "-component").ParseFiles(filepath); err != nil {
+ return err
+ } else {
+ return nil
+ }
+}
diff --git a/cmd/webserver/components/header/header.tmpl b/cmd/webserver/components/header/header.tmpl
new file mode 100644
index 0000000..eedc4d6
--- /dev/null
+++ b/cmd/webserver/components/header/header.tmpl
@@ -0,0 +1,11 @@
+{{ define "header" }}
+
+ {{ template "ascii" . }}
+ {{ template "nav" . }}
+
+
+{{ end }}
+
+{{ define "header-oob" }}
+ {{ template "nav-oob" . }}
+{{ end }}
diff --git a/cmd/webserver/components/nav/nav.css b/cmd/webserver/components/nav/nav.css
new file mode 100644
index 0000000..f908eec
--- /dev/null
+++ b/cmd/webserver/components/nav/nav.css
@@ -0,0 +1,25 @@
+#nav {
+ width: 100%;
+
+ & a.selected {
+ font-weight: 700;
+ text-decoration: underline;
+ }
+
+ & ul {
+ display: flex;
+ justify-content: space-evenly;
+ list-style-type: none;
+ text-align: center;
+
+ & li {
+ flex: 1;
+
+ & a {
+ display: block;
+ padding-block: var(--space-2xs);
+ padding-inline: var(--space-xs);
+ }
+ }
+ }
+}
diff --git a/cmd/webserver/components/nav/nav.go b/cmd/webserver/components/nav/nav.go
new file mode 100644
index 0000000..56afe3c
--- /dev/null
+++ b/cmd/webserver/components/nav/nav.go
@@ -0,0 +1,22 @@
+package components
+
+import (
+ "html/template"
+)
+
+type Props struct {
+ PageCurrent string
+ Pages []string
+}
+
+func (props Props) Component(t *template.Template) error {
+ name := "nav"
+
+ filepath := "cmd/webserver/components/" + name + "/" + name + ".tmpl"
+
+ if _, err := t.New(name + "-component").ParseFiles(filepath); err != nil {
+ return err
+ } else {
+ return nil
+ }
+}
diff --git a/cmd/webserver/components/header.tmpl b/cmd/webserver/components/nav/nav.tmpl
similarity index 55%
rename from cmd/webserver/components/header.tmpl
rename to cmd/webserver/components/nav/nav.tmpl
index d4a16ed..d26f9a0 100644
--- a/cmd/webserver/components/header.tmpl
+++ b/cmd/webserver/components/nav/nav.tmpl
@@ -1,16 +1,3 @@
-{{ define "nav-links" }}
- {{ range $name := newRange "home" "blog" "projects" }}
- {{ title $name }}
- {{ end }}
-{{ end }}
-
{{ define "nav" }}
{{ end }}
-{{ define "nav-links-updater" }}
+{{ define "nav-oob" }}
{{ template "nav" . }}
{{ end }}
-{{ define "header" }}
-
- {{ template "ascii" . }}
- {{ template "nav" . }}
-
-
+{{ define "nav-links" }}
+ {{ range $name := .Pages }}
+ {{ $name }}
+ {{ end }}
{{ end }}
diff --git a/static/styles/components/spacer.css b/cmd/webserver/components/spacer/spacer.css
similarity index 100%
rename from static/styles/components/spacer.css
rename to cmd/webserver/components/spacer/spacer.css
diff --git a/cmd/webserver/components/spacer/spacer.go b/cmd/webserver/components/spacer/spacer.go
new file mode 100644
index 0000000..71cf87b
--- /dev/null
+++ b/cmd/webserver/components/spacer/spacer.go
@@ -0,0 +1,19 @@
+package components
+
+import (
+ "html/template"
+)
+
+type Props struct{}
+
+func (props Props) Component(t *template.Template) error {
+ name := "spacer"
+
+ filepath := "cmd/webserver/components/" + name + "/" + name + ".tmpl"
+
+ if _, err := t.New(name + "-component").ParseFiles(filepath); err != nil {
+ return err
+ } else {
+ return nil
+ }
+}
diff --git a/cmd/webserver/components/spacer/spacer.tmpl b/cmd/webserver/components/spacer/spacer.tmpl
new file mode 100644
index 0000000..4d3e96a
--- /dev/null
+++ b/cmd/webserver/components/spacer/spacer.tmpl
@@ -0,0 +1,3 @@
+{{ define "spacer" }}
+ -
+{{ end }}
diff --git a/cmd/webserver/layouts/base.go b/cmd/webserver/layouts/base.go
new file mode 100644
index 0000000..0213032
--- /dev/null
+++ b/cmd/webserver/layouts/base.go
@@ -0,0 +1,40 @@
+package layouts
+
+import (
+ "html/template"
+
+ // Components
+ footer "personal-website/cmd/webserver/components/footer"
+ header "personal-website/cmd/webserver/components/header"
+)
+
+type BaseLayout struct {
+ Ascii [][]string
+ Pages []string
+ PageCurrent string
+}
+
+func (props BaseLayout) Layout(t *template.Template) error {
+ name := "base"
+
+ filepath := "cmd/webserver/layouts/" + name + ".tmpl"
+
+ if _, err := t.New(name + "-layout").ParseFiles(filepath); err != nil {
+ return err
+ }
+
+ // Components
+ if err := (footer.Props{}.Component(t)); err != nil {
+ return err
+ }
+
+ if err := (header.Props{
+ Ascii: props.Ascii,
+ PageCurrent: props.PageCurrent,
+ Pages: props.Pages,
+ }.Component(t)); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/cmd/webserver/layouts/base.tmpl b/cmd/webserver/layouts/base.tmpl
new file mode 100644
index 0000000..f5aa560
--- /dev/null
+++ b/cmd/webserver/layouts/base.tmpl
@@ -0,0 +1,26 @@
+{{ define "base-layout" }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ template "header" . }}
+
+ {{ template "content" . }}
+
+ {{ template "footer" . }}
+
+
+{{ end }}
diff --git a/cmd/webserver/main.go b/cmd/webserver/main.go
index faab813..d44b881 100644
--- a/cmd/webserver/main.go
+++ b/cmd/webserver/main.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
+ "personal-website/cmd/webserver/cache"
"personal-website/cmd/webserver/pages"
)
@@ -18,7 +19,7 @@ var logRequests = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request
func main() {
log.Println("Starting server...")
- pages.InitCache()
+ cache.InitCache()
http.HandleFunc("GET /healthy", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
@@ -26,39 +27,36 @@ func main() {
http.HandleFunc("GET /robots.txt", staticHandler(http.Dir("static/seo")))
- renderer := pages.NewRenderer("cmd/webserver/components", "cmd/webserver/pages")
ascii := createAscii()
- pageHome := &pages.Home{Renderer: renderer, Ascii: ascii}
+ pageHome := &pages.Home{Pages: []string{"home", "blog", "projects"}, Ascii: ascii}
http.Handle("GET /", pageHome)
http.Handle("GET /home", pageHome)
http.Handle("GET /home/content", pageHome)
- pageBlog := &pages.Blog{Renderer: renderer, Ascii: ascii}
+ pageBlog := &pages.Blog{Pages: []string{"home", "blog", "projects"}, Ascii: ascii}
http.Handle("GET /blog", pageBlog)
http.Handle("GET /blog/content", pageBlog)
- pagePost := &pages.Post{Renderer: renderer, Ascii: ascii}
+ pagePost := &pages.Post{Pages: []string{"home", "blog", "projects"}, Ascii: ascii}
http.Handle("GET /post/{slug}", pagePost)
http.Handle("GET /post/{slug}/content", pagePost)
- pageProject := &pages.Project{Renderer: renderer, Ascii: ascii}
- http.Handle("GET /projects", pageProject)
- http.Handle("GET /projects/content", pageProject)
-
- pageWasm := &pages.Wasm{Renderer: renderer, Ascii: ascii}
- http.Handle("GET /wasm", pageWasm)
- http.Handle("GET /wasm/content", pageWasm)
+ pageProjects := &pages.Projects{Pages: []string{"home", "blog", "projects"}, Ascii: ascii}
+ http.Handle("GET /projects", pageProjects)
+ http.Handle("GET /projects/content", pageProjects)
http.Handle("GET /static/", http.StripPrefix("/static/", staticHandler(http.Dir("static"))))
+ //http.Handle("GET /cmd/webserver/components/", http.StripPrefix("/cmd/webserver/components", staticHandler(http.Dir("cmd/webserver/components"))))
+
log.Fatal(http.ListenAndServe(":8080", logRequests))
}
func createAscii() [][]string {
fileBuffer, err := os.ReadFile("static/images/ascii.txt")
if err != nil {
- log.Fatalf("Error reading ascii: %v", err)
+ log.Printf("main: reading ascii (%v)", err)
}
lines := strings.Split(string(fileBuffer), "\n")
diff --git a/cmd/webserver/pages/blog.go b/cmd/webserver/pages/blog.go
old mode 100644
new mode 100755
index 1e7de5c..110a0c9
--- a/cmd/webserver/pages/blog.go
+++ b/cmd/webserver/pages/blog.go
@@ -1,41 +1,85 @@
package pages
import (
+ "html/template"
"log"
"net/http"
+ "strings"
+ "time"
+ "personal-website/cmd/webserver/layouts"
+
+ spacer "personal-website/cmd/webserver/components/spacer"
+
+ "personal-website/cmd/webserver/cache"
"personal-website/internal"
)
type Blog struct {
- Renderer *Renderer
- Ascii [][]string
+ Ascii [][]string
+ PageCurrent string
+ Pages []string
+ Posts []internal.Post
}
func (p *Blog) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- type data struct {
- Ascii [][]string
- CurrentPage string
- Posts []internal.Post
+ name := "blog"
+
+ // Page props
+ p.PageCurrent = name
+
+ posts, err := cache.Cache.GetPosts()
+ if err != nil {
+ log.Printf(name+": failed to get posts (%v)", err)
}
+ p.Posts = posts
- name := "blog"
+ // Page Template
+ t, err := template.New("").Funcs(template.FuncMap{
+ "formatDate": func(date time.Time) string {
+ return date.Format("20060102")
+ },
+ }).ParseFiles("cmd/webserver/pages/" + name + ".tmpl")
+ if err != nil {
+ log.Printf(name+": failed to parse tmpl file (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
- d := data{
+ // Layout
+ if err = (layouts.BaseLayout{
Ascii: p.Ascii,
- CurrentPage: name,
+ PageCurrent: p.PageCurrent,
+ Pages: p.Pages,
+ }.Layout(t)); err != nil {
+ log.Printf(name+": failed to render layout (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
- posts, err := Cache.GetPosts()
- if err != nil {
- log.Printf("Error failed to get posts: %v", err)
+ // Components
+ if err = (spacer.Props{}).Component(t); err != nil {
+ log.Printf(name+": failed to render spacer (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
- d.Posts = posts
+ // Render
+ if strings.HasSuffix(r.URL.Path, "/content") {
+ if err = t.ExecuteTemplate(w, "content", p); err != nil {
+ log.Printf(name+": failed to render content (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
- err = p.Renderer.page(w, r, http.StatusOK, name, d)
- if err != nil {
- log.Printf("Error rendering %s: %v", name, err)
- http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ if err = t.ExecuteTemplate(w, "oob", p); err != nil {
+ log.Printf(name+": failed to render oob (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ } else if err = t.ExecuteTemplate(w, "page", p); err != nil {
+ log.Printf(name+": failed to render page (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
}
diff --git a/cmd/webserver/pages/blog.tmpl b/cmd/webserver/pages/blog.tmpl
index 2e6888d..e8b28bb 100644
--- a/cmd/webserver/pages/blog.tmpl
+++ b/cmd/webserver/pages/blog.tmpl
@@ -1,15 +1,15 @@
-{{ define "title" }}
- Ethan Thoma \ Blog
+{{ define "page" }}
+ {{ template "base-layout" . }}
{{ end }}
{{ define "content" }}
- {{ template "title" . }}
+ Ethan Thoma \ Blog
Blog
{{ range $post := .Posts }}
-
- -
+ {{ template "spacer" . }}
Ethan Thoma
+{{ define "page" }}
+ {{ template "base-layout" . }}
{{ end }}
{{ define "content" }}
- {{ template "title" . }}
+ Ethan Thoma
Ethan Thoma
@@ -22,5 +22,5 @@
{{ end }}
{{ define "oob" }}
- {{ template "nav-links-updater" . }}
+ {{ template "header-oob" . }}
{{ end }}
diff --git a/cmd/webserver/pages/pages.go b/cmd/webserver/pages/pages.go
deleted file mode 100644
index f3c6c70..0000000
--- a/cmd/webserver/pages/pages.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package pages
-
-import (
- "html/template"
- "log"
- "net/http"
- "strings"
- "time"
-)
-
-type Renderer struct {
- pagesDir string
- tmpl *template.Template
-}
-
-func NewRenderer(componentsDir string, pagesDir string) *Renderer {
- funcMap := template.FuncMap{
- "title": strings.Title,
- "formatDate": func(date time.Time) string {
- return date.Format("20060102")
- },
- "newRange": func(strings ...string) []string {
- return strings
- },
- }
-
- tmpl := template.New("").Funcs(funcMap)
- tmpl = template.Must(tmpl.ParseGlob(componentsDir + "/*.tmpl"))
-
- return &Renderer{
- pagesDir: pagesDir,
- tmpl: tmpl,
- }
-}
-
-func (t *Renderer) page(w http.ResponseWriter, r *http.Request, statusCode int, name string, data interface{}) error {
- tmpl, err := t.tmpl.Clone()
- if err != nil {
- log.Println("Failed to clone Renderer template")
- return err
- }
- tmpl.ParseFiles(t.pagesDir + "/" + name + ".tmpl")
-
- if statusCode != http.StatusOK {
- w.WriteHeader(statusCode)
- }
-
- if strings.HasSuffix(r.URL.Path, "/content") {
- if tmpl.ExecuteTemplate(w, "content", data) != nil {
- log.Println("Failed to render content")
- }
-
- if tmpl.ExecuteTemplate(w, "oob", data) != nil {
- log.Println("Failed to render oob")
- }
- } else {
- tmpl.ParseGlob(t.pagesDir + "/" + name + ".tmpl")
-
- if tmpl.ExecuteTemplate(w, "base", data) != nil {
- log.Println("Failed to render base")
- }
- }
-
- return err
-}
diff --git a/cmd/webserver/pages/post.go b/cmd/webserver/pages/post.go
old mode 100644
new mode 100755
index 09cfeb2..1adf96d
--- a/cmd/webserver/pages/post.go
+++ b/cmd/webserver/pages/post.go
@@ -5,47 +5,84 @@ import (
"html/template"
"log"
"net/http"
+ "strings"
+ "time"
"github.com/yuin/goldmark"
highlighting "github.com/yuin/goldmark-highlighting/v2"
+ "personal-website/cmd/webserver/cache"
+ "personal-website/cmd/webserver/layouts"
"personal-website/internal"
)
type Post struct {
- Renderer *Renderer
- Ascii [][]string
+ Ascii [][]string
+ PageCurrent string
+ Pages []string
+ Post internal.Post
}
func (p *Post) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- type data struct {
- Ascii [][]string
- CurrentPage string
- Post internal.Post
- }
+ name := "post"
- d := data{
- Ascii: p.Ascii,
- CurrentPage: "blog",
- }
+ // Page props
+ p.PageCurrent = "blog"
slug := r.PathValue("slug")
post, err := getPost(slug)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
}
- d.Post = post
+ p.Post = post
- w.Header().Set("Cache-Control", "public, max-age=86400, immutable")
- err = p.Renderer.page(w, r, http.StatusOK, "post", d)
+ // Page Template
+ t, err := template.New("").Funcs(template.FuncMap{
+ "formatDate": func(date time.Time) string {
+ return date.Format("20060102")
+ },
+ }).ParseFiles("cmd/webserver/pages/" + name + ".tmpl")
if err != nil {
- log.Printf("Error rendering post %s: %v", slug, err)
- http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ log.Printf(name+": failed to parse tmpl file (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ // Layout
+ if err = (layouts.BaseLayout{
+ Ascii: p.Ascii,
+ PageCurrent: p.PageCurrent,
+ Pages: p.Pages,
+ }.Layout(t)); err != nil {
+ log.Printf(name+": failed to render layout (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ // Render
+ w.Header().Set("Cache-Control", "public, max-age=86400, immutable")
+
+ if strings.HasSuffix(r.URL.Path, "/content") {
+ if err = t.ExecuteTemplate(w, "content", p); err != nil {
+ log.Printf(name+": failed to render content (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if err = t.ExecuteTemplate(w, "oob", p); err != nil {
+ log.Printf(name+": failed to render oob (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ } else if err = t.ExecuteTemplate(w, "page", p); err != nil {
+ log.Printf(name+": failed to render page (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
}
func getPost(slug string) (internal.Post, error) {
- post, err := Cache.GetPost(slug)
+ post, err := cache.Cache.GetPost(slug)
if err != nil {
log.Printf("Error getting post %s: %v", slug, err)
return post, err
diff --git a/cmd/webserver/pages/post.tmpl b/cmd/webserver/pages/post.tmpl
index 8e9dac5..8854fd2 100644
--- a/cmd/webserver/pages/post.tmpl
+++ b/cmd/webserver/pages/post.tmpl
@@ -1,9 +1,9 @@
-{{ define "title" }}
- Ethan Thoma \ {{ .Post.Title }}
+{{ define "page" }}
+ {{ template "base-layout" . }}
{{ end }}
{{ define "content" }}
- {{ template "title" . }}
+ Ethan Thoma \ {{ .Post.Title }}
{{ .Post.HTML }}
@@ -11,5 +11,5 @@
{{ end }}
{{ define "oob" }}
- {{ template "nav-links-updater" . }}
+ {{ template "header-oob" . }}
{{ end }}
diff --git a/cmd/webserver/pages/projects.go b/cmd/webserver/pages/projects.go
old mode 100644
new mode 100755
index d43b07a..bc8ce59
--- a/cmd/webserver/pages/projects.go
+++ b/cmd/webserver/pages/projects.go
@@ -1,31 +1,75 @@
package pages
import (
+ "html/template"
"log"
"net/http"
+ "strings"
+ "time"
+
+ "personal-website/cmd/webserver/layouts"
+
+ spacer "personal-website/cmd/webserver/components/spacer"
)
-type Project struct {
- Renderer *Renderer
- Ascii [][]string
+type Projects struct {
+ Ascii [][]string
+ PageCurrent string
+ Pages []string
}
-func (p *Project) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- type data struct {
- Ascii [][]string
- CurrentPage string
- }
-
+func (p *Projects) ServeHTTP(w http.ResponseWriter, r *http.Request) {
name := "projects"
- d := data{
+ // Page props
+ p.PageCurrent = name
+
+ // Page Template
+ t, err := template.New("").Funcs(template.FuncMap{
+ "formatDate": func(date time.Time) string {
+ return date.Format("20060102")
+ },
+ }).ParseFiles("cmd/webserver/pages/" + name + ".tmpl")
+ if err != nil {
+ log.Printf(name+": failed to parse tmpl file (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ // Layout
+ if err = (layouts.BaseLayout{
Ascii: p.Ascii,
- CurrentPage: name,
+ PageCurrent: p.PageCurrent,
+ Pages: p.Pages,
+ }.Layout(t)); err != nil {
+ log.Printf(name+": failed to render layout (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
- err := p.Renderer.page(w, r, http.StatusOK, name, d)
- if err != nil {
- log.Printf("Error rendering %s: %v", name, err)
- http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ // Components
+ if err = (spacer.Props{}).Component(t); err != nil {
+ log.Printf(name+": failed to render spacer (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ // Render
+ if strings.HasSuffix(r.URL.Path, "/content") {
+ if err = t.ExecuteTemplate(w, "content", p); err != nil {
+ log.Printf(name+": failed to render content (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if err = t.ExecuteTemplate(w, "oob", p); err != nil {
+ log.Printf(name+": failed to render oob (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ } else if err = t.ExecuteTemplate(w, "page", p); err != nil {
+ log.Printf(name+": failed to render page (%v)", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
}
diff --git a/cmd/webserver/pages/projects.tmpl b/cmd/webserver/pages/projects.tmpl
index d52af5f..f0771e8 100644
--- a/cmd/webserver/pages/projects.tmpl
+++ b/cmd/webserver/pages/projects.tmpl
@@ -1,9 +1,9 @@
-{{ define "title" }}
- Ethan Thoma \ Projects
+{{ define "page" }}
+ {{ template "base-layout" . }}
{{ end }}
{{ define "content" }}
- {{ template "title" . }}
+ Ethan Thoma \ Projects