diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bbd7a24..e46e518 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -18,7 +18,7 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Login to Docker Hub @@ -40,7 +40,7 @@ jobs: needs: build steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Run deploy script diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index af860d4..9b1d153 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1 +1,43 @@ -# TODO: implement pull request workflow +name: Pull Request +on: + pull_request: + branches: + - main +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: '1.25' + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v9 + with: + version: latest + build: + name: Build server + runs-on: ubuntu-24.04-arm + steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version: '1.25' + - name: Download dependencies + run: go mod download + - name: Build application + run: CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/web/main.go + docker: + name: Build Docker image + runs-on: ubuntu-24.04-arm + steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Build Docker image + run: docker build -t links.stevanfreeborn.com . + diff --git a/cmd/web/main.go b/cmd/web/main.go index 7dcae99..bff4884 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -20,6 +20,7 @@ func main() { mux.HandleFunc("/", handlers.Index) mux.HandleFunc("/css/", handlers.CSS) mux.HandleFunc("/fonts/", handlers.Fonts) + mux.HandleFunc("/images/", handlers.Images) loggingMux := middleware.Logging(mux) diff --git a/internal/assets/images/favicon.ico b/internal/assets/images/favicon.ico new file mode 100644 index 0000000..e1cc98a Binary files /dev/null and b/internal/assets/images/favicon.ico differ diff --git a/internal/assets/json/links.json b/internal/assets/json/links.json new file mode 100644 index 0000000..5b17358 --- /dev/null +++ b/internal/assets/json/links.json @@ -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" + } +] diff --git a/internal/assets/main.go b/internal/assets/main.go index ce695cb..6867e41 100644 --- a/internal/assets/main.go +++ b/internal/assets/main.go @@ -12,4 +12,8 @@ var ( CSS embed.FS //go:embed "fonts/*" Fonts embed.FS + //go:embed "json/*" + JSON embed.FS + //go:embed "images/*" + Images embed.FS ) diff --git a/internal/assets/templates/index.gohtml b/internal/assets/templates/index.gohtml index e12222b..21a211a 100644 --- a/internal/assets/templates/index.gohtml +++ b/internal/assets/templates/index.gohtml @@ -9,6 +9,7 @@ integrity="sha512-2SwdPD6INVrV/lHTZbO2nodKhrnDdJK9/kg2XD1r9uGqPo1cUbujc+IYdlYdEErWNu69gVcYgdxlmVmzTWnetw==" crossorigin="anonymous" referrerpolicy="no-referrer" /> + @@ -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." />

Stevan Freeborn

-

I'm a {{ .Age }}-year old dad of 2 who enjoys drinking coffee, lifting weights, and solving problems with code.

+

I'm a {{ .Age }}-year old dad of 2 who enjoys drinking coffee, lifting weights, and solving problems with code. +

diff --git a/internal/handlers/main.go b/internal/handlers/main.go index d55c241..5273311 100644 --- a/internal/handlers/main.go +++ b/internal/handlers/main.go @@ -2,6 +2,8 @@ package handlers import ( + "encoding/json" + "io/fs" "math" "net/http" "text/template" @@ -10,35 +12,58 @@ import ( "github.com/StevanFreeborn/links.stevanfreeborn.com/internal/assets" ) +const LINKS_JSON_PATH = "json/links.json" const DAYS_IN_YEAR = 365 const HOURS_IN_DAY = 24 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 { - Age float64 + Age float64 + Links []Link } 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, parseTemplateError := template.ParseFS(assets.Templates, "templates/index.gohtml") - t, err := template.ParseFS(assets.Templates, "templates/index.gohtml") - - if err != nil { + if parseTemplateError != nil { http.Error(w, "Unable to load template", http.StatusInternalServerError) return } + linksFile, openLinksFileError := assets.JSON.Open(LINKS_JSON_PATH) + + if openLinksFileError != nil { + http.Error(w, "Unable to load links", http.StatusInternalServerError) + return + } + + links, readLinksFileError := readLinksFromJSON(linksFile) + + if readLinksFileError != nil { + http.Error(w, "Unable to parse links", http.StatusInternalServerError) + return + } + age := time.Since(birthday).Hours() / HOURS_IN_DAY / DAYS_IN_YEAR viewModel := IndexViewModel{ - Age: math.Floor(age), + Age: math.Floor(age), + Links: links, } - t.Execute(w, viewModel) + executeError := t.Execute(w, viewModel) + + if executeError != nil { + http.Error(w, "Unable to render template", http.StatusInternalServerError) + return + } } func CSS(w http.ResponseWriter, r *http.Request) { @@ -48,3 +73,31 @@ func CSS(w http.ResponseWriter, r *http.Request) { func Fonts(w http.ResponseWriter, r *http.Request) { 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) { + var closeErr error = nil + + defer func() { + closeErr = file.Close() + }() + + if closeErr != nil { + return nil, closeErr + } + + var links []Link + + decoder := json.NewDecoder(file) + + err := decoder.Decode(&links) + + if err != nil { + return nil, err + } + + return links, nil +}