Skip to content

Commit 6c6316a

Browse files
author
DanielRyanSmith
committed
header has mobile functionality
1 parent 5d983d2 commit 6c6316a

File tree

1 file changed

+197
-29
lines changed

1 file changed

+197
-29
lines changed

webapp/components/wpt-header.js

Lines changed: 197 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ class WPTHeader extends WPTFlags(PolymerElement) {
1515
static get template() {
1616
return html`
1717
<style>
18+
:host {
19+
display: block;
20+
position: relative;
21+
background: #fff;
22+
}
1823
* {
1924
margin: 0;
2025
padding: 0;
@@ -42,57 +47,167 @@ class WPTHeader extends WPTFlags(PolymerElement) {
4247
header > div {
4348
align-items: center;
4449
display: flex;
50+
}
51+
header nav a {
52+
margin-right: 1em;
53+
}
54+
#title-area {
4555
justify-content: space-between;
4656
}
57+
.mobile-title {
58+
display: none; /* Shown on desktop via media query */
59+
}
60+
.logo-area > a {
61+
align-items: center;
62+
gap: 16px;
63+
}
64+
.logo-area img {
65+
height: 32px;
66+
width: 32px;
67+
vertical-align: middle;
68+
}
69+
.login-area {
70+
display: none; /* Shown on desktop via media query */
71+
}
72+
73+
.menu-button {
74+
display: none; /* Hidden on desktop */
75+
flex-direction: column;
76+
justify-content: space-around;
77+
width: 30px;
78+
height: 30px;
79+
background: transparent;
80+
border: none;
81+
cursor: pointer;
82+
padding: 0;
83+
z-index: 1001; /* Above the nav panel */
84+
}
85+
.menu-button span {
86+
display: block;
87+
width: 100%;
88+
height: 3px;
89+
background: #333;
90+
border-radius: 3px;
91+
transition: all 0.3s ease;
92+
}
93+
/* Hamburger to "X" animation */
94+
.menu-button.open span:nth-of-type(1) {
95+
transform: rotate(45deg) translate(7px, 7px);
96+
}
97+
.menu-button.open span:nth-of-type(2) {
98+
opacity: 0;
99+
}
100+
.menu-button.open span:nth-of-type(3) {
101+
transform: rotate(-45deg) translate(7px, -7px);
102+
}
47103
header nav a {
48104
margin-right: 1em;
49105
}
50106
51-
/* Media Query for Mobile Devices */
107+
/* Navigation Links */
108+
.nav-links {
109+
display: flex;
110+
align-items: center;
111+
gap: 1.5em;
112+
}
113+
.nav-links a {
114+
font-weight: 500;
115+
color: #555;
116+
}
117+
.nav-links a:last-of-type {
118+
margin-right: 0;
119+
}
120+
121+
/* Mobile Styles */
52122
@media (max-width: 768px) {
53-
header {
54-
padding: 1em;
55-
}
56123
header h1 {
57-
font-size: 1em; /* Slightly adjusted for balance */
124+
margin-bottom: 0;
58125
}
59-
header > div {
60-
flex-direction: column; /* Stack logo/title and login button */
61-
align-items: flex-start; /* Align items to the left */
62-
gap: 1em; /* Add space between the stacked items */
63-
margin-bottom: 1em;
126+
#desktop-login {
127+
display: none;
64128
}
65-
nav {
129+
#mobile-navigation {
130+
z-index: 2;
131+
}
132+
.desktop-title {
133+
display: none;
134+
}
135+
.mobile-title {
66136
display: flex;
67-
flex-direction: column; /* Stack nav links vertically */
68-
align-items: stretch; /* Stretch links to fill width */
69-
border-top: 1px solid #e0e0e0;
70-
padding-top: 0.5em;
71137
}
72-
nav a {
73-
margin-right: 0;
74-
padding: 0.25em;
138+
.menu-button {
139+
display: flex; /* Show button on mobile */
140+
}
141+
.nav-links {
142+
display: flex;
143+
flex-direction: column;
144+
align-items: center;
145+
justify-content: flex-start;
146+
gap: 1em;
147+
background: #fff;
148+
position: fixed;
149+
top: 0;
150+
right: 0;
151+
height: 100vh;
152+
width: 80%;
153+
max-width: 300px;
154+
padding-top: 6em;
155+
box-shadow: -2px 0 8px rgba(0,0,0,0.1);
156+
157+
/* Hidden by default, slides in */
158+
transform: translateX(100%);
159+
transition: transform 0.3s ease-in-out;
160+
}
161+
.nav-links.open {
162+
transform: translateX(0);
163+
}
164+
.nav-links a {
165+
font-size: 1.2em;
166+
width: 100%;
75167
text-align: center;
76-
border-bottom: 1px solid #f0f0f0;
168+
padding: 0.5em 0;
169+
margin: 0;
77170
}
78-
nav a:last-child {
79-
border-bottom: none;
171+
/* Hide the main nav container, but not the links inside the panel */
172+
nav {
173+
display: none;
174+
}
175+
}
176+
177+
/* Desktop Styles */
178+
@media (min-width: 769px) {
179+
.login-area {
180+
display: block; /* Show login on desktop */
80181
}
81-
img {
82-
vertical-align: middle;
182+
183+
#mobile-navigation {
184+
display: none;
83185
}
84186
}
85187
</style>
86188
<header>
87-
<div>
189+
<div id="title-area">
190+
<div class="logo-area">
88191
<h1>
89192
<img src="/static/logo.svg" alt="wpt.fyi logo">
90-
<a href="/">web-platform-tests dashboard</a>
91-
</h1>
92-
<template is="dom-if" if="[[githubLogin]]">
93-
<github-login user="[[user]]" is-triage-mode="[[isTriageMode]]"></github-login>
94-
</template>
193+
<a class=desktop-title href="/">web-platform-tests dashboard</a>
194+
<a class="mobile-title" href="/">WPT dashboard</a>
195+
<h1>
95196
</div>
197+
<template is="dom-if" if="[[githubLogin]]">
198+
<github-login user="[[user]]" is-triage-mode="[[isTriageMode]]"></github-login>
199+
</template>
200+
<button
201+
class$="[[_computeMenuButtonClass(_isMenuOpen)]]"
202+
on-click="_toggleMenu"
203+
aria-label$="[[_computeAriaLabel(_isMenuOpen)]]"
204+
aria-expanded$="[[_isMenuOpen]]"
205+
aria-controls="mobile-navigation">
206+
<span></span>
207+
<span></span>
208+
<span></span>
209+
</button>
210+
</div>
96211
97212
<nav>
98213
<!-- TODO: handle onclick with wpt-results.navigate if available -->
@@ -105,6 +220,20 @@ class WPTHeader extends WPTFlags(PolymerElement) {
105220
</template>
106221
<a href="/about">About</a>
107222
</nav>
223+
224+
<div id="mobile-navigation" class$="[[_computeNavLinksClass(_isMenuOpen)]]">
225+
<a href="/">Latest Run</a>
226+
<a href="/runs">Recent Runs</a>
227+
<a href="/interop">&#10024;Interop 2025&#10024;</a>
228+
<a href="/insights">Insights</a>
229+
<template is="dom-if" if="[[processorTab]]">
230+
<a href="/status">Processor</a>
231+
</template>
232+
<a href="/about">About</a>
233+
<template is="dom-if" if="[[githubLogin]]">
234+
<github-login user="[[user]]" is-triage-mode="[[isTriageMode]]"></github-login>
235+
</template>
236+
</div>
108237
</header>
109238
`;
110239
}
@@ -126,8 +255,47 @@ class WPTHeader extends WPTFlags(PolymerElement) {
126255
user: String,
127256
isTriageMode: {
128257
type: Boolean,
258+
},
259+
// New property to manage the menu's open/closed state
260+
_isMenuOpen: {
261+
type: Boolean,
262+
value: false,
129263
}
130264
};
131265
}
266+
267+
/**
268+
* Toggles the state of the mobile menu.
269+
*/
270+
_toggleMenu() {
271+
this._isMenuOpen = !this._isMenuOpen;
272+
}
273+
274+
/**
275+
* Computes the class string for the hamburger menu button.
276+
* @param {boolean} isOpen
277+
* @return {string}
278+
*/
279+
_computeMenuButtonClass(isOpen) {
280+
return isOpen ? 'menu-button open' : 'menu-button';
281+
}
282+
283+
/**
284+
* Computes the class string for the slide-out navigation panel.
285+
* @param {boolean} isOpen
286+
* @return {string}
287+
*/
288+
_computeNavLinksClass(isOpen) {
289+
return isOpen ? 'nav-links open' : 'nav-links';
290+
}
291+
292+
/**
293+
* Computes the ARIA label for accessibility based on the menu state.
294+
* @param {boolean} isOpen
295+
* @return {string}
296+
*/
297+
_computeAriaLabel(isOpen) {
298+
return isOpen ? 'Close navigation menu' : 'Open navigation menu';
299+
}
132300
}
133301
window.customElements.define(WPTHeader.is, WPTHeader);

0 commit comments

Comments
 (0)