<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>GitHub Stars - myOpenSourceCollection</title><style>* { margin: 0; padding: 0; box-sizing: border-box; }body {background: #151515;color: #eaeaea;font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;font-size: 14px;line-height: 1.5;min-height: 100vh;-webkit-font-smoothing: antialiased;}.container { width: 90%; max-width: 1400px; margin: 0 auto; padding: 20px 40px; }header {border-bottom: 1px dashed #b5e853;padding-bottom: 20px;margin-bottom: 40px;display: flex;justify-content: space-between;align-items: center;flex-wrap: wrap;gap: 10px;}h1 {font-size: 28px;color: #b5e853;font-weight: bold;letter-spacing: -1px;text-shadow: 0 1px 1px rgba(0,0,0,0.1), 0 0 5px rgba(181,232,83,0.1), 0 0 10px rgba(181,232,83,0.1);}h1::before { content: "./ "; font-size: 22px; }.back-link {display: inline-block;color: rgba(255,255,255,0.8);text-decoration: none;padding: 8px 18px;border-radius: 50px;border: 2px solid rgba(0,0,0,0.7);border-top: 2px solid #000;font-family: Helvetica, Arial, sans-serif;font-weight: bold;font-size: 11px;text-shadow: 0 -1px 0 rgba(0,0,0,0.75);background: -webkit-linear-gradient(top, rgba(40,40,40,0.3), rgba(35,35,35,0.3) 50%, rgba(10,10,10,0.3) 50%, rgba(0,0,0,0.3));transition: all 0.3s;}.back-link:hover {background: -webkit-linear-gradient(top, rgba(40,40,40,0.6), rgba(35,35,35,0.6) 50%, rgba(10,10,10,0.8) 50%, rgba(0,0,0,0.8));}.subtitle { color: #aaa; font-size: 16px; font-weight: 300; }.controls { margin-bottom: 30px; }.search-box {width: 100%;padding: 15px;background: rgba(0,0,0,0.9);border: 1px solid rgba(255,255,255,0.15);color: #b5e853;font-family: inherit;font-size: 14px;margin-bottom: 20px;border-radius: 2px;}.search-box:focus { outline: none; box-shadow: 0 0 10px rgba(181,232,83,0.3); border-color: #b5e853; }.search-box::placeholder { color: #888; }.filter-bar { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 15px; }.filter-btn {background: transparent;border: 1px dashed #b5e853;color: #aaa;padding: 8px 16px;cursor: pointer;font-family: inherit;font-size: 0.9em;transition: all 0.3s;}.filter-btn:hover { color: #b5e853; }.filter-btn.active { background: #b5e853; color: #151515; border-color: #b5e853; border-style: solid; }.sort-bar { display: flex; align-items: center; gap: 10px; color: #aaa; font-size: 0.9em; }.sort-btn {background: transparent;border: none;color: #aaa;cursor: pointer;font-family: inherit;font-size: 1em;padding: 5px 10px;transition: color 0.3s;}.sort-btn:hover, .sort-btn.active { color: #b5e853; }.stats { color: #aaa; margin-bottom: 20px; font-size: 0.9em; }.repo-list { display: grid; gap: 15px; }.repo-card {background: rgba(0,0,0,0.9);border: 1px solid rgba(255,255,255,0.15);padding: 20px;transition: all 0.3s;text-decoration: none;display: block;border-radius: 2px;}.repo-card:hover {border-color: #b5e853;box-shadow: 0 0 15px rgba(181,232,83,0.2);transform: translateY(-2px);}.repo-header {display: flex;justify-content: space-between;align-items: flex-start;margin-bottom: 10px;gap: 10px;}.repo-name {color: #b5e853;font-size: 1.1em;font-weight: bold;word-break: break-word;text-shadow: 0 1px 1px rgba(0,0,0,0.1), 0 0 5px rgba(181,232,83,0.1), 0 0 10px rgba(181,232,83,0.1);}.repo-row { display: flex; align-items: center; gap: 15px; }.repo-idx { color: #b5e853; font-size: 0.9em; min-width: 2em; }.repo-stars { color: #f4bf75; white-space: nowrap; font-size: 0.9em; }.repo-desc { color: #eaeaea; margin-bottom: 10px; font-size: 0.9em; }.repo-meta { display: flex; flex-wrap: wrap; gap: 15px; font-size: 0.8em; color: #bbb; }.lang-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; vertical-align: middle; }.repo-lang { color: #63c0f5; text-shadow: 0 0 5px rgba(104,182,255,0.5); }.repo-topics { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }.topic-tag { background: #2a2a2a; color: #bbb; padding: 2px 8px; font-size: 0.75em; border-radius: 2px; }.pagination {display: flex;justify-content: center;align-items: center;gap: 8px;margin-top: 30px;flex-wrap: wrap;}.page-btn {background: transparent;border: 1px solid rgba(255,255,255,0.15);color: #aaa;padding: 8px 14px;cursor: pointer;font-family: inherit;font-size: 0.9em;transition: all 0.3s;border-radius: 2px;}.page-btn:hover { border-color: #b5e853; color: #b5e853; }.page-btn.active { background: #b5e853; color: #151515; border-color: #b5e853; }.page-btn.disabled { opacity: 0.3; cursor: default; pointer-events: none; }.page-info { color: #aaa; font-size: 0.85em; }footer {margin-top: 40px;padding-top: 20px;border-top: 1px dashed #b5e853;color: #aaa;font-size: 0.85em;text-align: center;}.loading { text-align: center; padding: 50px; color: #aaa; }.loading::after { content: '...'; animation: dots 1.5s infinite; }@keyframes dots {0%, 20% { content: '.'; }40% { content: '..'; }60%, 100% { content: '...'; }}.error { text-align: center; padding: 50px; color: #ac4142; }.no-results { text-align: center; padding: 50px; color: #aaa; }@media (max-width: 600px) {.container { padding: 15px; }h1 { font-size: 1.4em; }.repo-card { padding: 15px; }.page-btn { padding: 6px 10px; font-size: 0.85em; }}</style></head><body><div class="container"><header><div><h1>GitHub Stars</h1><div class="subtitle">@think3r's starred repositories</div></div><a href="/" class="back-link">← Back to Home</a></header><div class="controls"><input type="text" class="search-box" id="searchInput" placeholder="Search repositories by name, description, or topics..."><div class="filter-bar" id="filterBar"><button class="filter-btn active" data-lang="all">All</button></div><div class="sort-bar"><span>Sort by:</span><button class="sort-btn active" data-sort="stars">⭐ Stars</button><button class="sort-btn" data-sort="name">Name</button><button class="sort-btn" data-sort="pushed">Pushed</button><button class="sort-btn" data-sort="updated">Updated</button></div></div><div class="stats" id="stats"></div><div class="repo-list" id="repoList"><div class="loading">Loading repositories</div></div><div class="pagination" id="pagination"></div><footer><p>Data auto-generated from GitHub API · Last updated: <span id="updateTime">-</span></p></footer></div><script>const PAGE_SIZE = 50;let allRepos = [];let currentFilter = 'all';let currentSort = 'stars';let currentSearch = '';let currentPage = 1;let dataTimestamp = '';const LANG_COLORS = {'C': '#555555', 'C++': '#f34b7d', 'C#': '#178600', 'Go': '#00ADD8','Java': '#b07219', 'JavaScript': '#f1e05a', 'Kotlin': '#A97BFF','Lua': '#000080', 'Objective-C': '#438eff', 'PHP': '#4F5D95','Python': '#3572A5', 'R': '#198CE7', 'Ruby': '#701516','Rust': '#dea584', 'Scala': '#c22d40', 'Shell': '#89e051','Swift': '#F05138', 'TypeScript': '#2b7489', 'Vim script': '#199f4d','Vue': '#41b883', 'Zig': '#ec915c', 'Dart': '#00B4AB','Elixir': '#6e4a7e', 'Erlang': '#B83998', 'Haskell': '#29b544','Perl': '#0298c3', 'PowerShell': '#012456', 'SQL': '#e38c00','Assembly': '#6E4C13', 'Clojure': '#db5855', 'CoffeeScript': '#244776','F#': '#b845fc', 'Groovy': '#e69f56', 'Julia': '#a270ba','Matlab': '#e16737', 'OCaml': '#3be133', 'Racket': '#ae17ff','Sass': '#a53b70', 'Solidity': '#AA6746', 'Tcl': '#e4cc98','Wasm': '#654ff0', 'CSS': '#563d7c', 'HTML': '#e34c26','Markdown': '#083fa1', 'YAML': '#cb171e', 'JSON': '#292929','Makefile': '#427819', 'Nix': '#7e7eff', 'D': '#ba595e','Vala': '#fbe5cd', 'Apex': '#1798c1', 'WebAssembly': '#654ff0',};function escapeHtml(str) {if (!str) return '';return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');}function safeUrl(url) {if (!url) return '';try {const parsed = new URL(url);if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return '';return url;} catch { return ''; }}function formatStars(num) {if (num >= 1000) return (num / 1000).toFixed(1) + 'k';return num.toString();}function formatDate(dateStr) {return new Date(dateStr).toISOString().split('T')[0];}function getLangColor(lang) {return LANG_COLORS[lang] || '#8b8b8b';}function getFilteredRepos() {let filtered = allRepos.filter(repo => {if (currentFilter !== 'all' && (repo.language || 'Other') !== currentFilter) return false;if (currentSearch) {const s = currentSearch.toLowerCase();return repo.full_name.toLowerCase().includes(s)|| (repo.description || '').toLowerCase().includes(s)|| (repo.topics || []).some(t => t.toLowerCase().includes(s));}return true;});filtered.sort((a, b) => {if (currentSearch) {const s = currentSearch.toLowerCase();const maxStars = Math.max(...filtered.map(r => r.stargazers_count), 1);const logMax = Math.log(maxStars + 1);const relA = a.full_name.toLowerCase().includes(s) ? 2: (a.description || '').toLowerCase().includes(s) ? 1 : 0;const relB = b.full_name.toLowerCase().includes(s) ? 2: (b.description || '').toLowerCase().includes(s) ? 1 : 0;const starsScoreA = Math.log(a.stargazers_count + 1) / logMax;const starsScoreB = Math.log(b.stargazers_count + 1) / logMax;let wRel, wStars;switch (currentSort) {case 'stars': wRel = 3; wStars = 5; break;case 'name': wRel = 5; wStars = 2; break;case 'pushed': wRel = 3; wStars = 4; break;case 'updated': wRel = 3; wStars = 4; break;default: wRel = 3; wStars = 5; break;}const scoreA = relA * wRel + starsScoreA * wStars;const scoreB = relB * wRel + starsScoreB * wStars;if (scoreA !== scoreB) return scoreB - scoreA;switch (currentSort) {case 'stars': return b.stargazers_count - a.stargazers_count;case 'name': return a.full_name.localeCompare(b.full_name);case 'pushed': return new Date(b.pushed_at) - new Date(a.pushed_at);case 'updated': return new Date(b.updated_at) - new Date(a.updated_at);default: return 0;}}switch (currentSort) {case 'stars': return b.stargazers_count - a.stargazers_count;case 'name': return a.full_name.localeCompare(b.full_name);case 'pushed': return new Date(b.pushed_at) - new Date(a.pushed_at);case 'updated': return new Date(b.updated_at) - new Date(a.updated_at);default: return 0;}});return filtered;}function saveState() {const params = new URLSearchParams();if (currentSearch) params.set('search', currentSearch);if (currentFilter !== 'all') params.set('lang', currentFilter);if (currentSort !== 'stars') params.set('sort', currentSort);if (currentPage !== 1) params.set('page', currentPage);const hash = params.toString();history.replaceState(null, '', hash ? '#' + hash : location.pathname);}function loadState() {const hash = location.hash.slice(1);if (!hash) return;const params = new URLSearchParams(hash);if (params.has('search')) {currentSearch = params.get('search');document.getElementById('searchInput').value = currentSearch;}if (params.has('lang')) currentFilter = params.get('lang');if (params.has('sort')) currentSort = params.get('sort');if (params.has('page')) currentPage = parseInt(params.get('page')) || 1;}function applyStateToUI() {document.querySelectorAll('.filter-btn').forEach(btn => {btn.classList.toggle('active', btn.dataset.lang === currentFilter);});document.querySelectorAll('.sort-btn').forEach(btn => {btn.classList.toggle('active', btn.dataset.sort === currentSort);});}function renderFilters() {const langs = {};allRepos.forEach(repo => {const lang = repo.language || 'Other';langs[lang] = (langs[lang] || 0) + 1;});const sortedLangs = Object.entries(langs).sort((a, b) => b[1] - a[1]).slice(0, 8);const filterBar = document.getElementById('filterBar');filterBar.innerHTML = '<button class="filter-btn' + (currentFilter === 'all' ? ' active' : '') + '" data-lang="all">All (' + allRepos.length + ')</button>';sortedLangs.forEach(([lang, count]) => {const btn = document.createElement('button');btn.className = 'filter-btn' + (currentFilter === lang ? ' active' : '');btn.dataset.lang = lang;const dot = '<span class="lang-dot" style="background:' + getLangColor(lang) + '"></span>';btn.innerHTML = dot + escapeHtml(lang) + ' (' + count + ')';filterBar.appendChild(btn);});filterBar.querySelectorAll('.filter-btn').forEach(btn => {btn.addEventListener('click', () => {currentFilter = btn.dataset.lang;currentPage = 1;saveState();renderFilters();renderRepos();});});}function renderPagination(filtered) {const totalPages = Math.ceil(filtered.length / PAGE_SIZE);const pagEl = document.getElementById('pagination');if (totalPages <= 1) { pagEl.innerHTML = ''; return; }let html = '';html += '<button class="page-btn' + (currentPage === 1 ? ' disabled' : '') + '" data-page="prev">← Prev</button>';const maxVisible = 7;let start = Math.max(1, currentPage - Math.floor(maxVisible / 2));let end = Math.min(totalPages, start + maxVisible - 1);if (end - start < maxVisible - 1) start = Math.max(1, end - maxVisible + 1);if (start > 1) {html += '<button class="page-btn" data-page="1">1</button>';if (start > 2) html += '<span class="page-info">...</span>';}for (let i = start; i <= end; i++) {html += '<button class="page-btn' + (i === currentPage ? ' active' : '') + '" data-page="' + i + '">' + i + '</button>';}if (end < totalPages) {if (end < totalPages - 1) html += '<span class="page-info">...</span>';html += '<button class="page-btn" data-page="' + totalPages + '">' + totalPages + '</button>';}html += '<button class="page-btn' + (currentPage === totalPages ? ' disabled' : '') + '" data-page="next">Next →</button>';html += '<span class="page-info">Page ' + currentPage + ' / ' + totalPages + '</span>';pagEl.innerHTML = html;pagEl.querySelectorAll('.page-btn:not(.disabled)').forEach(btn => {btn.addEventListener('click', () => {const val = btn.dataset.page;if (val === 'prev') currentPage = Math.max(1, currentPage - 1);else if (val === 'next') currentPage = Math.min(totalPages, currentPage + 1);else currentPage = parseInt(val);saveState();renderRepos();window.scrollTo({ top: 0, behavior: 'smooth' });});});}function renderRepos() {const filtered = getFilteredRepos();const totalPages = Math.ceil(filtered.length / PAGE_SIZE);if (currentPage > totalPages && totalPages > 0) currentPage = totalPages;const startIdx = (currentPage - 1) * PAGE_SIZE;const pageItems = filtered.slice(startIdx, startIdx + PAGE_SIZE);document.getElementById('stats').textContent = 'Showing ' + (filtered.length === 0 ? 0 : startIdx + 1) + '-' + Math.min(startIdx + PAGE_SIZE, filtered.length) + ' of ' + filtered.length + ' repositories (total: ' + allRepos.length + ')';const repoList = document.getElementById('repoList');if (filtered.length === 0) {repoList.innerHTML = '<div class="no-results">No repositories found</div>';renderPagination(filtered);return;}repoList.innerHTML = pageItems.map((repo, i) => {const topics = (repo.topics || []).slice(0, 5).map(t => '<span class="topic-tag">' + escapeHtml(t) + '</span>').join('');const lang = repo.language || 'Other';const langColor = getLangColor(lang);return '<div class="repo-row">'+ '<span class="repo-idx">' + (i + 1) + '.</span>'+ '<a href="' + escapeHtml(safeUrl(repo.html_url)) + '" target="_blank" class="repo-card">'+ '<div class="repo-header">'+ '<span class="repo-name">' + escapeHtml(repo.full_name) + '</span>'+ '<span class="repo-stars">⭐ ' + formatStars(repo.stargazers_count) + '</span>'+ '</div>'+ '<div class="repo-desc">' + escapeHtml(repo.description || 'No description') + '</div>'+ '<div class="repo-meta">'+ '<span class="repo-lang"><span class="lang-dot" style="background:' + langColor + '"></span>' + escapeHtml(lang) + '</span>'+ '<span>Pushed: ' + formatDate(repo.pushed_at) + '</span>'+ '<span>Updated: ' + formatDate(repo.updated_at) + '</span>'+ '</div>'+ (topics ? '<div class="repo-topics">' + topics + '</div>' : '')+ '</a>'+ '</div>';}).join('');renderPagination(filtered);saveState();}document.getElementById('searchInput').addEventListener('input', e => {currentSearch = e.target.value;currentPage = 1;saveState();renderRepos();});document.querySelectorAll('.sort-btn').forEach(btn => {btn.addEventListener('click', () => {currentSort = btn.dataset.sort;currentPage = 1;saveState();applyStateToUI();renderRepos();});});fetch('./stars-data.json').then(res => {if (!res.ok) throw new Error('Failed to load data');return res.json();}).then(data => {allRepos = data.repos;dataTimestamp = data.timestamp;document.getElementById('updateTime').textContent = new Date(dataTimestamp).toISOString().slice(0, 16).replace("T", "");loadState();applyStateToUI();renderFilters();renderRepos();}).catch(err => {document.getElementById('repoList').innerHTML ='<div class="error">Failed to load repositories: ' + err.message + '</div>';});</script></body></html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。