demo.py 1.7 KB

123456789101112131415161718192021222324252627282930313233343536
  1. from typing import Callable, Optional, Union
  2. from nicegui import helpers, json, ui
  3. from .code_extraction import get_full_code
  4. from .intersection_observer import IntersectionObserver as intersection_observer
  5. from .windows import browser_window, python_window
  6. def demo(f: Callable, *, lazy: bool = True, tab: Optional[Union[str, Callable]] = None) -> Callable:
  7. """Render a callable as a demo with Python code and browser window."""
  8. with ui.column().classes('w-full items-stretch gap-8 no-wrap min-[1500px]:flex-row'):
  9. full_code = get_full_code(f)
  10. with python_window(classes='w-full max-w-[44rem]'):
  11. ui.markdown(f'````python\n{full_code}\n````')
  12. ui.icon('content_copy', size='xs') \
  13. .classes('absolute right-2 top-10 opacity-10 hover:opacity-80 cursor-pointer') \
  14. .on('click', js_handler=f'() => navigator.clipboard.writeText({json.dumps(full_code)})') \
  15. .on('click', lambda: ui.notify('Copied to clipboard', type='positive', color='primary'), [])
  16. with browser_window(title=tab,
  17. classes='w-full max-w-[44rem] min-[1500px]:max-w-[20rem] min-h-[10rem] browser-window') as window:
  18. if lazy:
  19. spinner = ui.spinner(size='lg').props('thickness=2')
  20. async def handle_intersection():
  21. window.remove(spinner)
  22. if helpers.is_coroutine_function(f):
  23. await f()
  24. else:
  25. f()
  26. intersection_observer(on_intersection=handle_intersection)
  27. else:
  28. assert not helpers.is_coroutine_function(f), 'async functions are not supported in non-lazy demos'
  29. f()
  30. return f