taipy
taipy copied to clipboard
[DOCS] Styling needs to be more accessible for Python users
Issue Description
Most of the support requests we get from Enterprise customers are about styling. They either don't know or don't want to learn how to style in Taipy. A tutorial should clearly explain how to change colors, fonts, sizes, and layouts of visual elements. This tutorial should explain how we style applications by inspecting the page, applying CSS directly in the browser, and then creating a .css file to apply the style.
Code of Conduct
- [X] I have checked the existing issues.
- [ ] I am willing to work on this issue (optional)
Is it a duplicate of issue https://github.com/Avaiga/taipy-doc/issues/1095 ?
For information, we also have the following issues on the topic: https://github.com/Avaiga/taipy-doc/issues/1113 https://github.com/Avaiga/taipy-doc/issues/1085 https://github.com/Avaiga/taipy-doc/issues/1095 https://github.com/Avaiga/taipy/issues/1077
Ah my bad, I though we decided to move all issues to "taipy" repo, I only looked there for duplicates
Would a Stylekit object be useful that provide ways to:
- see what is inside the stylekit
- set variables within the Stylekit
- set the theme of your application from a set of predefined theme (that you could change)
POC:
main.py
from taipy.gui import Gui, notify
import taipy.gui.builder as tgb
from stylekit import stylekit as sk
import pandas as pd
from math import exp, cos
data = pd.DataFrame(
{
"Name": ["Florian", "John", "Jane", "Alice", "Bob"],
"Value": [6, 7, 8, 9, 10],
}
)
value = 10
def notify_user(state):
notify(state, "info", "Date is clicked!")
def compute(value):
return [cos(i / 6) * exp(-i * value / 600) for i in range(100)]
with tgb.Page() as page:
tgb.text(
"Hello World from Taipy",
class_name=sk.typography.h1
+ sk.text_alignment.underline
+ sk.text_alignment.uppercase,
)
tgb.text(
"This is a caption of my chart: we are seeing a sine wave",
class_name=sk.typography.text_caption,
)
with tgb.layout(columns="1 1", class_name=sk.layout.align_columns_center):
with tgb.part(sk.components.sidebar):
tgb.chart(lambda value: compute(value))
with tgb.part(sk.opacity.half_transparent):
tgb.text("Change the data", class_name=sk.typography.h2)
with tgb.layout("1 1"):
tgb.date("2021-01-01", on_change=notify_user, class_name=sk.paddings.p4)
tgb.selector(
"Florian",
lov=["Florian", "John", "Jane", "Alice", "Bob"],
on_change=notify_user,
class_name=sk.paddings.p4,
dropdown=True,
)
tgb.table("{data}")
sk.set_theme(sk.themes.Coffee)
# sk.set_primary_color("red")
# sk.set_secondary_color("red")
# sk.set_border_radius("10px")
# sk.set_font_family("Arial")
# sk.set_color_background_light("black")
# sk.set_color_background_dark("black")
# sk.set_color_paper_light("grey")
# sk.set_color_paper_dark("white")
# sk.set_input_button_height("40px")
Gui(page).run(stylekit=sk.get_stylekit())
Coffee
Industrial
Monospace
stylekit.py
# stylekit.py
class Components:
card = "card "
sidebar = "sidebar "
# Add other components as needed
class Typography:
h1 = "h1 "
h2 = "h2 "
h3 = "h3 "
h4 = "h4 "
h5 = "h5 "
h6 = "h6 "
text_body = "text-body "
text_small = "text-small "
text_caption = "text-caption "
# Add other typography styles as needed
class TextWeights:
weight300 = "text-weight300 "
weight400 = "text-weight400 "
weight500 = "text-weight500 "
weight600 = "text-weight600 "
weight700 = "text-weight700 "
weight800 = "text-weight800 "
weight900 = "text-weight900 "
# Add other text weights as needed
class TextAlignment:
left = "text-left "
center = "text-center "
right = "text-right "
uppercase = "text-uppercase "
no_transform = "text-no-transform "
underline = "text-underline "
no_underline = "text-no-underline "
# Add other text alignments as needed
class Margins:
"""Margins ..."""
m0 = "m0 "
m_auto = "m-auto "
m_half = "m-half "
m1 = "m1 "
m2 = "m2 "
m3 = "m3 "
m4 = "m4 "
m5 = "m5 "
m6 = "m6 "
mt0 = "mt0 "
mt_auto = "mt-auto "
mt_half = "mt-half "
mt1 = "mt1 "
mt2 = "mt2 "
mt3 = "mt3 "
mt4 = "mt4 "
mt5 = "mt5 "
mt6 = "mt6 "
mb0 = "mb0 "
mb_auto = "mb-auto "
mb_half = "mb-half "
mb1 = "mb1 "
mb2 = "mb2 "
mb3 = "mb3 "
mb4 = "mb4 "
mb5 = "mb5 "
mb6 = "mb6 "
ml0 = "ml0 "
ml_auto = "ml-auto "
ml_half = "ml-half "
ml1 = "ml1 "
ml2 = "ml2 "
ml3 = "ml3 "
ml4 = "ml4 "
ml5 = "ml5 "
ml6 = "ml6 "
mr0 = "mr0 "
mr_auto = "mr-auto "
mr_half = "mr-half "
mr1 = "mr1 "
mr2 = "mr2 "
mr3 = "mr3 "
mr4 = "mr4 "
mr5 = "mr5 "
mr6 = "mr6 "
# Add other margins as needed
class Paddings:
p0 = "p0 "
p_half = "p-half "
p1 = "p1 "
p2 = "p2 "
p3 = "p3 "
p4 = "p4 "
p5 = "p5 "
p6 = "p6 "
pt0 = "pt0 "
pt_half = "pt-half "
pt1 = "pt1 "
pt2 = "pt2 "
pt3 = "pt3 "
pt4 = "pt4 "
pt5 = "pt5 "
pt6 = "pt6 "
pb0 = "pb0 "
pb_half = "pb-half "
pb1 = "pb1 "
pb2 = "pb2 "
pb3 = "pb3 "
pb4 = "pb4 "
pb5 = "pb5 "
pb6 = "pb6 "
pl0 = "pl0 "
pl_half = "pl-half "
pl1 = "pl1 "
pl2 = "pl2 "
pl3 = "pl3 "
pl4 = "pl4 "
pl5 = "pl5 "
pl6 = "pl6 "
pr0 = "pr0 "
pr_half = "pr-half "
pr1 = "pr1 "
pr2 = "pr2 "
pr3 = "pr3 "
pr4 = "pr4 "
pr5 = "pr5 "
pr6 = "pr6 "
# Add other paddings as needed
class Visibility:
d_none = "d-none "
d_flex = "d-flex "
d_block = "d-block "
d_inline = "d-inline "
d_inline_block = "d-inline-block "
# Add other visibility classes as needed
class Opacity:
transparent = "transparent "
half_transparent = "half-transparent "
opaque = "opaque "
# Add other opacity classes as needed
class LayoutModifiers:
# Layout block modifiers
align_columns_top = "align-columns-top "
align_columns_center = "align-columns-center "
align_columns_bottom = "align-columns-bottom "
align_columns_stretch = "align-columns-stretch "
# Layout child part modifiers
align_item_top = "align-item-top "
align_item_center = "align-item-center "
align_item_bottom = "align-item-bottom "
align_item_stretch = "align-item-stretch "
# Add other layout modifiers as needed
class Layout:
taipy_layout = "taipy-layout"
taipy_part = "taipy-part"
taipy_dark = "taipy-dark"
taipy_light = "taipy-light"
# Add other layout classes as needed
class Theme:
"""Base Theme class."""
def __init__(
self,
name,
primary_color,
secondary_color,
border_radius,
font_family,
color_background_light,
color_background_dark,
color_paper_light,
color_paper_dark,
input_button_height,
):
self.name = name
self.primary_color = primary_color
self.secondary_color = secondary_color
self.border_radius = border_radius
self.font_family = font_family
self.color_background_light = color_background_light
self.color_background_dark = color_background_dark
self.color_paper_light = color_paper_light
self.color_paper_dark = color_paper_dark
self.input_button_height = input_button_height
class Themes:
"""Collection of themes for the Stylekit."""
Default = Theme(
name="Default",
primary_color="#FF462B",
secondary_color="#283282",
border_radius=8,
font_family="Lato, Arial, sans-serif",
color_background_light="#F0F5F7",
color_background_dark="#152335",
color_paper_light="#FFFFFF",
color_paper_dark="#1F2F44",
input_button_height="48px",
)
#: Monospace Theme: Coding or terminal-like appearance.
Monospace = Theme(
name="Monospace",
primary_color="#333333",
secondary_color="#555555",
border_radius="0px",
font_family="'Courier New', monospace",
color_background_light="#EFEFEF",
color_background_dark="#2E2E2E",
color_paper_light="#FFFFFF",
color_paper_dark="#3C3C3C",
input_button_height="44px",
)
#: Coffee Theme: Warm, cozy coffee shop atmosphere.
Coffee = Theme(
name="Coffee",
primary_color="#6F4E37",
secondary_color="#A67B5B",
border_radius="12px",
font_family="'Georgia', serif",
color_background_light="#F5F5DC",
color_background_dark="#4B3832",
color_paper_light="#FFFFFF",
color_paper_dark="#854442",
input_button_height="50px",
)
#: Ocean Theme: Calm and refreshing aquatic feel.
Ocean = Theme(
name="Ocean",
primary_color="#2E8BC0",
secondary_color="#145DA0",
border_radius="16px",
font_family="'Arial', sans-serif",
color_background_light="#B1D4E0",
color_background_dark="#133B5C",
color_paper_light="#FFFFFF",
color_paper_dark="#1E5F74",
input_button_height="48px",
)
#: Minimalist Theme: Clean and simple design.
Minimalist = Theme(
name="Minimalist",
primary_color="#000000",
secondary_color="#7F7F7F",
border_radius="0px",
font_family="'Helvetica Neue', sans-serif",
color_background_light="#FFFFFF",
color_background_dark="#F2F2F2",
color_paper_light="#FFFFFF",
color_paper_dark="#E6E6E6",
input_button_height="46px",
)
#: Vibrant Theme: Playful and energetic appearance.
Vibrant = Theme(
name="Vibrant",
primary_color="#FF6F61",
secondary_color="#6B5B95",
border_radius="24px",
font_family="'Comic Sans MS', cursive, sans-serif",
color_background_light="#FFF0E6",
color_background_dark="#4A4A4A",
color_paper_light="#FFFFFF",
color_paper_dark="#FF6F61",
input_button_height="52px",
)
#: Industrial Theme: Rugged and mechanical aesthetic.
Industrial = Theme(
name="Industrial",
primary_color="#5A5A5A",
secondary_color="#A1A1A1",
border_radius="4px",
font_family="'Roboto', sans-serif",
color_background_light="#D3D3D3",
color_background_dark="#2C2C2C",
color_paper_light="#E0E0E0",
color_paper_dark="#3A3A3A",
input_button_height="48px",
)
#: Futuristic Theme: Sleek and modern design.
Futuristic = Theme(
name="Futuristic",
primary_color="#00FFFF",
secondary_color="#FF00FF",
border_radius="20px",
font_family="'Orbitron', sans-serif",
color_background_light="#1A1A1A",
color_background_dark="#000000",
color_paper_light="#262626",
color_paper_dark="#0D0D0D",
input_button_height="50px",
)
#: Classic Theme: Traditional and timeless appearance.
Classic = Theme(
name="Classic",
primary_color="#003366",
secondary_color="#336699",
border_radius="8px",
font_family="'Times New Roman', serif",
color_background_light="#CCCCCC",
color_background_dark="#F0F0F0",
color_paper_light="#CCCCCC",
color_paper_dark="#E0E0E0",
input_button_height="48px",
)
#: Nature Theme: Earthy and natural tones.
Nature = Theme(
name="Nature",
primary_color="#6B8E23",
secondary_color="#556B2F",
border_radius="12px",
font_family="'Verdana', sans-serif",
color_background_light="#F5FFFA",
color_background_dark="#2F4F4F",
color_paper_light="#FFFFFF",
color_paper_dark="#8FBC8F",
input_button_height="48px",
)
#: HighContrast Theme: For accessibility and readability.
HighContrast = Theme(
name="HighContrast",
primary_color="#FFFFFF",
secondary_color="#000000",
border_radius="0px",
font_family="'Arial Black', sans-serif",
color_background_light="#000000",
color_background_dark="#000000",
color_paper_light="#FFFFFF",
color_paper_dark="#FFFFFF",
input_button_height="48px",
)
class Stylekit:
components = Components()
typography = Typography()
text_weights = TextWeights()
text_alignment = TextAlignment()
margins = Margins()
paddings = Paddings()
visibility = Visibility()
opacity = Opacity()
layout = LayoutModifiers()
themes = Themes()
# Add other style properties as needed
def __init__(self):
# Default theme is 'Default'
self.set_theme(self.themes.Default)
def set_theme(self, theme):
if isinstance(theme, Theme):
self.stylekit = {
"primary_color": theme.primary_color,
"secondary_color": theme.secondary_color,
"border_radius": theme.border_radius,
"font_family": theme.font_family,
"color_background_light": theme.color_background_light,
"color_background_dark": theme.color_background_dark,
"color_paper_light": theme.color_paper_light,
"color_paper_dark": theme.color_paper_dark,
"input_button_height": theme.input_button_height,
}
elif isinstance(theme, str):
theme_obj = getattr(self.themes, theme, None)
if theme_obj and isinstance(theme_obj, Theme):
self.set_theme(theme_obj)
else:
available_themes = [
t
for t in dir(self.themes)
if not t.startswith("__")
and isinstance(getattr(self.themes, t), Theme)
]
print(
f"Theme '{theme}' not recognized. Available themes: {', '.join(available_themes)}"
)
else:
raise TypeError(
"Theme must be a Theme instance or a string representing the theme name."
)
# You can add individual setter methods if needed
def set_primary_color(self, color):
self.stylekit["primary_color"] = color
def set_secondary_color(self, color):
self.stylekit["secondary_color"] = color
def set_border_radius(self, radius):
self.stylekit["border_radius"] = radius
def set_font_family(self, family):
self.stylekit["font_family"] = family
def set_color_background_light(self, color):
self.stylekit["color_background_light"] = color
def set_color_background_dark(self, color):
self.stylekit["color_background_dark"] = color
def set_color_paper_light(self, color):
self.stylekit["color_paper_light"] = color
def set_color_paper_dark(self, color):
self.stylekit["color_paper_dark"] = color
def set_input_button_height(self, height):
self.stylekit["input_button_height"] = height
def get_stylekit(self):
return self.stylekit
# Create an instance of Stylekit
stylekit = Stylekit()
Yes this could help