Improve image preview controls
Browse files- backend/app.py +1 -1
- frontend/app.js +30 -0
- frontend/style.css +1 -0
backend/app.py
CHANGED
|
@@ -572,7 +572,7 @@ async def create_webp(post_id, image_url, phpsessid, page=0, kind="t"):
|
|
| 572 |
if kind == "v":
|
| 573 |
image = image.resize((max(image.width // 2, 1), max(image.height // 2, 1)))
|
| 574 |
else:
|
| 575 |
-
image.
|
| 576 |
if image.mode not in ("RGB", "RGBA"):
|
| 577 |
image = image.convert("RGB")
|
| 578 |
image.save(out, "WEBP", quality=82 if kind == "v" else 72)
|
|
|
|
| 572 |
if kind == "v":
|
| 573 |
image = image.resize((max(image.width // 2, 1), max(image.height // 2, 1)))
|
| 574 |
else:
|
| 575 |
+
image = image.resize((max(image.width // 3, 1), max(image.height // 3, 1)))
|
| 576 |
if image.mode not in ("RGB", "RGBA"):
|
| 577 |
image = image.convert("RGB")
|
| 578 |
image.save(out, "WEBP", quality=82 if kind == "v" else 72)
|
frontend/app.js
CHANGED
|
@@ -5,6 +5,7 @@ const LONG_DIGITS_RE = /\d{6,}/g
|
|
| 5 |
const PAGE_SIZE = 60
|
| 6 |
const SEARCH_PAGE_SIZE = 5
|
| 7 |
let viewerScale = 1
|
|
|
|
| 8 |
|
| 9 |
|
| 10 |
$$(".tab").forEach(tab => {
|
|
@@ -241,6 +242,8 @@ function closeViewer() {
|
|
| 241 |
$("#viewer").setAttribute("aria-hidden", "true")
|
| 242 |
$("#viewer-img").src = ""
|
| 243 |
$("#viewer-download").href = ""
|
|
|
|
|
|
|
| 244 |
}
|
| 245 |
|
| 246 |
function applyViewerZoom() {
|
|
@@ -265,6 +268,33 @@ $("#viewer-stage").addEventListener("wheel", e => {
|
|
| 265 |
viewerScale = Math.min(Math.max(viewerScale + (e.deltaY < 0 ? .15 : -.15), .25), 6)
|
| 266 |
applyViewerZoom()
|
| 267 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
window.addEventListener("keydown", e => { if (e.key === "Escape") closeViewer() })
|
| 269 |
|
| 270 |
function renderPager(id, data, exifOnly) {
|
|
|
|
| 5 |
const PAGE_SIZE = 60
|
| 6 |
const SEARCH_PAGE_SIZE = 5
|
| 7 |
let viewerScale = 1
|
| 8 |
+
let viewerDrag = null
|
| 9 |
|
| 10 |
|
| 11 |
$$(".tab").forEach(tab => {
|
|
|
|
| 242 |
$("#viewer").setAttribute("aria-hidden", "true")
|
| 243 |
$("#viewer-img").src = ""
|
| 244 |
$("#viewer-download").href = ""
|
| 245 |
+
viewerDrag = null
|
| 246 |
+
$("#viewer-stage").classList.remove("dragging")
|
| 247 |
}
|
| 248 |
|
| 249 |
function applyViewerZoom() {
|
|
|
|
| 268 |
viewerScale = Math.min(Math.max(viewerScale + (e.deltaY < 0 ? .15 : -.15), .25), 6)
|
| 269 |
applyViewerZoom()
|
| 270 |
})
|
| 271 |
+
$("#viewer-stage").addEventListener("pointerdown", e => {
|
| 272 |
+
if (e.button !== 0) return
|
| 273 |
+
const stage = $("#viewer-stage")
|
| 274 |
+
viewerDrag = {
|
| 275 |
+
x: e.clientX,
|
| 276 |
+
y: e.clientY,
|
| 277 |
+
left: stage.scrollLeft,
|
| 278 |
+
top: stage.scrollTop,
|
| 279 |
+
}
|
| 280 |
+
stage.classList.add("dragging")
|
| 281 |
+
stage.setPointerCapture(e.pointerId)
|
| 282 |
+
})
|
| 283 |
+
$("#viewer-stage").addEventListener("pointermove", e => {
|
| 284 |
+
if (!viewerDrag) return
|
| 285 |
+
const stage = $("#viewer-stage")
|
| 286 |
+
stage.scrollLeft = viewerDrag.left - e.clientX + viewerDrag.x
|
| 287 |
+
stage.scrollTop = viewerDrag.top - e.clientY + viewerDrag.y
|
| 288 |
+
})
|
| 289 |
+
$("#viewer-stage").addEventListener("pointerup", e => {
|
| 290 |
+
viewerDrag = null
|
| 291 |
+
$("#viewer-stage").classList.remove("dragging")
|
| 292 |
+
$("#viewer-stage").releasePointerCapture(e.pointerId)
|
| 293 |
+
})
|
| 294 |
+
$("#viewer-stage").addEventListener("pointercancel", () => {
|
| 295 |
+
viewerDrag = null
|
| 296 |
+
$("#viewer-stage").classList.remove("dragging")
|
| 297 |
+
})
|
| 298 |
window.addEventListener("keydown", e => { if (e.key === "Escape") closeViewer() })
|
| 299 |
|
| 300 |
function renderPager(id, data, exifOnly) {
|
frontend/style.css
CHANGED
|
@@ -86,6 +86,7 @@ input:focus, select:focus { outline: none; border-color: #6c63ff; }
|
|
| 86 |
.viewer-bar { display: flex; align-items: center; justify-content: flex-end; gap: .5rem; padding: .75rem; background: #111; border-bottom: 1px solid #333; }
|
| 87 |
#viewer-zoom { min-width: 4rem; text-align: center; color: #ccc; font-size: .85rem; }
|
| 88 |
#viewer-stage { flex: 1; overflow: auto; display: flex; align-items: flex-start; justify-content: center; padding: 1rem; }
|
|
|
|
| 89 |
#viewer-img { max-width: none; max-height: none; transform-origin: top center; transition: transform .08s ease; }
|
| 90 |
|
| 91 |
@media (max-width: 800px) {
|
|
|
|
| 86 |
.viewer-bar { display: flex; align-items: center; justify-content: flex-end; gap: .5rem; padding: .75rem; background: #111; border-bottom: 1px solid #333; }
|
| 87 |
#viewer-zoom { min-width: 4rem; text-align: center; color: #ccc; font-size: .85rem; }
|
| 88 |
#viewer-stage { flex: 1; overflow: auto; display: flex; align-items: flex-start; justify-content: center; padding: 1rem; }
|
| 89 |
+
#viewer-stage.dragging { cursor: grabbing; }
|
| 90 |
#viewer-img { max-width: none; max-height: none; transform-origin: top center; transition: transform .08s ease; }
|
| 91 |
|
| 92 |
@media (max-width: 800px) {
|