Initial commit: Shelly Manager with Textual CLI, Streamlit UI, and comprehensive .gitignore
Shelly device management app with mDNS/subnet discovery, inventory, configuration, and mass operations for Gen1/Gen2+ devices. Includes .gitignore excluding runtime data (device DB, user config), AI conversation history, build artifacts, and common Python/OS patterns.
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
# Streamlit theme templates
|
||||
|
||||
Ready-to-use theme templates for Streamlit apps.
|
||||
|
||||
## Available themes
|
||||
|
||||
| Theme | Base | Primary color | Fonts |
|
||||
|-------|------|---------------|-------|
|
||||
| **snowflake** | Light | `#29B5E8` (cyan) | Inter, JetBrains Mono |
|
||||
| **dracula** | Dark | `#BD93F9` (purple) | Fira Sans, JetBrains Mono |
|
||||
| **nord** | Dark | `#88C0D0` (frost blue) | Inter, JetBrains Mono |
|
||||
| **stripe** | Light | `#635BFF` (indigo) | Inter, Source Code Pro |
|
||||
| **solarized-light** | Light | `#268BD2` (blue) | Source Sans 3, Source Code Pro |
|
||||
| **spotify** | Dark | `#1DB954` (green) | Inter, Fira Code |
|
||||
| **github** | Light | `#0969DA` (blue) | Inter, JetBrains Mono |
|
||||
| **minimal** | Dark | `#6366f1` (indigo) | Inter, JetBrains Mono |
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# Run a theme locally
|
||||
cd templates/themes/spotify
|
||||
uv sync
|
||||
uv run streamlit run streamlit_app.py
|
||||
```
|
||||
|
||||
## Deploying to Snowflake
|
||||
|
||||
Before deploying, update `snowflake.yml` with your account-specific resources:
|
||||
|
||||
```yaml
|
||||
# Find available compute pools
|
||||
SHOW COMPUTE POOLS;
|
||||
|
||||
# Find available external access integrations
|
||||
SHOW EXTERNAL ACCESS INTEGRATIONS;
|
||||
```
|
||||
|
||||
Then edit `snowflake.yml` to replace the placeholders:
|
||||
- `<YOUR_COMPUTE_POOL>` → e.g., `STREAMLIT_DEDICATED_POOL`
|
||||
- `<YOUR_PYPI_INTEGRATION>` → e.g., `PYPI_ACCESS_INTEGRATION`
|
||||
- `<FROM_CONNECTION>` values are filled from your active connection
|
||||
|
||||
Deploy with:
|
||||
```bash
|
||||
snow streamlit deploy --replace
|
||||
```
|
||||
|
||||
## How Streamlit theming works
|
||||
|
||||
A custom theme requires two things:
|
||||
|
||||
### 1. Theme configuration in `.streamlit/config.toml`
|
||||
|
||||
```toml
|
||||
[theme]
|
||||
base = "dark" # "dark" or "light"
|
||||
primaryColor = "#1DB954" # Buttons, links, highlights
|
||||
backgroundColor = "#121212" # Main background
|
||||
secondaryBackgroundColor = "#181818" # Sidebar, cards
|
||||
textColor = "#FFFFFF" # Main text color
|
||||
font = "Inter" # Body font
|
||||
codeFont = "FiraCode" # Code blocks
|
||||
```
|
||||
|
||||
### 2. For Snowflake deployment: local font files
|
||||
|
||||
Snowflake doesn't allow remote URL fetches, so fonts must be bundled locally:
|
||||
|
||||
```toml
|
||||
[server]
|
||||
enableStaticServing = true # Required for static files
|
||||
|
||||
[[theme.fontFaces]]
|
||||
family = "Inter"
|
||||
url = "app/static/Inter-Regular.ttf" # Note: app/ prefix required
|
||||
weight = 400
|
||||
|
||||
[[theme.fontFaces]]
|
||||
family = "Inter"
|
||||
url = "app/static/Inter-Bold.ttf"
|
||||
weight = 700
|
||||
```
|
||||
|
||||
Font files go in `static/` directory and are referenced with `app/static/` prefix.
|
||||
|
||||
### Sidebar theming (optional)
|
||||
|
||||
```toml
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#181818"
|
||||
secondaryBackgroundColor = "#121212"
|
||||
borderColor = "#282828"
|
||||
```
|
||||
|
||||
## Theme file structure
|
||||
|
||||
Each theme directory contains:
|
||||
|
||||
```
|
||||
{theme}/
|
||||
├── .streamlit/config.toml # Theme colors and fonts
|
||||
├── streamlit_app.py # Demo app showing the theme
|
||||
├── pyproject.toml # Dependencies
|
||||
├── snowflake.yml # Snowflake deployment config
|
||||
└── static/ # Bundled font files (*.ttf)
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
All themes require Python >=3.11 and use:
|
||||
- `snowflake-connector-python>=3.3.0` (required — `streamlit[snowflake]` silently skips this on Python 3.12+)
|
||||
- `streamlit[snowflake]>=1.54.0`
|
||||
- `altair>=5.5.0`
|
||||
- `pandas>=2.2.3`
|
||||
|
||||
## Font licensing
|
||||
|
||||
All bundled fonts are licensed under the [SIL Open Font License 1.1](https://openfontlicense.org/), which permits free use, redistribution, and modification:
|
||||
|
||||
| Font | Used by | Source |
|
||||
|------|---------|--------|
|
||||
| Inter | snowflake, nord, spotify, github, minimal, stripe | [github.com/rsms/inter](https://github.com/rsms/inter) |
|
||||
| JetBrains Mono | snowflake, dracula, nord, github, minimal | [github.com/JetBrains/JetBrainsMono](https://github.com/JetBrains/JetBrainsMono) |
|
||||
| Fira Sans | dracula | [github.com/mozilla/Fira](https://github.com/mozilla/Fira) |
|
||||
| Fira Code | spotify | [github.com/tonsky/FiraCode](https://github.com/tonsky/FiraCode) |
|
||||
| Source Sans 3 | solarized-light | [github.com/adobe-fonts/source-sans](https://github.com/adobe-fonts/source-sans) |
|
||||
| Source Code Pro | solarized-light, stripe | [github.com/adobe-fonts/source-code-pro](https://github.com/adobe-fonts/source-code-pro) |
|
||||
@@ -0,0 +1,39 @@
|
||||
# Dracula Theme for Streamlit
|
||||
# Popular dark theme with vibrant colors on dark background
|
||||
[theme]
|
||||
base = "dark"
|
||||
primaryColor = "#bd93f9"
|
||||
backgroundColor = "#282a36"
|
||||
secondaryBackgroundColor = "#21222c"
|
||||
codeBackgroundColor = "#21222c"
|
||||
textColor = "#f8f8f2"
|
||||
linkColor = "#8be9fd"
|
||||
borderColor = "#44475a"
|
||||
showWidgetBorder = true
|
||||
showSidebarBorder = true
|
||||
baseRadius = "8px"
|
||||
buttonRadius = "8px"
|
||||
font = "'Fira Sans':https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
codeFontSize = "0.875rem"
|
||||
codeTextColor = "#f8f8f2"
|
||||
baseFontSize = 14
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
|
||||
headingFontWeights = [700, 600, 600, 600, 600, 600]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#bd93f9", "#50fa7b", "#ff79c6", "#8be9fd", "#ffb86c", "#ff5555", "#f1fa8c"]
|
||||
|
||||
# Dracula color palette
|
||||
violetColor = "#bd93f9"
|
||||
greenColor = "#50fa7b"
|
||||
redColor = "#ff5555"
|
||||
blueColor = "#8be9fd"
|
||||
yellowColor = "#f1fa8c"
|
||||
orangeColor = "#ffb86c"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#21222c"
|
||||
secondaryBackgroundColor = "#191a21"
|
||||
codeBackgroundColor = "#191a21"
|
||||
borderColor = "#44475a"
|
||||
@@ -0,0 +1,37 @@
|
||||
# GitHub Theme for Streamlit
|
||||
# Clean, developer-friendly, functional with signature blue accents
|
||||
[theme]
|
||||
primaryColor = "#0969da"
|
||||
backgroundColor = "#ffffff"
|
||||
secondaryBackgroundColor = "#f6f8fa"
|
||||
codeBackgroundColor = "#f6f8fa"
|
||||
textColor = "#1F2328"
|
||||
linkColor = "#0969da"
|
||||
borderColor = "#d0d7de"
|
||||
showWidgetBorder = true
|
||||
showSidebarBorder = true
|
||||
baseRadius = "6px"
|
||||
buttonRadius = "6px"
|
||||
font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
codeFontSize = "0.85rem"
|
||||
codeTextColor = "#1F2328"
|
||||
baseFontSize = 14
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
|
||||
headingFontWeights = [600, 600, 600, 600, 600, 600]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#0969da", "#1a7f37", "#bf3989", "#8250df", "#cf222e", "#bf8700", "#57606a"]
|
||||
|
||||
# GitHub color palette
|
||||
blueColor = "#0969da"
|
||||
greenColor = "#1a7f37"
|
||||
redColor = "#cf222e"
|
||||
violetColor = "#8250df"
|
||||
orangeColor = "#bf8700"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#f6f8fa"
|
||||
secondaryBackgroundColor = "#eaeef2"
|
||||
codeBackgroundColor = "#eaeef2"
|
||||
borderColor = "#d0d7de"
|
||||
@@ -0,0 +1,39 @@
|
||||
# Minimal Dark Theme for Streamlit
|
||||
# Clean, distraction-free dark theme with subtle accents
|
||||
[theme]
|
||||
base = "dark"
|
||||
primaryColor = "#6366f1"
|
||||
backgroundColor = "#18181b"
|
||||
secondaryBackgroundColor = "#27272a"
|
||||
codeBackgroundColor = "#27272a"
|
||||
textColor = "#fafafa"
|
||||
linkColor = "#818cf8"
|
||||
borderColor = "#3f3f46"
|
||||
showWidgetBorder = false
|
||||
showSidebarBorder = false
|
||||
baseRadius = "6px"
|
||||
buttonRadius = "6px"
|
||||
font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
codeFontSize = "0.85rem"
|
||||
codeTextColor = "#e4e4e7"
|
||||
baseFontSize = 14
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
|
||||
headingFontWeights = [600, 600, 500, 500, 500, 500]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#6366f1", "#8b5cf6", "#ec4899", "#14b8a6", "#f59e0b", "#ef4444", "#22c55e"]
|
||||
|
||||
# Color palette
|
||||
violetColor = "#8b5cf6"
|
||||
blueColor = "#6366f1"
|
||||
greenColor = "#22c55e"
|
||||
yellowColor = "#f59e0b"
|
||||
orangeColor = "#f97316"
|
||||
redColor = "#ef4444"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#09090b"
|
||||
secondaryBackgroundColor = "#18181b"
|
||||
codeBackgroundColor = "#18181b"
|
||||
borderColor = "#27272a"
|
||||
@@ -0,0 +1,39 @@
|
||||
# Nord Theme for Streamlit
|
||||
# Arctic, north-bluish color palette with frost-inspired accents
|
||||
[theme]
|
||||
base = "dark"
|
||||
primaryColor = "#88c0d0"
|
||||
backgroundColor = "#2e3440"
|
||||
secondaryBackgroundColor = "#3b4252"
|
||||
codeBackgroundColor = "#3b4252"
|
||||
textColor = "#eceff4"
|
||||
linkColor = "#81a1c1"
|
||||
borderColor = "#4c566a"
|
||||
showWidgetBorder = true
|
||||
showSidebarBorder = true
|
||||
baseRadius = "4px"
|
||||
buttonRadius = "4px"
|
||||
font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
codeFontSize = "0.875rem"
|
||||
codeTextColor = "#d8dee9"
|
||||
baseFontSize = 14
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
|
||||
headingFontWeights = [600, 600, 600, 600, 600, 600]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#88c0d0", "#81a1c1", "#5e81ac", "#a3be8c", "#ebcb8b", "#d08770", "#bf616a"]
|
||||
|
||||
# Nord color palette (Frost + Aurora)
|
||||
blueColor = "#81a1c1"
|
||||
greenColor = "#a3be8c"
|
||||
yellowColor = "#ebcb8b"
|
||||
orangeColor = "#d08770"
|
||||
redColor = "#bf616a"
|
||||
violetColor = "#b48ead"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#3b4252"
|
||||
secondaryBackgroundColor = "#434c5e"
|
||||
codeBackgroundColor = "#434c5e"
|
||||
borderColor = "#4c566a"
|
||||
@@ -0,0 +1,42 @@
|
||||
# Snowflake Theme for Streamlit
|
||||
# The Data Cloud company aesthetic - clean, professional, icy blue branding
|
||||
[theme]
|
||||
primaryColor = "#29B5E8"
|
||||
backgroundColor = "#ffffff"
|
||||
secondaryBackgroundColor = "#f4f9fc"
|
||||
codeBackgroundColor = "#e8f4f8"
|
||||
textColor = "#11567F"
|
||||
linkColor = "#29B5E8"
|
||||
borderColor = "#d0e8f2"
|
||||
showWidgetBorder = true
|
||||
showSidebarBorder = true
|
||||
baseRadius = "8px"
|
||||
buttonRadius = "8px"
|
||||
font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
codeFontSize = "13px"
|
||||
codeTextColor = "#11567F"
|
||||
baseFontSize = 14
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
|
||||
headingFontWeights = [600, 600, 600, 500, 500, 500]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#29B5E8", "#FF8B00", "#36B37E", "#6554C0", "#DE350B", "#11567F", "#FFAB00", "#00A3BF"]
|
||||
|
||||
# Snowflake color palette
|
||||
blueColor = "#29B5E8"
|
||||
greenColor = "#36B37E"
|
||||
yellowColor = "#FFAB00"
|
||||
orangeColor = "#FF8B00"
|
||||
redColor = "#DE350B"
|
||||
violetColor = "#6554C0"
|
||||
|
||||
dataframeBorderColor = "#d0e8f2"
|
||||
dataframeHeaderBackgroundColor = "#e8f4f8"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#11567F"
|
||||
secondaryBackgroundColor = "#174D6A"
|
||||
codeBackgroundColor = "#0E4D6B"
|
||||
textColor = "#ffffff"
|
||||
borderColor = "#1E6D94"
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Solarized Light Theme for Streamlit
|
||||
# Precision colors designed for readability and reduced eye strain
|
||||
[theme]
|
||||
primaryColor = "#268bd2"
|
||||
backgroundColor = "#fdf6e3"
|
||||
secondaryBackgroundColor = "#eee8d5"
|
||||
codeBackgroundColor = "#eee8d5"
|
||||
textColor = "#657b83"
|
||||
linkColor = "#268bd2"
|
||||
borderColor = "#93a1a1"
|
||||
showWidgetBorder = true
|
||||
showSidebarBorder = true
|
||||
baseRadius = "4px"
|
||||
buttonRadius = "4px"
|
||||
font = "'Source Sans 3':https://fonts.googleapis.com/css2?family=Source+Sans+3:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'Source Code Pro':https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500&display=swap"
|
||||
codeFontSize = "0.875rem"
|
||||
codeTextColor = "#586e75"
|
||||
baseFontSize = 14
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
|
||||
headingFontWeights = [600, 600, 600, 600, 600, 600]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#268bd2", "#2aa198", "#859900", "#b58900", "#cb4b16", "#dc322f", "#d33682"]
|
||||
|
||||
# Solarized color palette
|
||||
blueColor = "#268bd2"
|
||||
greenColor = "#859900"
|
||||
yellowColor = "#b58900"
|
||||
orangeColor = "#cb4b16"
|
||||
redColor = "#dc322f"
|
||||
violetColor = "#6c71c4"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#eee8d5"
|
||||
secondaryBackgroundColor = "#fdf6e3"
|
||||
codeBackgroundColor = "#fdf6e3"
|
||||
borderColor = "#93a1a1"
|
||||
@@ -0,0 +1,34 @@
|
||||
# Spotify Theme for Streamlit
|
||||
# Bold, energetic, high contrast with signature green
|
||||
[theme]
|
||||
base = "dark"
|
||||
primaryColor = "#1DB954"
|
||||
backgroundColor = "#191414"
|
||||
secondaryBackgroundColor = "#282828"
|
||||
codeBackgroundColor = "#282828"
|
||||
textColor = "#ffffff"
|
||||
linkColor = "#1DB954"
|
||||
borderColor = "#404040"
|
||||
showWidgetBorder = false
|
||||
showSidebarBorder = false
|
||||
baseRadius = "8px"
|
||||
buttonRadius = "full"
|
||||
font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'Fira Code':https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap"
|
||||
codeFontSize = "0.85rem"
|
||||
baseFontSize = 16
|
||||
baseFontWeight = 400
|
||||
headingFontWeights = [800, 700, 700, 600, 600, 600]
|
||||
headingFontSizes = ["48px", "36px", "28px", "22px", "18px", "16px"]
|
||||
chartCategoricalColors = ["#1DB954", "#1ED760", "#B3B3B3", "#535353", "#191414", "#FFFFFF", "#509BF5"]
|
||||
|
||||
# Spotify color palette
|
||||
greenColor = "#1DB954"
|
||||
blueColor = "#509BF5"
|
||||
grayColor = "#B3B3B3"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#000000"
|
||||
secondaryBackgroundColor = "#282828"
|
||||
codeBackgroundColor = "#282828"
|
||||
borderColor = "#333333"
|
||||
@@ -0,0 +1,35 @@
|
||||
# Stripe Theme for Streamlit
|
||||
# Polished, professional, modern with signature purple/indigo gradients
|
||||
[theme]
|
||||
primaryColor = "#635bff"
|
||||
backgroundColor = "#ffffff"
|
||||
secondaryBackgroundColor = "#f6f9fc"
|
||||
codeBackgroundColor = "#f7f9fc"
|
||||
textColor = "#425466"
|
||||
linkColor = "#635bff"
|
||||
borderColor = "#e3e8ee"
|
||||
showWidgetBorder = true
|
||||
showSidebarBorder = true
|
||||
baseRadius = "8px"
|
||||
buttonRadius = "8px"
|
||||
font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
||||
codeFont = "'Source Code Pro':https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500&display=swap"
|
||||
codeFontSize = "0.85rem"
|
||||
codeTextColor = "#425466"
|
||||
baseFontSize = 15
|
||||
baseFontWeight = 400
|
||||
headingFontSizes = ["40px", "32px", "24px", "20px", "16px", "14px"]
|
||||
headingFontWeights = [600, 600, 600, 600, 600, 600]
|
||||
linkUnderline = false
|
||||
chartCategoricalColors = ["#635bff", "#00d4ff", "#0a2540", "#adbdcc", "#80e9ff", "#7a73ff", "#425466"]
|
||||
|
||||
# Stripe color palette
|
||||
violetColor = "#635bff"
|
||||
blueColor = "#00d4ff"
|
||||
grayColor = "#adbdcc"
|
||||
|
||||
[theme.sidebar]
|
||||
backgroundColor = "#f6f9fc"
|
||||
secondaryBackgroundColor = "#ebeef1"
|
||||
codeBackgroundColor = "#ebeef1"
|
||||
borderColor = "#e3e8ee"
|
||||
@@ -0,0 +1,336 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **{{title}}**")
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# DO NOT EDIT — managed by manage.py, edit _templates/pyproject.toml.tmpl instead
|
||||
[project]
|
||||
name = "theme-{{slug}}"
|
||||
version = "1.0.0"
|
||||
description = "{{title}} theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"snowflake-connector-python>=3.3.0",
|
||||
"streamlit[snowflake]>=1.54.0",
|
||||
]
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-dracula"
|
||||
version = "1.0.0"
|
||||
description = "Dracula theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Dracula**")
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-github"
|
||||
version = "1.0.0"
|
||||
description = "GitHub theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **GitHub**")
|
||||
@@ -0,0 +1,332 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Manage theme template directories (fully generated from _configs/).
|
||||
|
||||
Usage:
|
||||
python manage.py sync # Regenerate all theme directories
|
||||
python manage.py check # Verify generated files haven't drifted
|
||||
python manage.py new NAME # Scaffold a new theme config
|
||||
"""
|
||||
|
||||
import ast
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent
|
||||
SHARED = ROOT / "_shared"
|
||||
TEMPLATES = ROOT / "_templates"
|
||||
CONFIGS = ROOT / "_configs"
|
||||
FONTS = SHARED / "fonts"
|
||||
|
||||
MANAGED_HEADER_PY = (
|
||||
"# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead\n"
|
||||
)
|
||||
MANAGED_HEADER_TOML = (
|
||||
"# DO NOT EDIT — managed by manage.py, edit _configs/{slug}.toml instead\n"
|
||||
)
|
||||
|
||||
GITATTR_START = "# BEGIN managed by manage.py"
|
||||
GITATTR_END = "# END managed by manage.py"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Theme discovery
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
TITLE_OVERRIDES = {"github": "GitHub"}
|
||||
|
||||
|
||||
def slug_to_title(slug):
|
||||
"""Derive a display title from a directory slug: 'solarized-light' -> 'Solarized Light'."""
|
||||
if slug in TITLE_OVERRIDES:
|
||||
return TITLE_OVERRIDES[slug]
|
||||
return " ".join(w.capitalize() for w in slug.split("-"))
|
||||
|
||||
|
||||
def discover_themes():
|
||||
"""Find themes by scanning _configs/*.toml."""
|
||||
return [
|
||||
{"slug": c.stem, "title": slug_to_title(c.stem)}
|
||||
for c in sorted(CONFIGS.glob("*.toml"))
|
||||
]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Font discovery from config content
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def discover_fonts(config_text):
|
||||
"""Extract font filenames referenced in config.toml content."""
|
||||
return re.findall(r'url\s*=\s*["\']app/static/([^"\']+\.(?:ttf|otf|woff2?))["\']', config_text)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Content builders
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def expected_app(title):
|
||||
"""Build expected streamlit_app.py content for a theme."""
|
||||
source = (SHARED / "streamlit_app.py").read_text()
|
||||
body = source.replace("{{title}}", title)
|
||||
# Insert managed header after the module docstring
|
||||
tree = ast.parse(body)
|
||||
if ast.get_docstring(tree) is not None:
|
||||
# The docstring is the first statement; find end of its line
|
||||
docstring_node = tree.body[0]
|
||||
end_line = docstring_node.end_lineno # 1-indexed
|
||||
lines = body.split("\n")
|
||||
insert_pos = end_line
|
||||
return "\n".join(lines[:insert_pos]) + "\n" + MANAGED_HEADER_PY + "\n".join(lines[insert_pos:])
|
||||
return MANAGED_HEADER_PY + body
|
||||
|
||||
|
||||
def expected_config(slug):
|
||||
"""Build expected .streamlit/config.toml content for a theme."""
|
||||
source = (CONFIGS / f"{slug}.toml").read_text()
|
||||
header = MANAGED_HEADER_TOML.replace("{slug}", slug)
|
||||
return header + source
|
||||
|
||||
|
||||
def expected_from_template(tmpl_path, replacements):
|
||||
"""Build expected file content from a .tmpl template."""
|
||||
text = tmpl_path.read_text()
|
||||
for key, value in replacements.items():
|
||||
text = text.replace("{{" + key + "}}", value)
|
||||
return text
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sync
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def sync_theme(theme):
|
||||
"""Regenerate all files for a single theme directory."""
|
||||
slug = theme["slug"]
|
||||
title = theme["title"]
|
||||
identifier = slug.replace("-", "_")
|
||||
theme_dir = ROOT / slug
|
||||
|
||||
# Create directories
|
||||
theme_dir.mkdir(exist_ok=True)
|
||||
(theme_dir / ".streamlit").mkdir(exist_ok=True)
|
||||
(theme_dir / "static").mkdir(exist_ok=True)
|
||||
|
||||
# .streamlit/config.toml — from _configs/
|
||||
(theme_dir / ".streamlit" / "config.toml").write_text(expected_config(slug))
|
||||
|
||||
# streamlit_app.py
|
||||
(theme_dir / "streamlit_app.py").write_text(expected_app(title))
|
||||
|
||||
# pyproject.toml
|
||||
(theme_dir / "pyproject.toml").write_text(
|
||||
expected_from_template(
|
||||
TEMPLATES / "pyproject.toml.tmpl",
|
||||
{"slug": slug, "title": title},
|
||||
)
|
||||
)
|
||||
|
||||
# snowflake.yml
|
||||
(theme_dir / "snowflake.yml").write_text(
|
||||
expected_from_template(
|
||||
TEMPLATES / "snowflake.yml.tmpl",
|
||||
{"slug": slug, "title": title, "identifier": identifier},
|
||||
)
|
||||
)
|
||||
|
||||
# Fonts — copy from _shared/fonts/ based on config references
|
||||
config_text = (CONFIGS / f"{slug}.toml").read_text()
|
||||
font_names = discover_fonts(config_text)
|
||||
static_dir = theme_dir / "static"
|
||||
for fname in font_names:
|
||||
src = FONTS / fname
|
||||
if not src.exists():
|
||||
print(f" Warning: font {fname} referenced in _configs/{slug}.toml not found in _shared/fonts/", file=sys.stderr)
|
||||
continue
|
||||
shutil.copy2(src, static_dir / fname)
|
||||
|
||||
|
||||
def update_gitattributes():
|
||||
"""Update .gitattributes with entries for generated theme files."""
|
||||
gitattr_path = ROOT / ".gitattributes"
|
||||
|
||||
new_section = "\n".join([
|
||||
GITATTR_START,
|
||||
"*/.streamlit/config.toml linguist-generated",
|
||||
"*/streamlit_app.py linguist-generated",
|
||||
"*/pyproject.toml linguist-generated",
|
||||
"*/snowflake.yml linguist-generated",
|
||||
"*/static/*.ttf linguist-generated",
|
||||
GITATTR_END,
|
||||
])
|
||||
|
||||
if gitattr_path.exists():
|
||||
content = gitattr_path.read_text()
|
||||
if GITATTR_START in content:
|
||||
start = content.index(GITATTR_START)
|
||||
end = content.index(GITATTR_END) + len(GITATTR_END)
|
||||
content = content[:start] + new_section + content[end:]
|
||||
else:
|
||||
content = content.rstrip() + "\n\n" + new_section + "\n"
|
||||
else:
|
||||
content = new_section + "\n"
|
||||
|
||||
gitattr_path.write_text(content)
|
||||
|
||||
|
||||
def cmd_sync():
|
||||
themes = discover_themes()
|
||||
for t in themes:
|
||||
sync_theme(t)
|
||||
print(f" Synced {t['slug']}/")
|
||||
|
||||
# Remove orphaned theme directories (directories not matching any config)
|
||||
config_slugs = {t["slug"] for t in themes}
|
||||
orphans = [
|
||||
d for d in sorted(ROOT.iterdir())
|
||||
if d.is_dir() and not d.name.startswith("_") and d.name not in config_slugs
|
||||
]
|
||||
if orphans:
|
||||
print("\nOrphaned directories (no matching config):")
|
||||
for d in orphans:
|
||||
print(f" {d.name}/")
|
||||
answer = input("Remove these directories? [y/N] ").strip().lower()
|
||||
if answer == "y":
|
||||
for d in orphans:
|
||||
shutil.rmtree(d)
|
||||
print(f" Removed {d.name}/")
|
||||
else:
|
||||
print(" Skipped orphan removal.")
|
||||
|
||||
update_gitattributes()
|
||||
print(f"\nSynced {len(themes)} theme directories.")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Check
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def cmd_check():
|
||||
themes = discover_themes()
|
||||
drifted = []
|
||||
missing = []
|
||||
|
||||
for theme in themes:
|
||||
slug = theme["slug"]
|
||||
title = theme["title"]
|
||||
identifier = slug.replace("-", "_")
|
||||
theme_dir = ROOT / slug
|
||||
|
||||
# .streamlit/config.toml
|
||||
target = theme_dir / ".streamlit" / "config.toml"
|
||||
expected = expected_config(slug)
|
||||
if not target.exists():
|
||||
missing.append(f"{slug}/.streamlit/config.toml")
|
||||
elif target.read_text() != expected:
|
||||
drifted.append(f"{slug}/.streamlit/config.toml")
|
||||
|
||||
# streamlit_app.py
|
||||
target = theme_dir / "streamlit_app.py"
|
||||
if not target.exists():
|
||||
missing.append(f"{slug}/streamlit_app.py")
|
||||
elif target.read_text() != expected_app(title):
|
||||
drifted.append(f"{slug}/streamlit_app.py")
|
||||
|
||||
# pyproject.toml
|
||||
target = theme_dir / "pyproject.toml"
|
||||
expected = expected_from_template(
|
||||
TEMPLATES / "pyproject.toml.tmpl",
|
||||
{"slug": slug, "title": title},
|
||||
)
|
||||
if not target.exists():
|
||||
missing.append(f"{slug}/pyproject.toml")
|
||||
elif target.read_text() != expected:
|
||||
drifted.append(f"{slug}/pyproject.toml")
|
||||
|
||||
# snowflake.yml
|
||||
target = theme_dir / "snowflake.yml"
|
||||
expected = expected_from_template(
|
||||
TEMPLATES / "snowflake.yml.tmpl",
|
||||
{"slug": slug, "title": title, "identifier": identifier},
|
||||
)
|
||||
if not target.exists():
|
||||
missing.append(f"{slug}/snowflake.yml")
|
||||
elif target.read_text() != expected:
|
||||
drifted.append(f"{slug}/snowflake.yml")
|
||||
|
||||
# Fonts
|
||||
config_text = (CONFIGS / f"{slug}.toml").read_text()
|
||||
font_names = discover_fonts(config_text)
|
||||
for fname in font_names:
|
||||
src = FONTS / fname
|
||||
dest = theme_dir / "static" / fname
|
||||
if not dest.exists():
|
||||
missing.append(f"{slug}/static/{fname}")
|
||||
elif src.exists() and src.read_bytes() != dest.read_bytes():
|
||||
drifted.append(f"{slug}/static/{fname}")
|
||||
|
||||
ok = True
|
||||
if missing:
|
||||
print("Missing files (run 'python manage.py sync' to fix):")
|
||||
for f in missing:
|
||||
print(f" {f}")
|
||||
ok = False
|
||||
if drifted:
|
||||
print("Drifted files (run 'python manage.py sync' to fix):")
|
||||
for f in drifted:
|
||||
print(f" {f}")
|
||||
ok = False
|
||||
if ok:
|
||||
print(f"All generated files in sync across {len(themes)} theme directories.")
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# New
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def cmd_new(name):
|
||||
config_path = CONFIGS / f"{name}.toml"
|
||||
if config_path.exists():
|
||||
print(f"Error: _configs/{name}.toml already exists", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
config_path.write_text(
|
||||
f"[server]\nenableStaticServing = true\n\n"
|
||||
f"# {name} theme\n[theme]\nbase = \"dark\"\n"
|
||||
)
|
||||
|
||||
print(f"Created _configs/{name}.toml — edit it, then run 'python manage.py sync'")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CLI
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
|
||||
print(__doc__.strip())
|
||||
sys.exit(0 if len(sys.argv) > 1 else 1)
|
||||
|
||||
if not SHARED.is_dir():
|
||||
print(f"Error: {SHARED} not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not CONFIGS.is_dir():
|
||||
print(f"Error: {CONFIGS} not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
cmd = sys.argv[1]
|
||||
if cmd == "sync":
|
||||
cmd_sync()
|
||||
elif cmd == "new":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python manage.py new NAME", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
cmd_new(sys.argv[2])
|
||||
elif cmd == "check":
|
||||
cmd_check()
|
||||
else:
|
||||
print(f"Unknown command: {cmd}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-minimal"
|
||||
version = "1.0.0"
|
||||
description = "Minimal theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Minimal**")
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-nord"
|
||||
version = "1.0.0"
|
||||
description = "Nord theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Nord**")
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-snowflake"
|
||||
version = "1.0.0"
|
||||
description = "Snowflake theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Snowflake**")
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-solarized-light"
|
||||
version = "1.0.0"
|
||||
description = "Solarized Light theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
+337
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Solarized Light**")
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-spotify"
|
||||
version = "1.0.0"
|
||||
description = "Spotify theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Spotify**")
|
||||
@@ -0,0 +1,10 @@
|
||||
[project]
|
||||
name = "theme-stripe"
|
||||
version = "1.0.0"
|
||||
description = "Stripe theme for Streamlit"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"numpy>=1.26.0",
|
||||
"pandas>=2.2.3",
|
||||
"streamlit>=1.53.0",
|
||||
]
|
||||
@@ -0,0 +1,337 @@
|
||||
"""
|
||||
Streamlit Element Explorer - Theme Demo
|
||||
|
||||
A comprehensive single-page app showcasing all major Streamlit components
|
||||
with custom theming. Use this to preview how your theme looks across
|
||||
different element types.
|
||||
"""
|
||||
# DO NOT EDIT — managed by manage.py, edit _shared/streamlit_app.py instead
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="Element Explorer", page_icon="🎨", layout="wide")
|
||||
|
||||
# Initialize sample data in session state
|
||||
if "chart_data" not in st.session_state:
|
||||
np.random.seed(42)
|
||||
st.session_state.chart_data = pd.DataFrame(
|
||||
np.random.randn(20, 3), columns=["a", "b", "c"]
|
||||
)
|
||||
|
||||
chart_data = st.session_state.chart_data
|
||||
|
||||
st.title("Streamlit Element Explorer")
|
||||
st.markdown(
|
||||
"Explore how Streamlit's built-in elements look with this theme. "
|
||||
"Select a category below to preview different components."
|
||||
)
|
||||
|
||||
# Navigation using segmented_control for better performance
|
||||
section = st.segmented_control(
|
||||
"Section",
|
||||
["Widgets", "Data", "Charts", "Text", "Layouts", "Chat", "Status"],
|
||||
default="Widgets",
|
||||
label_visibility="collapsed",
|
||||
)
|
||||
|
||||
st.divider()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WIDGETS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
if section == "Widgets":
|
||||
st.header("Widgets")
|
||||
|
||||
# Buttons
|
||||
st.subheader("Buttons")
|
||||
cols = st.columns(4)
|
||||
cols[0].button("Primary", type="primary")
|
||||
cols[1].button("Secondary", type="secondary")
|
||||
cols[2].button("Tertiary", type="tertiary")
|
||||
cols[3].link_button("Link", url="https://streamlit.io", icon=":material/open_in_new:")
|
||||
|
||||
# Form
|
||||
with st.form(key="demo_form"):
|
||||
st.subheader("Form")
|
||||
form_cols = st.columns(2)
|
||||
form_cols[0].text_input("Name", placeholder="Enter your name")
|
||||
form_cols[1].text_input("Email", placeholder="you@example.com")
|
||||
st.form_submit_button("Submit", type="primary")
|
||||
|
||||
# Selection widgets
|
||||
st.subheader("Selection Widgets")
|
||||
sel_cols = st.columns(2)
|
||||
|
||||
with sel_cols[0]:
|
||||
st.checkbox("Checkbox option")
|
||||
st.toggle("Toggle switch")
|
||||
st.selectbox("Selectbox", options=["Option A", "Option B", "Option C"])
|
||||
st.multiselect("Multiselect", options=["Tag 1", "Tag 2", "Tag 3"], default=["Tag 1"])
|
||||
|
||||
with sel_cols[1]:
|
||||
st.radio("Radio buttons", options=["Choice 1", "Choice 2", "Choice 3"], horizontal=True)
|
||||
st.pills("Pills", options=["Small", "Medium", "Large"], default="Medium")
|
||||
st.segmented_control("Segmented", options=["Day", "Week", "Month"], default="Week")
|
||||
st.caption("Feedback widget")
|
||||
st.feedback("stars")
|
||||
|
||||
# Numeric & Sliders
|
||||
st.subheader("Numeric Inputs")
|
||||
num_cols = st.columns(3)
|
||||
num_cols[0].number_input("Number input", value=42)
|
||||
num_cols[1].slider("Slider", 0, 100, 50)
|
||||
num_cols[2].select_slider("Select slider", options=["XS", "S", "M", "L", "XL"], value="M")
|
||||
|
||||
# Date/Time
|
||||
st.subheader("Date & Time")
|
||||
dt_cols = st.columns(2)
|
||||
dt_cols[0].date_input("Date input")
|
||||
dt_cols[1].time_input("Time input")
|
||||
|
||||
# Text inputs
|
||||
st.subheader("Text Inputs")
|
||||
txt_cols = st.columns(2)
|
||||
txt_cols[0].text_input("Text input", placeholder="Type something...")
|
||||
txt_cols[1].text_area("Text area", placeholder="Longer text goes here...", height=100)
|
||||
|
||||
# File upload
|
||||
st.subheader("File Upload")
|
||||
st.file_uploader("Upload a file", type=["csv", "txt", "pdf"])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATA SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Data":
|
||||
st.header("Data Display")
|
||||
|
||||
# Metrics
|
||||
st.subheader("Metrics")
|
||||
m_cols = st.columns(4)
|
||||
m_cols[0].metric("Revenue", "$45,231", "+12.5%")
|
||||
m_cols[1].metric("Users", "2,847", "+8.2%")
|
||||
m_cols[2].metric("Conversion", "3.24%", "-0.4%", delta_color="inverse")
|
||||
m_cols[3].metric("Avg. Session", "4m 32s", "+1.2%")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Dataframe
|
||||
st.subheader("Dataframe")
|
||||
df = pd.DataFrame({
|
||||
"Name": ["Alice", "Bob", "Charlie", "Diana", "Eve"],
|
||||
"Department": ["Engineering", "Sales", "Marketing", "Engineering", "Sales"],
|
||||
"Salary": [95000, 78000, 82000, 105000, 71000],
|
||||
"Start Date": pd.date_range("2022-01-15", periods=5, freq="3M"),
|
||||
"Active": [True, True, False, True, True],
|
||||
})
|
||||
st.dataframe(
|
||||
df,
|
||||
hide_index=True,
|
||||
column_config={
|
||||
"Salary": st.column_config.NumberColumn(format="$%d"),
|
||||
"Start Date": st.column_config.DateColumn(format="MMM DD, YYYY"),
|
||||
"Active": st.column_config.CheckboxColumn("Active?"),
|
||||
},
|
||||
)
|
||||
|
||||
# Table
|
||||
st.subheader("Static Table")
|
||||
st.table(chart_data.head(5))
|
||||
|
||||
# JSON
|
||||
st.subheader("JSON Display")
|
||||
st.json({"name": "Streamlit", "version": "1.41.0", "features": ["themes", "widgets", "charts"]})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHARTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Charts":
|
||||
st.header("Charts")
|
||||
|
||||
chart_cols = st.columns(2)
|
||||
|
||||
with chart_cols[0]:
|
||||
st.subheader("Line Chart")
|
||||
st.line_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Bar Chart")
|
||||
st.bar_chart(chart_data, height=250)
|
||||
|
||||
with chart_cols[1]:
|
||||
st.subheader("Area Chart")
|
||||
st.area_chart(chart_data, height=250)
|
||||
|
||||
st.subheader("Scatter Chart")
|
||||
st.scatter_chart(chart_data, height=250)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TEXT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Text":
|
||||
st.header("Text Elements")
|
||||
|
||||
# Headers
|
||||
st.subheader("Headers")
|
||||
st.title("Title Element")
|
||||
st.header("Header Element")
|
||||
st.subheader("Subheader Element")
|
||||
st.caption("Caption text - smaller, muted")
|
||||
|
||||
st.divider()
|
||||
|
||||
# Markdown
|
||||
st.subheader("Markdown Formatting")
|
||||
st.markdown(
|
||||
"**Bold text**, *italic text*, ~~strikethrough~~, "
|
||||
"`inline code`, [link](https://streamlit.io)"
|
||||
)
|
||||
st.markdown("Math: $E = mc^2$ and $\\int_0^\\infty e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$")
|
||||
st.markdown("Emojis: 🚀 🎨 📊 ✨ and icons: :material/home: :material/settings:")
|
||||
|
||||
# Colored text
|
||||
st.subheader("Colored Text")
|
||||
color_cols = st.columns(3)
|
||||
color_cols[0].markdown(":red[Red text] and :orange[Orange text]")
|
||||
color_cols[1].markdown(":green[Green text] and :blue[Blue text]")
|
||||
color_cols[2].markdown(":violet[Violet text] and :rainbow[Rainbow text]")
|
||||
|
||||
# Code blocks
|
||||
st.subheader("Code Block")
|
||||
st.code(
|
||||
'''import streamlit as st
|
||||
|
||||
# Create a themed dashboard
|
||||
st.set_page_config(page_title="My App", layout="wide")
|
||||
st.title("Hello, Streamlit!")
|
||||
|
||||
# Display metrics
|
||||
col1, col2 = st.columns(2)
|
||||
col1.metric("Users", "1,234", "+5%")
|
||||
col2.metric("Revenue", "$56K", "+12%")''',
|
||||
language="python",
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LAYOUTS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Layouts":
|
||||
st.header("Layout Elements")
|
||||
|
||||
# Columns
|
||||
st.subheader("Columns with Borders")
|
||||
layout_cols = st.columns(3, border=True)
|
||||
layout_cols[0].write("**Column 1**\n\nFirst column content")
|
||||
layout_cols[1].write("**Column 2**\n\nSecond column content")
|
||||
layout_cols[2].write("**Column 3**\n\nThird column content")
|
||||
|
||||
# Tabs
|
||||
st.subheader("Tabs")
|
||||
tab1, tab2, tab3 = st.tabs(["📈 Chart", "📋 Data", "⚙️ Settings"])
|
||||
with tab1:
|
||||
st.write("Chart tab content")
|
||||
st.line_chart(chart_data["a"], height=150)
|
||||
with tab2:
|
||||
st.write("Data tab content")
|
||||
st.dataframe(chart_data.head(3))
|
||||
with tab3:
|
||||
st.write("Settings tab content")
|
||||
st.checkbox("Enable feature X")
|
||||
st.checkbox("Enable feature Y", value=True)
|
||||
|
||||
# Expander
|
||||
st.subheader("Expander")
|
||||
with st.expander("Click to expand"):
|
||||
st.write("This content is hidden by default.")
|
||||
st.image("https://placehold.co/400x200/29B5E8/white?text=Expanded+Content")
|
||||
|
||||
# Popover
|
||||
st.subheader("Popover")
|
||||
pop_cols = st.columns(3)
|
||||
with pop_cols[0].popover("Open popover", icon=":material/info:"):
|
||||
st.write("Popover content here!")
|
||||
st.slider("Popover slider", 0, 100, 50)
|
||||
|
||||
# Container
|
||||
st.subheader("Container with Border")
|
||||
with st.container(border=True):
|
||||
st.write("**Bordered Container**")
|
||||
st.write("Content inside a container with a visible border.")
|
||||
st.button("Button inside container")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CHAT SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Chat":
|
||||
st.header("Chat Elements")
|
||||
|
||||
# Chat messages
|
||||
st.subheader("Chat Messages")
|
||||
with st.chat_message("user"):
|
||||
st.write("Hello! How can I analyze my sales data?")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("I can help you with that! Here are a few options:")
|
||||
st.markdown("""
|
||||
1. **Revenue trends** - View monthly/quarterly patterns
|
||||
2. **Top products** - Identify best sellers
|
||||
3. **Customer segments** - Analyze by region or category
|
||||
""")
|
||||
|
||||
with st.chat_message("user"):
|
||||
st.write("Show me the revenue trends please.")
|
||||
|
||||
with st.chat_message("assistant"):
|
||||
st.write("Here's your revenue trend for the past 20 periods:")
|
||||
st.line_chart(chart_data["a"], height=200)
|
||||
|
||||
# Chat input
|
||||
st.chat_input("Type a message...")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STATUS SECTION
|
||||
# -----------------------------------------------------------------------------
|
||||
elif section == "Status":
|
||||
st.header("Status Elements")
|
||||
|
||||
# Alert messages
|
||||
st.subheader("Alert Messages")
|
||||
st.error("Error: Something went wrong with the data pipeline.")
|
||||
st.warning("Warning: API rate limit approaching (80% used).")
|
||||
st.info("Info: New features available in the latest release.")
|
||||
st.success("Success: Data exported successfully to warehouse.")
|
||||
|
||||
# Exception
|
||||
st.subheader("Exception Display")
|
||||
try:
|
||||
raise ValueError("This is an example exception for demonstration")
|
||||
except ValueError as e:
|
||||
st.exception(e)
|
||||
|
||||
# Interactive status
|
||||
st.subheader("Interactive Status")
|
||||
status_cols = st.columns(3)
|
||||
if status_cols[0].button("Show Toast", icon=":material/notifications:"):
|
||||
st.toast("This is a toast notification!", icon="🔔")
|
||||
if status_cols[1].button("Balloons", icon=":material/celebration:"):
|
||||
st.balloons()
|
||||
if status_cols[2].button("Snow", icon=":material/ac_unit:"):
|
||||
st.snow()
|
||||
|
||||
# Progress
|
||||
st.subheader("Progress Indicators")
|
||||
st.progress(0.7, text="70% complete")
|
||||
with st.spinner("Loading..."):
|
||||
st.write("Spinner is active (non-blocking in this demo)")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SIDEBAR
|
||||
# -----------------------------------------------------------------------------
|
||||
with st.sidebar:
|
||||
st.header("Settings")
|
||||
st.selectbox("Time Period", ["Last 7 days", "Last 30 days", "Last 90 days", "All time"])
|
||||
st.multiselect("Metrics", ["Revenue", "Users", "Sessions"], default=["Revenue", "Users"])
|
||||
st.slider("Confidence threshold", 0.0, 1.0, 0.8)
|
||||
st.divider()
|
||||
st.caption("Element Explorer v1.0")
|
||||
st.caption("Theme: **Stripe**")
|
||||
Reference in New Issue
Block a user