diff --git a/frontend/code/components/progressBar.ts b/frontend/code/components/progressBar.ts index e2dde8eb..32a8ccce 100644 --- a/frontend/code/components/progressBar.ts +++ b/frontend/code/components/progressBar.ts @@ -1,9 +1,12 @@ +import { ColorSet } from '../dataModels'; +import { applySwitcheroo } from '../designApplication'; import { LayoutContext } from '../layouting'; import { ComponentBase, ComponentState } from './componentBase'; export type ProgressBarState = ComponentState & { _type_: 'ProgressBar-builtin'; progress?: number | null; + color?: ColorSet; }; export class ProgressBarComponent extends ComponentBase { @@ -11,12 +14,12 @@ export class ProgressBarComponent extends ComponentBase { createElement(): HTMLElement { let element = document.createElement('div'); - element.classList.add('rio-progressbar'); + element.classList.add('rio-progress-bar'); element.innerHTML = ` -
-
-
+
+
+
`; @@ -33,7 +36,7 @@ export class ProgressBarComponent extends ComponentBase { // Indeterminate progress else if (deltaState.progress === null) { - this.element.classList.add('rio-progressbar-indeterminate'); + this.element.classList.add('rio-progress-bar-indeterminate'); } // Known progress @@ -41,10 +44,18 @@ export class ProgressBarComponent extends ComponentBase { let progress = Math.max(0, Math.min(1, deltaState.progress)); this.element.style.setProperty( - '--rio-progressbar-fraction', + '--rio-progress-bar-fraction', `${progress * 100}%` ); - this.element.classList.remove('rio-progressbar-indeterminate'); + this.element.classList.remove('rio-progress-bar-indeterminate'); + } + + // Apply the color + if (deltaState.color !== undefined) { + applySwitcheroo( + this.element, + deltaState.color === 'keep' ? 'bump' : deltaState.color + ); } } diff --git a/frontend/code/components/progressCircle.ts b/frontend/code/components/progressCircle.ts index 938a8e2a..6019c7df 100644 --- a/frontend/code/components/progressCircle.ts +++ b/frontend/code/components/progressCircle.ts @@ -4,8 +4,8 @@ import { ComponentBase, ComponentState } from './componentBase'; export type ProgressCircleState = ComponentState & { _type_: 'ProgressCircle-builtin'; - color: ColorSet; progress?: number | null; + color?: ColorSet; }; export class ProgressCircleComponent extends ComponentBase { @@ -45,9 +45,11 @@ export class ProgressCircleComponent extends ComponentBase { } // Apply the color - applySwitcheroo( - this.element, - deltaState.color === 'keep' ? 'bump' : deltaState.color - ); + if (deltaState.color !== undefined) { + applySwitcheroo( + this.element, + deltaState.color === 'keep' ? 'bump' : deltaState.color + ); + } } } diff --git a/frontend/css/style.scss b/frontend/css/style.scss index df433c26..348837b0 100644 --- a/frontend/css/style.scss +++ b/frontend/css/style.scss @@ -549,12 +549,12 @@ textarea:not(:placeholder-shown) ~ .rio-input-box-label, } // Progress Bar -.rio-progressbar { +.rio-progress-bar { pointer-events: none; overflow: hidden; } -.rio-progressbar-track { +.rio-progress-bar-track { position: absolute; width: 100%; height: 100%; @@ -563,14 +563,14 @@ textarea:not(:placeholder-shown) ~ .rio-input-box-label, opacity: 0.3; } -.rio-progressbar-fill { +.rio-progress-bar-fill { position: absolute; height: 100%; - background: var(--rio-local-level-2-bg); + background: var(--rio-local-bg); } -@keyframes rio-progressbar-animation-indeterminate { +@keyframes rio-progress-bar-animation-indeterminate { 0% { left: -20%; width: 6%; @@ -586,14 +586,15 @@ textarea:not(:placeholder-shown) ~ .rio-input-box-label, } } -.rio-progressbar-indeterminate .rio-progressbar-fill { +.rio-progress-bar-indeterminate .rio-progress-bar-fill { transform: translateX(-50%); - animation: rio-progressbar-animation-indeterminate 1.5s ease-in-out infinite; + animation: rio-progress-bar-animation-indeterminate 1.5s ease-in-out + infinite; } -.rio-progressbar:not(.rio-progressbar-indeterminate) .rio-progressbar-fill { +.rio-progress-bar:not(.rio-progress-bar-indeterminate) .rio-progress-bar-fill { left: 0; - width: var(--rio-progressbar-fraction); + width: var(--rio-progress-bar-fraction); transition: width 0.3s ease-in-out; } @@ -617,7 +618,7 @@ textarea:not(:placeholder-shown) ~ .rio-input-box-label, .rio-progress-circle circle { fill: none; stroke-width: 3.5; - color: var(--rio-local-level-2-bg); + color: var(--rio-local-bg); } .spinning svg { diff --git a/rio/cli/run_project/arbiter.py b/rio/cli/run_project/arbiter.py index 136c5f8e..a47eaa01 100644 --- a/rio/cli/run_project/arbiter.py +++ b/rio/cli/run_project/arbiter.py @@ -545,13 +545,19 @@ class Arbiter: except ValueError: pass else: + # From experience, people don't even notice the warnings in `rio + # run` anymore after some time, because they show up so + # frequently. Intentionally style this one differently, since + # its important and must be noticed. if newest_rio_version != installed_rio_version: - revel.warning( - f"Rio [bold]{newest_rio_version}[/] is available, but" - f" you have [bold]{installed_rio_version}[/] installed." + revel.print( + f"[bg-yellow] [/] [bold yellow]Rio [bold]{newest_rio_version}[/] is available![/]" ) - revel.warning( - "Run `pip install --upgrade rio-ui` to get the latest bugfixes and improvements." + revel.print( + f"[bg-yellow] [/] [bold yellow]Please update to get the newest features, bugfixes and security updates.[/]" + ) + revel.print( + "[bg-yellow] [/] Run `[bold]pip install --upgrade rio-ui[/]` to get the newest version." ) print() diff --git a/rio/components/list_view.py b/rio/components/list_view.py index 8d21232e..71c74a76 100644 --- a/rio/components/list_view.py +++ b/rio/components/list_view.py @@ -47,7 +47,7 @@ class ListView(FundamentalComponent): ## Examples - A minimal example of a `ListView` with two items will be shown: + This example will display a list of two products: ```python rio.ListView( @@ -56,8 +56,9 @@ class ListView(FundamentalComponent): ) ``` - `ListView`s are commonly used to display lists of dynamic length. You can easily - achieve this by adding the children to a list first, and then unpacking that list: + `ListView`s are commonly used to display lists of dynamic length. You can + easily achieve this by first creating a `ListView`, then adding the children + after the fact: ```python import functools @@ -70,16 +71,17 @@ class ListView(FundamentalComponent): print(f"Selected {product}") def build(self) -> rio.Component: - # Store all children in an intermediate list - list_items = [] + # First create the ListView + result = rio.ListView() + # Then add the children one by one for product in self.products: - list_items.append( + result.add( rio.SimpleListItem( text=product, key=product, - # Note the use of `functools.partial` to pass the product - # to the event handler. + # Note the use of `functools.partial` to pass the + # product to the event handler. on_press=functools.partial( self.on_press_heading_list_item, product=product, @@ -87,8 +89,7 @@ class ListView(FundamentalComponent): ) ) - # Then unpack the list to pass the children to the `ListView` - return rio.ListView(*list_items) + return result ``` """ diff --git a/rio/components/progress_bar.py b/rio/components/progress_bar.py index f0e0bdcd..1fedac82 100644 --- a/rio/components/progress_bar.py +++ b/rio/components/progress_bar.py @@ -1,4 +1,8 @@ -from typing import final +from __future__ import annotations + +from typing import * # type: ignore + +import rio from .fundamental_component import FundamentalComponent @@ -25,10 +29,14 @@ class ProgressBar(FundamentalComponent): `progress`: The progress to display, as a fraction from 0 to 1. If `None`, the progress indicator will be indeterminate. + `color`: The color scheme of the progress indicator. Keeping the default + is recommended, but it may make sense to change the color in + case the default is hard to perceive on your background. + ## Examples - A minimal example displaying a progress bar that is 40% complete. + Here's a minimal example displaying a progress circle that is 40% complete: ```python rio.ProgressBar(progress=0.4) @@ -43,7 +51,54 @@ class ProgressBar(FundamentalComponent): ``` """ - progress: float | None = None + progress: float | None + color: rio.ColorSet + + def __init__( + self, + *, + progress: float | None = None, + color: rio.ColorSet = "keep", + key: str | None = None, + margin: float | None = None, + margin_x: float | None = None, + margin_y: float | None = None, + margin_left: float | None = None, + margin_top: float | None = None, + margin_right: float | None = None, + margin_bottom: float | None = None, + width: float | Literal["natural", "grow"] = "natural", + height: float | Literal["natural", "grow"] = "natural", + align_x: float | None = None, + align_y: float | None = None, + ): + """ + ## Parameters + + progress: The progress to display, as a fraction from 0 to 1. If `None`, + the progress indicator will be indeterminate. + + color: The color scheme of the progress indicator. Keeping the default + is recommended, but it may make sense to change the color in case + the default is hard to perceive on your background. + """ + super().__init__( + key=key, + margin=margin, + margin_x=margin_x, + margin_y=margin_y, + margin_left=margin_left, + margin_top=margin_top, + margin_right=margin_right, + margin_bottom=margin_bottom, + width=width, + height=height, + align_x=align_x, + align_y=align_y, + ) + + self.progress = progress + self.color = color ProgressBar._unique_id = "ProgressBar-builtin" diff --git a/rio/components/progress_circle.py b/rio/components/progress_circle.py index b94cddcd..978047c3 100644 --- a/rio/components/progress_circle.py +++ b/rio/components/progress_circle.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Literal, final +from typing import * # type: ignore import rio @@ -40,7 +40,7 @@ class ProgressCircle(FundamentalComponent): ## Examples - A minimal example displaying a progress circle that is 40% complete. + Here's a minimal example displaying a progress circle that is 40% complete: ```python rio.ProgressCircle(progress=0.4) diff --git a/rio/components/slideshow.py b/rio/components/slideshow.py index f9758b81..33a6e4e4 100644 --- a/rio/components/slideshow.py +++ b/rio/components/slideshow.py @@ -40,7 +40,7 @@ class Slideshow(FundamentalComponent): ## Examples - A minimal example of `Slideshow` displaying two images will be shown: + Here's a simple example that will continuously switch between two images: ```python from pathlib import Path diff --git a/rio/components/switcher.py b/rio/components/switcher.py index 5dab7f92..709f75dd 100644 --- a/rio/components/switcher.py +++ b/rio/components/switcher.py @@ -22,15 +22,6 @@ class Switcher(FundamentalComponent): `content`: The currently displayed component. - ## Examples - - A minimal example of a `Switcher` will be shown: - - ```python - rio.Switcher(content=rio.Text("Hello, world!")) - ``` - - ## Metadata `public`: False diff --git a/rio/components/text.py b/rio/components/text.py index 06ff7810..a740c0b2 100644 --- a/rio/components/text.py +++ b/rio/components/text.py @@ -41,11 +41,26 @@ class Text(FundamentalComponent): ## Examples - A minimal example of a `Text` will be shown: + Here's a minimal example for displaying text. Just pass it a string: ```python rio.Text("Hello, world!") ``` + + To change the style of the text, you can pass a `TextStyle` instance: + + ```python + rio.Text( + "Hello, world!", + style=rio.TextStyle( + font_size=3, + # Text Style has a lot of optional parameters. Have a look at its + # docs for all details! + # + # https://rio.dev/docs/api/textstyle + ), + ) + ``` """ text: str diff --git a/rio/components/tooltip.py b/rio/components/tooltip.py index ae8605d3..099b4204 100644 --- a/rio/components/tooltip.py +++ b/rio/components/tooltip.py @@ -33,7 +33,7 @@ class Tooltip(FundamentalComponent): ## Examples - A minimal example of a `Tooltip` will be shown: + This example will display a label for an icon when the user hovers over it: ```python rio.Tooltip( @@ -42,6 +42,10 @@ class Tooltip(FundamentalComponent): position="top", ) ``` + + ## Metadata + + `experimental`: True """ anchor: rio.Component diff --git a/rio/components/website.py b/rio/components/website.py index edbd9c2c..462e0bbd 100644 --- a/rio/components/website.py +++ b/rio/components/website.py @@ -24,7 +24,7 @@ class Website(FundamentalComponent): ## Examples - A minimal example of a `Website` will be shown: + Here's a simple example that will display an example website: ```python rio.Website( diff --git a/rio/snippets/snippet-files/howtos/deployment.md b/rio/snippets/snippet-files/howtos/deployment.md index 1cc54970..615e2acb 100644 --- a/rio/snippets/snippet-files/howtos/deployment.md +++ b/rio/snippets/snippet-files/howtos/deployment.md @@ -6,6 +6,7 @@ needs. - One-click deployment (coming soon) - Manual deployment using `rio` - Manual deployment using `uvicorn` +- running the app directly from Python - Deployment inside a Docker container ## One-click deployment @@ -35,8 +36,13 @@ Make sure **not** to pass the `--public` flag. We want to make sure Rio is only available on your local machine. **Alternatively**, you can run your app via a server such as `uvicorn`. At its -core, Rio is a `fastapi` app, which means you can follow [FastAPI's deployment -guide](https://fastapi.tiangolo.com/deployment/). +core, Rio is a `fastapi` app and you can get the FastAPI object by calling +`App.as_fastapi`. Then follow [FastAPI's deployment +guide](https://fastapi.tiangolo.com/deployment/) to host your app. + +**Another alternative** is to run your app directly from Python. Apps have a +`App.run_as_web_server` method, which will block and serve your app. Make sure +to configure a port so that it doesn't run on a random one each time! **Use Nginx as a reverse proxy**. Nginx is a powerful web server that is hardened against attacks and safe to run on the internet. This will be what your