Bläddra i källkod

`log.push` support `classes`, `style`, and `props` (#4750)

This PR addresses the most basic demand highlighted in #2508, that is to
color individual lines in `ui.log`.

#### Implementation details

Note that, the user may have already styled the `ui.label` via
`default_classes`, `default_style` and/or `default_props`.

Since: 
- It would be way too much parameters if we allow 3 (add/remove/replace)
* 3 (classes/style/props) = 9 parameters to skip into `log.push`
- Users are not supposed to receive the `ui.label` instances and style
it themselves since
  - Function returns None, and, 
  - They will be deleted automatically via `self.remove(0)`

I have elected to make the `classes`, `style`, and `props`, should they
be passed in, **replace existing one and be final**.

#### Test script

```py
from nicegui import ui

ui.label.default_classes('text-gray-500')
ui.label.default_style('font-size: 2rem')
ui.label.default_props('my_label_props')

ui.add_css('''
*[my_label_props] {
    font-style: italic;
}
*[my_log_props] {
    font-weight: bold;
}
''')

ui.label('This is how a normal label looks like')

ui.log().push('This is how a log label looks like', classes='text-red-500', style='font-size: 1rem', props='my_log_props')

ui.run()
```

<img width="380" alt="{3B0DEA0A-E006-4A54-950E-58F06FBD5E3D}"
src="https://github.com/user-attachments/assets/f54a8b7e-2ead-4976-8977-9593fc51aee4"
/>

<img width="514" alt="{F0E4BAC4-A13B-494A-A350-7D0F8560B501}"
src="https://github.com/user-attachments/assets/652e594c-b72d-481b-b6b5-ce174ee77401"
/>

#### What this PR doesn't do

- Let you style individual characters in each line
- Let you put custom HTML in `ui.log`
- Accept ANSI escape sequences and display as colors appropriately
- Be a replacement to `Xterm.js` in #4520 

#### To-do

- [x] Pytest? 
- [x] Documentation? 
  - [x] Drafted documentation text

#### Questions left on the table, which is best if we can answer them

- [x] Why no `replace` for `props`, and I had to do
`label.props.clear()`?
  - Considered a missing future feature for NiceGUI

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Evan Chan 1 dag sedan
förälder
incheckning
dfb78e871d
3 ändrade filer med 53 tillägg och 2 borttagningar
  1. 15 2
      nicegui/elements/log.py
  2. 15 0
      tests/test_log.py
  3. 23 0
      website/documentation/content/log_documentation.py

+ 15 - 2
nicegui/elements/log.py

@@ -16,13 +16,26 @@ class Log(Element, default_classes='nicegui-log'):
         super().__init__()
         self.max_lines = max_lines
 
-    def push(self, line: Any) -> None:
+    def push(self, line: Any, *,
+             classes: Optional[str] = None,
+             style: Optional[str] = None,
+             props: Optional[str] = None) -> None:
         """Add a new line to the log.
 
         :param line: the line to add (can contain line breaks)
+        :param classes: classes to apply to the line (*added in version 2.18.0*)
+        :param style: style to apply to the line (*added in version 2.18.0*)
+        :param props: props to apply to the line (*added in version 2.18.0*)
         """
         for text in str(line).splitlines():
             with self:
-                Label(text)
+                label = Label(text)
+                if classes is not None:
+                    label.classes(replace=classes)
+                if style is not None:
+                    label.style(replace=style)
+                if props is not None:
+                    label.props.clear()
+                    label.props(props)
         while self.max_lines is not None and len(self.default_slot.children) > self.max_lines:
             self.remove(0)

+ 15 - 0
tests/test_log.py

@@ -53,3 +53,18 @@ def test_special_characters(screen: Screen):
     screen.should_contain('50%')
     screen.click('push')
     screen.should_contain('100%')
+
+
+def test_log_against_defaults(screen: Screen):
+    ui.label.default_classes('text-red')
+    ui.label.default_style('margin: 1rem')
+    ui.label.default_props('my-prop=A')
+
+    log = ui.log()
+    log.push('Log line', classes='text-green', style='margin: 2rem', props='my-prop=B')
+
+    screen.open('/')
+    line = screen.find('Log line')
+    assert line.get_attribute('my-prop') == 'B'
+    assert line.get_attribute('class') == 'text-green'
+    assert line.get_attribute('style') == 'margin: 2rem;'

+ 23 - 0
website/documentation/content/log_documentation.py

@@ -46,4 +46,27 @@ def logger_handler():
     page()  # HIDE
 
 
+@doc.demo('Styling lines', '''
+    On the basis that individual lines in `ui.log` are `ui.label` instances,
+    it is possible to style the inserted lines via `classes`, `style` and `props`.
+    One notable use would be colored logs.
+
+    Note that if applied, this would clear any existing
+    [classes](element#default_classes),
+    [style](element#default_style), and
+    [props](element#default_props)
+    currently set as default on `ui.label`.
+
+    *Added in version 2.18.0*
+''')
+def styling_lines_demo():
+    log = ui.log(max_lines=10).classes('w-full h-40')
+    with ui.row():
+        ui.button('Normal', on_click=lambda: log.push('Text'))
+        ui.button('Debug', on_click=lambda: log.push('Debug', classes='text-grey'))
+        ui.button('Info', on_click=lambda: log.push('Info', classes='text-blue'))
+        ui.button('Warning', on_click=lambda: log.push('Warning', classes='text-orange'))
+        ui.button('Error', on_click=lambda: log.push('Error', classes='text-red'))
+
+
 doc.reference(ui.log)