Skip to content

Commit d13816b

Browse files
yepzdkclaude
andcommitted
feat: replace collapsible sidebar with mobile hamburger nav
The collapsible sidebar had usability issues. Replace it with a mobile-friendly approach: on desktop the sidebar is always visible, on mobile (<768px) it is hidden behind a hamburger menu in a top bar. Tapping a nav item or the overlay automatically closes the sidebar. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 84f66b9 commit d13816b

1 file changed

Lines changed: 153 additions & 87 deletions

File tree

docs/projects/salary-negotiation/mocks/salary-negotiation.html

Lines changed: 153 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -48,86 +48,9 @@
4848
display: flex;
4949
flex-direction: column;
5050
height: 100%;
51-
transition: width 0.2s, min-width 0.2s;
5251
overflow: hidden;
5352
}
5453

55-
.sidebar.collapsed {
56-
width: 56px;
57-
min-width: 56px;
58-
}
59-
60-
.sidebar.collapsed .sidebar-logo span,
61-
.sidebar.collapsed .sidebar-year label,
62-
.sidebar.collapsed .sidebar-year select,
63-
.sidebar.collapsed .sidebar-section-label,
64-
.sidebar.collapsed .nav-item span:not(.nav-icon),
65-
.sidebar.collapsed .sidebar-user .user-info {
66-
display: none;
67-
}
68-
69-
.sidebar.collapsed .sidebar-logo {
70-
justify-content: center;
71-
padding: 20px 0 16px;
72-
}
73-
74-
.sidebar.collapsed .sidebar-year {
75-
display: none;
76-
}
77-
78-
.sidebar.collapsed .nav-item {
79-
justify-content: center;
80-
padding: 10px 0;
81-
border-left: none;
82-
}
83-
84-
.sidebar.collapsed .nav-item.active {
85-
border-left: none;
86-
border-right: 3px solid #16a34a;
87-
}
88-
89-
.sidebar.collapsed .sidebar-user {
90-
justify-content: center;
91-
padding: 16px 0;
92-
}
93-
94-
.sidebar-toggle {
95-
position: absolute;
96-
bottom: 70px;
97-
left: 220px;
98-
width: 24px;
99-
height: 24px;
100-
background: #fff;
101-
border: 1px solid #e0e0e0;
102-
border-radius: 50%;
103-
cursor: pointer;
104-
display: flex;
105-
align-items: center;
106-
justify-content: center;
107-
z-index: 10;
108-
transition: left 0.2s;
109-
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
110-
}
111-
112-
.sidebar-toggle svg {
113-
width: 14px;
114-
height: 14px;
115-
stroke: #888;
116-
stroke-width: 2;
117-
fill: none;
118-
stroke-linecap: round;
119-
stroke-linejoin: round;
120-
transition: transform 0.2s;
121-
}
122-
123-
.sidebar.collapsed ~ .sidebar-toggle {
124-
left: 36px;
125-
}
126-
127-
.sidebar.collapsed ~ .sidebar-toggle svg {
128-
transform: rotate(180deg);
129-
}
130-
13154
.sidebar-logo {
13255
padding: 20px 20px 16px;
13356
font-size: 18px;
@@ -780,10 +703,125 @@
780703
font-size: 13px;
781704
}
782705

783-
/* Responsive */
784-
@media (max-width: 900px) {
785-
.summary-cards { grid-template-columns: repeat(2, 1fr); }
786-
.sidebar { width: 200px; min-width: 200px; }
706+
/* ========== MOBILE TOPBAR ========== */
707+
.mobile-topbar {
708+
display: none;
709+
}
710+
711+
.sidebar-overlay {
712+
display: none;
713+
}
714+
715+
/* ========== RESPONSIVE ========== */
716+
@media (max-width: 768px) {
717+
.mobile-topbar {
718+
display: flex;
719+
align-items: center;
720+
justify-content: space-between;
721+
position: fixed;
722+
top: 32px; /* below mock banner */
723+
left: 0;
724+
right: 0;
725+
height: 48px;
726+
padding: 0 16px;
727+
background: #fff;
728+
border-bottom: 1px solid #e8e8e8;
729+
z-index: 90;
730+
}
731+
732+
.hamburger-btn {
733+
width: 36px;
734+
height: 36px;
735+
border: none;
736+
background: none;
737+
cursor: pointer;
738+
display: flex;
739+
align-items: center;
740+
justify-content: center;
741+
border-radius: 4px;
742+
transition: background 0.15s;
743+
}
744+
745+
.hamburger-btn:hover {
746+
background: #f0f0f0;
747+
}
748+
749+
.hamburger-btn svg {
750+
width: 22px;
751+
height: 22px;
752+
stroke: #333;
753+
stroke-width: 2;
754+
fill: none;
755+
stroke-linecap: round;
756+
stroke-linejoin: round;
757+
}
758+
759+
.mobile-topbar-title {
760+
font-size: 16px;
761+
font-weight: 700;
762+
color: #1a1a1a;
763+
}
764+
765+
.mobile-topbar-avatar {
766+
width: 32px;
767+
height: 32px;
768+
border-radius: 50%;
769+
background: #e8e8e8;
770+
display: flex;
771+
align-items: center;
772+
justify-content: center;
773+
font-size: 12px;
774+
font-weight: 600;
775+
color: #666;
776+
}
777+
778+
.app-layout {
779+
padding-top: 80px; /* mock banner 32px + topbar 48px */
780+
}
781+
782+
.sidebar {
783+
position: fixed;
784+
top: 0;
785+
left: 0;
786+
bottom: 0;
787+
z-index: 200;
788+
transform: translateX(-100%);
789+
transition: transform 0.25s ease;
790+
box-shadow: none;
791+
}
792+
793+
.sidebar.open {
794+
transform: translateX(0);
795+
box-shadow: 4px 0 16px rgba(0,0,0,0.12);
796+
}
797+
798+
.sidebar-overlay {
799+
display: block;
800+
position: fixed;
801+
inset: 0;
802+
background: rgba(0,0,0,0.3);
803+
z-index: 150;
804+
opacity: 0;
805+
visibility: hidden;
806+
transition: opacity 0.25s ease, visibility 0.25s ease;
807+
}
808+
809+
.sidebar-overlay.open {
810+
opacity: 1;
811+
visibility: visible;
812+
}
813+
814+
.summary-cards {
815+
grid-template-columns: repeat(2, 1fr);
816+
}
817+
818+
.main-body {
819+
padding: 16px;
820+
}
821+
822+
.main-header {
823+
padding: 16px;
824+
}
787825
}
788826

789827
/* ========== EXPANDABLE HISTORY ROW ========== */
@@ -930,10 +968,19 @@
930968
<strong>MOCK</strong> — Lønforhandlingssystem for Aarhus Kommune (interaktiv prototype)
931969
</div>
932970

971+
<header class="mobile-topbar">
972+
<button class="hamburger-btn" id="hamburger-btn" aria-label="Åbn menu">
973+
<svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
974+
</button>
975+
<span class="mobile-topbar-title">Lønforhandling</span>
976+
<div class="mobile-topbar-avatar">MH</div>
977+
</header>
978+
933979
<div class="app-layout">
934980

935981
<!-- ========== SIDEBAR ========== -->
936982
<aside class="sidebar">
983+
937984
<div class="sidebar-logo">
938985
<div class="logo-icon">L</div>
939986
Lønforhandling
@@ -971,9 +1018,7 @@
9711018
</div>
9721019
</aside>
9731020

974-
<button class="sidebar-toggle" id="sidebar-toggle" title="Skjul/vis sidemenu">
975-
<svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
976-
</button>
1021+
<div class="sidebar-overlay" id="sidebar-overlay"></div>
9771022

9781023
<!-- ========== MAIN ========== -->
9791024
<main class="main-content">
@@ -1648,9 +1693,30 @@ <h3>Begrundelse</h3>
16481693
if (e.key === 'Enter' && e.ctrlKey && modalOverlay.classList.contains('open')) saveReason();
16491694
});
16501695

1651-
// ========== SIDEBAR TOGGLE ==========
1652-
document.getElementById('sidebar-toggle').addEventListener('click', () => {
1653-
document.querySelector('.sidebar').classList.toggle('collapsed');
1696+
// ========== MOBILE HAMBURGER NAV ==========
1697+
const sidebar = document.querySelector('.sidebar');
1698+
const overlay = document.getElementById('sidebar-overlay');
1699+
const hamburgerBtn = document.getElementById('hamburger-btn');
1700+
1701+
function openSidebar() {
1702+
sidebar.classList.add('open');
1703+
overlay.classList.add('open');
1704+
}
1705+
1706+
function closeSidebar() {
1707+
sidebar.classList.remove('open');
1708+
overlay.classList.remove('open');
1709+
}
1710+
1711+
hamburgerBtn.addEventListener('click', () => {
1712+
sidebar.classList.contains('open') ? closeSidebar() : openSidebar();
1713+
});
1714+
1715+
overlay.addEventListener('click', closeSidebar);
1716+
1717+
// Close sidebar on mobile when a nav item is clicked
1718+
navItems.forEach(item => {
1719+
item.addEventListener('click', closeSidebar);
16541720
});
16551721

16561722
// ========== INIT ==========

0 commit comments

Comments
 (0)