Add favicon, shortcut icon, and apple-touch-icon matching app logo
This commit is contained in:
1 parent
8a91a05c2a
commit
801008adfe
7 files changed
+106
No files matched your search
@@ -0,0 +1,78 @@
|
|||||||
|
import math
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
def create_icons(output_dir):
|
||||||
|
size = 256
|
||||||
|
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
|
||||||
|
# Draw linear gradient on rounded rectangle
|
||||||
|
# Gradient: (31, 111, 235) to (137, 87, 229)
|
||||||
|
mask = Image.new("L", (size, size), 0)
|
||||||
|
draw_mask = ImageDraw.Draw(mask)
|
||||||
|
radius = int(size * 0.24)
|
||||||
|
draw_mask.rounded_rectangle([(0, 0), (size - 1, size - 1)], radius=radius, fill=255)
|
||||||
|
|
||||||
|
grad = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||||
|
draw_grad = ImageDraw.Draw(grad)
|
||||||
|
for y in range(size):
|
||||||
|
for x in range(size):
|
||||||
|
t = (x + y) / (2 * size)
|
||||||
|
r = int(31 * (1 - t) + 137 * t)
|
||||||
|
g = int(111 * (1 - t) + 87 * t)
|
||||||
|
b = int(235 * (1 - t) + 229 * t)
|
||||||
|
draw_grad.point((x, y), fill=(r, g, b, 255))
|
||||||
|
|
||||||
|
img = Image.composite(grad, img, mask)
|
||||||
|
|
||||||
|
# Draw the white link chain icon in center
|
||||||
|
# Scale from 24x24 viewBox to fit nicely (about 130x130)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
stroke_w = int(size * 0.08)
|
||||||
|
|
||||||
|
# To draw smooth link curves, we draw at 4x and downsample
|
||||||
|
hi_size = size * 4
|
||||||
|
hi_img = Image.new("RGBA", (hi_size, hi_size), (0, 0, 0, 0))
|
||||||
|
hi_draw = ImageDraw.Draw(hi_img)
|
||||||
|
|
||||||
|
# Center = (hi_size/2, hi_size/2)
|
||||||
|
# The SVG path:
|
||||||
|
# Top-right link loop: center around (hi_size*0.58, hi_size*0.42)
|
||||||
|
# Bottom-left link loop: center around (hi_size*0.42, hi_size*0.58)
|
||||||
|
# We can draw the rounded pills rotated by 45 degrees
|
||||||
|
|
||||||
|
# Create rotated pill for upper right link
|
||||||
|
link_w = int(hi_size * 0.28)
|
||||||
|
link_h = int(hi_size * 0.52)
|
||||||
|
pill = Image.new("RGBA", (link_w, link_h), (0, 0, 0, 0))
|
||||||
|
pdraw = ImageDraw.Draw(pill)
|
||||||
|
pw = int(hi_size * 0.075)
|
||||||
|
pdraw.rounded_rectangle([(0, 0), (link_w - 1, link_h - 1)], radius=link_w // 2, outline=(255, 255, 255, 255), width=pw)
|
||||||
|
|
||||||
|
# Rotate pill 45 deg
|
||||||
|
rot_pill = pill.rotate(45, resample=Image.Resampling.BICUBIC, expand=True)
|
||||||
|
|
||||||
|
# Paste upper right link
|
||||||
|
offset_x1 = int(hi_size * 0.38)
|
||||||
|
offset_y1 = int(hi_size * 0.16)
|
||||||
|
hi_img.alpha_composite(rot_pill, (offset_x1, offset_y1))
|
||||||
|
|
||||||
|
# Paste bottom left link
|
||||||
|
offset_x2 = int(hi_size * 0.16)
|
||||||
|
offset_y2 = int(hi_size * 0.38)
|
||||||
|
hi_img.alpha_composite(rot_pill, (offset_x2, offset_y2))
|
||||||
|
|
||||||
|
# Downscale hi_img with anti-aliasing
|
||||||
|
icon_layer = hi_img.resize((size, size), Image.Resampling.LANCZOS)
|
||||||
|
img.alpha_composite(icon_layer)
|
||||||
|
|
||||||
|
# Save outputs
|
||||||
|
# 1. High-res PNG (256x256)
|
||||||
|
img.save(f"{output_dir}/favicon.png", "PNG")
|
||||||
|
img.save(f"{output_dir}/apple-touch-icon.png", "PNG")
|
||||||
|
|
||||||
|
# 2. Multi-size ICO (16, 32, 48, 64)
|
||||||
|
img.save(f"{output_dir}/favicon.ico", format="ICO", sizes=[(16, 16), (32, 32), (48, 48), (64, 64)])
|
||||||
|
print("Generated favicon.png, apple-touch-icon.png, favicon.ico successfully!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
create_icons(r"C:\Users\Chris\.gemini\antigravity\scratch\thread-ripper\thread_ripper\static")
|
||||||
@@ -115,6 +115,14 @@ def download_thread(thread_id: str, format: str):
|
|||||||
def health_check():
|
def health_check():
|
||||||
return {"status": "ok", "app": "Thread Ripper", "version": "1.0.0"}
|
return {"status": "ok", "app": "Thread Ripper", "version": "1.0.0"}
|
||||||
|
|
||||||
|
# Direct favicon endpoint for browsers requesting /favicon.ico
|
||||||
|
@app.get("/favicon.ico", include_in_schema=False)
|
||||||
|
def get_favicon():
|
||||||
|
fav_file = os.path.join(static_dir, "favicon.ico")
|
||||||
|
if os.path.exists(fav_file):
|
||||||
|
return FileResponse(fav_file)
|
||||||
|
return Response(status_code=404)
|
||||||
|
|
||||||
# Mount static frontend directory
|
# Mount static frontend directory
|
||||||
static_dir = os.path.join(os.path.dirname(__file__), "static")
|
static_dir = os.path.join(os.path.dirname(__file__), "static")
|
||||||
if os.path.exists(static_dir):
|
if os.path.exists(static_dir):
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,15 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="logo-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#1f6feb" />
|
||||||
|
<stop offset="100%" stop-color="#8957e5" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<!-- Rounded badge background -->
|
||||||
|
<rect width="64" height="64" rx="16" fill="url(#logo-grad)" />
|
||||||
|
<!-- Centered Chain/Link Icon -->
|
||||||
|
<g transform="translate(8, 8) scale(2)" fill="none" stroke="#ffffff" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
||||||
|
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 739 B |
@@ -4,6 +4,11 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Thread Ripper - Stitch Threads into Single Posts</title>
|
<title>Thread Ripper - Stitch Threads into Single Posts</title>
|
||||||
|
<!-- Favicon and Shortcut Icons matching the app logo -->
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||||
|
<link rel="alternate icon" type="image/png" href="/favicon.png">
|
||||||
|
<link rel="shortcut icon" href="/favicon.ico">
|
||||||
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
|||||||
Reference in new issue
Block a user