Spaces:
Sleeping
Sleeping
Update ui/okr_ui_generator.py
Browse files- ui/okr_ui_generator.py +81 -55
ui/okr_ui_generator.py
CHANGED
@@ -15,7 +15,7 @@ def create_enhanced_okr_tab():
|
|
15 |
gr.HTML: The Gradio HTML component that will display the formatted OKRs.
|
16 |
"""
|
17 |
|
18 |
-
# Custom CSS for modern OKR styling with Dark Mode support
|
19 |
okr_custom_css = """
|
20 |
<style>
|
21 |
/* ----------------------------------------- */
|
@@ -34,6 +34,8 @@ def create_enhanced_okr_tab():
|
|
34 |
--content-shadow: rgba(0,0,0,0.1);
|
35 |
--objective-card-bg: #f8fafc;
|
36 |
--objective-card-border: #3b82f6;
|
|
|
|
|
37 |
--objective-header-bg: transparent; /* Cleaner header background */
|
38 |
--objective-title-color: #1e40af; /* Make title the colored element */
|
39 |
--objective-meta-text-color: #475569;
|
@@ -66,43 +68,47 @@ def create_enhanced_okr_tab():
|
|
66 |
--priority-low-border: #86efac;
|
67 |
}
|
68 |
|
|
|
69 |
html.dark {
|
70 |
--header-text-color: #e5e7eb;
|
71 |
-
--stat-card-bg: rgba(
|
72 |
-
--stat-card-bg-hover: rgba(
|
73 |
-
--stat-card-border: rgba(
|
74 |
-
--content-bg: #
|
75 |
-
--content-shadow: rgba(0,0,0,0.
|
76 |
-
--objective-card-bg: #
|
77 |
-
--objective-
|
78 |
-
--objective-
|
79 |
-
--
|
80 |
-
--
|
81 |
-
--
|
82 |
-
--
|
83 |
-
--
|
84 |
-
--
|
85 |
-
--kr-
|
86 |
-
--kr-
|
87 |
-
--
|
88 |
-
--
|
89 |
-
--
|
90 |
-
--task-item-
|
91 |
-
--task-
|
92 |
-
--task-
|
93 |
-
--task-
|
94 |
-
--task-
|
95 |
-
--task-
|
96 |
-
--task-
|
97 |
-
--
|
98 |
-
--
|
99 |
-
--
|
100 |
-
--priority-
|
101 |
-
--priority-
|
102 |
-
--priority-
|
103 |
-
--priority-
|
104 |
-
--priority-
|
105 |
-
--priority-
|
|
|
|
|
|
|
106 |
}
|
107 |
|
108 |
/* Overall Container */
|
@@ -218,37 +224,23 @@ def create_enhanced_okr_tab():
|
|
218 |
margin: 2rem;
|
219 |
border-radius: 16px;
|
220 |
overflow: hidden;
|
221 |
-
box-shadow:
|
222 |
transition: all 0.3s ease;
|
223 |
}
|
224 |
-
|
225 |
-
html.dark .okr-objective {
|
226 |
-
box-shadow: 0 4px 16px rgba(0,0,0,0.2);
|
227 |
-
}
|
228 |
|
229 |
.okr-objective:hover {
|
230 |
transform: translateY(-2px);
|
231 |
-
box-shadow:
|
232 |
}
|
233 |
|
234 |
-
html.dark .okr-objective:hover {
|
235 |
-
box-shadow: 0 8px 24px rgba(0,0,0,0.3);
|
236 |
-
}
|
237 |
-
|
238 |
/* --- Objective Header (REDESIGNED) --- */
|
239 |
.objective-header {
|
240 |
padding: 2rem;
|
241 |
background: var(--objective-header-bg);
|
242 |
-
border-bottom: 1px solid
|
243 |
position: relative;
|
244 |
}
|
245 |
|
246 |
-
html.dark .objective-header {
|
247 |
-
border-bottom-color: #334155;
|
248 |
-
}
|
249 |
-
|
250 |
-
/* REMOVED distracting ::before dot pattern */
|
251 |
-
|
252 |
.objective-title {
|
253 |
font-size: 1.5rem;
|
254 |
font-weight: 700;
|
@@ -458,7 +450,7 @@ def create_enhanced_okr_tab():
|
|
458 |
font-size: 1.5rem;
|
459 |
font-weight: 600;
|
460 |
margin-bottom: 0.5rem;
|
461 |
-
color: var(--
|
462 |
}
|
463 |
|
464 |
/* Loading Spinner */
|
@@ -504,10 +496,44 @@ def create_enhanced_okr_tab():
|
|
504 |
}
|
505 |
}
|
506 |
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
507 |
"""
|
508 |
|
509 |
with gr.Column(elem_classes=["okr-root-column"]):
|
510 |
-
# Inject custom CSS
|
511 |
gr.HTML(okr_custom_css)
|
512 |
|
513 |
# Main OKR display area with enhanced styling
|
|
|
15 |
gr.HTML: The Gradio HTML component that will display the formatted OKRs.
|
16 |
"""
|
17 |
|
18 |
+
# Custom CSS for modern OKR styling with Dark Mode support and JS theme syncing
|
19 |
okr_custom_css = """
|
20 |
<style>
|
21 |
/* ----------------------------------------- */
|
|
|
34 |
--content-shadow: rgba(0,0,0,0.1);
|
35 |
--objective-card-bg: #f8fafc;
|
36 |
--objective-card-border: #3b82f6;
|
37 |
+
--objective-shadow: 0 4px 16px rgba(0,0,0,0.05);
|
38 |
+
--objective-shadow-hover: 0 8px 24px rgba(0,0,0,0.1);
|
39 |
--objective-header-bg: transparent; /* Cleaner header background */
|
40 |
--objective-title-color: #1e40af; /* Make title the colored element */
|
41 |
--objective-meta-text-color: #475569;
|
|
|
68 |
--priority-low-border: #86efac;
|
69 |
}
|
70 |
|
71 |
+
/* --- DARK MODE OVERRIDES (IMPROVED) --- */
|
72 |
html.dark {
|
73 |
--header-text-color: #e5e7eb;
|
74 |
+
--stat-card-bg: rgba(28, 28, 28, 0.7);
|
75 |
+
--stat-card-bg-hover: rgba(40, 40, 40, 0.8);
|
76 |
+
--stat-card-border: rgba(50, 50, 50, 0.8);
|
77 |
+
--content-bg: #0d1117; /* Black background for content */
|
78 |
+
--content-shadow: rgba(0,0,0,0.6);
|
79 |
+
--objective-card-bg: #161b22; /* Blackish card background */
|
80 |
+
--objective-card-border: #3b82f6;
|
81 |
+
--objective-shadow: 0 8px 24px rgba(0,0,0,0.5);
|
82 |
+
--objective-shadow-hover: 0 10px 28px rgba(0,0,0,0.6);
|
83 |
+
--objective-title-color: #58a6ff; /* White-ish blue for title */
|
84 |
+
--objective-meta-text-color: #8b949e; /* White-ish grey for meta */
|
85 |
+
--key-result-bg: #161b22;
|
86 |
+
--key-result-border: #30363d;
|
87 |
+
--key-result-border-hover: #58a6ff;
|
88 |
+
--kr-header-bg: #161b22;
|
89 |
+
--kr-title-color: #c9d1d9; /* White text */
|
90 |
+
--kr-metric-bg: rgba(56, 139, 253, 0.15);
|
91 |
+
--kr-metric-color: #58a6ff;
|
92 |
+
--kr-metric-border: rgba(56, 139, 253, 0.4);
|
93 |
+
--task-item-bg: #21262d;
|
94 |
+
--task-item-bg-hover: #30363d;
|
95 |
+
--task-item-border: #30363d;
|
96 |
+
--task-item-border-hover: #8b949e;
|
97 |
+
--task-title-color: #c9d1d9; /* White text */
|
98 |
+
--task-detail-label-color: #8b949e;
|
99 |
+
--task-detail-text-color: #8b949e;
|
100 |
+
--task-description-bg: #0d1117;
|
101 |
+
--task-description-border: #30363d;
|
102 |
+
--task-description-color: #8b949e;
|
103 |
+
--priority-high-bg: rgba(248, 81, 73, 0.15);
|
104 |
+
--priority-high-color: #ff7b72;
|
105 |
+
--priority-high-border: rgba(248, 81, 73, 0.4);
|
106 |
+
--priority-medium-bg: rgba(210, 153, 34, 0.15);
|
107 |
+
--priority-medium-color: #d29922;
|
108 |
+
--priority-medium-border: rgba(210, 153, 34, 0.4);
|
109 |
+
--priority-low-bg: rgba(63, 185, 80, 0.15);
|
110 |
+
--priority-low-color: #56d364;
|
111 |
+
--priority-low-border: rgba(63, 185, 80, 0.4);
|
112 |
}
|
113 |
|
114 |
/* Overall Container */
|
|
|
224 |
margin: 2rem;
|
225 |
border-radius: 16px;
|
226 |
overflow: hidden;
|
227 |
+
box-shadow: var(--objective-shadow);
|
228 |
transition: all 0.3s ease;
|
229 |
}
|
|
|
|
|
|
|
|
|
230 |
|
231 |
.okr-objective:hover {
|
232 |
transform: translateY(-2px);
|
233 |
+
box-shadow: var(--objective-shadow-hover);
|
234 |
}
|
235 |
|
|
|
|
|
|
|
|
|
236 |
/* --- Objective Header (REDESIGNED) --- */
|
237 |
.objective-header {
|
238 |
padding: 2rem;
|
239 |
background: var(--objective-header-bg);
|
240 |
+
border-bottom: 1px solid var(--key-result-border); /* Use variable for consistency */
|
241 |
position: relative;
|
242 |
}
|
243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
.objective-title {
|
245 |
font-size: 1.5rem;
|
246 |
font-weight: 700;
|
|
|
450 |
font-size: 1.5rem;
|
451 |
font-weight: 600;
|
452 |
margin-bottom: 0.5rem;
|
453 |
+
color: var(--objective-title-color);
|
454 |
}
|
455 |
|
456 |
/* Loading Spinner */
|
|
|
496 |
}
|
497 |
}
|
498 |
</style>
|
499 |
+
<script>
|
500 |
+
function syncThemeWithParent() {
|
501 |
+
// This script runs inside the Gradio iframe. It looks at the parent page's
|
502 |
+
// <html> tag to see if the 'dark' class is present and applies it to the
|
503 |
+
// iframe's own <html> tag, ensuring the CSS variables for dark mode are activated.
|
504 |
+
try {
|
505 |
+
const parentHtml = window.parent.document.querySelector('html');
|
506 |
+
if (parentHtml) {
|
507 |
+
if (parentHtml.classList.contains('dark')) {
|
508 |
+
document.documentElement.classList.add('dark');
|
509 |
+
} else {
|
510 |
+
document.documentElement.classList.remove('dark');
|
511 |
+
}
|
512 |
+
}
|
513 |
+
} catch (e) {
|
514 |
+
// This can fail due to cross-origin policies, but it's safe in Gradio.
|
515 |
+
console.error("Error syncing theme with parent:", e);
|
516 |
+
}
|
517 |
+
}
|
518 |
+
|
519 |
+
// Use a MutationObserver to detect when the theme is toggled on the parent page.
|
520 |
+
try {
|
521 |
+
const observer = new MutationObserver(syncThemeWithParent);
|
522 |
+
const parentHtml = window.parent.document.querySelector('html');
|
523 |
+
if (parentHtml) {
|
524 |
+
observer.observe(parentHtml, { attributes: true, attributeFilter: ['class'] });
|
525 |
+
}
|
526 |
+
} catch (e) {
|
527 |
+
console.error("Could not set up theme MutationObserver:", e);
|
528 |
+
}
|
529 |
+
|
530 |
+
// Also run the sync function once when the iframe's content has loaded.
|
531 |
+
document.addEventListener('DOMContentLoaded', syncThemeWithParent);
|
532 |
+
</script>
|
533 |
"""
|
534 |
|
535 |
with gr.Column(elem_classes=["okr-root-column"]):
|
536 |
+
# Inject custom CSS and the theme-syncing JS
|
537 |
gr.HTML(okr_custom_css)
|
538 |
|
539 |
# Main OKR display area with enhanced styling
|