Skip to content

Commit 2126f7a

Browse files
Kasper Jungeclaude
authored andcommitted
feat: redesign sidebar with branded header and improved run cards
Dark gradient header with ambient glow gives the sidebar a warm, distinctive identity. Run cards now show pass-rate percentages and prompt tags at a glance. Also fixes three unused-import lint errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8a095e5 commit 2126f7a

4 files changed

Lines changed: 118 additions & 45 deletions

File tree

src/ralphify/ui/static/dashboard.css

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -76,53 +76,98 @@ body {
7676
display: flex;
7777
flex-direction: column;
7878
flex-shrink: 0;
79-
box-shadow: 1px 0 3px rgba(0, 0, 0, 0.03);
79+
box-shadow: 1px 0 8px rgba(46, 42, 66, 0.04);
8080
}
8181

8282
.sidebar-header {
83-
padding: 20px 20px 16px;
84-
border-bottom: 1px solid var(--border);
83+
padding: 0;
84+
display: flex;
85+
flex-direction: column;
86+
background: linear-gradient(135deg, #2a2045 0%, #1C1730 100%);
87+
position: relative;
88+
overflow: hidden;
89+
}
90+
91+
.sidebar-header::before {
92+
content: '';
93+
position: absolute;
94+
inset: 0;
95+
background: radial-gradient(ellipse at 70% 20%, rgba(109, 74, 232, 0.25) 0%, transparent 60%),
96+
radial-gradient(ellipse at 20% 80%, rgba(232, 123, 74, 0.15) 0%, transparent 60%);
97+
pointer-events: none;
98+
}
99+
100+
.sidebar-header-inner {
85101
display: flex;
86102
align-items: center;
87103
gap: 10px;
104+
padding: 20px 20px 16px;
105+
position: relative;
106+
z-index: 1;
88107
}
89108

90109
.sidebar-header h1 {
91110
font-size: 18px;
92111
font-weight: 700;
93-
background: linear-gradient(135deg, var(--primary), var(--accent));
94-
-webkit-background-clip: text;
95-
-webkit-text-fill-color: transparent;
96-
background-clip: text;
112+
color: #ffffff;
113+
letter-spacing: -0.01em;
97114
}
98115

99116
.sidebar-header .version {
100117
font-size: 10px;
101-
color: var(--text-secondary);
102118
font-family: var(--font-sans);
103-
font-weight: 500;
104-
background: var(--primary-light);
105-
color: var(--primary);
106-
padding: 2px 6px;
119+
font-weight: 600;
120+
background: rgba(255, 255, 255, 0.12);
121+
color: rgba(255, 255, 255, 0.7);
122+
padding: 2px 8px;
107123
border-radius: 4px;
124+
letter-spacing: 0.5px;
125+
}
126+
127+
.sidebar-new-run-btn {
128+
display: flex;
129+
align-items: center;
130+
justify-content: center;
131+
gap: 6px;
132+
margin: 0 16px 16px;
133+
padding: 9px 16px;
134+
border-radius: var(--radius);
135+
border: 1px solid rgba(255, 255, 255, 0.15);
136+
background: rgba(255, 255, 255, 0.08);
137+
color: rgba(255, 255, 255, 0.85);
138+
font-size: 13px;
139+
font-weight: 500;
140+
cursor: pointer;
141+
transition: all 0.15s ease;
142+
font-family: var(--font-sans);
143+
position: relative;
144+
z-index: 1;
145+
backdrop-filter: blur(4px);
146+
}
147+
148+
.sidebar-new-run-btn:hover {
149+
background: rgba(255, 255, 255, 0.14);
150+
border-color: rgba(255, 255, 255, 0.25);
151+
color: #ffffff;
108152
}
109153

110154
.sidebar-section {
111155
padding: 8px 12px;
112156
}
113157

114158
.sidebar-section-title {
115-
font-size: 11px;
159+
font-size: 10px;
116160
font-weight: 600;
117161
text-transform: uppercase;
118-
color: var(--text-secondary);
119-
padding: 12px 8px 6px;
120-
letter-spacing: 0.6px;
162+
color: var(--text-muted);
163+
padding: 14px 8px 6px;
164+
letter-spacing: 0.8px;
121165
}
122166

123167
.sidebar-runs {
124168
flex: 1;
125169
overflow-y: auto;
170+
border-top: 1px solid var(--border);
126171
}
127172

128173
/* ── Run cards ───────────────────────────────────────────────────── */
@@ -134,17 +179,20 @@ body {
134179
padding: 10px 12px;
135180
border-radius: var(--radius);
136181
cursor: pointer;
137-
transition: all 0.15s ease;
182+
transition: all 0.18s ease;
138183
margin-bottom: 2px;
184+
border: 1px solid transparent;
139185
}
140186

141187
.run-card:hover {
142188
background: var(--primary-light);
189+
border-color: var(--primary-border);
143190
}
144191

145192
.run-card.active {
146193
background: var(--primary-light);
147-
box-shadow: inset 3px 0 0 var(--primary);
194+
border-color: var(--primary-border);
195+
box-shadow: inset 3px 0 0 var(--primary), var(--shadow-sm);
148196
}
149197

150198
.run-badge {
@@ -198,6 +246,19 @@ body {
198246
.run-card-bar-fill.pass { background: var(--green); }
199247
.run-card-bar-fill.fail { background: var(--red); }
200248

249+
.run-card-tag {
250+
font-size: 10px;
251+
font-weight: 600;
252+
color: var(--accent);
253+
background: var(--accent-light);
254+
padding: 2px 7px;
255+
border-radius: 4px;
256+
white-space: nowrap;
257+
flex-shrink: 0;
258+
font-family: var(--font-sans);
259+
letter-spacing: 0.02em;
260+
}
261+
201262
/* ── Main area ───────────────────────────────────────────────────── */
202263

203264
.main {
@@ -876,18 +937,19 @@ body {
876937
/* ── Logo mark ──────────────────────────────────────────────────── */
877938

878939
.logo-mark {
879-
width: 28px;
880-
height: 28px;
881-
border-radius: 7px;
940+
width: 30px;
941+
height: 30px;
942+
border-radius: 8px;
882943
background: linear-gradient(135deg, #8B6CF0, #E87B4A);
883944
color: white;
884945
font-weight: 700;
885-
font-size: 15px;
946+
font-size: 16px;
886947
display: flex;
887948
align-items: center;
888949
justify-content: center;
889950
flex-shrink: 0;
890951
letter-spacing: -0.5px;
952+
box-shadow: 0 2px 8px rgba(139, 108, 240, 0.3);
891953
}
892954

893955
/* ── Empty state ─────────────────────────────────────────────────── */

src/ralphify/ui/static/dashboard.js

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -204,23 +204,30 @@ function Sidebar() {
204204
return html`
205205
<div class="sidebar">
206206
<div class="sidebar-header">
207-
<div class="logo-mark">R</div>
208-
<h1>Ralphify</h1>
209-
<span class="version">UI</span>
210-
</div>
211-
<div class="sidebar-section">
212-
<div class="sidebar-section-title">Active Runs</div>
213-
${active.length === 0 && html`
214-
<div style="padding: 8px 12px; font-size: 13px; color: var(--text-secondary)">No active runs</div>
215-
`}
216-
${active.map(r => html`<${RunCard} key=${r.run_id} run=${r} />`)}
207+
<div class="sidebar-header-inner">
208+
<div class="logo-mark">R</div>
209+
<h1>Ralphify</h1>
210+
<span class="version">UI</span>
211+
</div>
212+
<button class="sidebar-new-run-btn" onClick=${() => showNewRunModal.value = true}>
213+
+ New Run
214+
</button>
217215
</div>
218-
<div class="sidebar-section">
219-
<div class="sidebar-section-title">Recent</div>
220-
${recent.length === 0 && html`
221-
<div style="padding: 8px 12px; font-size: 13px; color: var(--text-secondary)">No recent runs</div>
222-
`}
223-
${recent.map(r => html`<${RunCard} key=${r.run_id} run=${r} />`)}
216+
<div class="sidebar-runs">
217+
<div class="sidebar-section">
218+
<div class="sidebar-section-title">Active Runs</div>
219+
${active.length === 0 && html`
220+
<div style="padding: 8px 12px; font-size: 13px; color: var(--text-muted)">No active runs</div>
221+
`}
222+
${active.map(r => html`<${RunCard} key=${r.run_id} run=${r} />`)}
223+
</div>
224+
<div class="sidebar-section">
225+
<div class="sidebar-section-title">Recent</div>
226+
${recent.length === 0 && html`
227+
<div style="padding: 8px 12px; font-size: 13px; color: var(--text-muted)">No recent runs</div>
228+
`}
229+
${recent.map(r => html`<${RunCard} key=${r.run_id} run=${r} />`)}
230+
</div>
224231
</div>
225232
</div>
226233
`;
@@ -230,17 +237,23 @@ function RunCard({ run }) {
230237
const isActive = activeRunId.value === run.run_id;
231238
const total = run.completed + run.failed;
232239
const passRate = total > 0 ? (run.completed / total) * 100 : 0;
240+
const shortId = run.run_id.length > 12 ? run.run_id.slice(0, 12) : run.run_id;
233241

234242
return html`
235243
<div class="run-card ${isActive ? 'active' : ''}" onClick=${() => activeRunId.value = run.run_id}>
236244
<div class="run-badge ${run.status}"></div>
237245
<div class="run-card-info">
238-
<div class="run-card-title">${run.run_id}</div>
239-
<div class="run-card-meta">iter ${run.iteration || 0} · ${run.status}</div>
246+
<div class="run-card-title">${shortId}</div>
247+
<div class="run-card-meta">
248+
iter ${run.iteration || 0}${total > 0 ? ` · ${Math.round(passRate)}% pass` : ` · ${run.status}`}
249+
</div>
240250
</div>
251+
${run.prompt_name && html`
252+
<span class="run-card-tag">${run.prompt_name}</span>
253+
`}
241254
${total > 0 && html`
242255
<div class="run-card-bar">
243-
<div class="run-card-bar-fill pass" style="width: ${passRate}%"></div>
256+
<div class="run-card-bar-fill ${passRate >= 50 ? 'pass' : 'fail'}" style="width: ${passRate}%"></div>
244257
</div>
245258
`}
246259
</div>

tests/test_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from ralphify._frontmatter import parse_frontmatter
99
from ralphify.checks import Check, CheckResult
1010
from ralphify.contexts import Context, ContextResult
11-
from ralphify.cli import app, CONFIG_FILENAME, RALPH_TOML_TEMPLATE, PROMPT_TEMPLATE, PROMPT_MD_TEMPLATE
11+
from ralphify.cli import app, CONFIG_FILENAME, RALPH_TOML_TEMPLATE, PROMPT_TEMPLATE
1212
from ralphify.engine import _format_duration
1313

1414
runner = CliRunner()

tests/test_prompts.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from pathlib import Path
2-
31
import pytest
42

5-
from ralphify.prompts import Prompt, discover_prompts, is_prompt_name, resolve_prompt_name
3+
from ralphify.prompts import discover_prompts, is_prompt_name, resolve_prompt_name
64

75

86
class TestDiscoverPrompts:

0 commit comments

Comments
 (0)