Skip to content

Commit bd54110

Browse files
committed
feat(viewer): add transcript/audio sync, copy-all button, and extract shared UI
1 parent f62ba9c commit bd54110

File tree

2 files changed

+1229
-192
lines changed

2 files changed

+1229
-192
lines changed

openadapt_ml/training/shared_ui.py

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
"""Shared UI components for dashboards and viewers.
2+
3+
This module contains CSS and HTML generation functions used by both
4+
the Training Dashboard and the Viewer for visual consistency.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
10+
def get_shared_header_css() -> str:
11+
"""Generate CSS for the shared dashboard header.
12+
13+
This CSS is used by both the Training Dashboard and the Viewer.
14+
Any changes here will affect all dashboards consistently.
15+
"""
16+
return '''
17+
.unified-header {
18+
display: flex;
19+
align-items: center;
20+
justify-content: space-between;
21+
padding: 12px 24px;
22+
background: linear-gradient(180deg, rgba(18,18,26,0.98) 0%, rgba(26,26,36,0.98) 100%);
23+
border-bottom: 1px solid rgba(255,255,255,0.08);
24+
margin-bottom: 20px;
25+
gap: 16px;
26+
flex-wrap: wrap;
27+
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
28+
}
29+
.unified-header .nav-tabs {
30+
display: flex;
31+
align-items: center;
32+
gap: 4px;
33+
background: rgba(0,0,0,0.3);
34+
padding: 4px;
35+
border-radius: 8px;
36+
}
37+
.unified-header .nav-tab {
38+
padding: 8px 16px;
39+
border-radius: 6px;
40+
font-size: 0.85rem;
41+
font-weight: 500;
42+
text-decoration: none;
43+
color: var(--text-secondary);
44+
background: transparent;
45+
border: none;
46+
transition: all 0.2s;
47+
cursor: pointer;
48+
}
49+
.unified-header .nav-tab:hover {
50+
color: var(--text-primary);
51+
background: rgba(255,255,255,0.05);
52+
}
53+
.unified-header .nav-tab.active {
54+
color: var(--bg-primary);
55+
background: var(--accent);
56+
font-weight: 600;
57+
}
58+
.unified-header .controls-section {
59+
display: flex;
60+
align-items: center;
61+
gap: 24px;
62+
flex-wrap: wrap;
63+
}
64+
.unified-header .control-group {
65+
display: flex;
66+
align-items: center;
67+
gap: 10px;
68+
}
69+
.unified-header .control-label {
70+
font-size: 0.7rem;
71+
color: var(--text-muted);
72+
font-weight: 600;
73+
letter-spacing: 0.5px;
74+
text-transform: uppercase;
75+
}
76+
.unified-header select {
77+
padding: 8px 32px 8px 12px;
78+
border-radius: 8px;
79+
font-size: 0.85rem;
80+
background: rgba(0,0,0,0.4);
81+
color: var(--text-primary);
82+
border: 1px solid rgba(255,255,255,0.1);
83+
cursor: pointer;
84+
appearance: none;
85+
background-image: url('data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 width=%2712%27 height=%278%27%3E%3Cpath fill=%27%23888%27 d=%27M0 0l6 8 6-8z%27/%3E%3C/svg%3E');
86+
background-repeat: no-repeat;
87+
background-position: right 10px center;
88+
transition: all 0.2s;
89+
}
90+
.unified-header select:hover {
91+
border-color: var(--accent);
92+
background-color: rgba(0,212,170,0.1);
93+
}
94+
.unified-header select:focus {
95+
outline: none;
96+
border-color: var(--accent);
97+
box-shadow: 0 0 0 2px rgba(0,212,170,0.2);
98+
}
99+
.unified-header .header-meta {
100+
font-size: 0.75rem;
101+
color: var(--text-muted);
102+
font-family: "SF Mono", Monaco, monospace;
103+
}
104+
'''
105+
106+
107+
def generate_shared_header_html(
108+
active_page: str,
109+
controls_html: str = "",
110+
meta_html: str = "",
111+
) -> str:
112+
"""Generate the shared header HTML.
113+
114+
Args:
115+
active_page: Either "training", "viewer", or "benchmarks" to highlight the active tab
116+
controls_html: Optional HTML for control groups (dropdowns, etc.)
117+
meta_html: Optional HTML for metadata display (job ID, capture ID, etc.)
118+
119+
Returns:
120+
HTML string for the header
121+
"""
122+
training_active = "active" if active_page == "training" else ""
123+
viewer_active = "active" if active_page == "viewer" else ""
124+
benchmarks_active = "active" if active_page == "benchmarks" else ""
125+
126+
controls_section = ""
127+
if controls_html or meta_html:
128+
controls_section = f'''
129+
<div class="controls-section">
130+
{controls_html}
131+
{f'<span class="header-meta">{meta_html}</span>' if meta_html else ''}
132+
</div>
133+
'''
134+
135+
return f'''
136+
<div class="unified-header">
137+
<div class="nav-tabs">
138+
<a href="dashboard.html" class="nav-tab {training_active}">Training</a>
139+
<a href="viewer.html" class="nav-tab {viewer_active}">Viewer</a>
140+
<a href="benchmark.html" class="nav-tab {benchmarks_active}">Benchmarks</a>
141+
</div>
142+
{controls_section}
143+
</div>
144+
'''
145+
146+
147+
def build_nav_links() -> list[tuple[str, str]]:
148+
"""Build navigation links for multi-capture dashboards.
149+
150+
Returns:
151+
List of (filename, label) tuples
152+
"""
153+
return [
154+
("dashboard.html", "Training"),
155+
("viewer.html", "Viewer"),
156+
("benchmark.html", "Benchmarks"),
157+
]

0 commit comments

Comments
 (0)