feat: define links in separate json file

This commit is contained in:
Stevan Freeborn
2025-11-24 21:34:15 -06:00
parent d423b5401b
commit a34467a67d
6 changed files with 81 additions and 29 deletions
+1
View File
@@ -20,6 +20,7 @@ func main() {
mux.HandleFunc("/", handlers.Index) mux.HandleFunc("/", handlers.Index)
mux.HandleFunc("/css/", handlers.CSS) mux.HandleFunc("/css/", handlers.CSS)
mux.HandleFunc("/fonts/", handlers.Fonts) mux.HandleFunc("/fonts/", handlers.Fonts)
mux.HandleFunc("/images/", handlers.Images)
loggingMux := middleware.Logging(mux) loggingMux := middleware.Logging(mux)
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+22
View File
@@ -0,0 +1,22 @@
[
{
"href": "https://youtube.stevanfreeborn.com",
"icon": "fa-brands fa-square-youtube fa-lg",
"text": "YouTube"
},
{
"href": "https://github.stevanfreeborn.com",
"icon": "fa-brands fa-square-github fa-lg",
"text": "GitHub"
},
{
"href": "https://blog.stevanfreeborn.com",
"icon": "fa-solid fa-square-rss fa-lg",
"text": "Blog"
},
{
"href": "https://linkedin.stevanfreeborn.com",
"icon": "fa-brands fa-square-linkedin fa-lg",
"text": "LinkedIn"
}
]
+4
View File
@@ -12,4 +12,8 @@ var (
CSS embed.FS CSS embed.FS
//go:embed "fonts/*" //go:embed "fonts/*"
Fonts embed.FS Fonts embed.FS
//go:embed "json/*"
JSON embed.FS
//go:embed "images/*"
Images embed.FS
) )
+8 -22
View File
@@ -9,6 +9,7 @@
integrity="sha512-2SwdPD6INVrV/lHTZbO2nodKhrnDdJK9/kg2XD1r9uGqPo1cUbujc+IYdlYdEErWNu69gVcYgdxlmVmzTWnetw==" integrity="sha512-2SwdPD6INVrV/lHTZbO2nodKhrnDdJK9/kg2XD1r9uGqPo1cUbujc+IYdlYdEErWNu69gVcYgdxlmVmzTWnetw=="
crossorigin="anonymous" referrerpolicy="no-referrer" /> crossorigin="anonymous" referrerpolicy="no-referrer" />
<link href="css/style.css" rel="stylesheet"> <link href="css/style.css" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="images/favicon.ico">
</head> </head>
<body> <body>
@@ -18,35 +19,20 @@
alt="A man with short brown hair, a grey hoodie, and a white t-shirt smiles at the camera. He has a white earbud in his left ear. The background is a blurred office setting with warm lighting visible through glass partitions." /> alt="A man with short brown hair, a grey hoodie, and a white t-shirt smiles at the camera. He has a white earbud in his left ear. The background is a blurred office setting with warm lighting visible through glass partitions." />
<div class="bio"> <div class="bio">
<h1>Stevan Freeborn</h1> <h1>Stevan Freeborn</h1>
<p>I'm a {{ .Age }}-year old dad of 2 who enjoys drinking coffee, lifting weights, and solving problems with code.</p> <p>I'm a {{ .Age }}-year old dad of 2 who enjoys drinking coffee, lifting weights, and solving problems with code.
</p>
</div> </div>
</div> </div>
<nav class="links-container"> <nav class="links-container">
<ul> <ul>
{{ range .Links }}
<li> <li>
<a class="link" href="https://youtube.stevanfreeborn.com"> <a class="link" href="{{ .Href }}">
<i class="fa-brands fa-square-youtube fa-lg"></i> <i class="{{ .Icon }}"></i>
<span>YouTube</span> <span>{{ .Text }}</span>
</a>
</li>
<li>
<a class="link" href="https://github.stevanfreeborn.com">
<i class="fa-brands fa-square-github fa-lg"></i>
<span>GitHub</span>
</a>
</li>
<li>
<a class="link" href="https://blog.stevanfreeborn.com">
<i class="fa-solid fa-square-rss fa-lg"></i>
<span>Blog</span>
</a>
</li>
<li>
<a class="link" href="https://linkedin.stevanfreeborn.com">
<i class="fa-brands fa-square-linkedin fa-lg"></i>
<span>LinkedIn</span>
</a> </a>
</li> </li>
{{ end }}
</ul> </ul>
</nav> </nav>
+44 -5
View File
@@ -2,6 +2,8 @@
package handlers package handlers
import ( import (
"encoding/json"
"io/fs"
"math" "math"
"net/http" "net/http"
"text/template" "text/template"
@@ -10,21 +12,24 @@ import (
"github.com/StevanFreeborn/links.stevanfreeborn.com/internal/assets" "github.com/StevanFreeborn/links.stevanfreeborn.com/internal/assets"
) )
const LINKS_JSON_PATH = "json/links.json"
const DAYS_IN_YEAR = 365 const DAYS_IN_YEAR = 365
const HOURS_IN_DAY = 24 const HOURS_IN_DAY = 24
var birthday time.Time = time.Date(1993, time.April, 21, 0, 0, 0, 0, time.UTC) var birthday time.Time = time.Date(1993, time.April, 21, 0, 0, 0, 0, time.UTC)
type Link struct {
Href string `json:"href"`
Icon string `json:"icon"`
Text string `json:"text"`
}
type IndexViewModel struct { type IndexViewModel struct {
Age float64 Age float64
Links []Link
} }
func Index(w http.ResponseWriter, r *http.Request) { func Index(w http.ResponseWriter, r *http.Request) {
// TODO: Links coming in external JSON data
// this could be static file in the repo
// or it could be fetched
// { link: "link", text: "text", "icon": "icon" }
t, err := template.ParseFS(assets.Templates, "templates/index.gohtml") t, err := template.ParseFS(assets.Templates, "templates/index.gohtml")
if err != nil { if err != nil {
@@ -32,10 +37,25 @@ func Index(w http.ResponseWriter, r *http.Request) {
return return
} }
linksFile, err := assets.JSON.Open(LINKS_JSON_PATH)
if err != nil {
http.Error(w, "Unable to load links", http.StatusInternalServerError)
return
}
links, err := readLinksFromJSON(linksFile)
if err != nil {
http.Error(w, "Unable to parse links", http.StatusInternalServerError)
return
}
age := time.Since(birthday).Hours() / HOURS_IN_DAY / DAYS_IN_YEAR age := time.Since(birthday).Hours() / HOURS_IN_DAY / DAYS_IN_YEAR
viewModel := IndexViewModel{ viewModel := IndexViewModel{
Age: math.Floor(age), Age: math.Floor(age),
Links: links,
} }
t.Execute(w, viewModel) t.Execute(w, viewModel)
@@ -48,3 +68,22 @@ func CSS(w http.ResponseWriter, r *http.Request) {
func Fonts(w http.ResponseWriter, r *http.Request) { func Fonts(w http.ResponseWriter, r *http.Request) {
http.ServeFileFS(w, r, assets.Fonts, r.URL.Path) http.ServeFileFS(w, r, assets.Fonts, r.URL.Path)
} }
func Images(w http.ResponseWriter, r *http.Request) {
http.ServeFileFS(w, r, assets.Images, r.URL.Path)
}
func readLinksFromJSON(file fs.File) ([]Link, error) {
defer file.Close()
var links []Link
decoder := json.NewDecoder(file)
err := decoder.Decode(&links)
if err != nil {
return nil, err
}
return links, nil
}