Skip to content

constants

pinky_streamlit.constants

Shared constants for the design system: color palette and icon registry.

Usage::

from pinky_streamlit import ICONS, PALETTE

st.badge("",  icon=ICONS.SUCCESS.material)   # :material/check_circle:
st.badge("✅", icon=ICONS.SUCCESS.emoji)      # ✅
st.badge("",  icon=str(ICONS.SUCCESS))        # same as .material (default)

ICONS

Kit icon registry — subclass to add app-specific icons.

Access via ICONS.<NAME>.material or ICONS.<NAME>.emoji.

Source code in src/pinky_streamlit/core/constants.py
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
class ICONS:
    """Kit icon registry — subclass to add app-specific icons.

    Access via ``ICONS.<NAME>.material`` or ``ICONS.<NAME>.emoji``.
    """

    # ── Navigation & layout ───────────────────────────────────────────────────
    HOME = Icon(":material/home:", "🏠")
    DASHBOARD = Icon(":material/dashboard:", "📋")
    WIDGETS = Icon(":material/widgets:", "🧩")
    SETTINGS = Icon(":material/settings:", "⚙️")
    ADMIN = Icon(":material/admin_panel_settings:", "🛡️")
    FILTER = Icon(":material/filter_list:", "🔽")
    SORT = Icon(":material/sort:", "↕️")
    SEARCH = Icon(":material/search:", "🔍")
    EXPAND = Icon(":material/expand_more:", "▼")
    COLLAPSE = Icon(":material/expand_less:", "▲")
    BACK = Icon(":material/arrow_back:", "◀")
    FORWARD = Icon(":material/arrow_forward:", "▶")
    ARROW_RIGHT = Icon(":material/arrow_right:", "→")
    LINK = Icon(":material/link:", "🔗")
    PIN = Icon(":material/push_pin:", "📌")
    TAG = Icon(":material/tag:", "🏷️")
    COPY = Icon(":material/content_copy:", "📋")

    # ── Status & feedback ─────────────────────────────────────────────────────
    SUCCESS = Icon(":material/check_circle:", "✅")
    WARNING = Icon(":material/warning:", "⚠️")
    ERROR = Icon(":material/error:", "🚨")
    INFO = Icon(":material/info:", "ℹ️")  # noqa: RUF001
    HELP = Icon(":material/help:", "❓")
    LEGEND = Icon(":material/live_help:", "💡")
    UNDEFINED = Icon(":material/remove:", "—")
    CELEBRATION = Icon(":material/celebration:", "🎉")
    BLOCKED = Icon(":material/block:", "🚫")
    DO_NOT_DISTURB = Icon(":material/do_not_disturb_on:", "⛔")
    CHECK = Icon(":material/check:", "✓")
    CANCEL = Icon(":material/cancel:", "❌")
    FLAG = Icon(":material/flag:", "🚩")
    STAR = Icon(":material/star:", "⭐")
    SKULL = Icon(":material/skull:", "💀")
    NOTIFICATION = Icon(":material/notifications:", "🔔")
    SATISFIED = Icon(":material/sentiment_satisfied:", "🙂")
    NEUTRAL = Icon(":material/sentiment_neutral:", "😐")
    DISSATISFIED = Icon(":material/sentiment_dissatisfied:", "☹️")

    # ── Actions ───────────────────────────────────────────────────────────────
    ADD = Icon(":material/add:", "+")
    ADD_ROW = Icon(":material/docs_add_on:", "+")
    EDIT = Icon(":material/edit:", "✏️")
    EDIT_COLUMN = Icon(":material/edit_note:", "📝")
    DELETE = Icon(":material/delete:", "🗑️")
    SAVE = Icon(":material/save:", "💾")
    CLOSE = Icon(":material/close:", "✖️")
    REFRESH = Icon(":material/refresh:", "🔄")
    SYNC = Icon(":material/sync:", "🔄")
    PLAY = Icon(":material/play_arrow:", "▶️")
    PAUSE = Icon(":material/pause:", "⏸️")
    STOP = Icon(":material/stop:", "⏹️")
    EXECUTE = Icon(":material/electric_bolt:", "⚡")
    MANUAL = Icon(":material/touch_app:", "👆")
    TRIGGERED = Icon(":material/calendar_clock:", "⏰")
    SP_PARAMS = Icon(":material/settings_timelapse:", "⏱️")
    LOCK = Icon(":material/lock:", "🔒")
    UNLOCK = Icon(":material/lock_open:", "🔓")
    VISIBLE = Icon(":material/visibility:", "👁️")
    HIDDEN = Icon(":material/visibility_off:", "🙈")

    # ── Files & data ──────────────────────────────────────────────────────────
    DOWNLOAD = Icon(":material/cloud_download:", "📥")
    UPLOAD = Icon(":material/upload_file:", "📤")
    CLOUD_UPLOAD = Icon(":material/cloud_upload:", "☁️")
    FILE = Icon(":material/description:", "📄")
    FOLDER = Icon(":material/folder:", "📁")
    TABLE = Icon(":material/table:", "📋")
    TABLE_EDIT = Icon(":material/table_edit:", "📝")
    TABLE_READONLY = Icon(":material/edit_off:", "🔒")
    OUTPUT = Icon(":material/output:", "📤")

    # ── Content ───────────────────────────────────────────────────────────────
    ARTICLE = Icon(":material/article:", "📄")
    IMAGE = Icon(":material/image:", "🖼️")
    CHAT = Icon(":material/chat:", "💬")
    CARDS = Icon(":material/cards:", "🃏")
    MAIL = Icon(":material/mail:", "📧")

    # ── Users & org ───────────────────────────────────────────────────────────
    USER = Icon(":material/person:", "👤")
    USERS = Icon(":material/group:", "👥")
    BUILDING = Icon(":material/apartment:", "🏢")
    COMPANY = Icon(":material/business:", "🏢")

    # ── Analytics & time ──────────────────────────────────────────────────────
    ANALYTICS = Icon(":material/analytics:", "📊")
    CHART = Icon(":material/bar_chart:", "📊")
    CHARTS = Icon(":material/insert_chart:", "📊")
    TIMELINE = Icon(":material/timeline:", "📈")
    TRENDING_UP = Icon(":material/trending_up:", "📈")
    TRENDING_DOWN = Icon(":material/trending_down:", "📉")
    CALENDAR = Icon(":material/calendar_month:", "📅")
    CLOCK = Icon(":material/schedule:", "🕐")
    HISTORY = Icon(":material/history:", "🕰️")
    UPDATE = Icon(":material/update:", "🔄")

    # ── Finance ───────────────────────────────────────────────────────────────
    MONEY = Icon(":material/payments:", "💰")
    RECEIPT = Icon(":material/receipt_long:", "🧾")

Icon dataclass

A design-system icon with both a Material Symbol and an emoji variant.

str(icon) returns the material string — safe to pass to any Streamlit argument that accepts a Material Symbol (icon=, st.badge, st.button…). Use .emoji for components that don't support :material/…: syntax.

To extend the registry with app-specific icons, subclass ICONS::

from pinky_streamlit import ICONS, Icon

class MyIcons(ICONS):
    CAT    = Icon(":material/pets:",          "🐱")
    RABBIT = Icon(":material/cruelty_free:",  "🐰")
Source code in src/pinky_streamlit/core/constants.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@dataclass(frozen=True)
class Icon:
    """A design-system icon with both a Material Symbol and an emoji variant.

    ``str(icon)`` returns the material string — safe to pass to any Streamlit
    argument that accepts a Material Symbol (icon=, st.badge, st.button…).
    Use ``.emoji`` for components that don't support ``:material/…:`` syntax.

    To extend the registry with app-specific icons, subclass ICONS::

        from pinky_streamlit import ICONS, Icon

        class MyIcons(ICONS):
            CAT    = Icon(":material/pets:",          "🐱")
            RABBIT = Icon(":material/cruelty_free:",  "🐰")
    """

    material: str
    emoji: str

    def __str__(self) -> str:
        return self.material

PALETTES

Pre-built color palettes — subclass to add app-specific themes.

Access via PALETTES.PYTHIA, PALETTES.STREAMLIT, etc. Pass to setup_page(palette=PALETTES.PYTHIA) to activate. Dark mode is auto-computed unless overridden via dark=PaletteColors(...).

To extend with custom palettes, subclass PALETTES::

from pinky_streamlit import PALETTES, Palette, PaletteColors

class AppPalettes(PALETTES):
    MY_BRAND = Palette(
        light=PaletteColors(primary="#6200ea", secondary="#00bcd4", tertiary="#76ff03"),
    )
Source code in src/pinky_streamlit/core/constants.py
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
class PALETTES:
    """Pre-built color palettes — subclass to add app-specific themes.

    Access via ``PALETTES.PYTHIA``, ``PALETTES.STREAMLIT``, etc.
    Pass to ``setup_page(palette=PALETTES.PYTHIA)`` to activate.
    Dark mode is auto-computed unless overridden via ``dark=PaletteColors(...)``.

    To extend with custom palettes, subclass ``PALETTES``::

        from pinky_streamlit import PALETTES, Palette, PaletteColors

        class AppPalettes(PALETTES):
            MY_BRAND = Palette(
                light=PaletteColors(primary="#6200ea", secondary="#00bcd4", tertiary="#76ff03"),
            )
    """

    # Pinky brand — coral / slate blue / raspberry pink
    PINKY = Palette(
        light=PaletteColors(primary="#f1a1a0", secondary="#7b8fa8", tertiary="#ca748f"),
    )

    # Pythia brand — violet / rose / cyan
    PYTHIA = Palette(
        light=PaletteColors(primary="#7056d7", secondary="#e07baa", tertiary="#60defb"),
    )

    # Anthropic brand — coral / teal / warm sand
    ANTHROPIC = Palette(
        light=PaletteColors(primary="#d97756", secondary="#4a8c8c", tertiary="#c9a07a"),
    )

    # Streamlit brand — red / blue / green (exact brand colors)
    STREAMLIT = Palette(
        light=PaletteColors(primary="#ff4b4b", secondary="#0068c9", tertiary="#09ab3b"),
    )

    # Apple — blue / orange / purple (with brand semantic tokens)
    APPLE = Palette(
        light=PaletteColors(
            primary="#0066cc",
            secondary="#ff9900",
            tertiary="#9900cc",
            success="#00cc44",
            warning="#ffcc00",
            error="#d10000",
        ),
    )

    # GitHub Primer — blue / green / purple
    GITHUB = Palette(
        light=PaletteColors(primary="#0969da", secondary="#2da44e", tertiary="#9a3ecb"),
    )

    # Python — blue / yellow / navy (logo colors)
    PYTHON = Palette(
        light=PaletteColors(primary="#3776ab", secondary="#ffd43b", tertiary="#1e415e"),
    )

    # Duck DB — black / yellow / white (logo colors)
    DUCK_DB = Palette(
        light=PaletteColors(primary="#000000", secondary="#fcf150", tertiary="#ffffff"),
    )

Palette dataclass

A complete theme with light and dark color sets.

Pass to setup_page(palette=...) to inject brand colors as CSS variables. All color-mix() shades in style.css are derived automatically from these base colors — no CSS file needs editing.

Usage::

from pinky_streamlit import PALETTES, setup_page

messages, main, df = setup_page(session, loaders=[...], palette=PALETTES.APPLE)

Extend with a custom palette::

from pinky_streamlit import Palette, PaletteColors

# Dark auto-computed from light
MY_PALETTE = Palette(
    light=PaletteColors(primary="#6200ea", secondary="#00bcd4", tertiary="#76ff03"),
)

# Full control over dark variant
MY_PALETTE = Palette(
    light=PaletteColors(primary="#6200ea", secondary="#00bcd4", tertiary="#76ff03"),
    dark=PaletteColors( primary="#b388ff", secondary="#80deea", tertiary="#ccff90"),
)
Source code in src/pinky_streamlit/core/constants.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
@dataclass(frozen=True)
class Palette:
    """A complete theme with light and dark color sets.

    Pass to ``setup_page(palette=...)`` to inject brand colors as CSS variables.
    All ``color-mix()`` shades in style.css are derived automatically from these
    base colors — no CSS file needs editing.

    Usage::

        from pinky_streamlit import PALETTES, setup_page

        messages, main, df = setup_page(session, loaders=[...], palette=PALETTES.APPLE)

    Extend with a custom palette::

        from pinky_streamlit import Palette, PaletteColors

        # Dark auto-computed from light
        MY_PALETTE = Palette(
            light=PaletteColors(primary="#6200ea", secondary="#00bcd4", tertiary="#76ff03"),
        )

        # Full control over dark variant
        MY_PALETTE = Palette(
            light=PaletteColors(primary="#6200ea", secondary="#00bcd4", tertiary="#76ff03"),
            dark=PaletteColors( primary="#b388ff", secondary="#80deea", tertiary="#ccff90"),
        )
    """

    light: PaletteColors
    dark: PaletteColors | None = None

    def to_config_toml(
        self,
        font_files: list[str] | None = None,
    ) -> str:
        """Generate ``.streamlit/config.toml`` content from this palette.

        For Streamlit Container Runtime apps: sets ``primaryColor`` natively
        for both light and dark themes. This fixes the KNOWN LIMITATIONS in
        ``style.css`` (slider track fill, date picker selected day) that
        cannot be overridden via CSS — Streamlit now applies the color
        at the React level.

        ``setup_page()`` still injects ``style.css`` + CSS variables for the
        full design system (``--primary-darker``, ``color-mix()`` shades,
        component overrides). This method handles what ``config.toml``
        can absorb; CSS handles the rest.

        Font injection via base64 (``AppFont``) is no longer needed in
        Container Runtime — pass font files instead and set ``font=None``
        in ``setup_page()``.

        Args:
            font_files: Project-relative paths to font files to bundle
                        (e.g. ``["static/DMSans.woff2"]``). ``None`` = no
                        custom font declared in config.toml.

        Returns:
            String content to write to ``.streamlit/config.toml``.

        Example::

            from pinky_streamlit import PALETTES

            toml = PALETTES.PYTHIA.to_config_toml(
                font_files=["static/DMSans.woff2"]
            )
            # Write to .streamlit/config.toml in your app project.
        """
        dc = self.dark if self.dark is not None else _auto_dark_palette(self.light)
        lines: list[str] = [
            "[theme.light]",
            f'primaryColor = "{self.light.primary}"',
            "",
            "[theme.dark]",
            f'primaryColor = "{dc.primary}"',
        ]
        if font_files:
            formatted = "[" + ", ".join(f'"{f}"' for f in font_files) + "]"
            lines += [
                "",
                "[theme]",
                'font = "custom"',
                f"fontFiles = {formatted}",
            ]
        return "\n".join(lines) + "\n"

to_config_toml(font_files=None)

Generate .streamlit/config.toml content from this palette.

For Streamlit Container Runtime apps: sets primaryColor natively for both light and dark themes. This fixes the KNOWN LIMITATIONS in style.css (slider track fill, date picker selected day) that cannot be overridden via CSS — Streamlit now applies the color at the React level.

setup_page() still injects style.css + CSS variables for the full design system (--primary-darker, color-mix() shades, component overrides). This method handles what config.toml can absorb; CSS handles the rest.

Font injection via base64 (AppFont) is no longer needed in Container Runtime — pass font files instead and set font=None in setup_page().

Parameters:

Name Type Description Default
font_files list[str] | None

Project-relative paths to font files to bundle (e.g. ["static/DMSans.woff2"]). None = no custom font declared in config.toml.

None

Returns:

Type Description
str

String content to write to .streamlit/config.toml.

Example::

from pinky_streamlit import PALETTES

toml = PALETTES.PYTHIA.to_config_toml(
    font_files=["static/DMSans.woff2"]
)
# Write to .streamlit/config.toml in your app project.
Source code in src/pinky_streamlit/core/constants.py
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
def to_config_toml(
    self,
    font_files: list[str] | None = None,
) -> str:
    """Generate ``.streamlit/config.toml`` content from this palette.

    For Streamlit Container Runtime apps: sets ``primaryColor`` natively
    for both light and dark themes. This fixes the KNOWN LIMITATIONS in
    ``style.css`` (slider track fill, date picker selected day) that
    cannot be overridden via CSS — Streamlit now applies the color
    at the React level.

    ``setup_page()`` still injects ``style.css`` + CSS variables for the
    full design system (``--primary-darker``, ``color-mix()`` shades,
    component overrides). This method handles what ``config.toml``
    can absorb; CSS handles the rest.

    Font injection via base64 (``AppFont``) is no longer needed in
    Container Runtime — pass font files instead and set ``font=None``
    in ``setup_page()``.

    Args:
        font_files: Project-relative paths to font files to bundle
                    (e.g. ``["static/DMSans.woff2"]``). ``None`` = no
                    custom font declared in config.toml.

    Returns:
        String content to write to ``.streamlit/config.toml``.

    Example::

        from pinky_streamlit import PALETTES

        toml = PALETTES.PYTHIA.to_config_toml(
            font_files=["static/DMSans.woff2"]
        )
        # Write to .streamlit/config.toml in your app project.
    """
    dc = self.dark if self.dark is not None else _auto_dark_palette(self.light)
    lines: list[str] = [
        "[theme.light]",
        f'primaryColor = "{self.light.primary}"',
        "",
        "[theme.dark]",
        f'primaryColor = "{dc.primary}"',
    ]
    if font_files:
        formatted = "[" + ", ".join(f'"{f}"' for f in font_files) + "]"
        lines += [
            "",
            "[theme]",
            'font = "custom"',
            f"fontFiles = {formatted}",
        ]
    return "\n".join(lines) + "\n"

PaletteColors dataclass

Color set for one mode (light or dark).

primary, secondary, tertiary are the brand accent colors. Semantic colors default to the pythia theme values and are usually kept stable across themes.

Source code in src/pinky_streamlit/core/constants.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
@dataclass(frozen=True)
class PaletteColors:
    """Color set for one mode (light or dark).

    ``primary``, ``secondary``, ``tertiary`` are the brand accent colors.
    Semantic colors default to the pythia theme values and are usually kept
    stable across themes.
    """

    primary: str
    secondary: str
    tertiary: str
    success: str = "#09ab3b"
    warning: str = "#ffa421"
    error: str = "#ff4b4b"
    grey: str = "#535353"