fix WCAG accessibility improvements and unified chevron style

Accessibility fixes: - Use <main> landmark element instead of <div id="main"> - Add lang="en" to error page <html> element - Fix .tree-hidden opacity from 0.6 to 0.75 for text contrast - Fix disabled pagination button contrast (#555 -> #777) - Make nav-toggle checkbox focusable for keyboard users Style unification: - Section toggles (Favorites, Repositories, Archived) now use the same tree-chevron circle indicator as directory toggles - Sticky headings apply on all viewport sizes

Commit
5e674124383627408883516661368ac833b636f3
Author
Marius Peter <dev@marius-peter.com>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/static/styles.css
index ec9487fa..d6717058 100644..100644
@@ -114,9 +114,10 @@
114 114 .nav-toggle {
115 115 position: absolute;
116 116 opacity: 0;
117 Removed: width: 0;
118 Removed: height: 0;
119 Removed: pointer-events: none;
117 Added: width: 1px;
118 Added: height: 1px;
119 Added: overflow: hidden;
120 Added: clip: rect(0, 0, 0, 0);
120 121 }
121 122
122 123 .nav-hamburger {
@@ -198,31 +199,31 @@
198 199 text-decoration: none;
199 200 }
200 201
201 Removed: div#main {
202 Added: #main {
202 203 padding: 0 1em;
203 204 }
204 205
205 Removed: div#main ul {
206 Added: #main ul {
206 207 padding-left: 0;
207 208 list-style: none;
208 209 }
209 210
210 Removed: div#main ul li {
211 Added: #main ul li {
211 212 border: 1px solid #303030;
212 213 }
213 214
214 Removed: div#main .tree-nested li {
215 Added: #main .tree-nested li {
215 216 border: none;
216 217 border-top: 1px solid #252525;
217 218 }
218 219
219 Removed: div#main .tree-nested li:first-child {
220 Added: #main .tree-nested li:first-child {
220 221 border-top: none;
221 222 }
222 223
223 224 /* File/branch/tag list items (still use li > a wrapping pattern) */
224 225
225 Removed: div#main ul li > a {
226 Added: #main ul li > a {
226 227 display: flex;
227 228 align-items: center;
228 229 gap: 1em;
@@ -231,11 +232,11 @@
231 232 box-sizing: border-box;
232 233 }
233 234
234 Removed: div#main ul li > a:hover {
235 Added: #main ul li > a:hover {
235 236 text-decoration: underline;
236 237 }
237 238
238 Removed: div#main ul li:has(> a:hover) {
239 Added: #main ul li:has(> a:hover) {
239 240 background-color: #252525;
240 241 }
241 242
@@ -262,6 +263,13 @@
262 263 cursor: pointer;
263 264 list-style: none;
264 265 user-select: none;
266 Added: position: sticky;
267 Added: top: var(--nav-height);
268 Added: background-color: #1a1a1a;
269 Added: z-index: 5;
270 Added: padding: 0.5em 0;
271 Added: display: flex;
272 Added: align-items: center;
265 273 }
266 274
267 275 .section-toggle::-webkit-details-marker {
@@ -270,29 +278,19 @@
270 278
271 279 .section-toggle h3 {
272 280 display: inline;
281 Added: font-size: 1.25em;
282 Added: letter-spacing: 0.02em;
283 Added: font-weight: 700;
273 284 }
274 285
275 Removed: .section-toggle::before {
276 Removed: content: "\25be";
277 Removed: display: inline-block;
278 Removed: margin-right: 0.4em;
279 Removed: transition: transform 0.15s ease;
286 Added: details[open] > .section-toggle > .tree-chevron {
287 Added: transform: rotate(90deg);
280 288 }
281 289
282 290 details:not([open]) > .section-toggle::before {
283 291 transform: rotate(-90deg);
284 292 }
285 293
286 Removed: @media (min-width: 960px) {
287 Removed: .section-toggle {
288 Removed: position: sticky;
289 Removed: top: var(--nav-height);
290 Removed: background-color: #1a1a1a;
291 Removed: z-index: 5;
292 Removed: padding: 0.5em 0;
293 Removed: }
294 Removed: }
295 Removed:
296 294 /* Root page repository items */
297 295 #repositories li,
298 296 .repo-section li {
@@ -302,8 +300,8 @@
302 300 gap: 0 1em;
303 301 }
304 302
305 Removed: div#main #repositories li > a,
306 Removed: div#main .repo-section li > a {
303 Added: #main #repositories li > a,
304 Added: #main .repo-section li > a {
307 305 display: flex;
308 306 align-items: center;
309 307 flex: 1;
@@ -331,7 +329,7 @@
331 329
332 330 /* Commit list items — flat layout, commit-title anchor fills the li height */
333 331
334 Removed: div#main ul li:has(.commit-title) {
332 Added: #main ul li:has(.commit-title) {
335 333 display: flex;
336 334 align-items: center;
337 335 line-height: 1.5rem;
@@ -341,7 +339,7 @@
341 339 padding: 0 0.75em;
342 340 }
343 341
344 Removed: div#main ul li:has(.commit-title):hover {
342 Added: #main ul li:has(.commit-title):hover {
345 343 background-color: #252525;
346 344 }
347 345
@@ -614,13 +612,13 @@
614 612 }
615 613
616 614 .pagination-disabled {
617 Removed: color: #555;
615 Added: color: #777;
618 616 background-color: #1e1e1e;
619 617 cursor: default;
620 618 }
621 619
622 620 .pagination-disabled:hover {
623 Removed: color: #555;
621 Added: color: #777;
624 622 background-color: #1e1e1e;
625 623 }
626 624
@@ -821,7 +819,7 @@
821 819
822 820 .tree-hidden {
823 821 font-style: italic;
824 Removed: opacity: 0.6;
822 Added: opacity: 0.75;
825 823 }
826 824
827 825 .tree-overflow {
@@ -979,7 +977,7 @@
979 977 padding: 0.5em 0.5em;
980 978 }
981 979
982 Removed: div#main {
980 Added: #main {
983 981 padding: 0 0.5em;
984 982 }
985 983
lib/views/error.ml
index 7622444e..fc3191dc 100644..100644
@@ -26,7 +26,8 @@
26 26 let hint = hint_of_status status in
27 27 let open HTML in
28 28 respond ~status
29 Removed: @@ html []
29 Added: @@ html
30 Added: [ lang "en" ]
30 31 [
31 32 head []
32 33 [
@@ -45,7 +46,7 @@
45 46 span [ class_ "error-code" ] [ txt "%s" status_code ];
46 47 h1 [] [ txt "%s" page_title ];
47 48 ];
48 Removed: div
49 Added: HTML.main
49 50 [ id "main" ]
50 51 [
51 52 p [ class_ "error-hint" ] [ txt "%s" hint ];
lib/views/layout.ml
index 8a56215d..7f4faeb3 100644..100644
@@ -123,7 +123,7 @@
123 123 (match page_data.repo with
124 124 | None -> HTML.null []
125 125 | Some _ -> page_header ~has_repo:true page_data.title page_data.subtitle);
126 Removed: div [ id "main" ] page_data.content;
126 Added: HTML.main [ id "main" ] page_data.content;
127 127 page_footer user_name;
128 128 script []
129 129 {|document.addEventListener("DOMContentLoaded",function(){var b=document.getElementById("blob");if(!b||typeof hljs==="undefined")return;var cls=b.className.match(/language-([\w-]+)/);if(!cls)return;var lang=cls[1];b.querySelectorAll("span.line").forEach(function(el){var r=hljs.highlight(el.textContent,{language:lang,ignoreIllegals:true});el.innerHTML=r.value})});|};
lib/views/root.ml
index b2a1e8de..a36f2de0 100644..100644
@@ -72,7 +72,10 @@
72 72 [
73 73 summary
74 74 [ class_ "section-toggle" ]
75 Removed: [ h3 [] [ txt "Favorites" ] ];
75 Added: [
76 Added: span [ class_ "tree-chevron" ] [ txt "\xe2\x80\xba" ];
77 Added: h3 [] [ txt "Favorites" ];
78 Added: ];
76 79 repo_list favorites;
77 80 ];
78 81 ])
@@ -93,7 +96,10 @@
93 96 [
94 97 summary
95 98 [ class_ "section-toggle" ]
96 Removed: [ h3 [] [ txt "Repositories" ] ];
99 Added: [
100 Added: span [ class_ "tree-chevron" ] [ txt "\xe2\x80\xba" ];
101 Added: h3 [] [ txt "Repositories" ];
102 Added: ];
97 103 repo_list nodes;
98 104 ];
99 105 ]))
@@ -110,7 +116,10 @@
110 116 [
111 117 summary
112 118 [ class_ "section-toggle" ]
113 Removed: [ h3 [] [ txt "Archived" ] ];
119 Added: [
120 Added: span [ class_ "tree-chevron" ] [ txt "\xe2\x80\xba" ];
121 Added: h3 [] [ txt "Archived" ];
122 Added: ];
114 123 repo_list archived;
115 124 ];
116 125 ])