Skip to content

Commit 37c193d

Browse files
authored
Merge pull request #79 from cyiallou/feat/card-dashboard
feat: add MicrogridOverviewDashboard for dynamic multi-microgrid display
2 parents 266e46d + 3c9275a commit 37c193d

File tree

4 files changed

+467
-0
lines changed

4 files changed

+467
-0
lines changed

RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
## New Features
1111

1212
- Introduced a `SolarAnalysisData` dataclass to structure the output of the `solar_maintenance_app.run_workflow()` function. This introduces a breaking change in the `Solar Maintenance.ipynb` notebook.
13+
- Added a modular `MicrogridOverviewDashboard` for dynamic multi-microgrid production display with light/dark theme support. Replaces the current hardcoded single-microgrid layout.
1314

1415
## Bug Fixes
1516

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Styles and scripts for the microgrid overview dashboard."""
5+
6+
STYLE_CONTENT = """
7+
<style>
8+
.container {{
9+
display: flex;
10+
flex-wrap: wrap;
11+
gap: 30px;
12+
justify-content: center;
13+
}}
14+
15+
/* Card Styles */
16+
.card {{
17+
width: 320px;
18+
min-height: 380px;
19+
padding: 20px;
20+
border-radius: 12px;
21+
background-color: #f8f9fa;
22+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
23+
font-family: Arial, sans-serif;
24+
transition: 0.3s;
25+
display: flex;
26+
flex-direction: column;
27+
align-items: center;
28+
}}
29+
30+
.card:hover {{
31+
transform: translateY(-5px);
32+
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
33+
background-color: #eef0f3;
34+
}}
35+
36+
.badge-wrapper {{
37+
height: 24px;
38+
margin-bottom: 10px;
39+
}}
40+
41+
.badge {{
42+
position: relative;
43+
display: inline-flex;
44+
align-items: center;
45+
justify-content: center;
46+
background: gold;
47+
color: black;
48+
font-weight: bold;
49+
font-size: 14px;
50+
padding: 6px 14px;
51+
border-radius: 20px;
52+
cursor: pointer;
53+
white-space: nowrap;
54+
}}
55+
56+
.badge-placeholder {{
57+
height: 34px;
58+
}}
59+
60+
.badge .tooltiptext {{
61+
visibility: hidden;
62+
width: 220px;
63+
background-color: black;
64+
color: #fff;
65+
text-align: center;
66+
border-radius: 6px;
67+
padding: 8px;
68+
position: absolute;
69+
z-index: 1;
70+
bottom: 125%;
71+
left: 50%;
72+
margin-left: -110px;
73+
opacity: 0;
74+
transform: translateY(10px);
75+
transition: opacity 0.4s ease, transform 0.4s ease;
76+
font-size: 12px;
77+
pointer-events: none;
78+
}}
79+
80+
.badge:hover .tooltiptext {{
81+
visibility: visible;
82+
opacity: 1;
83+
transform: translateY(0px);
84+
}}
85+
86+
h3 {{
87+
margin: 10px 0 15px 0;
88+
font-size: 20px;
89+
color: #333;
90+
}}
91+
92+
.stats {{
93+
width: 100%;
94+
display: flex;
95+
flex-direction: column;
96+
gap: 8px;
97+
}}
98+
99+
.stat {{
100+
display: flex;
101+
justify-content: space-between;
102+
background: #ffffff;
103+
padding: 8px 12px;
104+
border-radius: 6px;
105+
border: 1px solid #eee;
106+
font-size: 14px;
107+
}}
108+
109+
.stat-title {{
110+
color: #555;
111+
}}
112+
113+
.stat-value {{
114+
color: #555;
115+
transition: color 0.3s ease;
116+
}}
117+
118+
.highlight-green {{
119+
color: green;
120+
font-weight: bold;
121+
}}
122+
123+
.highlight-red {{
124+
color: red;
125+
font-weight: bold;
126+
}}
127+
128+
/* Dark Mode */
129+
.dark-mode .card {{
130+
background-color: #333;
131+
color: #eee;
132+
}}
133+
134+
.dark-mode .stat {{
135+
background-color: #555;
136+
border-color: #777;
137+
}}
138+
139+
.dark-mode h3 {{
140+
color: #eee;
141+
}}
142+
143+
.dark-mode .stat-title {{
144+
color: #eee;
145+
}}
146+
147+
.dark-mode .stat-value {{
148+
color: #eee;
149+
}}
150+
151+
.dark-mode .highlight-green {{
152+
color: #8f8;
153+
}}
154+
155+
.dark-mode .highlight-red {{
156+
color: #f88;
157+
}}
158+
159+
.dark-mode .badge {{
160+
background: orange;
161+
}}
162+
163+
.dark-mode .badge .tooltiptext {{
164+
background-color: #ccc;
165+
color: #222;
166+
}}
167+
168+
/* Toggle Switch */
169+
.switch {{
170+
position: relative;
171+
display: inline-block;
172+
width: 60px;
173+
height: 34px;
174+
margin: 20px;
175+
}}
176+
177+
.switch input {{
178+
opacity: 0;
179+
width: 0;
180+
height: 0;
181+
}}
182+
183+
.slider {{
184+
position: absolute;
185+
cursor: pointer;
186+
top: 0;
187+
left: 0;
188+
right: 0;
189+
bottom: 0;
190+
background-color: #ccc;
191+
transition: background-color 0.4s;
192+
border-radius: 34px;
193+
}}
194+
195+
.slider-icon {{
196+
position: absolute;
197+
height: 26px;
198+
width: 26px;
199+
left: 4px;
200+
bottom: 4px;
201+
background-color: white;
202+
transition: transform 0.4s, opacity 0.4s;
203+
border-radius: 50%;
204+
font-size: 18px;
205+
text-align: center;
206+
line-height: 26px;
207+
}}
208+
209+
input:checked + .slider {{
210+
background-color: #2196F3;
211+
}}
212+
213+
input:checked + .slider .slider-icon {{
214+
transform: translateX(26px);
215+
opacity: 1;
216+
}}
217+
</style>
218+
"""
219+
220+
TOGGLE_HTML = """
221+
<label class="switch">
222+
<input type="checkbox" id="theme-toggle" onclick="toggleDarkMode()" {checked}>
223+
<span class="slider"><span class="slider-icon">{icon}</span></span>
224+
</label>
225+
"""
226+
227+
TOGGLE_SCRIPT = """
228+
<script>
229+
function toggleDarkMode() {{
230+
document.body.classList.toggle('dark-mode');
231+
updateSliderIcon();
232+
}}
233+
234+
function updateSliderIcon() {{
235+
const isDarkMode = document.body.classList.contains('dark-mode');
236+
const sliderIcon = document.querySelector('.slider-icon');
237+
238+
if (sliderIcon) {{
239+
sliderIcon.textContent = isDarkMode ? '🌒' : '☀️';
240+
}}
241+
}}
242+
243+
window.addEventListener('DOMContentLoaded', (event) => {{
244+
updateSliderIcon();
245+
}});
246+
</script>
247+
"""
248+
249+
CLICK_SCRIPT_ONLOAD = """
250+
<script>
251+
window.onload = function() {{
252+
document.getElementById('theme-toggle').checked = true;
253+
toggleDarkMode();
254+
}};
255+
</script>
256+
"""
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# License: MIT
2+
# Copyright © 2025 Frequenz Energy-as-a-Service GmbH
3+
4+
"""Microgrid Overview Dashboard Templates."""
5+
6+
CARD_TEMPLATE = """
7+
<div class="card">
8+
{badge_html}
9+
<h3>Microgrid ID: {microgrid_id}</h3>
10+
<div class="stats">
11+
{stats_html}
12+
</div>
13+
</div>
14+
"""
15+
16+
STAT_TEMPLATE = """
17+
<div class="stat">
18+
<span class="stat-title">{col_name}</span>
19+
<span class="stat-value {extra_class}">{value}</span>
20+
</div>
21+
"""
22+
23+
BADGE_TEMPLATE = """
24+
<div class="badge-wrapper">
25+
<div class="badge">
26+
<span class="tooltiptext">Based on production today.</span>
27+
🏆 Top Producer
28+
</div>
29+
</div>
30+
"""
31+
32+
BADGE_PLACEHOLDER_TEMPLATE = """
33+
<div class="badge-wrapper">
34+
<div class="badge-placeholder"></div>
35+
</div>
36+
"""

0 commit comments

Comments
 (0)