generated from john/python-template
Removed the image viewer which wasn't working anyway.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Media viewer components for high-contrast image inspection."""
|
||||
"""Simple media display components."""
|
||||
|
||||
from nicegui import ui
|
||||
|
||||
@@ -9,116 +9,14 @@ def dark_room_viewer(
|
||||
*,
|
||||
container_height: str = "500px",
|
||||
) -> None:
|
||||
"""Isolated high-contrast container for image inspection with pan and zoom capabilities."""
|
||||
with ui.card().classes("ui-bg-viewer ui-border-viewer rounded-sm p-3 flex flex-col justify-between w-full"):
|
||||
# Viewer Header Bar
|
||||
with ui.row().classes("w-full justify-between items-center mb-2 ui-text-inverse text-xs"):
|
||||
ui.label("SOURCE MEDIA VIEWER").classes("font-mono font-bold tracking-wider")
|
||||
ui.label(count_label).classes("ui-text-accent")
|
||||
"""Render a plain responsive image that fills available width."""
|
||||
del count_label
|
||||
|
||||
# Interactive Pan/Zoom Canvas Area
|
||||
if image_path:
|
||||
# Container with fixed height and hidden overflow for contained panning/zooming
|
||||
with ui.element("div").classes(
|
||||
"relative w-full overflow-hidden border ui-border-viewer ui-bg-viewer-overlay rounded-sm flex items-center justify-center cursor-grab active:cursor-grabbing"
|
||||
).style(f"height: {container_height};") as viewport:
|
||||
if image_path:
|
||||
ui.image(image_path).classes("w-full rounded-sm block").style("height: auto;")
|
||||
return
|
||||
|
||||
# Image element targeted by client-side pan/zoom JS
|
||||
img = (
|
||||
ui.image(image_path)
|
||||
.classes("max-h-full max-w-full select-none transition-transform duration-75 ease-out")
|
||||
.style("transform-origin: center center;")
|
||||
)
|
||||
|
||||
viewer_key = str(img.id)
|
||||
|
||||
# Client-side JavaScript state management for smooth panning and scaling
|
||||
js_pan_zoom = f"""
|
||||
(() => {{
|
||||
const viewport = document.getElementById('{viewport.id}');
|
||||
const img = document.getElementById('{img.id}');
|
||||
if (!viewport || !img) return;
|
||||
|
||||
let scale = 1;
|
||||
let pointX = 0;
|
||||
let pointY = 0;
|
||||
let startX = 0;
|
||||
let startY = 0;
|
||||
let isDragging = false;
|
||||
|
||||
function updateTransform() {{
|
||||
img.style.transform = `translate(${{pointX}}px, ${{pointY}}px) scale(${{scale}})`;
|
||||
}}
|
||||
|
||||
function zoomIn() {{
|
||||
scale = Math.min(scale * 1.25, 8);
|
||||
updateTransform();
|
||||
}}
|
||||
|
||||
function zoomOut() {{
|
||||
scale = Math.max(scale / 1.25, 0.5);
|
||||
updateTransform();
|
||||
}}
|
||||
|
||||
function resetZoom() {{
|
||||
scale = 1;
|
||||
pointX = 0;
|
||||
pointY = 0;
|
||||
updateTransform();
|
||||
}}
|
||||
|
||||
viewport.addEventListener('wheel', (e) => {{
|
||||
e.preventDefault();
|
||||
const delta = -e.deltaY;
|
||||
if (delta > 0) zoomIn();
|
||||
else zoomOut();
|
||||
}}, {{ passive: false }});
|
||||
|
||||
viewport.addEventListener('mousedown', (e) => {{
|
||||
e.preventDefault();
|
||||
startX = e.clientX - pointX;
|
||||
startY = e.clientY - pointY;
|
||||
isDragging = true;
|
||||
}});
|
||||
|
||||
window.addEventListener('mouseup', () => {{
|
||||
isDragging = false;
|
||||
}});
|
||||
|
||||
viewport.addEventListener('mousemove', (e) => {{
|
||||
if (!isDragging) return;
|
||||
e.preventDefault();
|
||||
pointX = e.clientX - startX;
|
||||
pointY = e.clientY - startY;
|
||||
updateTransform();
|
||||
}});
|
||||
|
||||
window.__darkRoomViewer = window.__darkRoomViewer || {{}};
|
||||
window.__darkRoomViewer['{viewer_key}'] = {{ zoomIn, zoomOut, resetZoom }};
|
||||
}})();
|
||||
"""
|
||||
ui.run_javascript(js_pan_zoom)
|
||||
|
||||
# Control Toolbar
|
||||
with ui.row().classes("w-full justify-center items-center gap-2 mt-2 pt-2 border-t ui-border-viewer"):
|
||||
ui.button(
|
||||
icon="zoom_in",
|
||||
on_click=lambda: ui.run_javascript(f"window.__darkRoomViewer?.['{viewer_key}']?.zoomIn?.()"),
|
||||
).props("flat round dense color=white text-xs").tooltip("Zoom In")
|
||||
|
||||
ui.button(
|
||||
icon="zoom_out",
|
||||
on_click=lambda: ui.run_javascript(f"window.__darkRoomViewer?.['{viewer_key}']?.zoomOut?.()"),
|
||||
).props("flat round dense color=white text-xs").tooltip("Zoom Out")
|
||||
|
||||
ui.button(
|
||||
icon="center_focus_strong",
|
||||
on_click=lambda: ui.run_javascript(f"window.__darkRoomViewer?.['{viewer_key}']?.resetZoom?.()"),
|
||||
).props("flat round dense color=white text-xs").tooltip("Reset View")
|
||||
|
||||
else:
|
||||
# Fallback state when no image source is linked
|
||||
with ui.column().classes(
|
||||
"w-full flex-grow items-center justify-center border ui-border-viewer ui-bg-viewer-overlay-soft rounded-sm p-8"
|
||||
).style(f"min-height: {container_height};"):
|
||||
ui.label("No source media available for inspection.").classes("ui-text-muted text-xs italic")
|
||||
with ui.column().classes(
|
||||
"w-full items-center justify-center border ui-border-viewer ui-bg-viewer-overlay-soft rounded-sm p-8"
|
||||
).style(f"min-height: {container_height};"):
|
||||
ui.label("No source media available for inspection.").classes("ui-text-muted text-xs italic")
|
||||
@@ -421,7 +421,7 @@ def _render_document_form_fields(
|
||||
|
||||
|
||||
def _render_bento_viewer_zone(document: Document) -> None:
|
||||
with ui.column().classes("col-span-12 lg:col-span-5"):
|
||||
with ui.column().classes("col-span-12 lg:col-span-4"):
|
||||
source_path = document.sources[0].file_path if document.sources else None
|
||||
dark_room_viewer(source_path, count_label=f"{len(document.sources)} Source(s) Linked")
|
||||
with ui.row().classes("w-full justify-between items-center mt-2"):
|
||||
@@ -450,7 +450,7 @@ def _render_bento_metadata_zone(document: Document) -> None:
|
||||
|
||||
|
||||
def _render_bento_relations_zone(document: Document) -> None:
|
||||
with ui.column().classes("col-span-12 lg:col-span-3 gap-4"):
|
||||
with ui.column().classes("col-span-12 lg:col-span-4 gap-4"):
|
||||
with archival_card(title="Related People"):
|
||||
if not document.document_people:
|
||||
render_empty_state("No linked people yet.", italic=True)
|
||||
|
||||
@@ -218,7 +218,7 @@ def register_page() -> None:
|
||||
|
||||
|
||||
def _render_source_viewer_zone(source: Source, *, settings: Settings, request: Request) -> None:
|
||||
with ui.column().classes("col-span-12 lg:col-span-6"):
|
||||
with ui.column().classes("col-span-12 lg:col-span-4"):
|
||||
dark_room_viewer(
|
||||
_resolve_source_media_src(source.file_path, settings=settings, request=request),
|
||||
count_label=f"Page {source.page_number}",
|
||||
@@ -232,7 +232,7 @@ def _render_source_transcription_column(
|
||||
latest_job_source: JobSource | None,
|
||||
sources_service: TranscriptionService,
|
||||
) -> None:
|
||||
with ui.column().classes("col-span-12 lg:col-span-3 gap-4"):
|
||||
with ui.column().classes("col-span-12 lg:col-span-4 gap-4"):
|
||||
_render_source_transcription_zone(
|
||||
source=source,
|
||||
original_transcription=original_transcription,
|
||||
@@ -242,7 +242,7 @@ def _render_source_transcription_column(
|
||||
|
||||
|
||||
def _render_source_metadata_column(*, source: Source, latest_job_source: JobSource | None) -> None:
|
||||
with ui.column().classes("col-span-12 lg:col-span-3 gap-4"):
|
||||
with ui.column().classes("col-span-12 lg:col-span-4 gap-4"):
|
||||
_render_source_metadata_zone(source)
|
||||
_render_source_job_metadata_zone(latest_job_source)
|
||||
_render_source_revision_logistics_zone(source)
|
||||
|
||||
Reference in New Issue
Block a user