Skip to content

Commit 3199688

Browse files
authored
Merge pull request #128 from burinc/improve-darkmode-for-pyodide-example
feat: Add comprehensive dark mode support to all Pyodide demos
2 parents c26833f + 0fca33c commit 3199688

File tree

8 files changed

+400
-215
lines changed

8 files changed

+400
-215
lines changed

src/scittle/pyodide/code_editor.cljs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@
88
;; Interactive Python Code Editor
99
;; ============================================================================
1010

11+
;; ============================================================================
12+
;; Dark Mode Support
13+
;; ============================================================================
14+
15+
(defn dark-mode?
16+
"Check if dark mode is currently active by looking for 'quarto-dark' class on body"
17+
[]
18+
(when-let [body (js/document.querySelector "body")]
19+
(.contains (.-classList body) "quarto-dark")))
20+
21+
(defn get-color
22+
"Get appropriate color based on dark mode state"
23+
[light-color dark-color]
24+
(if (dark-mode?) dark-color light-color))
25+
1126
(defonce code (r/atom "# Try some Python code!\nimport math\n\nradius = 5\narea = math.pi * radius ** 2\nprint(f'Circle area: {area:.2f}')"))
1227

1328
(defonce output (r/atom ""))
@@ -40,22 +55,25 @@
4055
:padding "24px"}}
4156
[:h2 {:style {:font-size "24px"
4257
:font-weight "bold"
43-
:margin-bottom "16px"}}
58+
:margin-bottom "16px"
59+
:color (get-color "#111827" "#F3F4F6")}}
4460
"Python Code Editor 💻"]
4561

46-
[:div {:style {:background-color "#FEF3C7"
47-
:border-left "4px solid #F59E0B"
62+
[:div {:style {:background-color (get-color "#FEF3C7" "#78350F")
63+
:border-left (str "4px solid " (get-color "#F59E0B" "#FCD34D"))
4864
:padding "16px"
4965
:margin-bottom "24px"}}
50-
[:p {:style {:font-size "14px" :color "#374151"}}
66+
[:p {:style {:font-size "14px"
67+
:color (get-color "#374151" "#FDE68A")}}
5168
"Write Python code below and click Run to execute it in your browser!"]]
5269

5370
;; Code editor
5471
[:div {:style {:margin-bottom "16px"}}
5572
[:label {:style {:display "block"
5673
:font-size "14px"
5774
:font-weight "600"
58-
:margin-bottom "8px"}}
75+
:margin-bottom "8px"
76+
:color (get-color "#374151" "#D1D5DB")}}
5977
"Python Code:"]
6078
[:textarea {:value @code
6179
:on-change #(reset! code (.. % -target -value))
@@ -64,14 +82,18 @@
6482
:padding "12px"
6583
:font-family "monospace"
6684
:font-size "14px"
67-
:border "2px solid #D1D5DB"
85+
:background-color (get-color "#FFFFFF" "#1F2937")
86+
:color (get-color "#111827" "#F3F4F6")
87+
:border (str "2px solid " (get-color "#D1D5DB" "#4B5563"))
6888
:border-radius "6px"
6989
:resize "vertical"}}]]
7090

7191
;; Run button
7292
[:button {:style {:width "100%"
7393
:padding "12px 24px"
74-
:background-color (if @running? "#9CA3AF" "#10B981")
94+
:background-color (if @running?
95+
(get-color "#9CA3AF" "#6B7280")
96+
(get-color "#10B981" "#059669"))
7597
:color "#FFFFFF"
7698
:border "none"
7799
:border-radius "6px"
@@ -91,13 +113,14 @@
91113
[:label {:style {:display "block"
92114
:font-size "14px"
93115
:font-weight "600"
94-
:margin-bottom "8px"}}
116+
:margin-bottom "8px"
117+
:color (get-color "#374151" "#D1D5DB")}}
95118
"Output:"]
96-
[:pre {:style {:background-color "#F9FAFB"
97-
:color "#1F2937"
119+
[:pre {:style {:background-color (get-color "#F9FAFB" "#1F2937")
120+
:color (get-color "#1F2937" "#F3F4F6")
98121
:padding "16px"
99122
:border-radius "6px"
100-
:border "2px solid #E5E7EB"
123+
:border (str "2px solid " (get-color "#E5E7EB" "#4B5563"))
101124
:font-family "monospace"
102125
:font-size "14px"
103126
:min-height "120px"

src/scittle/pyodide/code_executor.cljs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
;; Uses shared pyodide-bridge for Pyodide state
1010
;; ============================================================================
1111

12+
;; ============================================================================
13+
;; Dark Mode Support
14+
;; ============================================================================
15+
16+
(defn dark-mode?
17+
"Check if dark mode is currently active by looking for 'quarto-dark' class on body"
18+
[]
19+
(when-let [body (js/document.querySelector "body")]
20+
(.contains (.-classList body) "quarto-dark")))
21+
22+
(defn get-color
23+
"Get appropriate color based on dark mode state"
24+
[light-color dark-color]
25+
(if (dark-mode?) dark-color light-color))
26+
1227
;; Local state - only UI/output state, Pyodide state is in bridge
1328
(defonce code (r/atom "# Write your Python code here\nprint('Hello, World!')\n\n# Try some calculations\nresult = 2 + 2\nprint(f'2 + 2 = {result}')"))
1429

@@ -134,7 +149,10 @@ sys.stderr = _output_capture
134149
:on-change #(reset! code (.. % -target -value))
135150
:disabled (not= status :ready)
136151
:placeholder "Write your Python code here..."
137-
:style {:background-color (if (= status :ready) "#ffffff" "#f5f5f5")
152+
:style {:background-color (if (= status :ready)
153+
(get-color "#ffffff" "#1F2937")
154+
(get-color "#f5f5f5" "#374151"))
155+
:color (get-color "#111827" "#F3F4F6")
138156
:resize "vertical"}}]]))
139157

140158
(defn output-display

src/scittle/pyodide/data_visualization.cljs

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@
33
[reagent.dom :as rdom]
44
[scittle.pyodide.pyodide-bridge :as pyodide]))
55

6+
;; ============================================================================
7+
;; Dark Mode Helpers
8+
;; ============================================================================
9+
10+
(defn dark-mode?
11+
"Check if dark mode is currently active by looking for 'quarto-dark' class on body"
12+
[]
13+
(when-let [body (js/document.querySelector "body")]
14+
(.contains (.-classList body) "quarto-dark")))
15+
16+
(defn get-color
17+
"Get appropriate color based on dark mode state"
18+
[light-color dark-color]
19+
(if (dark-mode?) dark-color light-color))
20+
621
;; ============================================================================
722
;; Matplotlib Data Visualization Demo
823
;; ============================================================================
@@ -134,20 +149,24 @@ plt.axis('equal')"})
134149
[:h2 {:style {:font-size "28px"
135150
:font-weight "bold"
136151
:margin-bottom "8px"
137-
:color "#111827"}}
152+
:color (get-color "#111827" "#F3F4F6")}}
138153
"📊 Data Visualization with Matplotlib"]
139-
[:p {:style {:color "#6B7280"
154+
[:p {:style {:color (get-color "#6B7280" "#9CA3AF")
140155
:margin-bottom "24px"
141156
:font-size "16px"}}
142157
"Create beautiful charts and visualizations using Python's matplotlib library, running entirely in your browser!"]
143158
;; Info banner
144-
[:div {:style {:background-color (if @matplotlib-loaded? "#D1FAE5" "#DBEAFE")
159+
[:div {:style {:background-color (if @matplotlib-loaded?
160+
(get-color "#D1FAE5" "#064E3B")
161+
(get-color "#DBEAFE" "#1E3A8A"))
145162
:border-left (str "4px solid " (if @matplotlib-loaded? "#10B981" "#3B82F6"))
146163
:padding "16px"
147164
:margin-bottom "24px"
148165
:border-radius "4px"}}
149166
[:p {:style {:font-size "14px"
150-
:color (if @matplotlib-loaded? "#065F46" "#1E40AF")
167+
:color (if @matplotlib-loaded?
168+
(get-color "#065F46" "#6EE7B7")
169+
(get-color "#1E40AF" "#93C5FD"))
151170
:margin "0"}}
152171
(if @matplotlib-loaded?
153172
"✓ Matplotlib is loaded and ready!"
@@ -158,45 +177,45 @@ plt.axis('equal')"})
158177
:font-size "14px"
159178
:font-weight "600"
160179
:margin-bottom "8px"
161-
:color "#374151"}}
180+
:color (get-color "#374151" "#D1D5DB")}}
162181
"Quick Examples:"]
163182
[:div {:style {:display "flex"
164183
:gap "8px"
165184
:flex-wrap "wrap"}}
166185
[:button {:style {:padding "8px 16px"
167-
:background-color "#F3F4F6"
168-
:color "#374151"
169-
:border "1px solid #D1D5DB"
186+
:background-color (get-color "#F3F4F6" "#374151")
187+
:color (get-color "#374151" "#E5E7EB")
188+
:border (str "1px solid " (get-color "#D1D5DB" "#6B7280"))
170189
:border-radius "6px"
171190
:font-size "14px"
172191
:cursor "pointer"
173192
:font-weight "500"}
174193
:on-click #(load-example! :line-chart)}
175194
"📈 Line Chart"]
176195
[:button {:style {:padding "8px 16px"
177-
:background-color "#F3F4F6"
178-
:color "#374151"
179-
:border "1px solid #D1D5DB"
196+
:background-color (get-color "#F3F4F6" "#374151")
197+
:color (get-color "#374151" "#E5E7EB")
198+
:border (str "1px solid " (get-color "#D1D5DB" "#6B7280"))
180199
:border-radius "6px"
181200
:font-size "14px"
182201
:cursor "pointer"
183202
:font-weight "500"}
184203
:on-click #(load-example! :bar-chart)}
185204
"📊 Bar Chart"]
186205
[:button {:style {:padding "8px 16px"
187-
:background-color "#F3F4F6"
188-
:color "#374151"
189-
:border "1px solid #D1D5DB"
206+
:background-color (get-color "#F3F4F6" "#374151")
207+
:color (get-color "#374151" "#E5E7EB")
208+
:border (str "1px solid " (get-color "#D1D5DB" "#6B7280"))
190209
:border-radius "6px"
191210
:font-size "14px"
192211
:cursor "pointer"
193212
:font-weight "500"}
194213
:on-click #(load-example! :scatter-plot)}
195214
"⚫ Scatter Plot"]
196215
[:button {:style {:padding "8px 16px"
197-
:background-color "#F3F4F6"
198-
:color "#374151"
199-
:border "1px solid #D1D5DB"
216+
:background-color (get-color "#F3F4F6" "#374151")
217+
:color (get-color "#374151" "#E5E7EB")
218+
:border (str "1px solid " (get-color "#D1D5DB" "#6B7280"))
200219
:border-radius "6px"
201220
:font-size "14px"
202221
:cursor "pointer"
@@ -209,7 +228,7 @@ plt.axis('equal')"})
209228
:font-size "14px"
210229
:font-weight "600"
211230
:margin-bottom "8px"
212-
:color "#374151"}}
231+
:color (get-color "#374151" "#D1D5DB")}}
213232
"Python Code (Matplotlib):"]
214233
[:textarea {:value @code
215234
:on-change #(reset! code (.. % -target -value))
@@ -218,11 +237,11 @@ plt.axis('equal')"})
218237
:padding "12px"
219238
:font-family "monospace"
220239
:font-size "14px"
221-
:border "2px solid #D1D5DB"
240+
:border (str "2px solid " (get-color "#D1D5DB" "#4B5563"))
222241
:border-radius "6px"
223242
:resize "vertical"
224-
:background-color "#FFFFFF"
225-
:color "#111827"}}]]
243+
:background-color (get-color "#FFFFFF" "#1F2937")
244+
:color (get-color "#111827" "#F3F4F6")}}]]
226245
;; Generate button
227246
[:button {:style {:width "100%"
228247
:padding "14px 24px"
@@ -246,16 +265,16 @@ plt.axis('equal')"})
246265
(not @matplotlib-loaded?) "Loading Matplotlib..."
247266
:else "📊 Generate Chart")]
248267
;; Output area
249-
[:div {:style {:background-color "#FFFFFF"
250-
:border "2px solid #E5E7EB"
268+
[:div {:style {:background-color (get-color "#FFFFFF" "#1F2937")
269+
:border (str "2px solid " (get-color "#E5E7EB" "#4B5563"))
251270
:border-radius "8px"
252271
:padding "20px"
253272
:min-height "400px"}}
254273
[:label {:style {:display "block"
255274
:font-size "14px"
256275
:font-weight "600"
257276
:margin-bottom "12px"
258-
:color "#374151"}}
277+
:color (get-color "#374151" "#D1D5DB")}}
259278
"Visualization Output:"]
260279
(if @output-image
261280
[:div {:style {:text-align "center"}}
@@ -267,7 +286,7 @@ plt.axis('equal')"})
267286
:box-shadow "0 2px 8px rgba(0,0,0,0.1)"}}]]
268287
[:div {:style {:padding "40px"
269288
:text-align "center"
270-
:color "#6B7280"
289+
:color (get-color "#6B7280" "#9CA3AF")
271290
:font-size "14px"}}
272291
[:p {:style {:margin "0"}} @output-text]])]])
273292

src/scittle/pyodide/hello_python.cljs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,21 @@
99
;; Uses shared pyodide-bridge for state management
1010
;; ============================================================================
1111

12+
;; ============================================================================
13+
;; Dark Mode Support
14+
;; ============================================================================
15+
16+
(defn dark-mode?
17+
"Check if dark mode is currently active by looking for 'quarto-dark' class on body"
18+
[]
19+
(when-let [body (js/document.querySelector "body")]
20+
(.contains (.-classList body) "quarto-dark")))
21+
22+
(defn get-color
23+
"Get appropriate color based on dark mode state"
24+
[light-color dark-color]
25+
(if (dark-mode?) dark-color light-color))
26+
1227
;; Local state (output only - Pyodide state is in bridge)
1328
(defonce output (r/atom "Click 'Initialize Pyodide' to start..."))
1429

@@ -51,11 +66,16 @@
5166
[]
5267
(let [status (pyodide/status)
5368
badge-style (case status
54-
:not-started {:background-color "#E5E7EB" :color "#374151"}
55-
:loading {:background-color "#DBEAFE" :color "#1E40AF"}
56-
:ready {:background-color "#D1FAE5" :color "#065F46"}
57-
:error {:background-color "#FEE2E2" :color "#991B1B"}
58-
{:background-color "#E5E7EB" :color "#374151"})
69+
:not-started {:background-color (get-color "#E5E7EB" "#4B5563")
70+
:color (get-color "#374151" "#D1D5DB")}
71+
:loading {:background-color (get-color "#DBEAFE" "#1E3A8A")
72+
:color (get-color "#1E40AF" "#93C5FD")}
73+
:ready {:background-color (get-color "#D1FAE5" "#064E3B")
74+
:color (get-color "#065F46" "#6EE7B7")}
75+
:error {:background-color (get-color "#FEE2E2" "#7F1D1D")
76+
:color (get-color "#991B1B" "#FCA5A5")}
77+
{:background-color (get-color "#E5E7EB" "#4B5563")
78+
:color (get-color "#374151" "#D1D5DB")})
5979
badge-text (case status
6080
:not-started "Not Started"
6181
:loading "Loading..."
@@ -66,7 +86,10 @@
6686
:align-items "center"
6787
:gap "8px"
6888
:margin-bottom "16px"}}
69-
[:div {:style {:font-size "14px" :font-weight "600"}} "Pyodide Status:"]
89+
[:div {:style {:font-size "14px"
90+
:font-weight "600"
91+
:color (get-color "#111827" "#F3F4F6")}}
92+
"Pyodide Status:"]
7093
[:span {:style (merge {:padding "6px 12px"
7194
:border-radius "9999px"
7295
:font-size "12px"
@@ -127,7 +150,14 @@
127150

128151
(defn output-display
129152
[]
130-
[:div.bg-gray-900.text-green-400.p-4.rounded-lg.font-mono.text-sm.min-h-24.whitespace-pre-wrap
153+
[:div {:style {:background-color (get-color "#111827" "#0F172A")
154+
:color (get-color "#10B981" "#6EE7B7")
155+
:padding "16px"
156+
:border-radius "8px"
157+
:font-family "monospace"
158+
:font-size "14px"
159+
:min-height "96px"
160+
:white-space "pre-wrap"}}
131161
@output])
132162

133163
(defn main-component
@@ -137,13 +167,15 @@
137167
:padding "24px"}}
138168
[:h2 {:style {:font-size "24px"
139169
:font-weight "bold"
140-
:margin-bottom "16px"}}
170+
:margin-bottom "16px"
171+
:color (get-color "#111827" "#F3F4F6")}}
141172
"Hello Python! 🐍"]
142-
[:div {:style {:background-color "#EFF6FF"
143-
:border-left "4px solid #3B82F6"
173+
[:div {:style {:background-color (get-color "#EFF6FF" "#1E3A8A")
174+
:border-left (str "4px solid " (get-color "#3B82F6" "#60A5FA"))
144175
:padding "16px"
145176
:margin-bottom "24px"}}
146-
[:p {:style {:font-size "14px" :color "#374151"}}
177+
[:p {:style {:font-size "14px"
178+
:color (get-color "#374151" "#BFDBFE")}}
147179
"This demo shows the simplest possible Pyodide integration. "
148180
"Click the button below to load the Python interpreter in your browser, "
149181
"then try the example buttons!"]]
@@ -168,7 +200,9 @@
168200
[example-buttons])
169201
[output-display]
170202
(when (= (pyodide/status) :ready)
171-
[:div {:style {:margin-top "16px" :font-size "12px" :color "#6B7280"}}
203+
[:div {:style {:margin-top "16px"
204+
:font-size "12px"
205+
:color (get-color "#6B7280" "#9CA3AF")}}
172206
[:p "✓ Pyodide is running entirely in your browser"]
173207
[:p "✓ No server required"]
174208
[:p "✓ Full Python 3.11 interpreter"]])])

0 commit comments

Comments
 (0)