|
865 | 865 | background: var(--bg-dark); |
866 | 866 | } |
867 | 867 |
|
868 | | - .contributor span { |
| 868 | + .contributor a { |
| 869 | + position: relative; |
| 870 | + display: inline-block; |
| 871 | + } |
| 872 | + |
| 873 | + .contributor-badge { |
| 874 | + position: absolute; |
| 875 | + bottom: -2px; |
| 876 | + right: -2px; |
| 877 | + font-size: 0.8rem; |
| 878 | + background: var(--bg-dark); |
| 879 | + border-radius: 50%; |
| 880 | + padding: 2px; |
| 881 | + line-height: 1; |
| 882 | + } |
| 883 | + |
| 884 | + .contributor span:not(.contributor-badge) { |
869 | 885 | margin-top: 0.3rem; |
870 | 886 | font-size: 0.75rem; |
871 | 887 | color: var(--text-secondary); |
| 888 | + display: block; |
872 | 889 | } |
873 | 890 |
|
874 | 891 | @keyframes float { |
@@ -2464,44 +2481,116 @@ <h4><i class="fas fa-clipboard-list"></i> Sugestões (<span id="cart-count">0</s |
2464 | 2481 | document.getElementById('table-scroll').scrollTop = 0; |
2465 | 2482 | } |
2466 | 2483 |
|
2467 | | - // Load contributors from GitHub |
| 2484 | + // Load contributors from GitHub + Issue authors |
2468 | 2485 | async function loadContributors() { |
| 2486 | + const orbit = document.getElementById('contributors-orbit'); |
| 2487 | + if (!orbit) return; |
| 2488 | + |
2469 | 2489 | try { |
2470 | | - // Get contributors who have PRs merged (simplified - using repo contributors) |
2471 | | - const response = await fetch(`https://api.github.com/repos/${CONFIG.GITHUB_REPO}/contributors?per_page=10`); |
2472 | | - if (!response.ok) throw new Error('Failed to fetch contributors'); |
| 2490 | + // Buscar em paralelo: contributors do repo + autores de issues aprovadas |
| 2491 | + const [contributorsResp, issuesResp] = await Promise.all([ |
| 2492 | + fetch(`https://api.github.com/repos/${CONFIG.GITHUB_REPO}/contributors?per_page=15`), |
| 2493 | + fetch(`https://api.github.com/repos/${CONFIG.GITHUB_OWNER}/${CONFIG.GITHUB_REPO_NAME}/issues?state=closed&labels=applied&per_page=50`) |
| 2494 | + ]); |
2473 | 2495 |
|
2474 | | - const contributors = await response.json(); |
2475 | | - const orbit = document.getElementById('contributors-orbit'); |
| 2496 | + // Processar contributors do repo (commits) |
| 2497 | + let repoContributors = []; |
| 2498 | + if (contributorsResp.ok) { |
| 2499 | + repoContributors = await contributorsResp.json(); |
| 2500 | + } |
2476 | 2501 |
|
2477 | | - if (contributors.length === 0) { |
2478 | | - orbit.innerHTML = '<div class="no-contributors">Seja o primeiro a contribuir!</div>'; |
2479 | | - return; |
| 2502 | + // Processar autores de issues aprovadas (traduções via site) |
| 2503 | + let issueAuthors = []; |
| 2504 | + if (issuesResp.ok) { |
| 2505 | + const issues = await issuesResp.json(); |
| 2506 | + // Contar contribuições por autor |
| 2507 | + const authorCounts = {}; |
| 2508 | + issues.forEach(issue => { |
| 2509 | + if (issue.user && issue.user.type === 'User') { |
| 2510 | + const login = issue.user.login; |
| 2511 | + if (!authorCounts[login]) { |
| 2512 | + authorCounts[login] = { |
| 2513 | + login: login, |
| 2514 | + avatar_url: issue.user.avatar_url, |
| 2515 | + html_url: issue.user.html_url, |
| 2516 | + contributions: 0, |
| 2517 | + type: 'User', |
| 2518 | + source: 'issues' |
| 2519 | + }; |
| 2520 | + } |
| 2521 | + // Contar sugestões dentro da issue |
| 2522 | + try { |
| 2523 | + const jsonMatch = issue.body?.match(/"total"\s*:\s*(\d+)/); |
| 2524 | + const count = jsonMatch ? parseInt(jsonMatch[1]) : 1; |
| 2525 | + authorCounts[login].contributions += count; |
| 2526 | + } catch (e) { |
| 2527 | + authorCounts[login].contributions += 1; |
| 2528 | + } |
| 2529 | + } |
| 2530 | + }); |
| 2531 | + issueAuthors = Object.values(authorCounts); |
2480 | 2532 | } |
2481 | 2533 |
|
2482 | | - // Filter to show only non-bot contributors (except the owner which should show) |
2483 | | - const displayContributors = contributors |
| 2534 | + // Combinar e mesclar (evitar duplicatas) |
| 2535 | + const allContributors = new Map(); |
| 2536 | + |
| 2537 | + // Primeiro, adicionar contributors do repo |
| 2538 | + repoContributors |
2484 | 2539 | .filter(c => c.type === 'User') |
| 2540 | + .forEach(c => { |
| 2541 | + allContributors.set(c.login, { |
| 2542 | + login: c.login, |
| 2543 | + avatar_url: c.avatar_url, |
| 2544 | + html_url: c.html_url, |
| 2545 | + contributions: c.contributions, |
| 2546 | + source: 'commits' |
| 2547 | + }); |
| 2548 | + }); |
| 2549 | + |
| 2550 | + // Depois, adicionar/mesclar autores de issues |
| 2551 | + issueAuthors.forEach(author => { |
| 2552 | + if (allContributors.has(author.login)) { |
| 2553 | + // Já existe - somar contribuições |
| 2554 | + const existing = allContributors.get(author.login); |
| 2555 | + existing.contributions += author.contributions; |
| 2556 | + existing.source = 'both'; |
| 2557 | + } else { |
| 2558 | + // Novo contributor via issues |
| 2559 | + allContributors.set(author.login, author); |
| 2560 | + } |
| 2561 | + }); |
| 2562 | + |
| 2563 | + // Ordenar por contribuições e pegar top 8 |
| 2564 | + const displayContributors = Array.from(allContributors.values()) |
| 2565 | + .sort((a, b) => b.contributions - a.contributions) |
2485 | 2566 | .slice(0, 8); |
2486 | 2567 |
|
2487 | 2568 | if (displayContributors.length === 0) { |
2488 | 2569 | orbit.innerHTML = '<div class="no-contributors">Seja o primeiro a contribuir!</div>'; |
2489 | 2570 | return; |
2490 | 2571 | } |
2491 | 2572 |
|
2492 | | - orbit.innerHTML = displayContributors.map((contributor, index) => ` |
2493 | | - <div class="contributor" style="animation-delay: ${index * 0.3}s; left: ${10 + (index * 12)}%; top: ${15 + Math.sin(index) * 25}%;"> |
2494 | | - <a href="${contributor.html_url}" target="_blank" rel="noopener" title="${contributor.login}"> |
2495 | | - <img src="${contributor.avatar_url}" alt="${contributor.login}"> |
2496 | | - </a> |
2497 | | - <span>@${contributor.login}</span> |
2498 | | - </div> |
2499 | | - `).join(''); |
| 2573 | + orbit.innerHTML = displayContributors.map((contributor, index) => { |
| 2574 | + // Ícone baseado no tipo de contribuição |
| 2575 | + const badgeIcon = contributor.source === 'issues' ? '💬' : |
| 2576 | + contributor.source === 'both' ? '⭐' : '💻'; |
| 2577 | + const badgeTitle = contributor.source === 'issues' ? 'Tradutor via site' : |
| 2578 | + contributor.source === 'both' ? 'Tradutor + Desenvolvedor' : 'Desenvolvedor'; |
| 2579 | + |
| 2580 | + return ` |
| 2581 | + <div class="contributor" style="animation-delay: ${index * 0.3}s; left: ${10 + (index * 12)}%; top: ${15 + Math.sin(index) * 25}%;"> |
| 2582 | + <a href="${contributor.html_url}" target="_blank" rel="noopener" title="${contributor.login} - ${contributor.contributions} contribuições (${badgeTitle})"> |
| 2583 | + <img src="${contributor.avatar_url}" alt="${contributor.login}"> |
| 2584 | + <span class="contributor-badge" title="${badgeTitle}">${badgeIcon}</span> |
| 2585 | + </a> |
| 2586 | + <span>@${contributor.login}</span> |
| 2587 | + </div> |
| 2588 | + `; |
| 2589 | + }).join(''); |
2500 | 2590 |
|
2501 | 2591 | } catch (error) { |
2502 | 2592 | console.error('Error loading contributors:', error); |
2503 | | - document.getElementById('contributors-orbit').innerHTML = |
2504 | | - '<div class="no-contributors">Seja o primeiro a contribuir!</div>'; |
| 2593 | + orbit.innerHTML = '<div class="no-contributors">Seja o primeiro a contribuir!</div>'; |
2505 | 2594 | } |
2506 | 2595 | } |
2507 | 2596 |
|
|
0 commit comments