@@ -15,6 +15,11 @@ class WPTHeader extends WPTFlags(PolymerElement) {
15
15
static get template ( ) {
16
16
return html `
17
17
< style >
18
+ : host {
19
+ dis play: block;
20
+ position: relative;
21
+ background: # fff;
22
+ }
18
23
* {
19
24
margin : 0 ;
20
25
padding : 0 ;
@@ -42,57 +47,167 @@ class WPTHeader extends WPTFlags(PolymerElement) {
42
47
header > div {
43
48
align-items : center;
44
49
display : flex;
50
+ }
51
+ header nav a {
52
+ margin-right : 1em ;
53
+ }
54
+ # title-area {
45
55
justify-content : space-between;
46
56
}
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
+ }
47
103
header nav a {
48
104
margin-right : 1em ;
49
105
}
50
106
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 */
52
122
@media (max-width : 768px ) {
53
- header {
54
- padding : 1em ;
55
- }
56
123
header h1 {
57
- font-size : 1 em ; /* Slightly adjusted for balance */
124
+ margin-bottom : 0 ;
58
125
}
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;
64
128
}
65
- nav {
129
+ # mobile-navigation {
130
+ z-index : 2 ;
131
+ }
132
+ .desktop-title {
133
+ display : none;
134
+ }
135
+ .mobile-title {
66
136
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 ;
71
137
}
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% ;
75
167
text-align : center;
76
- border-bottom : 1px solid # f0f0f0 ;
168
+ padding : 0.5em 0 ;
169
+ margin : 0 ;
77
170
}
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 */
80
181
}
81
- img {
82
- vertical-align : middle;
182
+
183
+ # mobile-navigation {
184
+ display : none;
83
185
}
84
186
}
85
187
</ style >
86
188
< header >
87
- < div >
189
+ < div id ="title-area ">
190
+ < div class ="logo-area ">
88
191
< h1 >
89
192
< 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 >
95
196
</ 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 >
96
211
97
212
< nav >
98
213
<!-- TODO: handle onclick with wpt-results.navigate if available -->
@@ -105,6 +220,20 @@ class WPTHeader extends WPTFlags(PolymerElement) {
105
220
</ template >
106
221
< a href ="/about "> About</ a >
107
222
</ 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 "> ✨Interop 2025✨</ 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 >
108
237
</ header >
109
238
` ;
110
239
}
@@ -126,8 +255,47 @@ class WPTHeader extends WPTFlags(PolymerElement) {
126
255
user : String ,
127
256
isTriageMode : {
128
257
type : Boolean ,
258
+ } ,
259
+ // New property to manage the menu's open/closed state
260
+ _isMenuOpen : {
261
+ type : Boolean ,
262
+ value : false ,
129
263
}
130
264
} ;
131
265
}
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
+ }
132
300
}
133
301
window . customElements . define ( WPTHeader . is , WPTHeader ) ;
0 commit comments