Improvements to Icons for the Website service (#21)

Reviewed-on: rock-n-code/loud-amsterdam#21
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit is contained in:
2026-07-19 03:35:50 +00:00
committed by javier
parent 698cd60521
commit 6bdc127057
11 changed files with 56 additions and 8 deletions
+21
View File
@@ -213,6 +213,27 @@ Preview the optimized output locally — requires only Docker and writes to the
make ast-minify
```
### Icons
All icons are renditions of the star mark in `icon.svg`, which is the canonical source — there is no external design file to regenerate from.
| File | Size | Used by | Dark mode |
| --- | --- | --- | --- |
| `icon.svg` | vector | Tab icon in modern browsers (preferred over the ICO) | Adapts: an embedded `prefers-color-scheme` style flips the accent paths from `#000` to `#f3ecf5`. |
| `favicon.ico` | 32×32 | Tab icon in browsers without SVG favicon support (Safari) | Theme-neutral **by design**: it is the orange star *without* the accent paths, so one raster reads on both themes. Keep it accent-free when regenerating. |
| `icon-192.png`, `icon-512.png` | 192/512 | `site.webmanifest` install icons and splash screens | None (no platform mechanism); full artwork, light rendering, on a transparent background. |
| `apple-touch-icon.png` | 180×180 | iOS home-screen bookmarks | None (fetched once, outside any page context); full artwork, deliberately opaque — iOS fills transparent regions with black. |
The landing page pairs the icons with two `theme-color` metas: `#0c0710` (media-qualified for dark, listed first — the first matching entry wins) and `#fafafa` as the fallback.
The raster icons are committed binaries, regenerated from `icon.svg` on demand via a throwaway container (no local toolchain needed) — e.g. for the 512px rendition:
```sh
docker run --rm -v "$PWD/Resources/Static:/work" alpine sh -c '
apk add --no-cache imagemagick librsvg oxipng &&
magick -background none -density 256 /work/icon.svg -depth 8 PNG32:/work/icon-512.png &&
oxipng --opt max --strip safe /work/icon-512.png'
```
(`-density` scales the 192px viewBox: `96 × target ÷ 192`. For `favicon.ico`, rasterize a star-only copy of the SVG at 32px and pack it with `icotool -c --raw`.)
### Required variables
The Makefile and Compose files read these from a `.env` file (or the environment). Provide your own values — do **not** commit secrets.
| Variable | Used for |
Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 192 192"><path fill="#e08524" d="M75.3 73.4H18.4l45.3 34.3L48.3 163l46.1-32.3 48.2 34.6-16.9-58.3 44.9-33.6H115l-20.5-55-19.2 55z"/><path d="m96.7 18.8 18.2 8.2 16.5 44.3h-15.1L96.7 18.8zm-47 146 18.7 9.9 42.6-29.9-16.5-11.4-44.8 31.4zm79.1-56.8 17.4 9.4 18.6 60.1-19.7-11.3-16.3-58.2z"/><path d="m173.1 74.3 17.8 9.2-44.7 34-17.4-9.4 44.3-33.8z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 192 192"><style>.accent{fill:#000}@media (prefers-color-scheme:dark){.accent{fill:#f3ecf5}}</style><path fill="#e08524" d="M75.3 73.4H18.4l45.3 34.3L48.3 163l46.1-32.3 48.2 34.6-16.9-58.3 44.9-33.6H115l-20.5-55-19.2 55z"/><path class="accent" d="m96.7 18.8 18.2 8.2 16.5 44.3h-15.1L96.7 18.8zm-47 146 18.7 9.9 42.6-29.9-16.5-11.4-44.8 31.4zm79.1-56.8 17.4 9.4 18.6 60.1-19.7-11.3-16.3-58.2z"/><path class="accent" d="m173.1 74.3 17.8 9.2-44.7 34-17.4-9.4 44.3-33.8z"/></svg>

Before

Width:  |  Height:  |  Size: 429 B

After

Width:  |  Height:  |  Size: 549 B

@@ -2,9 +2,13 @@
"short_name": "",
"name": "",
"icons": [{
"src": "icon.png",
"src": "icon-192.png",
"type": "image/png",
"sizes": "192x192"
}, {
"src": "icon-512.png",
"type": "image/png",
"sizes": "512x512"
}],
"start_url": "/?utm_source=homescreen",
"background_color": "#fafafa",
@@ -10,8 +10,12 @@ enum StaticFile: CaseIterable, Sendable {
case error
/// The `favicon.ico` icon.
case favicon
/// The `icon.png` and `icon.svg` icons.
/// The `icon.svg` icon.
case icon
/// The `icon-192.png` icon for the web manifest.
case icon192
/// The `icon-512.png` icon for the web manifest.
case icon512
/// The `css/index.css` stylesheet and `js/index.js` script for the landing page.
case index
/// The `robots.txt` crawler directives.
@@ -57,12 +61,14 @@ extension StaticFile {
/// The file extensions the file is available with.
var fileExtensions: [Extension] {
switch self {
case .appleTouchIcon: [.png]
case .appleTouchIcon,
.icon192,
.icon512: [.png]
case .error,
.index,
.shared: [.css, .js]
case .favicon: [.ico]
case .icon: [.png, .svg]
case .icon: [.svg]
case .robots: [.txt]
case .site: [.webmanifest]
case .sitemap: [.xml]
@@ -76,6 +82,8 @@ extension StaticFile {
case .error: "error"
case .favicon: "favicon"
case .icon: "icon"
case .icon192: "icon-192"
case .icon512: "icon-512"
case .index: "index"
case .robots: "robots"
case .shared: "shared"
@@ -74,6 +74,14 @@ struct IndexPage: HTMLDocument, Sendable {
.rel("manifest"),
.href(StaticFile.site.urlPath(for: .webmanifest))
)
meta(
.name("theme-color"),
.content("#0c0710"),
.custom(
name: "media",
value: "(prefers-color-scheme: dark)"
)
)
meta(
.name("theme-color"),
.content("#fafafa")
@@ -114,7 +114,7 @@ struct StaticFileTests {
@Test
func `all cases`() {
#expect(File.allCases.count == 9)
#expect(File.allCases.count == 11)
}
}
@@ -159,7 +159,9 @@ private extension StaticFileTests {
[.png],
[.css, .js],
[.ico],
[.png, .svg],
[.svg],
[.png],
[.png],
[.css, .js],
[.txt],
[.css, .js],
@@ -171,6 +173,8 @@ private extension StaticFileTests {
"error",
"favicon",
"icon",
"icon-192",
"icon-512",
"index",
"robots",
"shared",
@@ -181,7 +185,9 @@ private extension StaticFileTests {
["apple-touch-icon.png"],
["css/error.css", "js/error.js"],
["favicon.ico"],
["icon.png", "icon.svg"],
["icon.svg"],
["icon-192.png"],
["icon-512.png"],
["css/index.css", "js/index.js"],
["robots.txt"],
["css/shared.css", "js/shared.js"],
@@ -23,6 +23,7 @@ struct IndexPageTests {
#expect(html.contains("/icon.svg"))
#expect(html.contains("/apple-touch-icon.png"))
#expect(html.contains("/site.webmanifest"))
#expect(html.contains(#"media="(prefers-color-scheme: dark)""#))
#expect(html.contains("Hello world!"))
#expect(html.contains("/js/shared.js"))
#expect(html.contains("/js/index.js"))