Themes

Customizing Yuio’s appearance.

Create and install a theme class

All visual settings are configured in yuio.theme.Theme. Create a new class and derive if from yuio.theme.DefaultTheme:

import yuio.theme

class Theme(yuio.theme.DefaultTheme):
    ...

If you’re using Yuio apps, set App.theme, otherwise pass theme to yuio.io.setup():

import yuio.app

@yuio.app.app
def main():
    ...

main.theme = Theme
yuio.io.setup(theme=Theme)

Configure colors

Set up accent color

The easiest way to customize default theme is to change main colors:

class Theme(yuio.theme.DefaultTheme):
    colors = {
        "accent_color": "red",
        "task/progressbar/done/start": "term/bright_yellow",
        "task/progressbar/done/end": "term/bright_red",
    }

Add new color tags

Any item added to Theme.colors will be available for use as color tag:

class Theme(yuio.theme.DefaultTheme):
    colors = {
        "custom_tag": "bold magenta inverse"
    }

@yuio.app.app
def main():
    yuio.io.info("This is a <c custom_tag>custom color tag!</c>")

More color changes

All other colors can be configured in the same way. See documentation for Theme.colors to learn about structure of Yuio’s color namespaces, and see all available color paths in color paths reference.

Set colors dynamically

DefaultTheme receives a Term instance in its constructor, allowing you to set colors dynamically depending on the terminal’s color scheme:

import yuio.app
import yuio.color
import yuio.io
import yuio.term
import yuio.theme

class Theme(yuio.theme.DefaultTheme):
    def __init__(self, term: yuio.term.Term):
        super().__init__(term)

        if not term.terminal_theme:
            return

        background = term.terminal_theme.background
        magenta = term.terminal_theme.magenta

        match term.terminal_theme.lightness:
            case yuio.term.Lightness.LIGHT:
                # Slightly darker than background.
                dark_magenta = magenta.match_luminosity(background.darken(0.2))
            case yuio.term.Lightness.DARK:
                # Slightly lighter than background.
                dark_magenta = magenta.match_luminosity(background.lighten(0.2))
            case _:
                # As dark as background.
                dark_magenta = magenta.match_luminosity(background)

        self._set_color_if_not_overridden(
            "dark_magenta_bg", yuio.color.Color(back=dark_magenta)
        )

@yuio.app.app
def main():
    yuio.io.info("This is a <c dark_magenta_bg>dark magenta background!</c>")

main.theme = Theme

if __name__ == "__main__":
    main.run()

Configure decorations

Message decorations

class Theme(yuio.theme.DefaultTheme):
    separate_headings = False
    msg_decorations_unicode = {
        "heading/1": "=> ",
        "info": "-> ",
    }
    msg_decorations_ascii = {
        "heading/1": "=> ",
        "info": "-> ",
    }

Progress bars and spinners

class Theme(yuio.theme.DefaultTheme):
    spinner_update_rate_ms = 100
    msg_decorations_unicode = {
        # Custom progress bar symbols.
        "progress_bar/start_symbol": "|",
        "progress_bar/end_symbol": "|",
        "progress_bar/done_symbol": "█",
        "progress_bar/pending_symbol": " ",
        "progress_bar/transition_pattern": "█▉▊▋▌▍▎▏ ",
        # Custom spinner sequence.
        "spinner/pattern": "|||/-\\",
    }

More decorations

See all available decorations in decorations reference.