diff --git a/Makefile b/Makefile index 083c7f1..2ad5146 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ COMPOSE ?= podman compose BIN := foodster PKG := ./cmd/foodster +STATIC := cmd/foodster/static # Vendored Datastar client. Bump, run `make vendor`, commit the result. DATASTAR_VERSION ?= v1.0.3 @@ -18,7 +19,7 @@ endif GOFILES = $(shell find . -name '*.go' -not -name '*_templ.go' 2>/dev/null) .DEFAULT_GOAL := help -.PHONY: help generate build run seed test smoke check lint fix vendor image push release up down logs clean +.PHONY: help generate build run seed test smoke check lint fix icons vendor image push release up down logs clean help: ## Show this help @grep -hE '^[a-zA-Z_-]+:.*## ' $(MAKEFILE_LIST) \ @@ -51,10 +52,20 @@ check: ## Everything that must pass before a commit @$(MAKE) --no-print-directory smoke @echo "check: all passed" +icons: ## Rasterise home-screen PNGs from assets/icon.svg and optimise them + rsvg-convert -w 180 -h 180 assets/icon.svg -o $(STATIC)/apple-touch-icon.png + rsvg-convert -w 192 -h 192 assets/icon.svg -o $(STATIC)/icon-192.png + rsvg-convert -w 512 -h 512 assets/icon.svg -o $(STATIC)/icon-512.png + # oxipng -o max alone loses to optipng on the 512; --zopfli wins at every + # size. Slow, but these are three tiny files built by hand. + oxipng -o max --zopfli --quiet \ + $(STATIC)/apple-touch-icon.png $(STATIC)/icon-192.png $(STATIC)/icon-512.png + @ls -l $(STATIC)/*.png + vendor: ## Re-download the Datastar client (DATASTAR_VERSION=v1.0.3) - curl -sSfL -o cmd/foodster/static/datastar.js \ + curl -sSfL -o $(STATIC)/datastar.js \ "https://cdn.jsdelivr.net/gh/starfederation/datastar@$(DATASTAR_VERSION)/bundles/datastar.js" - @head -1 cmd/foodster/static/datastar.js + @head -1 $(STATIC)/datastar.js lint: generate ## go vet, gofmt check, golangci-lint when installed go vet ./... diff --git a/README.md b/README.md index ae8354d..3067b0b 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,12 @@ Working: Still to build: +- **UI polish.** Checkbox chips hide the native control and signal state only + through background colour, so "Tarjoillaan lisukkeiden kanssa" gives no + clear read of on versus off. Show a real checkbox. Same applies to the + category and side chips. - Light / dark theme switch, saved per device (PRD §7.4). -- A proper app header and a `favicon.svg`. +- A proper app header. - Stage 2: the seven-meal suggester, which starts once there is history to weight against. @@ -102,6 +106,21 @@ a scratch database: make seed # or: SEED=seeds/other.json make seed ``` +## Icons + +`cmd/foodster/static/favicon.svg` is the browser-tab icon and follows the +system theme. The home-screen icons are PNGs, because a home-screen icon +cannot be transparent and must not change with the theme; they are rasterised +from `assets/icon.svg`, which is opaque and keeps the artwork inside the +central 80% so Android can mask it to any shape. + +```sh +make icons # rsvg-convert, then optipng -o7 +``` + +The PNGs are committed so the build needs no rasterizer. Re-run `make icons` +after editing `assets/icon.svg`. + ## Migrations Numbered SQL files in `cmd/foodster/migrations`, embedded in the binary and diff --git a/assets/icon.svg b/assets/icon.svg new file mode 100644 index 0000000..5560ce2 --- /dev/null +++ b/assets/icon.svg @@ -0,0 +1,19 @@ + diff --git a/cmd/foodster/main.go b/cmd/foodster/main.go index 934f14e..e38b864 100644 --- a/cmd/foodster/main.go +++ b/cmd/foodster/main.go @@ -15,6 +15,7 @@ import ( "flag" "fmt" "log" + "mime" "net/http" "os" "os/signal" @@ -140,6 +141,10 @@ func openDB(path string) (*sql.DB, error) { } func routes(db *sql.DB, loc *time.Location, password string) http.Handler { + // Go's mime table has no entry for .webmanifest, and a manifest served as + // octet-stream is ignored by the browser. + _ = mime.AddExtensionType(".webmanifest", "application/manifest+json") + a := &app{db: db, loc: loc} mux := http.NewServeMux() diff --git a/cmd/foodster/static/apple-touch-icon.png b/cmd/foodster/static/apple-touch-icon.png new file mode 100644 index 0000000..6e893c0 Binary files /dev/null and b/cmd/foodster/static/apple-touch-icon.png differ diff --git a/cmd/foodster/static/favicon.svg b/cmd/foodster/static/favicon.svg new file mode 100644 index 0000000..a5e5918 --- /dev/null +++ b/cmd/foodster/static/favicon.svg @@ -0,0 +1,16 @@ + diff --git a/cmd/foodster/static/icon-192.png b/cmd/foodster/static/icon-192.png new file mode 100644 index 0000000..124ee5b Binary files /dev/null and b/cmd/foodster/static/icon-192.png differ diff --git a/cmd/foodster/static/icon-512.png b/cmd/foodster/static/icon-512.png new file mode 100644 index 0000000..1652c5a Binary files /dev/null and b/cmd/foodster/static/icon-512.png differ diff --git a/cmd/foodster/static/manifest.webmanifest b/cmd/foodster/static/manifest.webmanifest new file mode 100644 index 0000000..fb3d71b --- /dev/null +++ b/cmd/foodster/static/manifest.webmanifest @@ -0,0 +1,17 @@ +{ + "id": "/", + "name": "Foodster", + "short_name": "Foodster", + "lang": "fi", + "dir": "ltr", + "start_url": "/", + "scope": "/", + "display": "standalone", + "background_color": "#ECEDE8", + "theme_color": "#15616D", + "icons": [ + { "src": "/static/icon-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/static/icon-512.png", "sizes": "512x512", "type": "image/png" }, + { "src": "/static/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } + ] +} diff --git a/cmd/foodster/views.templ b/cmd/foodster/views.templ index 86e9fc2..454997f 100644 --- a/cmd/foodster/views.templ +++ b/cmd/foodster/views.templ @@ -76,7 +76,14 @@ templ page(title, current string) { + +
Objects from the kitchen rather than geometry. The 16 px row and the tab strips are the only test that counts.
+ + +A bowl with steam. This household's catalog is half keitto, so soup is honest branding.
+A pot with the lid on and handles out. About cooking rather than eating.
+One spoon on the diagonal. A fork is the cliché; a lone spoon is not, and it stays one solid shape at any size.
+The rye loaf with its hole. Nothing else in a tab strip looks like this — which is the appeal and also the risk of reading as a ring.
+