axiom-coding-agent-setup 1.0.10 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/.agents/skills/agent-browser/SKILL.md +55 -0
  2. package/.agents/skills/developing-with-streamlit/SKILL.md +220 -0
  3. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-chat-ui/SKILL.md +195 -0
  4. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/SKILL.md +233 -0
  5. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/packaged-components.md +212 -0
  6. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/state-sync.md +149 -0
  7. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/theme-css-variables.md +243 -0
  8. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/troubleshooting.md +121 -0
  9. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-dashboards/SKILL.md +147 -0
  10. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-multipage-apps/SKILL.md +218 -0
  11. package/.agents/skills/developing-with-streamlit/skills/choosing-streamlit-selection-widgets/SKILL.md +139 -0
  12. package/.agents/skills/developing-with-streamlit/skills/connecting-streamlit-to-snowflake/SKILL.md +188 -0
  13. package/.agents/skills/developing-with-streamlit/skills/creating-streamlit-themes/SKILL.md +486 -0
  14. package/.agents/skills/developing-with-streamlit/skills/displaying-streamlit-data/SKILL.md +199 -0
  15. package/.agents/skills/developing-with-streamlit/skills/improving-streamlit-design/SKILL.md +191 -0
  16. package/.agents/skills/developing-with-streamlit/skills/optimizing-streamlit-performance/SKILL.md +323 -0
  17. package/.agents/skills/developing-with-streamlit/skills/organizing-streamlit-code/SKILL.md +91 -0
  18. package/.agents/skills/developing-with-streamlit/skills/setting-up-streamlit-environment/SKILL.md +128 -0
  19. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-cli/SKILL.md +165 -0
  20. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-custom-components/SKILL.md +170 -0
  21. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-layouts/SKILL.md +229 -0
  22. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-markdown/SKILL.md +207 -0
  23. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-session-state/SKILL.md +144 -0
  24. package/.agents/skills/developing-with-streamlit/templates/.gitattributes +3 -0
  25. package/.agents/skills/developing-with-streamlit/templates/apps/README.md +188 -0
  26. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/pyproject.toml +12 -0
  27. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/streamlit_app.py +365 -0
  28. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/pyproject.toml +12 -0
  29. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/streamlit_app.py +461 -0
  30. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/.streamlit/secrets.toml.example +20 -0
  31. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/pyproject.toml +11 -0
  32. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/snowflake.yml +18 -0
  33. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/streamlit_app.py +527 -0
  34. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/pyproject.toml +12 -0
  35. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/streamlit_app.py +307 -0
  36. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/pyproject.toml +12 -0
  37. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/streamlit_app.py +426 -0
  38. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/.streamlit/secrets.toml.example +20 -0
  39. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/pyproject.toml +11 -0
  40. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/snowflake.yml +18 -0
  41. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/streamlit_app.py +463 -0
  42. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/pyproject.toml +12 -0
  43. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/streamlit_app.py +252 -0
  44. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/pyproject.toml +12 -0
  45. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/streamlit_app.py +342 -0
  46. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/.streamlit/secrets.toml.example +20 -0
  47. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/pyproject.toml +11 -0
  48. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/snowflake.yml +18 -0
  49. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/streamlit_app.py +384 -0
  50. package/.agents/skills/developing-with-streamlit/templates/themes/README.md +128 -0
  51. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/dracula.toml +39 -0
  52. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/github.toml +37 -0
  53. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/minimal.toml +39 -0
  54. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/nord.toml +39 -0
  55. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/snowflake.toml +42 -0
  56. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/solarized-light.toml +38 -0
  57. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/spotify.toml +34 -0
  58. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/stripe.toml +35 -0
  59. package/.agents/skills/developing-with-streamlit/templates/themes/_shared/streamlit_app.py +336 -0
  60. package/.agents/skills/developing-with-streamlit/templates/themes/_templates/pyproject.toml.tmpl +12 -0
  61. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/.streamlit/config.toml +39 -0
  62. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/pyproject.toml +10 -0
  63. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/streamlit_app.py +337 -0
  64. package/.agents/skills/developing-with-streamlit/templates/themes/github/.streamlit/config.toml +37 -0
  65. package/.agents/skills/developing-with-streamlit/templates/themes/github/pyproject.toml +10 -0
  66. package/.agents/skills/developing-with-streamlit/templates/themes/github/streamlit_app.py +337 -0
  67. package/.agents/skills/developing-with-streamlit/templates/themes/manage.py +332 -0
  68. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/.streamlit/config.toml +39 -0
  69. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/pyproject.toml +10 -0
  70. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/streamlit_app.py +337 -0
  71. package/.agents/skills/developing-with-streamlit/templates/themes/nord/.streamlit/config.toml +39 -0
  72. package/.agents/skills/developing-with-streamlit/templates/themes/nord/pyproject.toml +10 -0
  73. package/.agents/skills/developing-with-streamlit/templates/themes/nord/streamlit_app.py +337 -0
  74. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/.streamlit/config.toml +42 -0
  75. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/pyproject.toml +10 -0
  76. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/streamlit_app.py +337 -0
  77. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/.streamlit/config.toml +38 -0
  78. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/pyproject.toml +10 -0
  79. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/streamlit_app.py +337 -0
  80. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/.streamlit/config.toml +34 -0
  81. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/pyproject.toml +10 -0
  82. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/streamlit_app.py +337 -0
  83. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/.streamlit/config.toml +35 -0
  84. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/pyproject.toml +10 -0
  85. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/streamlit_app.py +337 -0
  86. package/.agents/skills/fastapi/SKILL.md +436 -0
  87. package/.agents/skills/fastapi/references/dependencies.md +142 -0
  88. package/.agents/skills/fastapi/references/other-tools.md +76 -0
  89. package/.agents/skills/fastapi/references/streaming.md +105 -0
  90. package/.agents/skills/frontend-design/LICENSE.txt +177 -0
  91. package/.agents/skills/frontend-design/SKILL.md +42 -0
  92. package/.agents/skills/gradio/SKILL.md +84 -0
  93. package/.agents/skills/gradio/references/api-signatures.md +115 -0
  94. package/.agents/skills/gradio/references/event-listeners.md +130 -0
  95. package/.agents/skills/gradio/references/examples.md +613 -0
  96. package/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
  97. package/.agents/skills/ui-ux-pro-max/data +1 -0
  98. package/.agents/skills/ui-ux-pro-max/scripts +1 -0
  99. package/.env.axiom +8 -0
  100. package/AGENTS.md +2 -1
  101. package/README.md +19 -3
  102. package/bin/cli.js +11 -1
  103. package/opencode.json +7 -4
  104. package/package.json +1 -1
  105. package/skills-lock.json +36 -0
  106. package/.agents/skills/n8n-patterns/SKILL.md +0 -272
@@ -0,0 +1,384 @@
1
+ """
2
+ Stock Peer Analysis Dashboard (Snowflake Edition)
3
+
4
+ A stock comparison dashboard demonstrating:
5
+ - Snowflake connection via st.connection("snowflake")
6
+ - Generating synthetic stock data in Snowflake
7
+ - Normalized price comparison charts
8
+ - Individual stock vs peer average analysis
9
+
10
+ This template uses synthetic stock data generated in Snowflake.
11
+ Replace the synthetic query with your actual stock data table.
12
+ """
13
+
14
+ import streamlit as st
15
+ import pandas as pd
16
+ import altair as alt
17
+
18
+ st.set_page_config(
19
+ page_title="Stock peer analysis dashboard",
20
+ page_icon=":chart_with_upwards_trend:",
21
+ layout="wide",
22
+ )
23
+
24
+ """
25
+ # :material/query_stats: Stock peer analysis
26
+
27
+ Easily compare stocks against others in their peer group.
28
+ """
29
+
30
+ "" # Add some space.
31
+
32
+
33
+ # =============================================================================
34
+ # Snowflake Connection
35
+ # =============================================================================
36
+
37
+
38
+ def get_snowflake_connection():
39
+ """Get Snowflake connection via st.connection.
40
+
41
+ Displays an error and stops the app if the connection fails.
42
+ """
43
+ try:
44
+ return st.connection("snowflake")
45
+ except Exception as e:
46
+ st.error(f"Failed to connect to Snowflake: {e}")
47
+ st.info(
48
+ "Make sure you have configured your Snowflake connection in "
49
+ "`.streamlit/secrets.toml` or via environment variables."
50
+ )
51
+ st.stop()
52
+
53
+
54
+ # =============================================================================
55
+ # Constants and Configuration
56
+ # =============================================================================
57
+
58
+ STOCKS = [
59
+ "AAPL", "ABBV", "ACN", "ADBE", "ADP", "AMD", "AMGN", "AMT", "AMZN", "APD",
60
+ "AVGO", "AXP", "BA", "BK", "BKNG", "BMY", "BSX", "C", "CAT", "CI",
61
+ "CL", "CMCSA", "COST", "CRM", "CSCO", "CVX", "DE", "DHR", "DIS", "DUK",
62
+ "ELV", "EOG", "EQR", "FDX", "GD", "GE", "GILD", "GOOG", "GOOGL", "HD",
63
+ "HON", "HUM", "IBM", "ICE", "INTC", "ISRG", "JNJ", "JPM", "KO", "LIN",
64
+ "LLY", "LMT", "LOW", "MA", "MCD", "MDLZ", "META", "MMC", "MO", "MRK",
65
+ "MSFT", "NEE", "NFLX", "NKE", "NOW", "NVDA", "ORCL", "PEP", "PFE", "PG",
66
+ "PLD", "PM", "PSA", "REGN", "RTX", "SBUX", "SCHW", "SLB", "SO", "SPGI",
67
+ "T", "TJX", "TMO", "TSLA", "TXN", "UNH", "UNP", "UPS", "V", "VZ",
68
+ "WFC", "WM", "WMT", "XOM",
69
+ ]
70
+
71
+ # Base prices for synthetic data (approximate real values for realism)
72
+ STOCK_BASE_PRICES = {
73
+ "AAPL": 175, "MSFT": 380, "GOOGL": 140, "AMZN": 180, "NVDA": 500,
74
+ "META": 350, "TSLA": 250, "JPM": 170, "V": 280, "UNH": 520,
75
+ "HD": 350, "PG": 160, "MA": 450, "COST": 580, "ABBV": 170,
76
+ "MRK": 120, "AVGO": 900, "PEP": 180, "KO": 60, "TMO": 550,
77
+ "ADBE": 550, "CRM": 280, "CSCO": 50, "ACN": 340, "NKE": 100,
78
+ }
79
+
80
+ DEFAULT_STOCKS = ["AAPL", "MSFT", "GOOGL", "NVDA", "AMZN", "TSLA", "META"]
81
+
82
+ # Time horizon mapping
83
+ HORIZON_MAP = {
84
+ "1 Month": 30,
85
+ "3 Months": 90,
86
+ "6 Months": 180,
87
+ "1 Year": 365,
88
+ "2 Years": 730,
89
+ }
90
+
91
+
92
+ def stocks_to_str(stocks):
93
+ return ",".join(stocks)
94
+
95
+
96
+ # =============================================================================
97
+ # Data Loading
98
+ # =============================================================================
99
+
100
+
101
+ # -----------------------------------------------------------------------------
102
+ # PRODUCTION PATTERN: Use parameterized queries for real stock data
103
+ # -----------------------------------------------------------------------------
104
+ # For production use with actual stock tables, use parameterized queries:
105
+ #
106
+ # STOCK_QUERY = """
107
+ # SELECT trade_date AS date, ticker, close_price
108
+ # FROM stock_prices
109
+ # WHERE ticker = ANY(:tickers)
110
+ # AND trade_date >= DATEADD(day, -:days, CURRENT_DATE())
111
+ # ORDER BY trade_date, ticker
112
+ # """
113
+ #
114
+ # def load_stock_data(tickers: list[str], days: int) -> pd.DataFrame:
115
+ # conn = get_snowflake_connection()
116
+ # df = conn.query(
117
+ # STOCK_QUERY,
118
+ # params={"tickers": tickers, "days": days}
119
+ # )
120
+ # return df
121
+ #
122
+ # The synthetic data generation below uses f-strings for the VALUES clause
123
+ # which cannot be parameterized. This is acceptable for demo/synthetic data
124
+ # but should NOT be used with user input in production.
125
+ # -----------------------------------------------------------------------------
126
+
127
+
128
+ def generate_stock_data_query(tickers: list[str], days: int) -> str:
129
+ """Generate SQL query that creates synthetic stock price data.
130
+
131
+ NOTE: This uses f-strings for VALUES clause construction which is acceptable
132
+ for synthetic data generation with controlled inputs. For production apps
133
+ with real tables, always use parameterized queries as shown above.
134
+ """
135
+ # Build ticker values and base prices (controlled data, not user input)
136
+ ticker_values = []
137
+ for ticker in tickers:
138
+ base_price = STOCK_BASE_PRICES.get(ticker, 100 + hash(ticker) % 400)
139
+ growth_rate = 0.0003 + (hash(ticker) % 10) * 0.00005
140
+ volatility = 0.02 + (hash(ticker) % 5) * 0.005
141
+ ticker_values.append(f"('{ticker}', {base_price}, {growth_rate}, {volatility})")
142
+
143
+ tickers_cte = ", ".join(ticker_values)
144
+
145
+ return f"""
146
+ WITH tickers AS (
147
+ SELECT column1 AS ticker, column2 AS base_price, column3 AS growth_rate, column4 AS volatility
148
+ FROM VALUES {tickers_cte}
149
+ ),
150
+ date_series AS (
151
+ SELECT DATEADD(day, -seq4(), CURRENT_DATE() - 1) AS trade_date
152
+ FROM TABLE(GENERATOR(ROWCOUNT => {days}))
153
+ ),
154
+ raw_prices AS (
155
+ SELECT
156
+ d.trade_date,
157
+ t.ticker,
158
+ t.base_price * POWER(1 + t.growth_rate, DATEDIFF(day, DATEADD(day, -{days}, CURRENT_DATE()), d.trade_date))
159
+ * (1 + (RANDOM() / 10000000000000000000.0 - 0.5) * t.volatility * 2) AS close_price
160
+ FROM date_series d
161
+ CROSS JOIN tickers t
162
+ WHERE DAYOFWEEK(d.trade_date) NOT IN (0, 6) -- Exclude weekends
163
+ )
164
+ SELECT
165
+ trade_date AS date,
166
+ ticker,
167
+ ROUND(close_price, 2) AS close_price
168
+ FROM raw_prices
169
+ ORDER BY trade_date, ticker
170
+ """
171
+
172
+
173
+ @st.cache_data(ttl=3600, show_spinner="Loading stock data from Snowflake...")
174
+ def load_stock_data(tickers: list[str], days: int) -> pd.DataFrame:
175
+ """Load stock price data from Snowflake."""
176
+ conn = get_snowflake_connection()
177
+ query = generate_stock_data_query(tickers, days)
178
+ df = conn.query(query)
179
+ df.columns = df.columns.str.lower()
180
+
181
+ # Pivot to get tickers as columns
182
+ pivoted = df.pivot(index="date", columns="ticker", values="close_price")
183
+ pivoted.index = pd.to_datetime(pivoted.index)
184
+ return pivoted
185
+
186
+
187
+ # =============================================================================
188
+ # Session State and Query Params
189
+ # =============================================================================
190
+
191
+ if "tickers_input" not in st.session_state:
192
+ st.session_state.tickers_input = st.query_params.get(
193
+ "stocks", stocks_to_str(DEFAULT_STOCKS)
194
+ ).split(",")
195
+
196
+
197
+ # =============================================================================
198
+ # Page Layout
199
+ # =============================================================================
200
+
201
+ # Check Snowflake connection
202
+ get_snowflake_connection()
203
+
204
+ cols = st.columns([1, 3])
205
+
206
+ top_left_cell = cols[0].container(
207
+ border=True, height="stretch", vertical_alignment="center"
208
+ )
209
+
210
+ with top_left_cell:
211
+ # Selectbox for stock tickers
212
+ tickers = st.multiselect(
213
+ "Stock tickers",
214
+ options=sorted(set(STOCKS) | set(st.session_state.tickers_input)),
215
+ default=st.session_state.tickers_input,
216
+ placeholder="Choose stocks to compare. Example: NVDA",
217
+ accept_new_options=True,
218
+ )
219
+
220
+ # Time horizon selector
221
+ horizon = st.pills(
222
+ "Time horizon",
223
+ options=list(HORIZON_MAP.keys()),
224
+ default="6 Months",
225
+ )
226
+
227
+ tickers = [t.upper() for t in tickers]
228
+
229
+ # Update query param when text input changes
230
+ if tickers:
231
+ st.query_params["stocks"] = stocks_to_str(tickers)
232
+ else:
233
+ st.query_params.pop("stocks", None)
234
+
235
+ if not tickers:
236
+ top_left_cell.info("Pick some stocks to compare", icon=":material/info:")
237
+ st.stop()
238
+
239
+ right_cell = cols[1].container(
240
+ border=True, height="stretch", vertical_alignment="center"
241
+ )
242
+
243
+ # Load the data from Snowflake
244
+ try:
245
+ data = load_stock_data(tickers, HORIZON_MAP[horizon])
246
+ except Exception as e:
247
+ st.error(f"Error loading stock data: {e}")
248
+ st.stop()
249
+
250
+ # Check for missing data
251
+ missing_tickers = [t for t in tickers if t not in data.columns]
252
+ if missing_tickers:
253
+ st.warning(f"No data available for: {', '.join(missing_tickers)}")
254
+ # Filter to available tickers
255
+ tickers = [t for t in tickers if t in data.columns]
256
+ if not tickers:
257
+ st.stop()
258
+
259
+ # Normalize prices (start at 1)
260
+ normalized = data[tickers].div(data[tickers].iloc[0])
261
+
262
+ latest_norm_values = {normalized[ticker].iat[-1]: ticker for ticker in tickers}
263
+ max_norm_value = max(latest_norm_values.items())
264
+ min_norm_value = min(latest_norm_values.items())
265
+
266
+ bottom_left_cell = cols[0].container(
267
+ border=True, height="stretch", vertical_alignment="center"
268
+ )
269
+
270
+ with bottom_left_cell:
271
+ metric_cols = st.columns(2)
272
+ metric_cols[0].metric(
273
+ "Best stock",
274
+ max_norm_value[1],
275
+ delta=f"{round((max_norm_value[0] - 1) * 100)}%",
276
+ width="content",
277
+ )
278
+ metric_cols[1].metric(
279
+ "Worst stock",
280
+ min_norm_value[1],
281
+ delta=f"{round((min_norm_value[0] - 1) * 100)}%",
282
+ width="content",
283
+ )
284
+
285
+ # Plot normalized prices
286
+ with right_cell:
287
+ st.altair_chart(
288
+ alt.Chart(
289
+ normalized.reset_index().melt(
290
+ id_vars=["date"], var_name="Stock", value_name="Normalized price"
291
+ )
292
+ )
293
+ .mark_line()
294
+ .encode(
295
+ alt.X("date:T", title="Date"),
296
+ alt.Y("Normalized price:Q").scale(zero=False),
297
+ alt.Color("Stock:N"),
298
+ )
299
+ .properties(height=400)
300
+ )
301
+
302
+ ""
303
+ ""
304
+
305
+ # Plot individual stock vs peer average
306
+ """
307
+ ## Individual stocks vs peer average
308
+
309
+ For the analysis below, the "peer average" when analyzing stock X always
310
+ excludes X itself.
311
+ """
312
+
313
+ if len(tickers) <= 1:
314
+ st.warning("Pick 2 or more tickers to compare them")
315
+ st.stop()
316
+
317
+ NUM_COLS = 4
318
+ chart_cols = st.columns(NUM_COLS)
319
+
320
+ for i, ticker in enumerate(tickers):
321
+ # Calculate peer average (excluding current stock)
322
+ peers = normalized.drop(columns=[ticker])
323
+ peer_avg = peers.mean(axis=1)
324
+
325
+ # Create DataFrame with peer average
326
+ plot_data = pd.DataFrame(
327
+ {
328
+ "Date": normalized.index,
329
+ ticker: normalized[ticker],
330
+ "Peer average": peer_avg,
331
+ }
332
+ ).melt(id_vars=["Date"], var_name="Series", value_name="Price")
333
+
334
+ chart = (
335
+ alt.Chart(plot_data)
336
+ .mark_line()
337
+ .encode(
338
+ alt.X("Date:T"),
339
+ alt.Y("Price:Q").scale(zero=False),
340
+ alt.Color(
341
+ "Series:N",
342
+ scale=alt.Scale(domain=[ticker, "Peer average"], range=["red", "gray"]),
343
+ legend=alt.Legend(orient="bottom"),
344
+ ),
345
+ alt.Tooltip(["Date", "Series", "Price"]),
346
+ )
347
+ .properties(title=f"{ticker} vs peer average", height=300)
348
+ )
349
+
350
+ cell = chart_cols[(i * 2) % NUM_COLS].container(border=True)
351
+ cell.write("")
352
+ cell.altair_chart(chart)
353
+
354
+ # Create Delta chart
355
+ plot_data = pd.DataFrame(
356
+ {
357
+ "Date": normalized.index,
358
+ "Delta": normalized[ticker] - peer_avg,
359
+ }
360
+ )
361
+
362
+ chart = (
363
+ alt.Chart(plot_data)
364
+ .mark_area()
365
+ .encode(
366
+ alt.X("Date:T"),
367
+ alt.Y("Delta:Q").scale(zero=False),
368
+ )
369
+ .properties(title=f"{ticker} minus peer average", height=300)
370
+ )
371
+
372
+ cell = chart_cols[(i * 2 + 1) % NUM_COLS].container(border=True)
373
+ cell.write("")
374
+ cell.altair_chart(chart)
375
+
376
+ ""
377
+ ""
378
+
379
+ """
380
+ ## Raw data
381
+ """
382
+
383
+ st.caption(":material/cloud: Data loaded from Snowflake (synthetic)")
384
+ data[tickers]
@@ -0,0 +1,128 @@
1
+ # Streamlit theme templates
2
+
3
+ Ready-to-use theme templates for Streamlit apps.
4
+
5
+ ## Available themes
6
+
7
+ | Theme | Base | Primary color | Fonts |
8
+ |-------|------|---------------|-------|
9
+ | **snowflake** | Light | `#29B5E8` (cyan) | Inter, JetBrains Mono |
10
+ | **dracula** | Dark | `#BD93F9` (purple) | Fira Sans, JetBrains Mono |
11
+ | **nord** | Dark | `#88C0D0` (frost blue) | Inter, JetBrains Mono |
12
+ | **stripe** | Light | `#635BFF` (indigo) | Inter, Source Code Pro |
13
+ | **solarized-light** | Light | `#268BD2` (blue) | Source Sans 3, Source Code Pro |
14
+ | **spotify** | Dark | `#1DB954` (green) | Inter, Fira Code |
15
+ | **github** | Light | `#0969DA` (blue) | Inter, JetBrains Mono |
16
+ | **minimal** | Dark | `#6366f1` (indigo) | Inter, JetBrains Mono |
17
+
18
+ ## Quick start
19
+
20
+ ```bash
21
+ # Run a theme locally
22
+ cd templates/themes/spotify
23
+ uv sync
24
+ uv run streamlit run streamlit_app.py
25
+ ```
26
+
27
+ ## Deploying to Snowflake
28
+
29
+ Before deploying, update `snowflake.yml` with your account-specific resources:
30
+
31
+ ```yaml
32
+ # Find available compute pools
33
+ SHOW COMPUTE POOLS;
34
+
35
+ # Find available external access integrations
36
+ SHOW EXTERNAL ACCESS INTEGRATIONS;
37
+ ```
38
+
39
+ Then edit `snowflake.yml` to replace the placeholders:
40
+ - `<YOUR_COMPUTE_POOL>` → e.g., `STREAMLIT_DEDICATED_POOL`
41
+ - `<YOUR_PYPI_INTEGRATION>` → e.g., `PYPI_ACCESS_INTEGRATION`
42
+ - `<FROM_CONNECTION>` values are filled from your active connection
43
+
44
+ Deploy with:
45
+ ```bash
46
+ snow streamlit deploy --replace
47
+ ```
48
+
49
+ ## How Streamlit theming works
50
+
51
+ A custom theme requires two things:
52
+
53
+ ### 1. Theme configuration in `.streamlit/config.toml`
54
+
55
+ ```toml
56
+ [theme]
57
+ base = "dark" # "dark" or "light"
58
+ primaryColor = "#1DB954" # Buttons, links, highlights
59
+ backgroundColor = "#121212" # Main background
60
+ secondaryBackgroundColor = "#181818" # Sidebar, cards
61
+ textColor = "#FFFFFF" # Main text color
62
+ font = "Inter" # Body font
63
+ codeFont = "FiraCode" # Code blocks
64
+ ```
65
+
66
+ ### 2. For Snowflake deployment: local font files
67
+
68
+ Snowflake doesn't allow remote URL fetches, so fonts must be bundled locally:
69
+
70
+ ```toml
71
+ [server]
72
+ enableStaticServing = true # Required for static files
73
+
74
+ [[theme.fontFaces]]
75
+ family = "Inter"
76
+ url = "app/static/Inter-Regular.ttf" # Note: app/ prefix required
77
+ weight = 400
78
+
79
+ [[theme.fontFaces]]
80
+ family = "Inter"
81
+ url = "app/static/Inter-Bold.ttf"
82
+ weight = 700
83
+ ```
84
+
85
+ Font files go in `static/` directory and are referenced with `app/static/` prefix.
86
+
87
+ ### Sidebar theming (optional)
88
+
89
+ ```toml
90
+ [theme.sidebar]
91
+ backgroundColor = "#181818"
92
+ secondaryBackgroundColor = "#121212"
93
+ borderColor = "#282828"
94
+ ```
95
+
96
+ ## Theme file structure
97
+
98
+ Each theme directory contains:
99
+
100
+ ```
101
+ {theme}/
102
+ ├── .streamlit/config.toml # Theme colors and fonts
103
+ ├── streamlit_app.py # Demo app showing the theme
104
+ ├── pyproject.toml # Dependencies
105
+ ├── snowflake.yml # Snowflake deployment config
106
+ └── static/ # Bundled font files (*.ttf)
107
+ ```
108
+
109
+ ## Dependencies
110
+
111
+ All themes require Python >=3.11 and use:
112
+ - `snowflake-connector-python>=3.3.0` (required — `streamlit[snowflake]` silently skips this on Python 3.12+)
113
+ - `streamlit[snowflake]>=1.54.0`
114
+ - `altair>=5.5.0`
115
+ - `pandas>=2.2.3`
116
+
117
+ ## Font licensing
118
+
119
+ All bundled fonts are licensed under the [SIL Open Font License 1.1](https://openfontlicense.org/), which permits free use, redistribution, and modification:
120
+
121
+ | Font | Used by | Source |
122
+ |------|---------|--------|
123
+ | Inter | snowflake, nord, spotify, github, minimal, stripe | [github.com/rsms/inter](https://github.com/rsms/inter) |
124
+ | JetBrains Mono | snowflake, dracula, nord, github, minimal | [github.com/JetBrains/JetBrainsMono](https://github.com/JetBrains/JetBrainsMono) |
125
+ | Fira Sans | dracula | [github.com/mozilla/Fira](https://github.com/mozilla/Fira) |
126
+ | Fira Code | spotify | [github.com/tonsky/FiraCode](https://github.com/tonsky/FiraCode) |
127
+ | Source Sans 3 | solarized-light | [github.com/adobe-fonts/source-sans](https://github.com/adobe-fonts/source-sans) |
128
+ | 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 @@
1
+ # Dracula Theme for Streamlit
2
+ # Popular dark theme with vibrant colors on dark background
3
+ [theme]
4
+ base = "dark"
5
+ primaryColor = "#bd93f9"
6
+ backgroundColor = "#282a36"
7
+ secondaryBackgroundColor = "#21222c"
8
+ codeBackgroundColor = "#21222c"
9
+ textColor = "#f8f8f2"
10
+ linkColor = "#8be9fd"
11
+ borderColor = "#44475a"
12
+ showWidgetBorder = true
13
+ showSidebarBorder = true
14
+ baseRadius = "8px"
15
+ buttonRadius = "8px"
16
+ font = "'Fira Sans':https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500;600;700&display=swap"
17
+ codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
18
+ codeFontSize = "0.875rem"
19
+ codeTextColor = "#f8f8f2"
20
+ baseFontSize = 14
21
+ baseFontWeight = 400
22
+ headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
23
+ headingFontWeights = [700, 600, 600, 600, 600, 600]
24
+ linkUnderline = false
25
+ chartCategoricalColors = ["#bd93f9", "#50fa7b", "#ff79c6", "#8be9fd", "#ffb86c", "#ff5555", "#f1fa8c"]
26
+
27
+ # Dracula color palette
28
+ violetColor = "#bd93f9"
29
+ greenColor = "#50fa7b"
30
+ redColor = "#ff5555"
31
+ blueColor = "#8be9fd"
32
+ yellowColor = "#f1fa8c"
33
+ orangeColor = "#ffb86c"
34
+
35
+ [theme.sidebar]
36
+ backgroundColor = "#21222c"
37
+ secondaryBackgroundColor = "#191a21"
38
+ codeBackgroundColor = "#191a21"
39
+ borderColor = "#44475a"
@@ -0,0 +1,37 @@
1
+ # GitHub Theme for Streamlit
2
+ # Clean, developer-friendly, functional with signature blue accents
3
+ [theme]
4
+ primaryColor = "#0969da"
5
+ backgroundColor = "#ffffff"
6
+ secondaryBackgroundColor = "#f6f8fa"
7
+ codeBackgroundColor = "#f6f8fa"
8
+ textColor = "#1F2328"
9
+ linkColor = "#0969da"
10
+ borderColor = "#d0d7de"
11
+ showWidgetBorder = true
12
+ showSidebarBorder = true
13
+ baseRadius = "6px"
14
+ buttonRadius = "6px"
15
+ font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
16
+ codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
17
+ codeFontSize = "0.85rem"
18
+ codeTextColor = "#1F2328"
19
+ baseFontSize = 14
20
+ baseFontWeight = 400
21
+ headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
22
+ headingFontWeights = [600, 600, 600, 600, 600, 600]
23
+ linkUnderline = false
24
+ chartCategoricalColors = ["#0969da", "#1a7f37", "#bf3989", "#8250df", "#cf222e", "#bf8700", "#57606a"]
25
+
26
+ # GitHub color palette
27
+ blueColor = "#0969da"
28
+ greenColor = "#1a7f37"
29
+ redColor = "#cf222e"
30
+ violetColor = "#8250df"
31
+ orangeColor = "#bf8700"
32
+
33
+ [theme.sidebar]
34
+ backgroundColor = "#f6f8fa"
35
+ secondaryBackgroundColor = "#eaeef2"
36
+ codeBackgroundColor = "#eaeef2"
37
+ borderColor = "#d0d7de"
@@ -0,0 +1,39 @@
1
+ # Minimal Dark Theme for Streamlit
2
+ # Clean, distraction-free dark theme with subtle accents
3
+ [theme]
4
+ base = "dark"
5
+ primaryColor = "#6366f1"
6
+ backgroundColor = "#18181b"
7
+ secondaryBackgroundColor = "#27272a"
8
+ codeBackgroundColor = "#27272a"
9
+ textColor = "#fafafa"
10
+ linkColor = "#818cf8"
11
+ borderColor = "#3f3f46"
12
+ showWidgetBorder = false
13
+ showSidebarBorder = false
14
+ baseRadius = "6px"
15
+ buttonRadius = "6px"
16
+ font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
17
+ codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
18
+ codeFontSize = "0.85rem"
19
+ codeTextColor = "#e4e4e7"
20
+ baseFontSize = 14
21
+ baseFontWeight = 400
22
+ headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
23
+ headingFontWeights = [600, 600, 500, 500, 500, 500]
24
+ linkUnderline = false
25
+ chartCategoricalColors = ["#6366f1", "#8b5cf6", "#ec4899", "#14b8a6", "#f59e0b", "#ef4444", "#22c55e"]
26
+
27
+ # Color palette
28
+ violetColor = "#8b5cf6"
29
+ blueColor = "#6366f1"
30
+ greenColor = "#22c55e"
31
+ yellowColor = "#f59e0b"
32
+ orangeColor = "#f97316"
33
+ redColor = "#ef4444"
34
+
35
+ [theme.sidebar]
36
+ backgroundColor = "#09090b"
37
+ secondaryBackgroundColor = "#18181b"
38
+ codeBackgroundColor = "#18181b"
39
+ borderColor = "#27272a"
@@ -0,0 +1,39 @@
1
+ # Nord Theme for Streamlit
2
+ # Arctic, north-bluish color palette with frost-inspired accents
3
+ [theme]
4
+ base = "dark"
5
+ primaryColor = "#88c0d0"
6
+ backgroundColor = "#2e3440"
7
+ secondaryBackgroundColor = "#3b4252"
8
+ codeBackgroundColor = "#3b4252"
9
+ textColor = "#eceff4"
10
+ linkColor = "#81a1c1"
11
+ borderColor = "#4c566a"
12
+ showWidgetBorder = true
13
+ showSidebarBorder = true
14
+ baseRadius = "4px"
15
+ buttonRadius = "4px"
16
+ font = "Inter:https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
17
+ codeFont = "'JetBrains Mono':https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap"
18
+ codeFontSize = "0.875rem"
19
+ codeTextColor = "#d8dee9"
20
+ baseFontSize = 14
21
+ baseFontWeight = 400
22
+ headingFontSizes = ["32px", "24px", "20px", "16px", "14px", "12px"]
23
+ headingFontWeights = [600, 600, 600, 600, 600, 600]
24
+ linkUnderline = false
25
+ chartCategoricalColors = ["#88c0d0", "#81a1c1", "#5e81ac", "#a3be8c", "#ebcb8b", "#d08770", "#bf616a"]
26
+
27
+ # Nord color palette (Frost + Aurora)
28
+ blueColor = "#81a1c1"
29
+ greenColor = "#a3be8c"
30
+ yellowColor = "#ebcb8b"
31
+ orangeColor = "#d08770"
32
+ redColor = "#bf616a"
33
+ violetColor = "#b48ead"
34
+
35
+ [theme.sidebar]
36
+ backgroundColor = "#3b4252"
37
+ secondaryBackgroundColor = "#434c5e"
38
+ codeBackgroundColor = "#434c5e"
39
+ borderColor = "#4c566a"