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:
@@ -286,3 +286,43 @@ def test_upload_dedupes_repeated_names(client):
|
||||
pid = r.headers["location"].split("/b/")[1].rstrip("/")
|
||||
names = sorted(p.name for p in (data / pid).iterdir() if not p.name.startswith("."))
|
||||
assert names == ["shot-1.png", "shot.png"]
|
||||
|
||||
|
||||
# ---- image viewer -----------------------------------------------------------
|
||||
|
||||
|
||||
def test_image_view_renders(client):
|
||||
c, data = client
|
||||
_touch(data / "run1" / "shot.png")
|
||||
r = c.get("/b/run1/view", params={"f": "shot.png"})
|
||||
assert r.status_code == 200
|
||||
assert 'id="vstage"' in r.text # the viewer stage
|
||||
assert ">Fit<" in r.text and ">1:1<" in r.text
|
||||
assert "shot.png" in r.text
|
||||
|
||||
|
||||
def test_gallery_image_links_to_viewer(client):
|
||||
c, data = client
|
||||
_touch(data / "run1" / "shot.png")
|
||||
page = c.get("/b/run1/")
|
||||
assert "view?f=shot.png" in page.text # gallery routes images to the viewer, not the raw file
|
||||
|
||||
|
||||
def test_image_view_missing_404(client):
|
||||
c, data = client
|
||||
(data / "run1").mkdir()
|
||||
assert c.get("/b/run1/view", params={"f": "nope.png"}).status_code == 404
|
||||
|
||||
|
||||
def test_image_view_traversal_404(client):
|
||||
c, data = client
|
||||
(data / "run1").mkdir()
|
||||
assert c.get("/b/run1/view", params={"f": "../../etc/passwd"}).status_code == 404
|
||||
|
||||
|
||||
def test_image_view_nonimage_redirects_to_raw(client):
|
||||
c, data = client
|
||||
_touch(data / "run1" / "notes.txt")
|
||||
r = c.get("/b/run1/view", params={"f": "notes.txt"}, follow_redirects=False)
|
||||
assert r.status_code == 307
|
||||
assert r.headers["location"] == "/b/run1/notes.txt"
|
||||
|
||||
Reference in New Issue
Block a user