Skip to content

Commit d071eb7

Browse files
committed
sticky header on second table
1 parent 964e77e commit d071eb7

File tree

2 files changed

+272
-2
lines changed

2 files changed

+272
-2
lines changed

index.html

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,110 @@
225225
.dark .hover\:bg-gray-600:hover {
226226
background-color: #4b5563;
227227
}
228+
229+
/* Sticky header styles */
230+
#stickyHeader {
231+
transition: opacity 0.2s ease-in-out;
232+
}
233+
234+
#stickyHeader.hidden {
235+
opacity: 0;
236+
pointer-events: none;
237+
}
238+
239+
/* Ensure the sticky header table has the same styling as the original */
240+
#stickyHeader table {
241+
min-width: 800px;
242+
}
243+
244+
@media (max-width: 768px) {
245+
#stickyHeader table {
246+
min-width: 600px;
247+
}
248+
}
249+
250+
/* Add some top padding to the main content when sticky header is visible */
251+
body.sticky-header-active {
252+
padding-top: 60px; /* Adjust based on your header height */
253+
}
254+
255+
/* Enhanced table container styles for horizontal scrolling */
256+
.table-container {
257+
overflow-x: auto;
258+
-webkit-overflow-scrolling: touch;
259+
position: relative;
260+
}
261+
262+
.table-container table {
263+
min-width: 800px;
264+
width: 100%;
265+
}
266+
267+
@media (max-width: 768px) {
268+
.table-container table {
269+
min-width: 600px;
270+
}
271+
}
272+
273+
/* Sticky header styles */
274+
#stickyHeader {
275+
transition: opacity 0.2s ease-in-out;
276+
}
277+
278+
#stickyHeader.hidden {
279+
opacity: 0;
280+
pointer-events: none;
281+
}
282+
283+
/* Ensure the sticky header table has the same styling as the original */
284+
#stickyHeader .table-container {
285+
overflow-x: auto;
286+
-webkit-overflow-scrolling: touch;
287+
}
288+
289+
#stickyHeader table {
290+
min-width: 800px;
291+
width: 100%;
292+
}
293+
294+
@media (max-width: 768px) {
295+
#stickyHeader table {
296+
min-width: 600px;
297+
}
298+
}
299+
300+
/* Hide scrollbars on the sticky header for cleaner look */
301+
#stickyHeader .table-container::-webkit-scrollbar {
302+
display: none;
303+
}
304+
305+
#stickyHeader .table-container {
306+
-ms-overflow-style: none;
307+
scrollbar-width: none;
308+
}
309+
310+
/* Ensure both containers have the same scroll behavior */
311+
.table-container {
312+
scrollbar-width: thin;
313+
scrollbar-color: #cbd5e0 transparent;
314+
}
315+
316+
.table-container::-webkit-scrollbar {
317+
height: 8px;
318+
}
319+
320+
.table-container::-webkit-scrollbar-track {
321+
background: transparent;
322+
}
323+
324+
.table-container::-webkit-scrollbar-thumb {
325+
background-color: #cbd5e0;
326+
border-radius: 4px;
327+
}
328+
329+
.dark .table-container::-webkit-scrollbar-thumb {
330+
background-color: #4b5563;
331+
}
228332
</style>
229333
</head>
230334
<body class="bg-gray-50 dark:bg-gray-900 min-h-screen">
@@ -345,15 +449,15 @@ <h2 class="text-xl font-bold border-l-4 border-black dark:border-gray-400 pl-4 m
345449
</div>
346450
</div>
347451

348-
<!-- Per-Test Results Table -->
452+
<!-- Update the per-test table section -->
349453
<div id="perTestResults">
350454
<h2 class="text-xl font-bold border-l-4 border-black dark:border-gray-400 pl-4 mb-2 text-gray-900 dark:text-white">
351455
Per-test result of latest run
352456
</h2>
353457
<p class="text-sm text-gray-600 dark:text-gray-400 mb-6 pl-4">
354458
( ✅ success ; ❌ error ; ➖ skipped )
355459
</p>
356-
<div class="table-container">
460+
<div class="table-container" id="perTestTableContainer">
357461
<table id="perTestTable" class="w-full border-collapse bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-lg">
358462
<thead id="perTestTableHead">
359463
<!-- Headers will be populated by JavaScript -->
@@ -364,6 +468,19 @@ <h2 class="text-xl font-bold border-l-4 border-black dark:border-gray-400 pl-4 m
364468
</table>
365469
</div>
366470
</div>
471+
472+
<!-- Update the sticky header -->
473+
<div id="stickyHeader" class="fixed top-0 left-0 right-0 z-50 hidden bg-white dark:bg-gray-800 shadow-lg border-b border-gray-200 dark:border-gray-700">
474+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
475+
<div class="table-container" id="stickyTableContainer">
476+
<table class="w-full border-collapse bg-white dark:bg-gray-800">
477+
<thead id="stickyTableHead">
478+
<!-- Will be populated by JavaScript -->
479+
</thead>
480+
</table>
481+
</div>
482+
</div>
483+
</div>
367484
</main>
368485

369486
<!-- Resources Section -->

script.js

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ document.addEventListener('DOMContentLoaded', function() {
2626
// Initialize theme first
2727
initializeTheme();
2828
initializeVersionSelector();
29+
initializeStickyHeader(); // Add this line
2930
loadTestResults();
3031
});
3132

@@ -413,6 +414,151 @@ function renderOverallTable(bundlersNames, latestResults) {
413414
});
414415
}
415416

417+
// Sticky header management
418+
let stickyHeader = null;
419+
let perTestTable = null;
420+
let perTestTableHead = null;
421+
let stickyTableHead = null;
422+
let perTestTableContainer = null;
423+
let stickyTableContainer = null;
424+
let isStickyHeaderVisible = false;
425+
let isScrolling = false; // Prevent infinite scroll loops
426+
427+
function initializeStickyHeader() {
428+
stickyHeader = document.getElementById('stickyHeader');
429+
perTestTable = document.getElementById('perTestTable');
430+
perTestTableHead = document.getElementById('perTestTableHead');
431+
stickyTableHead = document.getElementById('stickyTableHead');
432+
perTestTableContainer = document.getElementById('perTestTableContainer');
433+
stickyTableContainer = document.getElementById('stickyTableContainer');
434+
435+
if (!stickyHeader || !perTestTable || !perTestTableHead || !stickyTableHead || !perTestTableContainer || !stickyTableContainer) {
436+
console.warn('Sticky header elements not found');
437+
return;
438+
}
439+
440+
// Add scroll event listeners
441+
window.addEventListener('scroll', handleVerticalScroll);
442+
perTestTableContainer.addEventListener('scroll', handleHorizontalScroll);
443+
stickyTableContainer.addEventListener('scroll', handleStickyHorizontalScroll);
444+
445+
// Add resize event listener to update column widths
446+
window.addEventListener('resize', updateStickyHeaderWidths);
447+
}
448+
449+
function handleVerticalScroll() {
450+
if (!perTestTable || !stickyHeader) return;
451+
452+
const tableRect = perTestTable.getBoundingClientRect();
453+
const tableTop = tableRect.top;
454+
const tableBottom = tableRect.bottom;
455+
const headerHeight = perTestTableHead.offsetHeight;
456+
457+
// Show sticky header when original header is out of view
458+
if (tableTop < 0 && tableBottom > headerHeight) {
459+
if (!isStickyHeaderVisible) {
460+
showStickyHeader();
461+
}
462+
} else {
463+
if (isStickyHeaderVisible) {
464+
hideStickyHeader();
465+
}
466+
}
467+
}
468+
469+
function handleHorizontalScroll() {
470+
if (!stickyTableContainer || isScrolling) return;
471+
472+
isScrolling = true;
473+
stickyTableContainer.scrollLeft = perTestTableContainer.scrollLeft;
474+
475+
// Reset the flag after a short delay
476+
setTimeout(() => {
477+
isScrolling = false;
478+
}, 10);
479+
}
480+
481+
function handleStickyHorizontalScroll() {
482+
if (!perTestTableContainer || isScrolling) return;
483+
484+
isScrolling = true;
485+
perTestTableContainer.scrollLeft = stickyTableContainer.scrollLeft;
486+
487+
// Reset the flag after a short delay
488+
setTimeout(() => {
489+
isScrolling = false;
490+
}, 10);
491+
}
492+
493+
function showStickyHeader() {
494+
if (!stickyHeader) return;
495+
496+
stickyHeader.classList.remove('hidden');
497+
isStickyHeaderVisible = true;
498+
499+
// Update column widths to match the original table
500+
updateStickyHeaderWidths();
501+
502+
// Sync the horizontal scroll position
503+
if (perTestTableContainer && stickyTableContainer) {
504+
stickyTableContainer.scrollLeft = perTestTableContainer.scrollLeft;
505+
}
506+
}
507+
508+
function hideStickyHeader() {
509+
if (!stickyHeader) return;
510+
511+
stickyHeader.classList.add('hidden');
512+
isStickyHeaderVisible = false;
513+
}
514+
515+
function updateStickyHeaderWidths() {
516+
if (!perTestTableHead || !stickyTableHead) return;
517+
518+
// Copy the header structure from the original table
519+
stickyTableHead.innerHTML = perTestTableHead.innerHTML;
520+
521+
// Get all header cells from both tables
522+
const originalHeaders = perTestTableHead.querySelectorAll('th');
523+
const stickyHeaders = stickyTableHead.querySelectorAll('th');
524+
525+
// Match the widths of each column
526+
for (let i = 0; i < originalHeaders.length; i++) {
527+
if (stickyHeaders[i]) {
528+
const originalWidth = originalHeaders[i].offsetWidth;
529+
stickyHeaders[i].style.width = `${originalWidth}px`;
530+
stickyHeaders[i].style.minWidth = `${originalWidth}px`;
531+
}
532+
}
533+
534+
// Ensure both containers have the same scroll width
535+
if (perTestTableContainer && stickyTableContainer) {
536+
stickyTableContainer.style.width = `${perTestTableContainer.offsetWidth}px`;
537+
}
538+
}
539+
540+
// Add this to the existing functions for better performance
541+
function debounce(func, wait) {
542+
let timeout;
543+
return function executedFunction(...args) {
544+
const later = () => {
545+
clearTimeout(timeout);
546+
func(...args);
547+
};
548+
clearTimeout(timeout);
549+
timeout = setTimeout(later, wait);
550+
};
551+
}
552+
553+
// Use debounced scroll handlers for better performance
554+
const debouncedHandleHorizontalScroll = debounce(handleHorizontalScroll, 5);
555+
const debouncedHandleStickyHorizontalScroll = debounce(handleStickyHorizontalScroll, 5);
556+
557+
// Update the event listeners
558+
perTestTableContainer.addEventListener('scroll', debouncedHandleHorizontalScroll);
559+
stickyTableContainer.addEventListener('scroll', debouncedHandleStickyHorizontalScroll);
560+
561+
// Modify the existing renderPerTestTable function to also update sticky header
416562
function renderPerTestTable(bundlersNames, bundlersPerTestResults) {
417563
const tableHead = document.getElementById('perTestTableHead');
418564
const tableBody = document.getElementById('perTestTableBody');
@@ -468,6 +614,13 @@ function renderPerTestTable(bundlersNames, bundlersPerTestResults) {
468614

469615
tableBody.appendChild(row);
470616
});
617+
618+
// Update sticky header after a short delay to ensure table is rendered
619+
setTimeout(() => {
620+
if (isStickyHeaderVisible) {
621+
updateStickyHeaderWidths();
622+
}
623+
}, 100);
471624
}
472625

473626
function getTestResultDisplayEmoji(result) {

0 commit comments

Comments
 (0)