theme.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. from functools import partial
  2. from pywebio import start_server, config
  3. from pywebio.input import *
  4. from pywebio.output import *
  5. from pywebio.pin import *
  6. from pywebio.session import *
  7. def pin_widgets():
  8. put_markdown("# Pin widget")
  9. options = [
  10. {
  11. "label": "Option one",
  12. "value": 1,
  13. "selected": True,
  14. },
  15. {
  16. "label": "Option two",
  17. "value": 2,
  18. },
  19. {
  20. "label": "Disabled option",
  21. "value": 3,
  22. "disabled": True
  23. }
  24. ]
  25. put_input('input', label='Text input', placeholder="Enter email",
  26. help_text="We'll never share your email with anyone else.")
  27. put_input('valid_input', label="Valid input", value="correct value")
  28. put_input('invalid_input', label="Invalid input", value="wrong value")
  29. put_textarea('textarea', label='Textarea', rows=3, maxlength=10, minlength=20, value=None,
  30. placeholder='This is placeholder message', readonly=False)
  31. put_textarea('code', label='Code area', rows=4, code={'mode': 'python'},
  32. value='import pywebio\npywebio.output.put_text("hello world")')
  33. put_select('select', options=options, label='Select')
  34. put_select('select_multiple', options=options, label='Multiple select', multiple=True, value=None)
  35. put_checkbox('checkbox', options=options, label='Checkbox', inline=False, value=None)
  36. put_checkbox('checkbox_inline', options=options, label='Inline checkbox', inline=True, value=None)
  37. put_radio('radio', options=options, label='Radio', inline=False, value=None)
  38. put_radio('radio_inline', options=options, label='Inline radio', inline=True, value='B')
  39. put_slider('slider', label='Slider')
  40. put_actions('actions', buttons=[
  41. {'label': 'Submit', 'value': '1'},
  42. {'label': 'Warning', 'value': '2', 'color': 'warning'},
  43. {'label': 'Danger', 'value': '3', 'color': 'danger'},
  44. ], label='Actions')
  45. pin_update('valid_input', valid_status=True, valid_feedback="Success! You've done it.")
  46. pin_update('invalid_input', valid_status=False, invalid_feedback="Sorry, that username's taken. Try another?")
  47. def form():
  48. options = [
  49. {
  50. "label": "Option one",
  51. "value": 1,
  52. "selected": True,
  53. },
  54. {
  55. "label": "Option two",
  56. "value": 2,
  57. },
  58. {
  59. "label": "Disabled option",
  60. "value": 3,
  61. "disabled": True
  62. }
  63. ]
  64. input_group('Input group', [
  65. input('Text', type=TEXT, datalist=['candidate-%s' % i for i in range(10)], name='text', required=True,
  66. help_text='Required'),
  67. input('Number', type=NUMBER, value="42", name='number'),
  68. input('Float', type=FLOAT, name='float'),
  69. input('Password', type=PASSWORD, name='password'),
  70. textarea('Textarea', rows=3, maxlength=20, name='textarea',
  71. placeholder="The maximum number of characters you can input is 20"),
  72. textarea('Code', name='code', code={'mode': 'python'},
  73. value='import pywebio\npywebio.output.put_text("hello world")'),
  74. select('Multiple select', options, name='select-multiple', multiple=True),
  75. select('Select', options, name='select'),
  76. checkbox('Inline checkbox', options, inline=True, name='checkbox-inline'),
  77. checkbox('Checkbox', options, name='checkbox'),
  78. radio('Inline radio', options, inline=True, name='radio-inline'),
  79. radio('Radio', options, inline=False, name='radio'),
  80. file_upload('File upload', name='file_upload', max_size='10m'),
  81. actions('Actions', [
  82. {'label': 'Submit', 'value': 'submit'},
  83. {'label': 'Disabled', 'disabled': True},
  84. {'label': 'Reset', 'type': 'reset', 'color': 'warning'},
  85. {'label': 'Cancel', 'type': 'cancel', 'color': 'danger'},
  86. ], name='actions'),
  87. ])
  88. def output_widgets():
  89. ###########################################################################################
  90. put_markdown("# Typography")
  91. put_row([
  92. put_markdown("""
  93. ## Heading 2
  94. ### Heading 3
  95. #### Heading 4
  96. ##### Heading 5
  97. [PyWebIO](https://github.com/pywebio/PyWebIO) is awesome!
  98. *This text will be italic*
  99. **This text will be bold**
  100. _You **can** combine them_
  101. ~~Strikethrough~~
  102. This is `inline code`
  103. As Kanye West said:
  104. > We're living the future so
  105. > the present is our past.
  106. """),
  107. put_markdown("""
  108. ### Lists
  109. * Item 1
  110. * Item 2
  111. * Item 2a
  112. * Item 2b
  113. 1. Item 1
  114. 1. Item 2
  115. 1. Item 2a
  116. 1. Item 2b
  117. ### Task Lists
  118. - [x] [links](), **formatting**, and <del>tags</del> supported
  119. - [x] list syntax required (any unordered or ordered list supported)
  120. - [x] this is a complete item
  121. - [ ] this is an incomplete item
  122. """)
  123. ])
  124. ###########################################################################################
  125. put_markdown("""
  126. # Code
  127. ```python
  128. from pywebio import *
  129. def main(): # PyWebIO application function
  130. name = input.input("what's your name")
  131. output.put_text("hello", name)
  132. start_server(main, port=8080, debug=True)
  133. ```
  134. """)
  135. ###########################################################################################
  136. put_markdown('# Image')
  137. with use_scope('image'):
  138. put_image(
  139. "https://opengraph.githubassets.com/6bcea5272d0b5901f48a67d9d05da6c7a7c7c68da32a5327943070ff9c9a3dfb/pywebio/PyWebIO").style("""
  140. max-height: 250px;
  141. border: 2px solid #fff;
  142. border-radius: 25px;
  143. """)
  144. ###########################################################################################
  145. put_markdown("# Buttons")
  146. # small=None, link_style=False, outline=False, group=False
  147. put_buttons([
  148. dict(label=i, value=i, color=i)
  149. for i in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']
  150. ], onclick=lambda b: toast(f'Clicked {b} button'))
  151. put_buttons([
  152. dict(label=i, value=i, color=i)
  153. for i in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']
  154. ], onclick=lambda b: toast(f'Clicked {b} button'), small=True)
  155. put_buttons([
  156. dict(label=i, value=i, color=i)
  157. for i in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']
  158. ], onclick=lambda b: toast(f'Clicked {b} button'), link_style=True)
  159. put_buttons([
  160. dict(label=i, value=i, color=i)
  161. for i in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']
  162. ], onclick=lambda b: toast(f'Clicked {b} button'), outline=True)
  163. put_buttons([
  164. dict(label=i, value=i, color=i)
  165. for i in ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark']
  166. ], onclick=lambda b: toast(f'Clicked {b} button'), group=True)
  167. ###########################################################################################
  168. put_markdown('# Tables')
  169. put_markdown("""
  170. First Header | Second Header
  171. ------------ | -------------
  172. Content from cell 1 | Content from cell 2
  173. Content in the first column | Content in the second column
  174. """)
  175. put_table([
  176. ['Type', 'Content'],
  177. ['text', '<hr/>'],
  178. ['html', put_html('X<sup>2</sup>')],
  179. ['buttons', put_buttons(['A', 'B'], onclick=toast, small=True)],
  180. ['markdown', put_markdown('`awesome PyWebIO!`\n - 1\n - 2\n - 3')],
  181. ['file', put_file('hello.text', b'')],
  182. ['table', put_table([
  183. ['A', 'B'],
  184. [put_markdown('`C`'), put_markdown('`D`')]
  185. ])]
  186. ])
  187. ###########################################################################################
  188. put_markdown('# Popup')
  189. def show_popup():
  190. popup('Popup title', [
  191. 'Popup body text goes here.',
  192. put_table([
  193. ['Type', 'Content'],
  194. ['html', put_html('X<sup>2</sup>')],
  195. ['text', '<hr/>'],
  196. ['buttons', put_buttons(['A', 'B'], onclick=toast)],
  197. ['markdown', put_markdown('`Awesome PyWebIO!`')],
  198. ['file', put_file('hello.text', b'')],
  199. ['table', put_table([['A', 'B'], ['C', 'D']])]
  200. ]),
  201. put_button('Close', onclick=close_popup, outline=True)
  202. ], size=PopupSize.NORMAL)
  203. put_button("Click me to show a popup", onclick=show_popup)
  204. ###########################################################################################
  205. put_markdown('# Layout')
  206. put_row([
  207. put_column([
  208. put_code('A'),
  209. put_row([
  210. put_code('B1'), None,
  211. put_code('B2'), None,
  212. put_code('B3'),
  213. ]),
  214. put_code('C'),
  215. ]), None,
  216. put_code('python'), None,
  217. put_code('python\n' * 20).style('max-height:200px;'),
  218. ])
  219. ###########################################################################################
  220. put_markdown('# Loading')
  221. put_processbar('processbar', 0.3)
  222. put_text()
  223. put_grid([
  224. [
  225. put_loading(shape=shape, color=color)
  226. for color in ('primary', 'secondary', 'success', 'danger', 'warning', 'info', 'light', 'dark')
  227. ]
  228. for shape in ('border', 'grow')
  229. ], cell_width='50px', cell_height='50px')
  230. ###########################################################################################
  231. put_markdown('# Tabs')
  232. put_tabs([
  233. {'title': 'Text', 'content': 'Hello world'},
  234. {'title': 'Markdown', 'content': put_markdown('~~Strikethrough~~')},
  235. {'title': 'More content', 'content': [
  236. put_table([
  237. ['Commodity', 'Price'],
  238. ['Apple', '5.5'],
  239. ['Banana', '7'],
  240. ]),
  241. put_link('pywebio', 'https://github.com/wang0618/PyWebIO')
  242. ]},
  243. ])
  244. ###########################################################################################
  245. put_markdown('# Scrollable')
  246. put_scrollable("Long text " * 200, height=200)
  247. ###########################################################################################
  248. put_markdown('# Collapse')
  249. put_collapse('Click to expand', [
  250. 'text',
  251. put_markdown('~~Strikethrough~~'),
  252. put_table([
  253. ['Commodity', 'Price'],
  254. ['Apple', '5.5'],
  255. ])
  256. ])
  257. ###########################################################################################
  258. put_markdown('# Message')
  259. put_warning(
  260. put_markdown('### Warning!'),
  261. "Best check yo self, you're not looking too good. Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.",
  262. closable=True)
  263. put_success("Well done! You successfully read this important alert message.")
  264. put_info("Heads up! This alert needs your attention, but it's not super important.")
  265. put_error("Oh snap! Change a few things up and try submitting again.")
  266. ALL_THEME = ('default', 'dark', 'sketchy', 'minty', 'yeti')
  267. THEME_SUMMARY = {'default': 'The default theme', 'dark': 'A theme for night',
  268. 'sketchy': 'A hand-drawn look for mockups and mirth', 'minty': 'A fresh feel',
  269. 'yeti': 'A friendly foundation'}
  270. style = """
  271. table img:hover {
  272. transition-duration: 400ms;
  273. transform: translateY(-2px);
  274. box-shadow: 0px 2px 9px 2px rgb(0 0 0 / 27%), 0 30px 50px -30px rgb(0 0 0 / 30%)
  275. }
  276. .page-header h1 {
  277. font-size: 3em;
  278. }
  279. #pywebio-scope-image img {
  280. box-shadow: rgb(204 204 204) 3px 3px 13px;
  281. }
  282. .webio-theme-dark #pywebio-scope-image img {
  283. box-shadow: none !important;
  284. }
  285. """
  286. @config(css_style=style)
  287. def page():
  288. """PyWebIO Theme Preview"""
  289. theme = eval_js("new URLSearchParams(window.location.search).get('app')")
  290. if theme not in ALL_THEME:
  291. theme = 'default'
  292. put_html(f"""
  293. <div class="page-header">
  294. <div style="text-align: center">
  295. <h1>{theme[0].upper() + theme[1:]}</h1>
  296. <p class="lead">{THEME_SUMMARY.get(theme, '')}</p>
  297. </div>
  298. </div>
  299. """)
  300. put_markdown('# Switch Theme')
  301. themes = [
  302. put_image(f"https://fastly.jsdelivr.net/gh/wang0618/PyWebIO@dev/docs/assets/theme/{name}.png").onclick(
  303. partial(go_app, name=name, new_window=False))
  304. for name in ALL_THEME if name != theme
  305. ]
  306. if info.user_agent.is_mobile:
  307. put_table([themes[:2], themes[2:]])
  308. else:
  309. put_table([themes])
  310. if theme != 'default':
  311. put_markdown(f"""
  312. ### Usage
  313. Use `pywebio.config()` to apply this theme:
  314. ```python
  315. @config(theme="{theme}")
  316. def main():
  317. put_text("hello world")
  318. start_server(main, port=8080)
  319. ```
  320. """)
  321. put_markdown("""
  322. ### Credits
  323. The dark theme is modified from ForEvolve's [bootstrap-dark](https://github.com/ForEvolve/bootstrap-dark).
  324. The sketchy, minty and yeti theme are from [bootswatch](https://bootswatch.com/4/).
  325. """)
  326. set_env(input_panel_min_height=100, input_panel_init_height=190)
  327. output_widgets()
  328. pin_widgets()
  329. form()
  330. # bind each theme to the app
  331. main = {
  332. theme: config(theme=theme, title=f"PyWebIO {theme} theme")(page)
  333. for theme in ALL_THEME if theme != 'default'
  334. }
  335. main['index'] = page
  336. if __name__ == '__main__':
  337. start_server(main, debug=True, port=8080)