demo.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import inspect
  2. import re
  3. from typing import Callable
  4. import isort
  5. from nicegui import helpers, ui
  6. from .intersection_observer import IntersectionObserver as intersection_observer
  7. from .windows import browser_window, python_window
  8. UNCOMMENT_PATTERN = re.compile(r'^(\s*)# ?')
  9. def uncomment(text: str) -> str:
  10. """non-executed lines should be shown in the code examples"""
  11. return UNCOMMENT_PATTERN.sub(r'\1', text)
  12. def demo(f: Callable) -> Callable:
  13. with ui.column().classes('w-full items-stretch gap-8 no-wrap min-[1500px]:flex-row'):
  14. code = inspect.getsource(f).split('# END OF DEMO')[0].strip().splitlines()
  15. code = [line for line in code if not line.endswith("# HIDE")]
  16. while not code[0].strip().startswith('def') and not code[0].strip().startswith('async def'):
  17. del code[0]
  18. del code[0]
  19. if code[0].strip().startswith('"""'):
  20. while code[0].strip() != '"""':
  21. del code[0]
  22. del code[0]
  23. indentation = len(code[0]) - len(code[0].lstrip())
  24. code = [line[indentation:] for line in code]
  25. code = ['from nicegui import ui'] + [uncomment(line) for line in code]
  26. code = ['' if line == '#' else line for line in code]
  27. if not code[-1].startswith('ui.run('):
  28. code.append('')
  29. code.append('ui.run()')
  30. code = isort.code('\n'.join(code), no_sections=True, lines_after_imports=1)
  31. with python_window(classes='w-full max-w-[44rem]'):
  32. def copy_code():
  33. ui.run_javascript('navigator.clipboard.writeText(`' + code + '`)')
  34. ui.notify('Copied to clipboard', type='positive', color='primary')
  35. ui.markdown(f'````python\n{code}\n````')
  36. ui.icon('content_copy', size='xs') \
  37. .classes('absolute right-2 top-10 opacity-10 hover:opacity-80 cursor-pointer') \
  38. .on('click', copy_code, [])
  39. with browser_window(title=getattr(f, 'tab', None),
  40. classes='w-full max-w-[44rem] min-[1500px]:max-w-[20rem] min-h-[10rem] browser-window') as window:
  41. spinner = ui.spinner(size='lg').props('thickness=2')
  42. async def handle_intersection():
  43. window.remove(spinner)
  44. if helpers.is_coroutine_function(f):
  45. await f()
  46. else:
  47. f()
  48. intersection_observer(on_intersection=handle_intersection)
  49. return f