0.52.0 put every app logo on a white tile. The reason was real — a good number of logos are solid black line art and vanish into a dark surface — but the cure was applied to all of them, and in dark mode that makes each row look like it has a sticker pasted on it. So the tile goes back to the same neutral surface everything else uses, and the decision is made per image. The browser already holds the bytes, so it draws each one into a 24px canvas once and measures it: no new dependency, no second request, and it covers uploads as well as catalog logos. Measuring luminance alone was the first attempt and it is wrong. It plates Home Assistant, whose logo is a mid-blue house that reads on anything, and it plates Plex, which is dark *orange* — mean luminance cannot see that hue is doing the work. So chroma is measured too, and a plate requires low contrast **and** art with essentially no colour of its own. The threshold sits between the logos that only look monochrome (Sonarr 0.115, Uptime Kuma 0.129) and the ones that are (MinIO 0.065, Memos 0.037). Checked against 66 real logos rather than guessed: six get a plate in dark mode (Vaultwarden, Tailscale, Frigate, Heimdall, Miniflux, MinIO, all solid black), two in light mode (Ollama, Open-WebUI, solid white). The other ~90% sit bare. Mid-grey art like Bazarr is deliberately left alone — it already has contrast against both grounds, and a plate would be noise. Every failure path returns "no plate": jsdom with no canvas, a blocked canvas, an image that will not decode. Being wrong in that direction costs contrast on a handful of icons; being wrong the other way is the sticker problem again. The unit test is built from the measured luminance/chroma pairs, so it tests the rule against the art it actually has to handle. 0.53.0 because 0.52.0's images are already in the registry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
44 lines
1.1 KiB
JSON
44 lines
1.1 KiB
JSON
{
|
|
"name": "stackpilot-frontend",
|
|
"private": true,
|
|
"version": "0.53.0",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "tsc -b && vite build",
|
|
"preview": "vite preview",
|
|
"test": "vitest run"
|
|
},
|
|
"dependencies": {
|
|
"@fontsource-variable/schibsted-grotesk": "^5.2.8",
|
|
"@monaco-editor/react": "^4.6.0",
|
|
"@tanstack/react-query": "^5.62.7",
|
|
"@xterm/addon-fit": "^0.10.0",
|
|
"@xterm/xterm": "^5.5.0",
|
|
"axios": "^1.7.9",
|
|
"clsx": "^2.1.1",
|
|
"lucide-react": "^0.468.0",
|
|
"react": "^18.3.1",
|
|
"react-dom": "^18.3.1",
|
|
"react-router-dom": "^6.28.0",
|
|
"sonner": "^1.7.1",
|
|
"tailwind-merge": "^2.5.5",
|
|
"zustand": "^5.0.2"
|
|
},
|
|
"devDependencies": {
|
|
"@testing-library/dom": "^10.4.0",
|
|
"@testing-library/react": "^16.1.0",
|
|
"@types/node": "^20.17.10",
|
|
"@types/react": "^18.3.17",
|
|
"@types/react-dom": "^18.3.5",
|
|
"@vitejs/plugin-react": "^4.3.4",
|
|
"autoprefixer": "^10.4.20",
|
|
"jsdom": "^25.0.1",
|
|
"postcss": "^8.4.49",
|
|
"tailwindcss": "^3.4.17",
|
|
"typescript": "^5.7.2",
|
|
"vite": "^5.4.11",
|
|
"vitest": "^2.1.8"
|
|
}
|
|
}
|