package web import ( "encoding/json" "io/fs" "net/http" ) // The site installs as an app (a PWA): a web app manifest, plus the service worker in // assets/sw.js. The public site and the staff panel are separate apps, so each opens on its own // page; both cover the whole site, since signing in goes through /auth. type manifest struct { ID string `json:"id"` Name string `json:"name"` ShortName string `json:"short_name"` Description string `json:"description"` StartURL string `json:"start_url"` Scope string `json:"scope"` Display string `json:"display"` BackgroundColor string `json:"background_color"` ThemeColor string `json:"theme_color"` Icons []manifestIcon `json:"icons"` } type manifestIcon struct { Src string `json:"src"` Sizes string `json:"sizes"` Type string `json:"type"` Purpose string `json:"purpose,omitempty"` } func (s *Server) manifest(staff bool) http.HandlerFunc { m := manifest{ ID: "/", Name: s.site.Title, ShortName: s.site.Title, Description: "Live server, bans and staff.", StartURL: "/", Scope: "/", Display: "standalone", BackgroundColor: "#14161b", ThemeColor: "#1b1e25", Icons: []manifestIcon{ {Src: "/static/icon-192.png", Sizes: "192x192", Type: "image/png"}, {Src: "/static/icon-512.png", Sizes: "512x512", Type: "image/png"}, {Src: "/static/icon-maskable-512.png", Sizes: "512x512", Type: "image/png", Purpose: "maskable"}, }, } if staff { m.ID = "/admin" m.Name = s.site.Title + " staff panel" m.ShortName = s.site.Title + " staff" m.Description = "Bans, mutes, ranks and the live server, for staff." m.StartURL = "/admin" } body, _ := json.Marshal(m) return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/manifest+json") w.Header().Set("Cache-Control", "no-cache") w.Write(body) } } // serviceWorker serves sw.js from the root, since a worker only controls pages under its own path. func serviceWorker(static fs.FS) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-cache") http.ServeFileFS(w, r, static, "sw.js") } }