feat(booth): image viewer page with Fit/1:1, download, Esc-back (v0.1.2)
Clicking a gallery image now opens a dedicated viewer instead of dumping you on the raw file. - GET /b/<name>/view?f=<img> — full-viewport viewer (registered before the file catch-all so /view wins; non-image f 307-redirects to the raw file, traversal and missing f 404). - Fit (downscale-only) / 1:1 (natural pixels, scroll-to-pan) toggle that only appears when the image is larger than the viewport — when it already fits, Fit ≡ 1:1 so the toggle is hidden. Re-evaluates on resize. - Download button + ✕/Esc back to the gallery. Australis-themed, progressive JS (degrades to fit-only, no-JS still shows the image + download + back). - 5 new tests (34 total, all green); verified Fit/1:1/hidden-toggle states in a real browser.
This commit is contained in:
@@ -349,6 +349,31 @@ def create_app(
|
||||
},
|
||||
)
|
||||
|
||||
@app.get("/b/{name}/view", response_class=HTMLResponse)
|
||||
def booth_image_view(request: Request, name: str, f: str):
|
||||
booth = resolve_booth(name)
|
||||
try:
|
||||
target = (booth / f).resolve()
|
||||
except OSError:
|
||||
raise HTTPException(status_code=404, detail="no such file")
|
||||
if not str(target).startswith(str(booth) + os.sep) or not target.is_file():
|
||||
raise HTTPException(status_code=404, detail="no such file")
|
||||
file_url = quote(f, safe="/")
|
||||
if classify(target.name) != "image":
|
||||
# nothing to zoom on a non-image — hand back the raw file
|
||||
return RedirectResponse(url=f"/b/{quote(name, safe='')}/{file_url}", status_code=307)
|
||||
return templates.TemplateResponse(
|
||||
request,
|
||||
"view.html",
|
||||
{
|
||||
**base_ctx,
|
||||
"name": name,
|
||||
"name_url": quote(name, safe=""),
|
||||
"file": f,
|
||||
"file_url": file_url,
|
||||
},
|
||||
)
|
||||
|
||||
@app.get("/b/{name}/{filepath:path}")
|
||||
def booth_file(name: str, filepath: str):
|
||||
booth = resolve_booth(name)
|
||||
|
||||
Reference in New Issue
Block a user