|
30 | 30 | background: linear-gradient(135deg, #0d1117 0%, #161b22 40%, #1a2332 100%); |
31 | 31 | border-bottom:1px solid var(--border); position:relative; overflow:hidden; |
32 | 32 | } |
| 33 | +/* Animated gradient sweep */ |
33 | 34 | .hero::before { |
34 | 35 | content:''; position:absolute; top:-50%; left:-50%; width:200%; height:200%; |
35 | | - background: radial-gradient(ellipse at 30% 50%, rgba(88,166,255,0.06) 0%, transparent 60%), |
36 | | - radial-gradient(ellipse at 70% 30%, rgba(63,185,80,0.04) 0%, transparent 50%); |
37 | | - pointer-events:none; |
| 36 | + background: radial-gradient(ellipse at 30% 50%, rgba(88,166,255,0.12) 0%, transparent 50%), |
| 37 | + radial-gradient(ellipse at 70% 30%, rgba(63,185,80,0.10) 0%, transparent 40%), |
| 38 | + radial-gradient(ellipse at 50% 80%, rgba(163,113,247,0.08) 0%, transparent 50%); |
| 39 | + pointer-events:none; animation: heroSweep 8s ease-in-out infinite alternate; |
38 | 40 | } |
| 41 | +/* Floating orb 1 */ |
| 42 | +.hero::after { |
| 43 | + content:''; position:absolute; width:300px; height:300px; border-radius:50%; |
| 44 | + background: radial-gradient(circle, rgba(88,166,255,0.15) 0%, transparent 70%); |
| 45 | + top:-60px; right:-80px; pointer-events:none; |
| 46 | + animation: orbFloat1 6s ease-in-out infinite alternate; |
| 47 | +} |
| 48 | +@keyframes heroSweep { |
| 49 | + 0% { transform:translate(0,0) rotate(0deg); } |
| 50 | + 100% { transform:translate(3%,-3%) rotate(2deg); } |
| 51 | +} |
| 52 | +@keyframes orbFloat1 { |
| 53 | + 0% { transform:translate(0,0) scale(1); opacity:0.7; } |
| 54 | + 100% { transform:translate(-40px,50px) scale(1.2); opacity:1; } |
| 55 | +} |
| 56 | +@keyframes orbFloat2 { |
| 57 | + 0% { transform:translate(0,0) scale(1); opacity:0.5; } |
| 58 | + 100% { transform:translate(30px,-40px) scale(1.15); opacity:0.9; } |
| 59 | +} |
| 60 | +@keyframes shimmer { |
| 61 | + 0% { background-position:200% center; } |
| 62 | + 100% { background-position:-200% center; } |
| 63 | +} |
| 64 | +@keyframes fadeSlideUp { |
| 65 | + 0% { opacity:0; transform:translateY(18px); } |
| 66 | + 100% { opacity:1; transform:translateY(0); } |
| 67 | +} |
| 68 | +@keyframes gridPulse { |
| 69 | + 0%,100% { opacity:0.03; } |
| 70 | + 50% { opacity:0.08; } |
| 71 | +} |
| 72 | +/* Floating orb 2 (extra layer) */ |
| 73 | +.hero-orb { |
| 74 | + position:absolute; width:200px; height:200px; border-radius:50%; |
| 75 | + background: radial-gradient(circle, rgba(63,185,80,0.12) 0%, transparent 70%); |
| 76 | + bottom:-40px; left:-60px; pointer-events:none; |
| 77 | + animation: orbFloat2 7s ease-in-out infinite alternate; |
| 78 | +} |
| 79 | +/* Animated grid lines */ |
| 80 | +.hero-grid { |
| 81 | + position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; |
| 82 | + background-image: |
| 83 | + linear-gradient(rgba(88,166,255,0.05) 1px, transparent 1px), |
| 84 | + linear-gradient(90deg, rgba(88,166,255,0.05) 1px, transparent 1px); |
| 85 | + background-size:60px 60px; |
| 86 | + animation: gridPulse 4s ease-in-out infinite; |
| 87 | +} |
| 88 | +/* Shimmering gradient title */ |
39 | 89 | .hero h1 { |
40 | | - font-size:2.6em; background:linear-gradient(135deg,var(--accent),var(--green)); |
| 90 | + font-size:2.6em; |
| 91 | + background:linear-gradient(90deg,var(--accent),var(--green),var(--purple),var(--accent)); |
| 92 | + background-size:300% auto; |
41 | 93 | -webkit-background-clip:text; -webkit-text-fill-color:transparent; |
42 | 94 | background-clip:text; margin-bottom:10px; position:relative; |
| 95 | + animation: shimmer 6s linear infinite; |
| 96 | +} |
| 97 | +.hero .subtitle { |
| 98 | + color:var(--text-muted); font-size:1.1em; max-width:600px; margin:0 auto 24px; line-height:1.7; position:relative; |
| 99 | + animation: fadeSlideUp 0.8s ease-out 0.2s both; |
| 100 | +} |
| 101 | +.hero .badges { |
| 102 | + display:flex; gap:8px; justify-content:center; flex-wrap:wrap; margin-bottom:24px; position:relative; |
| 103 | + animation: fadeSlideUp 0.8s ease-out 0.4s both; |
43 | 104 | } |
44 | | -.hero .subtitle { color:var(--text-muted); font-size:1.1em; max-width:600px; margin:0 auto 24px; line-height:1.7; position:relative; } |
45 | | -.hero .badges { display:flex; gap:8px; justify-content:center; flex-wrap:wrap; margin-bottom:24px; position:relative; } |
46 | 105 | .badge { |
47 | 106 | background:var(--surface); border:1px solid var(--border); border-radius:20px; |
48 | | - padding:5px 13px; font-size:0.82em; color:var(--text); transition:all 0.2s; |
| 107 | + padding:5px 13px; font-size:0.82em; color:var(--text); transition:all 0.3s; |
49 | 108 | } |
50 | | -.badge:hover { border-color:var(--accent); color:var(--accent); } |
| 109 | +.badge:hover { border-color:var(--accent); color:var(--accent); transform:translateY(-2px); box-shadow:0 4px 12px rgba(88,166,255,0.15); } |
51 | 110 | .badge.accent { border-color:var(--accent); color:var(--accent); } |
52 | 111 | .badge.green { border-color:var(--green); color:var(--green); } |
53 | 112 |
|
|
317 | 376 |
|
318 | 377 | <!-- ═══ HERO ═══ --> |
319 | 378 | <div class="hero"> |
| 379 | + <div class="hero-grid"></div> |
| 380 | + <div class="hero-orb"></div> |
320 | 381 | <h1>📊 GitHub Issue Analytics</h1> |
321 | 382 | <p class="subtitle">Enter any public GitHub repo. Get instant issue intelligence —<br> |
322 | 383 | funnel, heatmap, gauges, and 13-metric scorecard. All in your browser.</p> |
@@ -516,8 +577,9 @@ <h2>📈 Filing Trend (12 months)</h2> |
516 | 577 | const issues = data.filter(i => !i.pull_request); |
517 | 578 | allIssues = allIssues.concat(issues); |
518 | 579 |
|
519 | | - // Progress |
520 | | - const pct = Math.min(95, page / (data.length < 100 ? page : maxPages) * 100); |
| 580 | + // Progress — fast-forward style: jump aggressively |
| 581 | + const pct = Math.min(95, (page / Math.min(maxPages, page + 2)) * 100); |
| 582 | + $('progressBar').style.transition = 'width 0.15s'; |
521 | 583 | $('progressBar').style.width = pct + '%'; |
522 | 584 | $('progressText').innerHTML = `<span class="spinner"></span>Fetched <strong>${allIssues.length}</strong> issues (page ${page})...`; |
523 | 585 |
|
@@ -666,6 +728,64 @@ <h2>📈 Filing Trend (12 months)</h2> |
666 | 728 | }; |
667 | 729 | } |
668 | 730 |
|
| 731 | +// ── DEMO DATA (static — renders instantly on page load) ────── |
| 732 | +const DEMO_METRICS = { |
| 733 | + total: 6224, openCount: 2341, closedCount: 3883, |
| 734 | + medianAgeDays: 487, fixRate: 62.4, escalationRate: 8.7, |
| 735 | + noResponseRate: 14.2, staleCount: 812, untriagedRate: 31.6, dsatScore: 284, shs: 42, |
| 736 | + areas: [ |
| 737 | + {name:'bug', total:1842, bugs:1842, regressions:67, age:'1.8yr', fix_rate:58.3, stale:312, dsat:89}, |
| 738 | + {name:'enhancement', total:1456, bugs:0, regressions:0, age:'2.1yr', fix_rate:41.2, stale:287, dsat:42}, |
| 739 | + {name:'documentation', total:389, bugs:0, regressions:0, age:'0.9yr', fix_rate:72.8, stale:48, dsat:12}, |
| 740 | + {name:'security', total:124, bugs:98, regressions:14, age:'0.4yr', fix_rate:87.1, stale:8, dsat:31}, |
| 741 | + {name:'performance', total:267, bugs:201, regressions:23, age:'1.4yr', fix_rate:53.6, stale:67, dsat:45}, |
| 742 | + {name:'api', total:512, bugs:156, regressions:11, age:'1.6yr', fix_rate:48.9, stale:134, dsat:38}, |
| 743 | + {name:'testing', total:198, bugs:42, regressions:5, age:'1.1yr', fix_rate:66.2, stale:29, dsat:14}, |
| 744 | + {name:'ux', total:341, bugs:87, regressions:3, age:'1.3yr', fix_rate:55.7, stale:72, dsat:28}, |
| 745 | + ], |
| 746 | + ageDist: [ |
| 747 | + {label:'0-7d', count:143}, {label:'7-30d', count:287}, {label:'30-90d', count:412}, |
| 748 | + {label:'90-180d', count:356}, {label:'180d-1yr', count:489}, {label:'1-2yr', count:384}, |
| 749 | + {label:'2-3yr', count:178}, {label:'>3yr', count:92}, |
| 750 | + ], |
| 751 | + monthly: [ |
| 752 | + {label:'Apr', count:87}, {label:'May', count:112}, {label:'Jun', count:98}, |
| 753 | + {label:'Jul', count:134}, {label:'Aug', count:121}, {label:'Sep', count:156}, |
| 754 | + {label:'Oct', count:143}, {label:'Nov', count:109}, {label:'Dec', count:78}, |
| 755 | + {label:'Jan', count:167}, {label:'Feb', count:142}, {label:'Mar', count:128}, |
| 756 | + ], |
| 757 | + statuses: [ |
| 758 | + {name:'untriaged', count:740, color:'#f85149'}, |
| 759 | + {name:'triaged', count:612, color:'#3fb950'}, |
| 760 | + {name:'labeled', count:534, color:'#a371f7'}, |
| 761 | + {name:'needs_info', count:298, color:'#d29922'}, |
| 762 | + {name:'in_progress', count:157, color:'#58a6ff'}, |
| 763 | + ], |
| 764 | + funnel: [ |
| 765 | + {label:'Total Filed', count:6224, desc:'All issues in repo', color:'#58a6ff'}, |
| 766 | + {label:'Labeled', count:4892, desc:'Issues with at least one label', color:'#a371f7'}, |
| 767 | + {label:'Triaged', count:2847, desc:'Has triage/priority label', color:'#3fb950'}, |
| 768 | + {label:'In Progress', count:157, desc:'Actively being worked on', color:'#d29922'}, |
| 769 | + {label:'Closed', count:3883, desc:'Resolved or closed', color:'#238636'}, |
| 770 | + ], |
| 771 | +}; |
| 772 | +const DEMO_REPO = 'pallets/flask'; |
| 773 | + |
| 774 | +// ── Demo Banner CSS ── |
| 775 | +const demoBannerStyle = document.createElement('style'); |
| 776 | +demoBannerStyle.textContent = ` |
| 777 | +.demo-banner { |
| 778 | + background:linear-gradient(135deg, rgba(88,166,255,0.12), rgba(63,185,80,0.12)); |
| 779 | + border:1px solid rgba(88,166,255,0.25); border-radius:10px; |
| 780 | + padding:12px 20px; margin:0 auto 18px; max-width:720px; |
| 781 | + text-align:center; font-size:0.9em; color:var(--text-muted); |
| 782 | + animation: fadeSlideUp 0.5s ease-out both; |
| 783 | +} |
| 784 | +.demo-banner strong { color:var(--accent); } |
| 785 | +.demo-banner a { color:var(--green); cursor:pointer; font-weight:600; } |
| 786 | +`; |
| 787 | +document.head.appendChild(demoBannerStyle); |
| 788 | + |
669 | 789 | // ── Render Engine ──────────────────────────────── |
670 | 790 |
|
671 | 791 | function renderDashboard(m) { |
@@ -911,6 +1031,9 @@ <h2>📈 Filing Trend (12 months)</h2> |
911 | 1031 | async function startAnalysis(event) { |
912 | 1032 | if (event) event.preventDefault(); |
913 | 1033 | hideError(); |
| 1034 | + // Remove demo banner if present |
| 1035 | + const db = document.getElementById('demoBanner'); |
| 1036 | + if (db) db.remove(); |
914 | 1037 | const raw = $('repoInput').value.trim(); |
915 | 1038 | if (!raw) return false; |
916 | 1039 |
|
@@ -960,12 +1083,28 @@ <h2>📈 Filing Trend (12 months)</h2> |
960 | 1083 | } |
961 | 1084 |
|
962 | 1085 | // ── URL param support: ?repo=owner/repo ────────── |
| 1086 | +// ── Auto-load demo data on page open ───────────── |
963 | 1087 | window.addEventListener('load', () => { |
964 | 1088 | const params = new URLSearchParams(window.location.search); |
965 | 1089 | const repo = params.get('repo'); |
966 | 1090 | if (repo) { |
967 | 1091 | $('repoInput').value = repo; |
968 | 1092 | startAnalysis(new Event('submit')); |
| 1093 | + } else { |
| 1094 | + // Show pre-computed demo dashboard instantly |
| 1095 | + currentRepo = DEMO_REPO; |
| 1096 | + $('repoInput').value = DEMO_REPO; |
| 1097 | + |
| 1098 | + // Insert demo banner above dashboard |
| 1099 | + const banner = document.createElement('div'); |
| 1100 | + banner.className = 'demo-banner'; |
| 1101 | + banner.id = 'demoBanner'; |
| 1102 | + banner.innerHTML = `📊 Showing <strong>demo data</strong> for <strong>${DEMO_REPO}</strong> — enter any repo above for live analysis or <a onclick="document.getElementById('demoBanner').remove()">dismiss</a>`; |
| 1103 | + const dashEl = $('dashboard'); |
| 1104 | + dashEl.parentNode.insertBefore(banner, dashEl); |
| 1105 | + |
| 1106 | + renderDashboard(DEMO_METRICS); |
| 1107 | + $('dashboard').scrollIntoView({ behavior: 'smooth', block: 'start' }); |
969 | 1108 | } |
970 | 1109 | }); |
971 | 1110 | </script> |
|
0 commit comments