posit-dev / py-shinyswatch

Bootswatch themes for py-shiny
https://posit-dev.github.io/py-shinyswatch/
MIT License
28 stars 3 forks source link

shinyswatch.theme.xxx() does not work #38

Closed webscale closed 4 months ago

webscale commented 5 months ago

This server side method does nothing. Calling any of the shinyswatch.theme.cerulean() methods does nothing.

Note : while this code is in a module , this does not work even when placed in core app.py


@module.server
def default_settings_tab_server(input: Inputs, output: Outputs, session: Session ,master : master.shiny_master):

    shinyswatch.theme_picker_server()

    @reactive.effect
    @reactive.event(input.app_theme)
    def _():
        print(f"Theme Changed = {input.app_theme()}")
        new_theme = input.app_theme()
        shinyswatch.get_theme(new_theme),
        if(new_theme == 'cerulean'):
             shinyswatch.theme.cerulean()
        elif(new_theme == 'cosmo'):
             shinyswatch.theme.cosmo()
        elif(new_theme == 'litera'):
             shinyswatch.theme.litera()

Client Side Code


def default_settings_tab_onstart(master : master.shiny_master):
    pass
@module.ui
def default_settings_tab_ui( master : master.shiny_master) -> str :
    return ui.card(
        ui.card_header("UI Settings"),
    #    shinyswatch.theme_picker_ui(default = "litera"),
        shinyswatch.theme.litera(),

        ui.input_radio_buttons("app_theme", "Theme", 
                               choices = ['cerulean', 'cosmo',  'litera' ],  
                               inline=True),
        ui.input_action_button("save_settings", "Save Settings"),

    )

Proof Points : print(f"Theme Changed = {input.app_theme()}") is printed in console but there is no change in UI.

Pip Freeze : shiny==0.10.2 shinyswatch==0.6.1 shinywidgets==0.3.2

OS - windows

Browser : Chrome

Screenshot 2024-06-01 134821

schloerke commented 5 months ago

So a couple things are going on... but it still leads to not a perfect solution.


The shinyswatch theme needs to be returned in the UI somehow. This can either be given in the initial UI definition in default_settings_tab_ui or it can be given in dynamic UI. (I'd strongly recommend the initial UI definition for a clean CSS experience). You've already done this with your litera theme. ✅

However, I'm guessing from the UI Settings that you'd like for the theme to update on the page when the Theme Setting is saved. If this is the case... the end goal should be to get the UI page to reload with the updated theme value. Unfortunately the package methods don't make this easier.

Really... The theme picker is there more for the app author to pick for the app for everyone, not really the app user to pick for themselves.


So my recommendation is to use the theme picker to decide which theme you'd like for your uses to have. Then use that single theme object within your app.

schloerke commented 5 months ago

Example app showing dynamic UI won't work as a solution to get the latest theme value: shinylive editor

adsribeiro commented 5 months ago

In shiny express it doesn't work. from shinyswatch import theme

theme.minty()

gadenbuie commented 4 months ago

In Shiny Express, with both the current and upcoming shinyswatch release, you can use:

from shiny.express import input, render, ui
from shinyswatch import theme

ui.page_opts(theme=theme.darkly)

ui.input_slider("n", "N", 0, 100, 20)

@render.code
def txt():
    return f"n*2 is {input.n() * 2}"

Here's an example app on shinylive.

gadenbuie commented 4 months ago

To the original post:

Calling any of the shinyswatch.theme.cerulean() methods does nothing.

In the current version of shinyswatch (0.6.1), the theme picker can only update themes that it controls. It isn't able to remove the theme added by shinyswatch.theme.litera() -- the initial theme can only be set by shinyswatch.theme_picker_ui().

Separately, I don't think we support using the theme picker in a module.

In the next shinyswatch release, due to some upstream changes in Shiny, the initial theme selection and the theme picker UI will be decoupled. The initial theme will need to be set via the theme argument of the shiny.ui.page_*() functions (Shiny Core) or of shiny.express.ui.page_opts(theme=) in Shiny Express.

from shiny.express import input, render, ui

import shinyswatch

ui.page_opts(theme=shinyswatch.theme.darkly)

ui.input_slider("n", "N", 0, 100, 20)

@render.code
def txt():
    return f"n*2 is {input.n() * 2}"

shinyswatch.theme_picker_ui()
shinyswatch.theme_picker_server()