Skip to content

Commit 26e6643

Browse files
committed
Navbar Option C: avatar dropdown, move GitHub/sponsor to sidebar
- Replace username + role + logout + theme + GitHub + sponsor with a single avatar circle (user initial) that opens a dropdown - Dropdown contains: username, role badge, theme toggle, sign out - Move GitHub and Sponsor links to sidebar footer - Topbar right is now: earnings | bell | avatar — clean and unified - Avatar dropdown closes on outside click
1 parent 10db3f3 commit 26e6643

3 files changed

Lines changed: 158 additions & 92 deletions

File tree

app/static/css/style.css

Lines changed: 94 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,24 @@ img { max-width: 100%; }
201201
.sidebar-footer {
202202
padding: 12px 20px;
203203
border-top: 1px solid var(--border-color);
204-
font-size: 0.8rem;
204+
display: flex;
205+
align-items: center;
206+
justify-content: space-between;
207+
}
208+
.sidebar-footer-links {
209+
display: flex;
210+
gap: 10px;
211+
}
212+
.sidebar-footer-links a {
213+
color: var(--text-muted);
214+
display: flex;
215+
transition: color var(--transition);
216+
}
217+
.sidebar-footer-links a:hover { color: var(--text-primary); }
218+
.sidebar-sponsor-link { color: #db61a2 !important; }
219+
.sidebar-sponsor-link:hover { color: #bf3984 !important; }
220+
.sidebar-footer-version {
221+
font-size: 0.75rem;
205222
color: var(--text-muted);
206223
}
207224

@@ -237,29 +254,6 @@ img { max-width: 100%; }
237254
gap: 8px;
238255
}
239256

240-
.topbar-actions {
241-
display: flex;
242-
align-items: center;
243-
gap: 2px;
244-
}
245-
246-
.topbar-divider {
247-
width: 1px;
248-
height: 20px;
249-
background: var(--border-color);
250-
margin: 0 4px;
251-
}
252-
253-
.topbar-user {
254-
display: flex;
255-
align-items: center;
256-
gap: 8px;
257-
}
258-
.topbar-username {
259-
color: var(--text-secondary);
260-
font-size: 0.8rem;
261-
font-weight: 500;
262-
}
263257
.topbar-role {
264258
font-size: 0.65rem;
265259
text-transform: uppercase;
@@ -271,18 +265,6 @@ img { max-width: 100%; }
271265
.badge-owner { background: var(--accent-soft); color: var(--accent); }
272266
.badge-writer { background: var(--success-soft); color: var(--success); }
273267
.badge-viewer { background: var(--warning-soft); color: var(--warning); }
274-
.topbar-logout {
275-
display: flex;
276-
align-items: center;
277-
color: var(--text-muted);
278-
padding: 4px;
279-
border-radius: var(--radius-sm);
280-
transition: color var(--transition), background var(--transition);
281-
}
282-
.topbar-logout:hover {
283-
color: var(--error);
284-
background: var(--error-soft);
285-
}
286268

287269
.topbar-icon-btn {
288270
display: flex;
@@ -301,18 +283,87 @@ img { max-width: 100%; }
301283
color: var(--text-primary);
302284
background: var(--bg-hover);
303285
}
304-
.topbar-sponsor {
305-
color: #db61a2;
306-
}
307-
.topbar-sponsor:hover {
308-
color: #bf3984;
309-
background: rgba(219, 97, 162, 0.1);
310-
}
311286

312287
/* Theme toggle icon visibility */
313288
#theme-toggle .icon-moon { display: none; }
314289
:root[data-theme="light"] #theme-toggle .icon-sun { display: none; }
315290
:root[data-theme="light"] #theme-toggle .icon-moon { display: block; }
291+
/* Theme label text */
292+
#theme-toggle .theme-label::after { content: 'Light mode'; }
293+
:root[data-theme="light"] #theme-toggle .theme-label::after { content: 'Dark mode'; }
294+
295+
/* Avatar button + dropdown */
296+
.topbar-avatar-wrap {
297+
position: relative;
298+
}
299+
.topbar-avatar {
300+
width: 32px;
301+
height: 32px;
302+
border-radius: 50%;
303+
border: none;
304+
background: var(--accent);
305+
color: #fff;
306+
font-size: 0.8rem;
307+
font-weight: 700;
308+
cursor: pointer;
309+
display: flex;
310+
align-items: center;
311+
justify-content: center;
312+
transition: box-shadow var(--transition), opacity var(--transition);
313+
}
314+
.topbar-avatar:hover {
315+
opacity: 0.85;
316+
}
317+
.avatar-dropdown {
318+
display: none;
319+
position: absolute;
320+
top: calc(100% + 8px);
321+
right: 0;
322+
width: 200px;
323+
background: var(--bg-secondary);
324+
border: 1px solid var(--border-light);
325+
border-radius: var(--radius);
326+
box-shadow: var(--shadow-card-hover);
327+
z-index: 200;
328+
overflow: hidden;
329+
}
330+
.avatar-dropdown.open { display: block; }
331+
.avatar-dropdown-header {
332+
padding: 12px 14px;
333+
display: flex;
334+
align-items: center;
335+
gap: 8px;
336+
}
337+
.avatar-dropdown-name {
338+
font-weight: 600;
339+
font-size: 0.85rem;
340+
color: var(--text-primary);
341+
}
342+
.avatar-dropdown-divider {
343+
height: 1px;
344+
background: var(--border-color);
345+
}
346+
.avatar-dropdown-item {
347+
display: flex;
348+
align-items: center;
349+
gap: 10px;
350+
width: 100%;
351+
padding: 10px 14px;
352+
font-size: 0.82rem;
353+
color: var(--text-secondary);
354+
background: none;
355+
border: none;
356+
cursor: pointer;
357+
text-decoration: none;
358+
transition: background var(--transition), color var(--transition);
359+
}
360+
.avatar-dropdown-item:hover {
361+
background: var(--bg-hover);
362+
color: var(--text-primary);
363+
}
364+
.avatar-dropdown-logout:hover {
365+
color: var(--error);
366+
}
316367

317368
/* Notification bell */
318369
.topbar-notifications {
@@ -1501,15 +1552,6 @@ img { max-width: 100%; }
15011552
display: flex;
15021553
}
15031554

1504-
.topbar-actions {
1505-
display: none;
1506-
}
1507-
.topbar-divider {
1508-
display: none;
1509-
}
1510-
.topbar-user {
1511-
display: none;
1512-
}
15131555
.topbar-currency-select {
15141556
display: none;
15151557
}

app/static/js/app.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1566,11 +1566,36 @@ const CP = (() => {
15661566
function initThemeToggle() {
15671567
const btn = document.getElementById('theme-toggle');
15681568
if (!btn) return;
1569-
btn.addEventListener('click', () => {
1569+
function updateLabel() {
1570+
const label = btn.querySelector('.theme-label');
1571+
if (label) {
1572+
const current = document.documentElement.getAttribute('data-theme') || 'dark';
1573+
label.textContent = current === 'dark' ? 'Light mode' : 'Dark mode';
1574+
}
1575+
}
1576+
btn.addEventListener('click', (e) => {
1577+
e.stopPropagation();
15701578
const current = document.documentElement.getAttribute('data-theme') || 'dark';
15711579
const next = current === 'dark' ? 'light' : 'dark';
15721580
document.documentElement.setAttribute('data-theme', next);
15731581
localStorage.setItem('cp-theme', next);
1582+
updateLabel();
1583+
});
1584+
updateLabel();
1585+
}
1586+
1587+
function initAvatarDropdown() {
1588+
const toggle = document.getElementById('avatar-toggle');
1589+
const dropdown = document.getElementById('avatar-dropdown');
1590+
if (!toggle || !dropdown) return;
1591+
toggle.addEventListener('click', (e) => {
1592+
e.stopPropagation();
1593+
dropdown.classList.toggle('open');
1594+
});
1595+
document.addEventListener('click', (e) => {
1596+
if (!dropdown.contains(e.target) && e.target !== toggle) {
1597+
dropdown.classList.remove('open');
1598+
}
15741599
});
15751600
}
15761601

@@ -1619,6 +1644,7 @@ const CP = (() => {
16191644
initSidebar();
16201645
initThemeToggle();
16211646
initNotifications();
1647+
initAvatarDropdown();
16221648

16231649
// Detect or restore display currency preference
16241650
_displayCurrency = localStorage.getItem('cp-display-currency') || detectDefaultCurrency();

app/templates/base.html

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,15 @@
7676
</a>
7777
</nav>
7878
<div class="sidebar-footer">
79-
CashPilot v0.1
79+
<div class="sidebar-footer-links">
80+
<a href="https://github.com/GeiserX/CashPilot" target="_blank" rel="noopener" title="GitHub">
81+
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
82+
</a>
83+
<a href="https://github.com/sponsors/GeiserX" target="_blank" rel="noopener" title="Sponsor" class="sidebar-sponsor-link">
84+
<svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor"><path d="M4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.6 20.6 0 008 13.393a20.6 20.6 0 003.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.749.749 0 01-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5z"/></svg>
85+
</a>
86+
</div>
87+
<span class="sidebar-footer-version">CashPilot v0.2</span>
8088
</div>
8189
</aside>
8290

@@ -97,48 +105,38 @@
97105
<span id="topbar-total">--</span>
98106
<select id="topbar-currency" class="topbar-currency-select" title="Display currency"></select>
99107
</div>
100-
<div class="topbar-actions">
101-
<div class="topbar-notifications" id="topbar-notifications">
102-
<button class="topbar-icon-btn topbar-notify-btn" id="notify-toggle" title="Collector alerts" aria-label="Collector alerts">
103-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
104-
<path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/>
105-
</svg>
106-
<span class="notify-badge" id="notify-badge" style="display:none;">0</span>
107-
</button>
108-
<div class="notify-dropdown" id="notify-dropdown">
109-
<div class="notify-header">Collector Alerts</div>
110-
<div class="notify-list" id="notify-list"></div>
111-
</div>
112-
</div>
113-
<button class="topbar-icon-btn" id="theme-toggle" title="Toggle theme" aria-label="Toggle theme">
114-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-sun">
115-
<circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
116-
</svg>
117-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-moon">
118-
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/>
108+
<div class="topbar-notifications" id="topbar-notifications">
109+
<button class="topbar-icon-btn topbar-notify-btn" id="notify-toggle" title="Collector alerts" aria-label="Collector alerts">
110+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
111+
<path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/>
119112
</svg>
113+
<span class="notify-badge" id="notify-badge" style="display:none;">0</span>
120114
</button>
121-
<a href="https://github.com/GeiserX/CashPilot" target="_blank" rel="noopener" class="topbar-icon-btn" title="GitHub">
122-
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
123-
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
124-
</svg>
125-
</a>
126-
<a href="https://github.com/sponsors/GeiserX" target="_blank" rel="noopener" class="topbar-icon-btn topbar-sponsor" title="Sponsor">
127-
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
128-
<path d="M4.25 2.5c-1.336 0-2.75 1.164-2.75 3 0 2.15 1.58 4.144 3.365 5.682A20.6 20.6 0 008 13.393a20.6 20.6 0 003.135-2.211C12.92 9.644 14.5 7.65 14.5 5.5c0-1.836-1.414-3-2.75-3-1.373 0-2.609.986-3.029 2.456a.749.749 0 01-1.442 0C6.859 3.486 5.623 2.5 4.25 2.5z"/>
129-
</svg>
130-
</a>
115+
<div class="notify-dropdown" id="notify-dropdown">
116+
<div class="notify-header">Collector Alerts</div>
117+
<div class="notify-list" id="notify-list"></div>
118+
</div>
131119
</div>
132120
{% if user %}
133-
<div class="topbar-divider"></div>
134-
<div class="topbar-user">
135-
<span class="topbar-username">{{ user.u }}</span>
136-
<span class="topbar-role badge badge-{{ user.r }}">{{ user.r }}</span>
137-
<a href="/logout" class="topbar-logout" title="Sign out">
138-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
139-
<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/>
140-
</svg>
141-
</a>
121+
<div class="topbar-avatar-wrap" id="avatar-wrap">
122+
<button class="topbar-avatar" id="avatar-toggle" aria-label="User menu">{{ user.u[0] | upper }}</button>
123+
<div class="avatar-dropdown" id="avatar-dropdown">
124+
<div class="avatar-dropdown-header">
125+
<span class="avatar-dropdown-name">{{ user.u }}</span>
126+
<span class="topbar-role badge badge-{{ user.r }}">{{ user.r }}</span>
127+
</div>
128+
<div class="avatar-dropdown-divider"></div>
129+
<button class="avatar-dropdown-item" id="theme-toggle">
130+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-sun"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
131+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-moon"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
132+
<span class="theme-label">Light mode</span>
133+
</button>
134+
<div class="avatar-dropdown-divider"></div>
135+
<a href="/logout" class="avatar-dropdown-item avatar-dropdown-logout">
136+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
137+
Sign out
138+
</a>
139+
</div>
142140
</div>
143141
{% endif %}
144142
</div>

0 commit comments

Comments
 (0)