Skip to content

Commit fe66814

Browse files
committed
refactor: use event delegation for tabs and improve card stagger animation
1 parent f3841e6 commit fe66814

2 files changed

Lines changed: 50 additions & 20 deletions

File tree

generate_index.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,10 @@ def generate_index(self) -> None:
163163
if category.startswith('.'):
164164
continue
165165

166-
title = self.get_html_title(filepath)
166+
try:
167+
title = self.get_html_title(filepath)
168+
except Exception:
169+
title = os.path.basename(filepath)
167170
structure[category].append((title, rel_path))
168171

169172
# Sort categories and files
@@ -611,13 +614,14 @@ def generate_index(self) -> None:
611614
<span class="search-icon">\U0001F50D</span>
612615
<input type="text" id="searchInput" class="search-input"
613616
placeholder="Search problems... (e.g. Binary Search, DP, LeetCode 91)"
617+
aria-label="Search problems"
614618
autocomplete="off">
615619
<span id="searchCount" class="search-count"></span>
616620
<button id="searchClear" class="search-clear" aria-label="Clear search">\u00D7</button>
617621
</div>
618622
619623
<div class="tabs" id="categoryTabs">
620-
<button class="tab-button active" data-category="all" onclick="openTab(event, 'All')">
624+
<button class="tab-button active" data-category="all" data-tab-target="All">
621625
<span class="tab-icon">\U0001F30D</span> All <span class="tab-count">{total_count}</span>
622626
</button>
623627
{tabs}
@@ -736,16 +740,16 @@ def generate_index(self) -> None:
736740
function applyStaggerAnimation(tabId) {{
737741
const tab = document.getElementById(tabId);
738742
const items = tab.querySelectorAll('.file-item:not(.hidden-item)');
743+
items.forEach(item => {{ item.style.animation = 'none'; }});
744+
tab.offsetHeight;
739745
items.forEach((item, i) => {{
740-
item.style.animation = 'none';
741-
item.offsetHeight;
742746
item.style.animation = '';
743747
item.style.animationDelay = (i * 0.04) + 's';
744748
}});
745749
}}
746750
747751
/* Tab Navigation */
748-
function openTab(evt, categoryName) {{
752+
function openTab(categoryName) {{
749753
document.querySelectorAll('.tab-content').forEach(tc => {{
750754
tc.style.display = 'none';
751755
tc.classList.remove('active');
@@ -757,7 +761,8 @@ def generate_index(self) -> None:
757761
const target = document.getElementById(categoryName);
758762
target.style.display = 'block';
759763
target.classList.add('active');
760-
evt.currentTarget.classList.add('active');
764+
const btn = document.querySelector('.tab-button[data-tab-target="' + categoryName + '"]');
765+
if (btn) btn.classList.add('active');
761766
762767
const input = document.getElementById('searchInput');
763768
if (input.value) {{
@@ -850,9 +855,20 @@ def generate_index(self) -> None:
850855
}});
851856
}}
852857
858+
/* Tab Delegation */
859+
function initTabs() {{
860+
document.getElementById('categoryTabs').addEventListener('click', (evt) => {{
861+
const btn = evt.target.closest('.tab-button');
862+
if (btn && btn.dataset.tabTarget) {{
863+
openTab(btn.dataset.tabTarget);
864+
}}
865+
}});
866+
}}
867+
853868
/* Init */
854869
window.addEventListener('DOMContentLoaded', () => {{
855870
initTheme();
871+
initTabs();
856872
initPagination();
857873
initSearch();
858874
}});
@@ -870,8 +886,9 @@ def generate_index(self) -> None:
870886
count = len(files)
871887
icon = category_icons.get(category, '')
872888
css_cat = category.lower()
889+
safe_category = html.escape(category, quote=True)
873890

874-
tabs_html += f'<button class="tab-button" data-category="{css_cat}" onclick="openTab(event, \'{category}\')"><span class="tab-icon">{icon}</span> {category} <span class="tab-count">{count}</span></button>\n'
891+
tabs_html += f'<button class="tab-button" data-category="{css_cat}" data-tab-target="{safe_category}"><span class="tab-icon">{icon}</span> {safe_category} <span class="tab-count">{count}</span></button>\n'
875892

876893
file_list_html = '<ul class="file-list">\n'
877894
for title, path in files:
@@ -883,7 +900,7 @@ def generate_index(self) -> None:
883900
all_files_html += item_html
884901
file_list_html += '</ul>'
885902

886-
tab_contents_html += f'<div id="{category}" class="tab-content">\n{file_list_html}\n<div class="no-results"><span class="no-results-icon">\U0001F50E</span>No results found</div>\n</div>\n'
903+
tab_contents_html += f'<div id="{safe_category}" class="tab-content">\n{file_list_html}\n<div class="no-results"><span class="no-results-icon">\U0001F50E</span>No results found</div>\n</div>\n'
887904

888905
final_html = html_template.format(
889906
tabs=tabs_html,

public/index.html

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -423,21 +423,22 @@ <h1 class="site-title">
423423
<span class="search-icon">🔍</span>
424424
<input type="text" id="searchInput" class="search-input"
425425
placeholder="Search problems... (e.g. Binary Search, DP, LeetCode 91)"
426+
aria-label="Search problems"
426427
autocomplete="off">
427428
<span id="searchCount" class="search-count"></span>
428429
<button id="searchClear" class="search-clear" aria-label="Clear search">×</button>
429430
</div>
430431

431432
<div class="tabs" id="categoryTabs">
432-
<button class="tab-button active" data-category="all" onclick="openTab(event, 'All')">
433+
<button class="tab-button active" data-category="all" data-tab-target="All">
433434
<span class="tab-icon">🌍</span> All <span class="tab-count">151</span>
434435
</button>
435-
<button class="tab-button" data-category="algorithm" onclick="openTab(event, 'Algorithm')"><span class="tab-icon">🧩</span> Algorithm <span class="tab-count">84</span></button>
436-
<button class="tab-button" data-category="concurrency" onclick="openTab(event, 'Concurrency')"><span class="tab-icon"></span> Concurrency <span class="tab-count">6</span></button>
437-
<button class="tab-button" data-category="datastructures" onclick="openTab(event, 'DataStructures')"><span class="tab-icon">🏗️</span> DataStructures <span class="tab-count">35</span></button>
438-
<button class="tab-button" data-category="javascript" onclick="openTab(event, 'JavaScript')"><span class="tab-icon">📜</span> JavaScript <span class="tab-count">11</span></button>
439-
<button class="tab-button" data-category="mathematics" onclick="openTab(event, 'Mathematics')"><span class="tab-icon">📐</span> Mathematics <span class="tab-count">12</span></button>
440-
<button class="tab-button" data-category="sql" onclick="openTab(event, 'SQL')"><span class="tab-icon">🗃️</span> SQL <span class="tab-count">3</span></button>
436+
<button class="tab-button" data-category="algorithm" data-tab-target="Algorithm"><span class="tab-icon">🧩</span> Algorithm <span class="tab-count">84</span></button>
437+
<button class="tab-button" data-category="concurrency" data-tab-target="Concurrency"><span class="tab-icon"></span> Concurrency <span class="tab-count">6</span></button>
438+
<button class="tab-button" data-category="datastructures" data-tab-target="DataStructures"><span class="tab-icon">🏗️</span> DataStructures <span class="tab-count">35</span></button>
439+
<button class="tab-button" data-category="javascript" data-tab-target="JavaScript"><span class="tab-icon">📜</span> JavaScript <span class="tab-count">11</span></button>
440+
<button class="tab-button" data-category="mathematics" data-tab-target="Mathematics"><span class="tab-icon">📐</span> Mathematics <span class="tab-count">12</span></button>
441+
<button class="tab-button" data-category="sql" data-tab-target="SQL"><span class="tab-icon">🗃️</span> SQL <span class="tab-count">3</span></button>
441442

442443
</div>
443444

@@ -784,7 +785,7 @@ <h1 class="site-title">
784785

785786
<footer>
786787
<span class="footer-icon">🧪</span>
787-
Generated on 2026-02-20 06:50:34 UTC
788+
Generated on 2026-02-20 07:11:56 UTC
788789
</footer>
789790

790791
<script>
@@ -886,16 +887,16 @@ <h1 class="site-title">
886887
function applyStaggerAnimation(tabId) {
887888
const tab = document.getElementById(tabId);
888889
const items = tab.querySelectorAll('.file-item:not(.hidden-item)');
890+
items.forEach(item => { item.style.animation = 'none'; });
891+
tab.offsetHeight;
889892
items.forEach((item, i) => {
890-
item.style.animation = 'none';
891-
item.offsetHeight;
892893
item.style.animation = '';
893894
item.style.animationDelay = (i * 0.04) + 's';
894895
});
895896
}
896897

897898
/* Tab Navigation */
898-
function openTab(evt, categoryName) {
899+
function openTab(categoryName) {
899900
document.querySelectorAll('.tab-content').forEach(tc => {
900901
tc.style.display = 'none';
901902
tc.classList.remove('active');
@@ -907,7 +908,8 @@ <h1 class="site-title">
907908
const target = document.getElementById(categoryName);
908909
target.style.display = 'block';
909910
target.classList.add('active');
910-
evt.currentTarget.classList.add('active');
911+
const btn = document.querySelector('.tab-button[data-tab-target="' + categoryName + '"]');
912+
if (btn) btn.classList.add('active');
911913

912914
const input = document.getElementById('searchInput');
913915
if (input.value) {
@@ -1000,9 +1002,20 @@ <h1 class="site-title">
10001002
});
10011003
}
10021004

1005+
/* Tab Delegation */
1006+
function initTabs() {
1007+
document.getElementById('categoryTabs').addEventListener('click', (evt) => {
1008+
const btn = evt.target.closest('.tab-button');
1009+
if (btn && btn.dataset.tabTarget) {
1010+
openTab(btn.dataset.tabTarget);
1011+
}
1012+
});
1013+
}
1014+
10031015
/* Init */
10041016
window.addEventListener('DOMContentLoaded', () => {
10051017
initTheme();
1018+
initTabs();
10061019
initPagination();
10071020
initSearch();
10081021
});

0 commit comments

Comments
 (0)