Discover books, shows, and movies at your level. Track your progress by filling your Shelf with what you find, and share with other language learners. *No dusting required. shlf.space

feat(static): serve static files and set up tailwind css

Added a new handler (handleStatic) in the server to serve static files like CSS, JavaScript, and images

Mounted "/static/*" in the router to use the new static file handler,
which allows requests like "/static/style.css" to be served

Setted up Tailwind to allow generation of style.css from the input CSS
file using Tailwind syntax, which ensures that the frontend can use
Tailwind utility classes and styling\

Signed-off-by: Digital2512 <valerieannabella123@gmail.com>

authored by

Digital2512 and committed by tangled.org efdfb4af fd5e9ecf

+70 -3
+6 -2
go.mod
··· 7 7 github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e 8 8 ) 9 9 10 - require github.com/a-h/templ v0.3.977 // indirect 10 + require ( 11 + github.com/a-h/templ v0.3.977 // indirect 12 + github.com/tdewolff/minify/v2 v2.24.8 // indirect 13 + github.com/tdewolff/parse/v2 v2.8.5 // indirect 14 + ) 11 15 12 16 require ( 13 17 github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect ··· 58 62 go.uber.org/zap v1.26.0 // indirect 59 63 golang.org/x/crypto v0.21.0 // indirect 60 64 golang.org/x/mod v0.26.0 // indirect 61 - golang.org/x/sys v0.34.0 // indirect 65 + golang.org/x/sys v0.37.0 // indirect 62 66 golang.org/x/tools v0.35.0 // indirect 63 67 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect 64 68 lukechampine.com/blake3 v1.2.1 // indirect
+6
go.sum
··· 135 135 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 136 136 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 137 137 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 138 + github.com/tdewolff/minify/v2 v2.24.8 h1:58/VjsbevI4d5FGV0ZSuBrHMSSkH4MCH0sIz/eKIauE= 139 + github.com/tdewolff/minify/v2 v2.24.8/go.mod h1:0Ukj0CRpo/sW/nd8uZ4ccXaV1rEVIWA3dj8U7+Shhfw= 140 + github.com/tdewolff/parse/v2 v2.8.5 h1:ZmBiA/8Do5Rpk7bDye0jbbDUpXXbCdc3iah4VeUvwYU= 141 + github.com/tdewolff/parse/v2 v2.8.5/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo= 142 + github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= 138 143 github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk= 139 144 github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 140 145 github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= ··· 212 217 golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= 213 218 golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 214 219 golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 220 + golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 215 221 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 216 222 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 217 223 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+1
input.css
··· 1 + @import "tailwindcss";
+1
internal/server/router.go
··· 10 10 router := chi.NewRouter() 11 11 12 12 router.Get("/", s.HandleIndexPage) 13 + router.Handle("/static/*", s.HandleStatic()) 13 14 14 15 return router 15 16 }
+3 -1
internal/server/server.go
··· 11 11 } 12 12 13 13 func Make(ctx context.Context, config *config.Config) (*Server, error) { 14 - return &Server{}, nil 14 + return &Server{ 15 + config: config, 16 + }, nil 15 17 } 16 18 17 19 func (s *Server) Close() error {
+53
internal/server/static.go
··· 1 + package server 2 + 3 + import ( 4 + "log" 5 + "net/http" 6 + "strings" 7 + 8 + "shelf.app/static" 9 + ) 10 + 11 + func (s *Server) HandleStatic () http.Handler { 12 + var staticHandler http.Handler; 13 + 14 + if s.config.Core.Dev { 15 + fileSystem := http.Dir("./static/files") 16 + fileServer := http.FileServer(fileSystem) 17 + staticHandler = NoCache(http.StripPrefix("/static/", fileServer)) 18 + } else { 19 + fs, err := static.FS() 20 + if err != nil { 21 + log.Fatal("failed to create embedded static file system: ", err) 22 + } 23 + 24 + fileSystem := fs 25 + fileServer := http.FileServer(fileSystem) 26 + staticHandler = Cache(http.StripPrefix("/static/", fileServer)) 27 + } 28 + 29 + return staticHandler 30 + } 31 + 32 + func Cache(h http.Handler) http.Handler { 33 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 34 + path:=strings.Split(r.URL.Path, "?")[0] 35 + 36 + if strings.HasSuffix(path, ".js"){ 37 + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 38 + }else{ 39 + w.Header().Set("Cache-Control", "public, max-age=3600") 40 + } 41 + 42 + h.ServeHTTP(w, r) 43 + }) 44 + } 45 + 46 + func NoCache(h http.Handler) http.Handler { 47 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 48 + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") 49 + w.Header().Set("Pragma", "no-cache") 50 + w.Header().Set("Expires", "0") 51 + h.ServeHTTP(w, r) 52 + }) 53 + }