|
735 | 735 | var opSlider = $('opacity-slider'), opVal = $('opacity-val'); |
736 | 736 | var swContainer = $('swipe-container'), swHandle = $('swipe-handle'), swClip = $('swipe-clip-box'); |
737 | 737 |
|
| 738 | + /* ── Filtered index list (kept in sync with search) ──────────────── */ |
| 739 | + var filtered = []; |
| 740 | + |
| 741 | + function rebuildFiltered() { |
| 742 | + var q = state.search.toLowerCase(); |
| 743 | + filtered = []; |
| 744 | + DATA.forEach(function(item, idx) { |
| 745 | + if (!q || item.name.toLowerCase().indexOf(q) !== -1) filtered.push(idx); |
| 746 | + }); |
| 747 | + /* If current item is no longer visible, jump to first match */ |
| 748 | + if (filtered.length && filtered.indexOf(state.current) === -1) { |
| 749 | + state.current = filtered[0]; |
| 750 | + } |
| 751 | + } |
| 752 | + |
738 | 753 | /* ── Sidebar ────────────────────────────────────────────────────────── */ |
739 | 754 | function buildSidebar() { |
740 | 755 | sidebarList.innerHTML = ''; |
741 | | - var q = state.search.toLowerCase(); |
742 | | - DATA.forEach(function(item, idx) { |
743 | | - if (q && item.name.toLowerCase().indexOf(q) === -1) return; |
| 756 | + filtered.forEach(function(idx) { |
| 757 | + var item = DATA[idx]; |
744 | 758 | var btn = document.createElement('button'); |
745 | 759 | btn.className = 'thumb-btn' + (idx === state.current ? ' active' : ''); |
746 | 760 | btn.setAttribute('title', item.name); |
|
764 | 778 |
|
765 | 779 | /* ── Selection ──────────────────────────────────────────────────────── */ |
766 | 780 | function selectItem(idx) { |
767 | | - if (!DATA.length) return; |
768 | | - idx = Math.max(0, Math.min(idx, DATA.length - 1)); |
| 781 | + if (!filtered.length) return; |
| 782 | + /* Clamp to filtered range */ |
| 783 | + var pos = filtered.indexOf(idx); |
| 784 | + if (pos === -1) { |
| 785 | + /* idx not in filtered list — find nearest */ |
| 786 | + pos = Math.max(0, Math.min(idx, filtered.length - 1)); |
| 787 | + idx = filtered[pos]; |
| 788 | + } |
769 | 789 | state.current = idx; |
770 | 790 | renderMain(); |
771 | 791 | buildSidebar(); |
772 | 792 | var active = sidebarList.querySelector('.thumb-btn.active'); |
773 | 793 | if (active) active.scrollIntoView({ block: 'nearest', inline: 'nearest' }); |
774 | 794 | } |
775 | 795 |
|
| 796 | + /* Navigate to next/prev within filtered list */ |
| 797 | + function selectNext() { |
| 798 | + var pos = filtered.indexOf(state.current); |
| 799 | + if (pos < filtered.length - 1) selectItem(filtered[pos + 1]); |
| 800 | + } |
| 801 | + function selectPrev() { |
| 802 | + var pos = filtered.indexOf(state.current); |
| 803 | + if (pos > 0) selectItem(filtered[pos - 1]); |
| 804 | + } |
| 805 | + |
776 | 806 | /* ── Render ─────────────────────────────────────────────────────────── */ |
777 | 807 | function renderMain() { |
778 | 808 | var item = DATA[state.current]; |
779 | 809 | if (!item) return; |
780 | 810 |
|
781 | 811 | topTitle.textContent = item.name; |
782 | | - navCounter.textContent = (state.current + 1) + '/' + DATA.length; |
| 812 | + var pos = filtered.indexOf(state.current); |
| 813 | + navCounter.textContent = (pos + 1) + '/' + filtered.length; |
783 | 814 | var hasDiff = item.diff || item.heatmap; |
784 | 815 | topBadge.textContent = hasDiff ? 'changed' : 'pass'; |
785 | 816 | topBadge.className = 'diff-badge ' + (hasDiff ? 'diff-badge-fail' : 'diff-badge-pass'); |
|
822 | 853 | }); |
823 | 854 |
|
824 | 855 | /* ── Nav buttons ───────────────────────────────────────────────────── */ |
825 | | - $('nav-prev').addEventListener('click', function() { selectItem(state.current - 1); }); |
826 | | - $('nav-next').addEventListener('click', function() { selectItem(state.current + 1); }); |
| 856 | + $('nav-prev').addEventListener('click', selectPrev); |
| 857 | + $('nav-next').addEventListener('click', selectNext); |
827 | 858 |
|
828 | 859 | /* ── Overlay slider ────────────────────────────────────────────────── */ |
829 | 860 | opSlider.addEventListener('input', function() { |
|
862 | 893 | document.addEventListener('touchend', function() { dragging = false; }); |
863 | 894 |
|
864 | 895 | /* ── Search ────────────────────────────────────────────────────────── */ |
865 | | - searchEl.addEventListener('input', function() { state.search = this.value; buildSidebar(); }); |
| 896 | + searchEl.addEventListener('input', function() { |
| 897 | + state.search = this.value; |
| 898 | + rebuildFiltered(); |
| 899 | + buildSidebar(); |
| 900 | + if (filtered.length) renderMain(); |
| 901 | + }); |
866 | 902 |
|
867 | 903 | /* ── Keyboard ──────────────────────────────────────────────────────── */ |
868 | 904 | document.addEventListener('keydown', function(e) { |
|
871 | 907 | return; |
872 | 908 | } |
873 | 909 | switch (e.key) { |
874 | | - case 'ArrowRight': case 'ArrowDown': e.preventDefault(); selectItem(state.current + 1); break; |
875 | | - case 'ArrowLeft': case 'ArrowUp': e.preventDefault(); selectItem(state.current - 1); break; |
| 910 | + case 'ArrowRight': case 'ArrowDown': e.preventDefault(); selectNext(); break; |
| 911 | + case 'ArrowLeft': case 'ArrowUp': e.preventDefault(); selectPrev(); break; |
876 | 912 | case '1': setMode('sidebyside'); break; |
877 | 913 | case '2': setMode('overlay'); break; |
878 | 914 | case '3': setMode('swipe'); break; |
|
888 | 924 | topBadge.style.display = 'none'; |
889 | 925 | Object.keys(views).forEach(function(m) { views[m].style.display = 'none'; }); |
890 | 926 | } else { |
| 927 | + rebuildFiltered(); |
891 | 928 | buildSidebar(); |
892 | 929 | renderMain(); |
893 | 930 | } |
|
0 commit comments