Grow the companion, fix idle fallback, add update banner
Companion: bump the corner mascot ~12% (128→144) and make animation resolution robust — fall back to the idle clip when a mood has no clip of its own, and pin the always-asleep cat to one pose so its Lottie never reloads. This stops a bare emoji from replacing the cute companion on idle. Update notifications: serve a build id at /api/version (a hash of the embedded dist/index.html, which changes on every frontend deploy). The client records its load-time id, polls every 90s (and on tab focus), and floats a Mandarin-first "new version available" banner offering a refresh when the id changes. Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"log"
|
||||
@@ -34,12 +36,26 @@ func main() {
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
// Build version: a hash of the embedded SPA shell. Vite rewrites index.html
|
||||
// with content-hashed asset names on every build, so this string changes
|
||||
// exactly when a new frontend is deployed — the client polls it to know when
|
||||
// to offer a refresh.
|
||||
version := buildVersion()
|
||||
log.Printf("frontend build version %s", version)
|
||||
|
||||
r.Route("/api", func(api chi.Router) {
|
||||
api.Get("/health", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"status":"ok"}`))
|
||||
})
|
||||
|
||||
api.Get("/version", func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// Never cache: a stale cached version would defeat the whole check.
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
_, _ = w.Write([]byte(`{"version":"` + version + `"}`))
|
||||
})
|
||||
|
||||
llmClient := llm.NewLLMClient(cfg)
|
||||
sug := suggestions.New(database, llmClient)
|
||||
|
||||
@@ -63,6 +79,19 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// buildVersion derives a short, stable identifier for the currently embedded
|
||||
// frontend by hashing dist/index.html. Vite stamps content-hashed asset names
|
||||
// into that file each build, so the digest is a reliable "did the deploy
|
||||
// change?" signal. Falls back to "dev" when the frontend hasn't been built.
|
||||
func buildVersion() string {
|
||||
data, err := fs.ReadFile(web.DistFS, "dist/index.html")
|
||||
if err != nil {
|
||||
return "dev"
|
||||
}
|
||||
sum := sha256.Sum256(data)
|
||||
return hex.EncodeToString(sum[:])[:12]
|
||||
}
|
||||
|
||||
// spaHandler serves the embedded web/dist as a single-page app: static files
|
||||
// when they exist, falling back to index.html for unknown paths. If the
|
||||
// frontend hasn't been built yet, it returns a friendly dev hint instead.
|
||||
|
||||
Reference in New Issue
Block a user