Skip to content

Design System / Système de design

Update date : 2026-05-16 02:50

Index and general conventions for Streamlit in Snowflake apps built with pinky-streamlit. Index et conventions générales pour les apps Streamlit in Snowflake construites avec pinky-streamlit.


Documentation

File / Fichier Content / Contenu
DESIGN_SYSTEM.md (this file / ce fichier) Index, architecture, general conventions, page patterns
DESIGN_SYSTEM_PALETTE.md Palette, tokens, dark mode, CSS variables, icons, spacing
DESIGN_SYSTEM_CORE.md Session, page setup, cache strategies, CRUD operations, NaN→None convention
DESIGN_SYSTEM_UI.md UI components (ui_components/ — planned L2)

Package architecture / Architecture du package

src/pinky_streamlit/
├── __init__.py                ← public API — flat re-exports from core/
├── core/                      ← L1: stable — implemented
│   ├── constants.py           ← PALETTES, PALETTE, ICONS, Icon, Palette, PaletteColors
│   ├── session.py             ← get_session(), LocalSessionConfig
│   ├── db.py                  ← load_analytic, load_crud, load_static, load_nocache
│   │                             update_data, insert_data, invalidate_crud, add_status_icons
│   ├── page.py                ← setup_page(), Logo, AppFont, DEFAULT_FONT
│   └── assets/
│       ├── style.css          ← Streamlit normalization, CSS variables, layout
│       └── fonts/DMSans.woff2 ← Default font (base64-embedded)
└── ui_components/             ← L2: planned
    ├── text/                  ← header, badge, empty_state
    ├── widgets/               ← filters, FilterConfig, action_grid
    ├── data/                  ← metric, detail, data_editor, drilldown
    ├── layouts/               ← card_grid, divider
    └── status/                ← status_card, StatusStepConfig

CSS architecture — module-scoped / Architecture CSS — par module : - style.css covers Streamlit normalization only (variables, layout, native component overrides). / style.css couvre uniquement la normalisation Streamlit (variables, layout, overrides des composants natifs). - Each ui_components/ module owns its .css file, injected on demand by setup_page(). / Chaque module ui_components/ possède son .css, injecté à la demande par setup_page(). - Never add component styles to style.css. / Ne jamais ajouter de styles de composants dans style.css.


Page pattern / Pattern de page

Every SiS page follows this structure. / Chaque page SiS suit cette structure.

from functools import partial
from pinky_streamlit import setup_page, load_analytic, PALETTES

# Call once at the top — before any other st.* calls
# Appeler une seule fois en haut — avant tout autre appel st.*
messages_container, main_container, df = setup_page(
    session=session,
    loaders=[partial(load_analytic, _query_fn=my_query, key="data")],
    palette=PALETTES.PYTHIA,
)

try:
    with main_container:
        st.title("My page")
        st.dataframe(df)
except Exception as e:
    messages_container.error(str(e), icon="‼️")

Rules / Règles : - messages_container → always above main_container. Use .error() / .warning() from the except block only. / Toujours au-dessus de main_container. Utiliser .error() / .warning() uniquement depuis le bloc except. - main_container → wrap all page content with with main_container:. / Envelopper tout le contenu de la page avec with main_container:. - setup_page() returns (messages_container, main_container, *loader_results) — one result per loader in declaration order. / Retourne (messages_container, main_container, *loader_results) — un résultat par loader dans l'ordre de déclaration.


CRUD page pattern / Pattern page CRUD

from functools import partial
from pinky_streamlit import (
    setup_page, load_crud, invalidate_crud, update_data, insert_data, PALETTES
)

KEY = "building"
TABLE = "USER_CONFIG_BUILDINGS"

@st.dialog(" ", width="large")
def add_building():
    with st.form("form-add"):
        code = st.text_input("Code")
        submitted = st.form_submit_button("Save")
        if submitted:
            insert_data(
                session=session, data=[{"CODE": code}], key="CODE", table=TABLE,
                on_success=lambda: invalidate_crud(KEY),
            )
            st.rerun()

messages, main, df = setup_page(
    session, loaders=[partial(load_crud, query_fn=my_query, key=KEY)]
)

with main:
    if st.button("Add"):
        add_building()
    st.dataframe(df)

Filter form — avoid unnecessary reruns / Formulaire de filtres — éviter les reruns inutiles

Use st.form when you have 3+ combined filters in a CRUD app. / Utiliser st.form avec 3+ filtres combinés dans une app CRUD.

Situation Approach / Approche
3+ combined filters, CRUD app st.form — single rerun on submit / rerun unique au clic
1–2 simple filters, analytic dashboard Free widgets — immediate rerun OK / rerun immédiat OK
Filters with dependency (B depends on A) Free widgets — rerun updates options
Sidebar pills / navigation Free widgets — immediate feedback expected

Multi-page navigation / Navigation multi-pages

# constants.py — centralize page config / centraliser la config des pages
PAGES_CONFIG: dict[str, dict] = {
    "home":     {"icon": str(ICONS.HOME),      "title": "Home",      "path": "pages/home.py"},
    "settings": {"icon": str(ICONS.SETTINGS),  "title": "Settings",  "path": "pages/settings.py"},
    "buildings":{"icon": str(ICONS.BUILDING),  "title": "Buildings", "path": "pages/buildings.py",
                 "table": "USER_CONFIG_BUILDINGS"},
}

# streamlit_app.py
home = st.Page(PAGES_CONFIG["home"]["path"], title="Home", icon=PAGES_CONFIG["home"]["icon"], default=True)
pg   = st.navigation({"": [home]})
pg.run()

Do not name the folder /pages/ — conflicts with Streamlit automatic page discovery. Ne pas nommer le dossier /pages/ — conflit avec la découverte automatique de pages Streamlit.


Streamlit version / Version Streamlit

Pin to the version validated against the SiS CSS design system. / Épingler à la version validée contre le système de design CSS SiS.

# pyproject.toml
[project]
dependencies = ["streamlit==1.52.2"]

Streamlit breaks CSS and widget APIs regularly. Never use >= or leave unpinned. / Streamlit casse régulièrement les CSS et les APIs de widgets. Ne jamais utiliser >= ni laisser sans version.


Integration checklist / Checklist d'intégration

For a new SiS app / Pour une nouvelle app SiS :

  1. Call setup_page() at the top of every page / Appeler setup_page() en haut de chaque page
  2. Choose a palette → palette=PALETTES.PYTHIA or custom / Choisir une palette → palette=PALETTES.PYTHIA ou custom
  3. Select the correct cache strategy for each dataset (see DESIGN_SYSTEM_CORE.md) / Sélectionner la bonne stratégie de cache par dataset
  4. Use ICONS.<NAME>.material for buttons/badges, .emoji for dataframe columns / Utiliser ICONS.<NAME>.material pour boutons/badges, .emoji pour colonnes dataframe
  5. Apply where(lambda d: d.notna(), None) after every to_pandas() / Appliquer where(lambda d: d.notna(), None) après chaque to_pandas()
  6. Follow key naming conventions: btn-{type}-{accent}-{name}, container-{accent}-{shade}-{name}, table-{accent}-{name} / Suivre les conventions de nommage des keys