main.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/env python3
  2. from typing import List
  3. import httpx
  4. from nicegui import events, ui
  5. class Lightbox:
  6. """A thumbnail gallery where each image can be clicked to enlarge.
  7. Inspired by https://lokeshdhakar.com/projects/lightbox2/.
  8. """
  9. def __init__(self) -> None:
  10. with ui.dialog().props('maximized').classes('bg-black') as self.dialog:
  11. ui.keyboard(self._handle_key)
  12. self.large_image = ui.image().props('no-spinner fit=scale-down')
  13. self.image_list: List[str] = []
  14. def add_image(self, thumb_url: str, orig_url: str) -> ui.image:
  15. """Place a thumbnail image in the UI and make it clickable to enlarge."""
  16. self.image_list.append(orig_url)
  17. with ui.button(on_click=lambda: self._open(orig_url)).props('flat dense square'):
  18. return ui.image(thumb_url)
  19. def _handle_key(self, event_args: events.KeyEventArguments) -> None:
  20. if not event_args.action.keydown:
  21. return
  22. if event_args.key.escape:
  23. self.dialog.close()
  24. image_index = self.image_list.index(self.large_image.source)
  25. if event_args.key.arrow_left and image_index > 0:
  26. self._open(self.image_list[image_index - 1])
  27. if event_args.key.arrow_right and image_index < len(self.image_list) - 1:
  28. self._open(self.image_list[image_index + 1])
  29. def _open(self, url: str) -> None:
  30. self.large_image.set_source(url)
  31. self.dialog.open()
  32. @ui.page('/')
  33. async def page():
  34. lightbox = Lightbox()
  35. async with httpx.AsyncClient() as client: # using async httpx instead of sync requests to avoid blocking the event loop
  36. images = await client.get('https://picsum.photos/v2/list?page=4&limit=30')
  37. with ui.row().classes('w-full'):
  38. for image in images.json(): # picsum returns a list of images as json data
  39. # we can use the image ID to construct the image URLs
  40. image_base_url = f'https://picsum.photos/id/{image["id"]}'
  41. # the lightbox allows us to add images which can be opened in a full screen dialog
  42. lightbox.add_image(
  43. thumb_url=f'{image_base_url}/300/200',
  44. orig_url=f'{image_base_url}/{image["width"]}/{image["height"]}',
  45. ).classes('w-[300px] h-[200px]')
  46. ui.run()