Use ⚔ emoji glyph for PWA icons matching the brand.

Adds monochrome manifest icon for Android themed icons and a script to regenerate PNGs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-20 11:22:26 +02:00
parent 1083dfdf2c
commit 2532531110
8 changed files with 82 additions and 34 deletions
+1
View File
@@ -71,6 +71,7 @@ PWA_MANIFEST = {
{"src": "/static/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any"},
{"src": "/static/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any"},
{"src": "/static/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable"},
{"src": "/static/icon-monochrome.png", "sizes": "512x512", "type": "image/png", "purpose": "monochrome"},
],
}
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""Generate PWA icons from the ⚔ (U+2694) brand glyph."""
from __future__ import annotations
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
ROOT = Path(__file__).resolve().parent.parent
STATIC = ROOT / "static"
FONT = "/usr/share/fonts/google-noto-emoji-fonts/NotoEmoji-Regular.ttf"
GLYPH = "\u2694"
BG = (0x1A, 0x1D, 0x27, 255)
FG = (0xE8, 0xEA, 0xF0, 255)
def _draw(size: int, *, transparent: bool = False) -> Image.Image:
bg = (0, 0, 0, 0) if transparent else BG
img = Image.new("RGBA", (size, size), bg)
draw = ImageDraw.Draw(img)
font_size = int(size * 0.63)
font = ImageFont.truetype(FONT, font_size)
bbox = draw.textbbox((0, 0), GLYPH, font=font)
tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
x = (size - tw) // 2 - bbox[0]
y = (size - th) // 2 - bbox[1]
color = (255, 255, 255, 255) if transparent else FG
draw.text((x, y), GLYPH, font=font, fill=color)
return img
def main() -> None:
_draw(512).save(STATIC / "icon-512.png")
_draw(192).save(STATIC / "icon-192.png")
_draw(512, transparent=True).save(STATIC / "icon-monochrome.png")
print("Wrote icon-192.png, icon-512.png, icon-monochrome.png")
if __name__ == "__main__":
main()
+18 -15
View File
@@ -1,18 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none" stroke="#e8eaf0" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round">
<rect width="32" height="32" rx="6" fill="#1a1d27"/>
<g transform="translate(16 16)">
<g transform="rotate(-45)">
<rect x="-1.1" y="-10.5" width="2.2" height="14" rx="0.6" fill="#6c8cff"/>
<rect x="-2.6" y="3" width="5.2" height="1" rx="0.3" fill="#8ba4ff"/>
<rect x="-0.9" y="4" width="1.8" height="2.8" rx="0.4" fill="#4a62b3"/>
<circle cx="0" cy="7.4" r="1" fill="#6c8cff"/>
</g>
<g transform="rotate(45)">
<rect x="-1.1" y="-10.5" width="2.2" height="14" rx="0.6" fill="#6c8cff"/>
<rect x="-2.6" y="3" width="5.2" height="1" rx="0.3" fill="#8ba4ff"/>
<rect x="-0.9" y="4" width="1.8" height="2.8" rx="0.4" fill="#4a62b3"/>
<circle cx="0" cy="7.4" r="1" fill="#6c8cff"/>
</g>
<circle cx="0" cy="0" r="1.5" fill="#8ba4ff"/>
<g transform="translate(16 16) rotate(-45)">
<path d="M0 -9.5 L0 4.5"/>
<path d="M0 -9.5 L0 -4.5" stroke-width="0.5"/>
<path d="M-2.2 4.5 Q0 3 2.2 4.5"/>
<path d="M-0.6 4.5 L-0.6 7.5"/>
<path d="M0.6 4.5 L0.6 7.5"/>
<path d="M-0.6 5.8 L0.6 5.8" stroke-width="0.5"/>
<circle cx="0" cy="8.4" r="0.9" fill="#e8eaf0" stroke="none"/>
</g>
<g transform="translate(16 16) rotate(45)">
<path d="M0 -9.5 L0 4.5"/>
<path d="M0 -9.5 L0 -4.5" stroke-width="0.5"/>
<path d="M-2.2 4.5 Q0 3 2.2 4.5"/>
<path d="M-0.6 4.5 L-0.6 7.5"/>
<path d="M0.6 4.5 L0.6 7.5"/>
<path d="M-0.6 5.8 L0.6 5.8" stroke-width="0.5"/>
<circle cx="0" cy="8.4" r="0.9" fill="#e8eaf0" stroke="none"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 949 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+20 -18
View File
@@ -1,21 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="none" stroke="#e8eaf0" stroke-width="14" stroke-linecap="round" stroke-linejoin="round">
<rect width="512" height="512" fill="#1a1d27"/>
<rect x="20" y="20" width="472" height="472" rx="104" fill="#232735"/>
<g transform="translate(256 256)">
<g transform="rotate(-45)">
<rect x="-18" y="-168" width="36" height="228" rx="10" fill="#6c8cff"/>
<rect x="-42" y="48" width="84" height="16" rx="5" fill="#8ba4ff"/>
<rect x="-14" y="64" width="28" height="44" rx="6" fill="#4a62b3"/>
<circle cx="0" cy="118" r="16" fill="#6c8cff"/>
</g>
<g transform="rotate(45)">
<rect x="-18" y="-168" width="36" height="228" rx="10" fill="#6c8cff"/>
<rect x="-42" y="48" width="84" height="16" rx="5" fill="#8ba4ff"/>
<rect x="-14" y="64" width="28" height="44" rx="6" fill="#4a62b3"/>
<circle cx="0" cy="118" r="16" fill="#6c8cff"/>
</g>
<circle cx="0" cy="0" r="24" fill="#4a62b3"/>
<circle cx="0" cy="0" r="14" fill="#8ba4ff"/>
<g transform="translate(256 256) rotate(-45)">
<path d="M0 -150 L0 70"/>
<path d="M0 -150 L0 -70" stroke-width="6"/>
<path d="M-36 70 Q0 46 36 70"/>
<path d="M-10 70 L-10 118"/>
<path d="M10 70 L10 118"/>
<path d="M-10 90 L10 90" stroke-width="6"/>
<path d="M-10 104 L10 104" stroke-width="6"/>
<circle cx="0" cy="132" r="14" fill="#e8eaf0" stroke="none"/>
</g>
<g transform="translate(256 256) rotate(45)">
<path d="M0 -150 L0 70"/>
<path d="M0 -150 L0 -70" stroke-width="6"/>
<path d="M-36 70 Q0 46 36 70"/>
<path d="M-10 70 L-10 118"/>
<path d="M10 70 L10 118"/>
<path d="M-10 90 L10 90" stroke-width="6"/>
<path d="M-10 104 L10 104" stroke-width="6"/>
<circle cx="0" cy="132" r="14" fill="#e8eaf0" stroke="none"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 979 B

After

Width:  |  Height:  |  Size: 1009 B

+2 -1
View File
@@ -1,9 +1,10 @@
const CACHE = "if-viewer-static-v2";
const CACHE = "if-viewer-static-v3";
const ASSETS = [
"/static/style.css",
"/static/favicon.svg",
"/static/icon-192.png",
"/static/icon-512.png",
"/static/icon-monochrome.png",
"/static/i18n.js",
"/static/locales/en.json",
"/static/locales/de.json",