Selaa lähdekoodia

Merge branch 'main' of github.com:zauberzeug/nicegui into main

Falko Schindler 4 vuotta sitten
vanhempi
säilyke
7db0a6e3f3

+ 7 - 1
README.md

@@ -2,14 +2,20 @@
 
 
 <img src="https://raw.githubusercontent.com/zauberzeug/nicegui/main/sceenshots/ui-elements.png" width="300" align="right">
 <img src="https://raw.githubusercontent.com/zauberzeug/nicegui/main/sceenshots/ui-elements.png" width="300" align="right">
 
 
-We like [Streamlit](https://streamlit.io/) but find it does to much magic when it comes to state handling. In search for an alernative nice library to write simple graphical user interfaces in Python we discovered [justpy](https://justpy.io/). While too "low-level-html" for our daily usage it provides a great basis for our shot at a "NiceGUI".
+We like [Streamlit](https://streamlit.io/) but find it does to much magic when it comes to state handling. In search for an alernative nice library to write simple graphical user interfaces in Python we discovered [justpy](https://justpy.io/). While too "low-level-html" for our daily usage it provides a great basis for "NiceGUI".
+
+## Purpose
+
+NiceGUI is intended to be used for small scripts and user interfaces with a very limited user base. Custom "Smart-Home Control" solutions or "Robotics" for example. It's also helpful for development like tweaking/configuring a machine learning training or tuning motor controllers.
 
 
 ## Features
 ## Features
 
 
 - browser-based GUI
 - browser-based GUI
+- shared state between multiple browser windows
 - implicit reload on code change
 - implicit reload on code change
 - clean set of GUI elements (label, button, checkbox, switch, slider, input, ...)
 - clean set of GUI elements (label, button, checkbox, switch, slider, input, ...)
 - simple grouping with rows, columns and cards
 - simple grouping with rows, columns and cards
+- genral-purpose html and markdown elements
 - built-in timer to refresh data in intervals (even every 10 ms)
 - built-in timer to refresh data in intervals (even every 10 ms)
 - straight-forward data bindings to write even less code
 - straight-forward data bindings to write even less code
 
 

+ 18 - 16
api_reference.py

@@ -13,11 +13,19 @@ import docutils.core
 wp.head_html += docutils.core.publish_parts('', writer_name='html')['stylesheet']
 wp.head_html += docutils.core.publish_parts('', writer_name='html')['stylesheet']
 
 
 @contextmanager
 @contextmanager
-def example():
+def example(element: Element):
+
     callFrame = inspect.currentframe().f_back.f_back
     callFrame = inspect.currentframe().f_back.f_back
     begin = callFrame.f_lineno
     begin = callFrame.f_lineno
     with ui.row():
     with ui.row():
-        with ui.card():
+
+        doc = element.__init__.__doc__
+        html = docutils.core.publish_parts(doc, writer_name='html')['html_body']
+        html = html.replace('<p>', '<h3>', 1)
+        html = html.replace('</p>', '</h3>', 1)
+        ui.html(html)
+
+        with ui.card(classes='mt-12'):
             yield
             yield
         callFrame = inspect.currentframe().f_back.f_back
         callFrame = inspect.currentframe().f_back.f_back
         end = callFrame.f_lineno
         end = callFrame.f_lineno
@@ -26,21 +34,15 @@ def example():
         code.insert(0, '```python')
         code.insert(0, '```python')
         code.append('```')
         code.append('```')
         code = '\n'.join(code)
         code = '\n'.join(code)
-        ui.markdown(code)
-
-def describe(element: Element):
-    doc = element.__init__.__doc__
-    html = docutils.core.publish_parts(doc, writer_name='html')['html_body']
-    html = html.replace('<p>', '<h3>', 1)
-    html = html.replace('</p>', '</h3>', 1)
-    ui.html(html)
+        ui.markdown(code, classes='mt-12')
 
 
 with open('README.md', 'r') as file:
 with open('README.md', 'r') as file:
     ui.markdown(file.read())
     ui.markdown(file.read())
 
 
-describe(ui.input)
-with example():
-    ui.input(label='Text', on_change=lambda e: result.set_text(e.value))
-    ui.number(label='Number', format='%.2f', on_change=lambda e: result.set_text(e.value))
-
-    result = ui.label('result', typography='bold')
+with example(ui.input):
+    ui.input(
+        label='Text',
+        placeholder='some placeholder',
+        on_change=lambda e: result.set_text('you typed: ' + e.value)
+    )
+    result = ui.label('', typography='bold')

+ 0 - 0
main.py → examples.py


+ 2 - 2
nicegui/elements/card.py

@@ -3,8 +3,8 @@ from .group import Group
 
 
 class Card(Group):
 class Card(Group):
 
 
-    def __init__(self, design: str = ''):
+    def __init__(self, design: str = '', classes: str = ''):
 
 
         view = jp.QCard(classes='column items-start q-pa-md', style='gap: 1em', delete_flag=False)
         view = jp.QCard(classes='column items-start q-pa-md', style='gap: 1em', delete_flag=False)
 
 
-        super().__init__(view, design)
+        super().__init__(view, design=design, classes=classes)

+ 2 - 1
nicegui/elements/element.py

@@ -8,7 +8,7 @@ class Element:
 
 
     visible = BindableProperty
     visible = BindableProperty
 
 
-    def __init__(self, view: jp.HTMLBaseComponent, design: str):
+    def __init__(self, view: jp.HTMLBaseComponent, design: str = '', classes: str = ''):
 
 
         for word in design.split():
         for word in design.split():
             if '=' in word:
             if '=' in word:
@@ -20,6 +20,7 @@ class Element:
         self.parent_view.add(view)
         self.parent_view.add(view)
         view.add_page(self.wp)
         view.add_page(self.wp)
         self.view = view
         self.view = view
+        self.view.classes += ' ' + classes
 
 
         self.visible = True
         self.visible = True
 
 

+ 3 - 3
nicegui/elements/html.py

@@ -3,10 +3,10 @@ from .element import Element
 
 
 class Html(Element):
 class Html(Element):
 
 
-    def __init__(self, content: str = ''):
+    def __init__(self, content: str = '', design='', classes: str = ''):
 
 
-        view = jp.Div()
-        super().__init__(view, '')
+        view = jp.QDiv()
+        super().__init__(view, design=design, classes=classes)
         self.content = content
         self.content = content
 
 
     @property
     @property

+ 3 - 0
nicegui/elements/input.py

@@ -15,6 +15,9 @@ class Input(StringElement):
 
 
         :param str label: display name for the text input
         :param str label: display name for the text input
         :param str placeholder: text to show if no value is entered
         :param str placeholder: text to show if no value is entered
+        :param str value: the current value of the field
+        :param str design: Quasar props to alter the appearance (see `their reference <https://quasar.dev/vue-components/input>`_)
+        :param Callable on_change: callback when the input is confirmed via leaving the focus
         """
         """
         view = jp.QInput(
         view = jp.QInput(
             label=label,
             label=label,

+ 2 - 2
nicegui/elements/markdown.py

@@ -3,9 +3,9 @@ from .html import Html
 
 
 class Markdown(Html):
 class Markdown(Html):
 
 
-    def __init__(self, content: str = ''):
+    def __init__(self, content: str = '', classes: str = ''):
 
 
-        super().__init__(content)
+        super().__init__(content, classes=classes)
 
 
     def set_content(self, content: str):
     def set_content(self, content: str):
 
 

+ 1 - 0
nicegui/nicegui.py

@@ -18,6 +18,7 @@ if not inspect.stack()[-2].filename.endswith('spawn.py'):
     sys.exit()
     sys.exit()
 
 
 wp = jp.QuasarPage(delete_flag=False, title='NiceGUI', favicon='favicon.png')
 wp = jp.QuasarPage(delete_flag=False, title='NiceGUI', favicon='favicon.png')
+wp.tailwind = True  # use Tailwind classes instead of Quasars
 wp.css = HtmlFormatter().get_style_defs('.codehilite')
 wp.css = HtmlFormatter().get_style_defs('.codehilite')
 wp.css += ''.join([f'h{i} {{ font-size: {80*(5-i)}%; line-height: normal; margin-block-end: {0.1*(5-1)}em }}' for i in range(1, 5)])
 wp.css += ''.join([f'h{i} {{ font-size: {80*(5-i)}%; line-height: normal; margin-block-end: {0.1*(5-1)}em }}' for i in range(1, 5)])
 wp.head_html = '<script>confirm = () => true;</script>'  # avoid confirmation dialog for reload
 wp.head_html = '<script>confirm = () => true;</script>'  # avoid confirmation dialog for reload

+ 27 - 1
poetry.lock

@@ -40,6 +40,17 @@ python-versions = "*"
 pycodestyle = ">=2.7.0"
 pycodestyle = ">=2.7.0"
 toml = "*"
 toml = "*"
 
 
+[[package]]
+name = "binding"
+version = "0.1.1"
+description = "Bindable properties for Python"
+category = "main"
+optional = false
+python-versions = ">=3.7,<4.0"
+
+[package.dependencies]
+forbiddenfruit = ">=0.1.4,<0.2.0"
+
 [[package]]
 [[package]]
 name = "certifi"
 name = "certifi"
 version = "2020.12.5"
 version = "2020.12.5"
@@ -107,6 +118,14 @@ category = "dev"
 optional = false
 optional = false
 python-versions = "*"
 python-versions = "*"
 
 
+[[package]]
+name = "forbiddenfruit"
+version = "0.1.4"
+description = "Patch python built-in objects"
+category = "main"
+optional = false
+python-versions = "*"
+
 [[package]]
 [[package]]
 name = "h11"
 name = "h11"
 version = "0.12.0"
 version = "0.12.0"
@@ -386,7 +405,7 @@ python-versions = ">=3.6.1"
 [metadata]
 [metadata]
 lock-version = "1.1"
 lock-version = "1.1"
 python-versions = "^3.7"
 python-versions = "^3.7"
-content-hash = "8e85098d955af42062b9f035490c66e0f724f245355248c1a4b62a5e9d3dfe53"
+content-hash = "70b47d9f805353e2b1db9ac1544837ede044b67c5eb1fa7b2004385f002b8c55"
 
 
 [metadata.files]
 [metadata.files]
 addict = [
 addict = [
@@ -405,6 +424,10 @@ autopep8 = [
     {file = "autopep8-1.5.7-py2.py3-none-any.whl", hash = "sha256:aa213493c30dcdac99537249ee65b24af0b2c29f2e83cd8b3f68760441ed0db9"},
     {file = "autopep8-1.5.7-py2.py3-none-any.whl", hash = "sha256:aa213493c30dcdac99537249ee65b24af0b2c29f2e83cd8b3f68760441ed0db9"},
     {file = "autopep8-1.5.7.tar.gz", hash = "sha256:276ced7e9e3cb22e5d7c14748384a5cf5d9002257c0ed50c0e075b68011bb6d0"},
     {file = "autopep8-1.5.7.tar.gz", hash = "sha256:276ced7e9e3cb22e5d7c14748384a5cf5d9002257c0ed50c0e075b68011bb6d0"},
 ]
 ]
+binding = [
+    {file = "binding-0.1.1-py3-none-any.whl", hash = "sha256:67802ebea17c4b2b459aed93fe0b1997eb1af1648ac8e7be8493110038ddd61c"},
+    {file = "binding-0.1.1.tar.gz", hash = "sha256:ce8be3a96620b6371424eee5f0ec08978357425acda42268a3e287adc8ac745e"},
+]
 certifi = [
 certifi = [
     {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
     {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
     {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
     {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
@@ -490,6 +513,9 @@ executing = [
     {file = "executing-0.6.0-py2.py3-none-any.whl", hash = "sha256:a2f10f802b4312b92bd256279b43720271b0d9b540a0dbab7be4c28fbc536479"},
     {file = "executing-0.6.0-py2.py3-none-any.whl", hash = "sha256:a2f10f802b4312b92bd256279b43720271b0d9b540a0dbab7be4c28fbc536479"},
     {file = "executing-0.6.0.tar.gz", hash = "sha256:a07046e608c56948a899e1c7dc45327ed84ee67edf245041eb8c6722658c14e3"},
     {file = "executing-0.6.0.tar.gz", hash = "sha256:a07046e608c56948a899e1c7dc45327ed84ee67edf245041eb8c6722658c14e3"},
 ]
 ]
+forbiddenfruit = [
+    {file = "forbiddenfruit-0.1.4.tar.gz", hash = "sha256:e3f7e66561a29ae129aac139a85d610dbf3dd896128187ed5454b6421f624253"},
+]
 h11 = [
 h11 = [
     {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
     {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"},
     {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},
     {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"},

+ 1 - 0
pyproject.toml

@@ -16,6 +16,7 @@ typing-extensions = "^3.10.0"
 markdown2 = "^2.4.0"
 markdown2 = "^2.4.0"
 Pygments = "^2.9.0"
 Pygments = "^2.9.0"
 docutils = "^0.17.1"
 docutils = "^0.17.1"
+binding = "^0.1.1"
 
 
 [tool.poetry.dev-dependencies]
 [tool.poetry.dev-dependencies]
 icecream = "^2.1.0"
 icecream = "^2.1.0"