ai cooking
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Favicon (#315)

* seasonal favicon

* better favicons

---------

Co-authored-by: paul miller <paul.miller>

authored by

Paul Miller
paul miller
and committed by
GitHub
23eb7db2 3926000b

+62 -3
internal/static/favicon-fall.png

This is a binary file and will not be displayed.

internal/static/favicon-spring.png

This is a binary file and will not be displayed.

internal/static/favicon-summer.png

This is a binary file and will not be displayed.

internal/static/favicon-winter.png

This is a binary file and will not be displayed.

+30 -3
internal/static/static.go
··· 1 1 package static 2 2 3 3 import ( 4 + "careme/internal/seasons" 4 5 "crypto/sha256" 5 6 _ "embed" 6 7 "fmt" ··· 14 15 //go:embed htmx@2.0.8.js 15 16 var htmx208JS []byte 16 17 17 - //go:embed favicon.png 18 - var favicon []byte 18 + //go:embed favicon-fall.png 19 + var faviconFall []byte 20 + 21 + //go:embed favicon-winter.png 22 + var faviconWinter []byte 23 + 24 + //go:embed favicon-spring.png 25 + var faviconSpring []byte 26 + 27 + //go:embed favicon-summer.png 28 + var faviconSummer []byte 19 29 20 30 var TailwindAssetPath string 21 31 ··· 46 56 47 57 mux.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { 48 58 w.Header().Set("Content-Type", "image/png") 49 - w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 59 + // Keep cache short so clients can refresh seasonally without manual cache clear. 60 + w.Header().Set("Cache-Control", "public, max-age=3600") 61 + favicon := faviconBySeason(seasons.GetCurrentSeason()) 50 62 if _, err := w.Write(favicon); err != nil { 51 63 slog.ErrorContext(r.Context(), "failed to write favicon", "error", err) 52 64 } 53 65 }) 54 66 } 67 + 68 + func faviconBySeason(season seasons.Season) []byte { 69 + switch season { 70 + case seasons.Winter: 71 + return faviconWinter 72 + case seasons.Spring: 73 + return faviconSpring 74 + case seasons.Summer: 75 + return faviconSummer 76 + case seasons.Fall: 77 + fallthrough 78 + default: 79 + return faviconFall 80 + } 81 + }
+32
internal/static/static_test.go
··· 1 + package static 2 + 3 + import ( 4 + "careme/internal/seasons" 5 + "testing" 6 + ) 7 + 8 + func TestFaviconBySeason(t *testing.T) { 9 + tests := []struct { 10 + name string 11 + season seasons.Season 12 + want []byte 13 + }{ 14 + {name: "fall", season: seasons.Fall, want: faviconFall}, 15 + {name: "winter", season: seasons.Winter, want: faviconWinter}, 16 + {name: "spring", season: seasons.Spring, want: faviconSpring}, 17 + {name: "summer", season: seasons.Summer, want: faviconSummer}, 18 + {name: "default falls back to fall", season: seasons.Season("unknown"), want: faviconFall}, 19 + } 20 + 21 + for _, tt := range tests { 22 + t.Run(tt.name, func(t *testing.T) { 23 + got := faviconBySeason(tt.season) 24 + if len(got) == 0 { 25 + t.Fatal("favicon should not be empty") 26 + } 27 + if len(got) != len(tt.want) { 28 + t.Fatalf("faviconBySeason(%q) length = %d, want %d", tt.season, len(got), len(tt.want)) 29 + } 30 + }) 31 + } 32 + }