feat: app icon (SVG crow), static file serving, favicon

- Add corvid.svg — stylised blue crow on dark background
- Mount /static via StaticFiles in main.py
- Wire favicon in base.html
- Add aiofiles dep (required by StaticFiles)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
caoimhinr 2026-05-25 20:03:12 +02:00
parent 961fc67528
commit 2a7686f398
4 changed files with 41 additions and 0 deletions

View file

@ -3,6 +3,7 @@ from contextlib import asynccontextmanager
from fastapi import FastAPI, Request from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from .config import TICKETS_API_KEY from .config import TICKETS_API_KEY
@ -10,6 +11,7 @@ from .database import get_db
from .router import make_router from .router import make_router
_TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates") _TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), "templates")
_STATIC_DIR = os.path.join(os.path.dirname(__file__), "static")
templates = Jinja2Templates(directory=_TEMPLATE_DIR) templates = Jinja2Templates(directory=_TEMPLATE_DIR)
@ -19,6 +21,7 @@ async def lifespan(app: FastAPI):
app = FastAPI(title="Corvid", lifespan=lifespan) app = FastAPI(title="Corvid", lifespan=lifespan)
app.mount("/static", StaticFiles(directory=_STATIC_DIR), name="static")
app.include_router(make_router(api_key=TICKETS_API_KEY, get_db=get_db)) app.include_router(make_router(api_key=TICKETS_API_KEY, get_db=get_db))

36
corvid/static/corvid.svg Normal file
View file

@ -0,0 +1,36 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<!-- App background -->
<rect width="100" height="100" rx="20" fill="#0f1117"/>
<!-- Crow silhouette in brand blue, perched, facing left -->
<!-- Head -->
<circle cx="32" cy="32" r="13" fill="#4f8ef7"/>
<!-- Beak (tip points left) -->
<polygon points="8,30 32,22 32,42" fill="#4f8ef7"/>
<!-- Neck / breast — fills gap between head and body -->
<polygon points="30,42 58,44 56,70 26,58" fill="#4f8ef7"/>
<!-- Body -->
<ellipse cx="62" cy="57" rx="20" ry="13" fill="#4f8ef7"/>
<!-- Tail fan (extends right) -->
<polygon points="80,47 96,34 98,46 93,52 97,62 86,59 80,67" fill="#4f8ef7"/>
<!-- Wing secondary feathers (subtle dark fold) -->
<path d="M 56,46 C 68,50 76,58 80,66 C 70,60 60,52 56,46 Z" fill="#1a3d80" opacity="0.55"/>
<!-- Eye -->
<circle cx="27" cy="27" r="3.5" fill="#0f1117"/>
<circle cx="26" cy="26" r="1.2" fill="#6aabff" opacity="0.6"/>
<!-- Legs -->
<rect x="52" y="70" width="4" height="13" rx="2" fill="#4f8ef7"/>
<rect x="65" y="70" width="4" height="13" rx="2" fill="#4f8ef7"/>
<!-- Feet -->
<line x1="43" y1="83" x2="62" y2="83" stroke="#4f8ef7" stroke-width="3" stroke-linecap="round"/>
<line x1="57" y1="83" x2="76" y2="83" stroke="#4f8ef7" stroke-width="3" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -4,6 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Corvid{% endblock %} — Corvid</title> <title>{% block title %}Corvid{% endblock %} — Corvid</title>
<link rel="icon" type="image/svg+xml" href="/static/corvid.svg">
<style> <style>
:root { :root {
--bg: #0f1117; --bg: #0f1117;

View file

@ -15,6 +15,7 @@ dependencies = [
"alembic>=1.14", "alembic>=1.14",
"pydantic>=2.0", "pydantic>=2.0",
"jinja2>=3.1", "jinja2>=3.1",
"aiofiles>=24.1",
] ]
[project.optional-dependencies] [project.optional-dependencies]