main.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #!/usr/bin/env python3
  2. from pathlib import Path
  3. import docutils.core
  4. from pygments.formatters import HtmlFormatter
  5. from nicegui import Client, ui
  6. from website import demo_card, reference
  7. from website.constants import ACCENT_COLOR, HEADER_HEIGHT, STATIC
  8. from website.example import bash_window, browser_window, python_window
  9. ui.add_static_files('/favicon', Path(__file__).parent / 'website' / 'favicon')
  10. def add_head_html() -> None:
  11. ui.add_head_html('<meta name="viewport" content="width=device-width, initial-scale=1" />')
  12. ui.add_head_html(docutils.core.publish_parts('', writer_name='html')['stylesheet'])
  13. ui.add_head_html(f'<style>{HtmlFormatter(nobackground=True).get_style_defs(".codehilite")}</style>')
  14. ui.add_head_html('''
  15. <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
  16. <link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
  17. <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
  18. <link rel="manifest" href="/favicon/site.webmanifest">
  19. <link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#000000">
  20. <link rel="shortcut icon" href="/favicon/favicon.ico">
  21. <meta name="msapplication-TileColor" content="#ffffff">
  22. <meta name="msapplication-config" content="/favicon/browserconfig.xml">
  23. <meta name="theme-color" content="#ffffff">
  24. ''') # https://realfavicongenerator.net/
  25. ui.add_head_html(f'''
  26. <style>
  27. html {{
  28. scroll-behavior: smooth;
  29. }}
  30. body {{
  31. background-color: #f8f8f8;
  32. }}
  33. em {{
  34. font-style: normal;
  35. color: {ACCENT_COLOR};
  36. }}
  37. a:hover {{
  38. opacity: 0.9;
  39. }}
  40. </style>
  41. ''')
  42. ui.add_head_html(f'''
  43. <style>
  44. .q-header {{
  45. height: calc({HEADER_HEIGHT} + 20px);
  46. background-color: {ACCENT_COLOR};
  47. }}
  48. .q-header.fade {{
  49. height: {HEADER_HEIGHT};
  50. background-color: {ACCENT_COLOR}d0;
  51. backdrop-filter: blur(5px);
  52. }}
  53. </style>
  54. <script>
  55. window.onscroll = () => {{
  56. const header = document.querySelector(".q-header");
  57. if (document.documentElement.scrollTop > 50)
  58. header.classList.add("fade");
  59. else
  60. header.classList.remove("fade");
  61. }};
  62. </script>
  63. ''')
  64. def add_header() -> None:
  65. with ui.header() \
  66. .classes('items-center duration-200 px-4', remove='q-pa-md') \
  67. .style('box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1)'):
  68. ui.html((STATIC / 'happy_face.svg').read_text()).classes('w-8 stroke-white')
  69. with ui.link(target=index_page):
  70. ui.html((STATIC / 'nicegui_word.svg').read_text()).classes('w-24')
  71. with ui.row().classes('items-center ml-auto'):
  72. ui.link('Features', '/#features').classes(replace='text-lg text-white')
  73. ui.link('Installation', '/#installation').classes(replace='text-lg text-white')
  74. ui.link('Examples', '/#examples').classes(replace='text-lg text-white')
  75. ui.link('API Reference', reference_page).classes(replace='text-lg text-white')
  76. with ui.link(target='https://github.com/zauberzeug/nicegui/'):
  77. ui.html((STATIC / 'github.svg').read_text()).classes('fill-white scale-125 m-1')
  78. @ui.page('/')
  79. async def index_page(client: Client):
  80. client.content.classes(remove='q-pa-md gap-4')
  81. add_head_html()
  82. add_header()
  83. with ui.row() \
  84. .classes('w-full h-screen q-pa-md items-center gap-12 no-wrap') \
  85. .style(f'transform: translateX(-250px)'):
  86. ui.html((STATIC / 'happy_face.svg').read_text()).classes('stroke-black').style('width: 500px')
  87. with ui.column().classes('gap-8'):
  88. ui.html('Meet the <em>NiceGUI</em>.') \
  89. .style('font-size: 400%; line-height: 0.9; font-weight: 500')
  90. ui.markdown('And let every browser be the frontend\n\nof your Python code.') \
  91. .style('font-size: 200%; line-height: 0.9')
  92. with ui.row() \
  93. .classes('w-full h-screen q-pa-md items-center gap-28 p-32 no-wrap') \
  94. .style(f'background: {ACCENT_COLOR}'):
  95. with ui.column().classes('gap-6'):
  96. ui.markdown('Interact with buttons, dialogs, 3D scenes, plots and much more.') \
  97. .style('font-size: 300%; color: white; line-height: 0.9; font-weight: 500').classes('mb-4')
  98. ui.label('''
  99. NiceGUI handles all the web development details for you.
  100. So you can focus Python code that needs a user interface.
  101. Anything from short scripts and dashboards to full robotics projects, IoT solutions,
  102. smart home automations and machine learning projects can benefit from having all code in one place.
  103. ''').style('font-size: 150%; color: white').classes('leading-tight')
  104. with ui.row().style('font-size: 150%; color: white').classes('leading-tight gap-2'):
  105. ui.html('''
  106. Available as
  107. <a href="https://pypi.org/project/nicegui/"><strong>PyPI package</strong><span class="material-icons">north_east</span></a>,
  108. <a href="https://hub.docker.com/r/zauberzeug/nicegui"><strong>Docker image</strong><span class="material-icons">north_east</span></a> and on
  109. <a href="https://github.com/zauberzeug/nicegui"><strong>GitHub</strong><span class="material-icons">north_east</span></a>.
  110. ''')
  111. demo_card.create()
  112. ui.link_target('features').style(f'position: relative; top: -{HEADER_HEIGHT}')
  113. with ui.column().classes('w-full q-pa-xl q-mb-xl'):
  114. ui.label('Features').classes('text-bold text-lg')
  115. ui.html('Do it the <em>nice</em> way') \
  116. .style('font-size: 300%; font-weight: 500; margin-top: -20px')
  117. with ui.row().classes('w-full no-wrap text-lg leading-tight justify-between'):
  118. with ui.column().classes('gap-1'):
  119. ui.label('User Interface').classes('text-bold mb-4')
  120. ui.markdown('- common elements like label, button, checkbox, switch, slider, input, ...')
  121. ui.markdown('- page layout with navigation bars, tabs, panels, ...')
  122. ui.markdown('- grouping with rows, columns, cards and dialogs')
  123. ui.markdown('- HTML and markdown elements')
  124. ui.markdown('- high-level elements like charts, tables, trees, 3D scenes, joystick, ...')
  125. ui.markdown('- built-in timer to refresh data in intervals')
  126. ui.markdown('- notifications, dialogs and menus')
  127. ui.markdown('- keyboard input')
  128. with ui.column().classes('gap-1'):
  129. ui.label('Under the hood').classes('text-bold mb-4')
  130. ui.markdown('- browser-based graphical user interface')
  131. ui.markdown('- based on FastAPI and Uvicorn')
  132. ui.markdown('- live-cycle events and session data')
  133. ui.markdown('- customizable page layout and colors')
  134. with ui.column().classes('gap-1'):
  135. ui.label('Development').classes('text-bold mb-4')
  136. ui.markdown('- implicit reload on code change')
  137. ui.markdown('- straight-forward data binding')
  138. ui.link_target('installation').style(f'position: relative; top: -{HEADER_HEIGHT}')
  139. with ui.column().classes('w-full q-pa-xl q-mb-xl'):
  140. ui.label('Installation').classes('text-bold text-lg')
  141. ui.html('Get <em>started</em>') \
  142. .style('font-size: 300%; font-weight: 500; margin-top: -20px')
  143. with ui.row().classes('w-full no-wrap text-lg leading-tight'):
  144. with ui.column().classes('w-1/3 gap-2'):
  145. ui.html('<em>1.</em>').classes('text-3xl text-bold')
  146. ui.markdown('Install').classes('text-lg')
  147. with bash_window().classes('w-full h-52'):
  148. ui.markdown('```bash\npython3 -m pip install nicegui\n```')
  149. with ui.column().classes('w-1/3 gap-2'):
  150. ui.html('<em>2.</em>').classes('text-3xl text-bold')
  151. ui.markdown('Write file __main.py__').classes('text-lg')
  152. with python_window().classes('w-full h-52'):
  153. ui.markdown('''```python\n
  154. from nicegui import ui
  155. ui.label('Hello NiceGUI!')
  156. ui.run()
  157. ```''')
  158. with ui.column().classes('w-1/3 gap-2'):
  159. ui.html('<em>3.</em>').classes('text-3xl text-bold')
  160. ui.markdown('Launch it with').classes('text-lg')
  161. with bash_window().classes('w-full h-52'):
  162. ui.markdown('```bash\npython3 main.py\n```')
  163. with ui.column().classes('w-1/3 gap-2'):
  164. ui.html('<em>4.</em>').classes('text-3xl text-bold')
  165. ui.markdown('Enjoy').classes('text-lg')
  166. with browser_window().classes('w-full h-52'):
  167. ui.label('Hello NiceGUI!')
  168. ui.link_target('examples').style(f'position: relative; top: -{HEADER_HEIGHT}')
  169. with ui.column().classes('w-full q-pa-xl q-mb-xl'):
  170. ui.label('Examples').classes('text-bold text-lg')
  171. ui.html('Try <em>this</em> out') \
  172. .style('font-size: 300%; font-weight: 500; margin-top: -20px')
  173. reference.create_intro()
  174. with ui.row() \
  175. .classes('w-full items-center gap-28 px-32 py-16 no-wrap') \
  176. .style(f'background: {ACCENT_COLOR}'):
  177. with ui.column().classes('gap-4'):
  178. ui.markdown('Go to the API reference to see a ton of live examples.') \
  179. .style('font-size: 220%; color: white; line-height: 0.9; font-weight: 500')
  180. ui.html('Fun-Fact: The whole page here is coded with NiceGUI itself.') \
  181. .style('font-size: 150%; color: white')
  182. ui.link('API reference', '/reference') \
  183. .classes('rounded-full mx-auto px-12 py-2 text-xl text-bold bg-white')
  184. with ui.column().classes('w-full q-pa-xl q-mb-xl'):
  185. ui.label('In-depth demonstrations').classes('text-bold text-lg')
  186. ui.html('Pick your <em>solution</em>') \
  187. .style('font-size: 300%; font-weight: 500; margin-top: -20px')
  188. with ui.row().classes('w-full no-wrap text-lg leading-tight'):
  189. with ui.column().classes('w-1/3'):
  190. example_link('Slideshow', 'implements a keyboard-controlled image slideshow')
  191. example_link('Authentication', 'shows how to use sessions to build a login screen')
  192. example_link(
  193. 'Modularization',
  194. 'provides an example of how to modularize your application into multiple files and reuse code')
  195. example_link(
  196. 'FastAPI',
  197. 'illustrates the integration of NiceGUI with an existing FastAPI application')
  198. with ui.column().classes('w-1/3'):
  199. example_link(
  200. 'Map',
  201. 'demonstrates wrapping the JavaScript library leaflet to display a map at specific locations')
  202. example_link(
  203. 'AI Interface',
  204. 'utilizes the great [replicate](https://replicate.com) library to perform voice-to-text transcription and generate images from prompts with Stable Diffusion')
  205. example_link('3D Scene', 'creates a webGL view and loads an STL mesh illuminated with a spotlight')
  206. with ui.column().classes('w-1/3'):
  207. example_link('Custom Vue Component', 'shows how to write and integrate a custom vue component')
  208. example_link('Image Mask Overlay', 'shows how to overlay an image with a mask')
  209. example_link('Infinite Scroll', 'presents an infinitely scrolling image gallery')
  210. with ui.row() \
  211. .classes('w-full h-screen q-pa-md items-center gap-28 p-32 no-wrap') \
  212. .style(f'background: {ACCENT_COLOR}'):
  213. with ui.column().classes('gap-6'):
  214. ui.markdown('Why?') \
  215. .style('font-size: 300%; color: white; line-height: 0.9; font-weight: 500').classes('mb-4')
  216. ui.html('''
  217. We like
  218. <strong><a href="https://streamlit.io/">Streamlit</a></strong>
  219. but find it does
  220. <strong><a href="https://github.com/zauberzeug/nicegui/issues/1#issuecomment-847413651">too much magic</a></strong>
  221. when it comes to state handling.
  222. In search for an alternative nice library to write simple graphical user interfaces in Python we discovered
  223. <strong><a href="https://justpy.io/">JustPy</a></strong>.
  224. Although we liked the approach, it is too "low-level HTML" for our daily usage.
  225. But it inspired us to use
  226. <strong><a href="https://vuejs.org/">Vue</a></strong>
  227. and
  228. <strong><a href="https://quasar.dev/">Quasar</a></strong>
  229. for the frontend.<br/>
  230. We have build on top of
  231. <strong><a href="https://fastapi.tiangolo.com/">FastAPI</a></strong>,
  232. which itself is based on the ASGI framework
  233. <strong><a href="https://www.starlette.io/">Starlette</a></strong>,
  234. and the ASGI webserver
  235. <strong><a href="https://www.uvicorn.org/">Uvicorn</a></strong>
  236. because of their great performance and ease of use.
  237. ''').style('font-size: 150%; color: white').classes('leading-tight')
  238. ui.html((STATIC / 'happy_face.svg').read_text()).classes('stroke-white').style('width: 1500px')
  239. def example_link(title: str, description: str) -> None:
  240. name = title.lower().replace(' ', '_')
  241. with ui.column().classes('gap-0'):
  242. ui.link(title, f'https://github.com/zauberzeug/nicegui/tree/main/examples/{name}/main.py') \
  243. .classes(replace='text-black text-bold')
  244. ui.markdown(description)
  245. @ui.page('/reference')
  246. def reference_page():
  247. add_head_html()
  248. add_header()
  249. reference.create_full()
  250. ui.run()