From 13e94f85951c88079e401414ef82b10a47666e8b Mon Sep 17 00:00:00 2001 From: arpit2006 Date: Sat, 30 May 2026 14:51:23 +0530 Subject: [PATCH 1/2] Add repo tracker analytics dashboard --- .../RepositoryAnalyticsDashboard.tsx | 659 ++++++++++++++++++ src/hooks/useGitHubData.ts | 149 ++++ src/pages/Tracker/Tracker.tsx | 32 +- 3 files changed, 838 insertions(+), 2 deletions(-) create mode 100644 src/components/RepositoryAnalyticsDashboard.tsx diff --git a/src/components/RepositoryAnalyticsDashboard.tsx b/src/components/RepositoryAnalyticsDashboard.tsx new file mode 100644 index 00000000..906a4613 --- /dev/null +++ b/src/components/RepositoryAnalyticsDashboard.tsx @@ -0,0 +1,659 @@ +import { useMemo } from 'react'; +import { + Area, + AreaChart, + Bar, + BarChart, + Cell, + CartesianGrid, + ComposedChart, + Legend, + Line, + Pie, + PieChart, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from 'recharts'; +import { Box, Grid, Paper, Theme, Typography } from '@mui/material'; +import { + Activity, + Database, + GitCommitVertical, + GitFork, + Languages, + Star, + TrendingUp, +} from 'lucide-react'; + +interface RepositorySummary { + id: number; + name: string; + full_name: string; + html_url: string; + created_at: string; + updated_at: string; + pushed_at: string; + stargazers_count: number; + forks_count: number; + language: string | null; + fork: boolean; + archived: boolean; +} + +interface WeeklyCommitPoint { + week: number; + commits: number; +} + +interface DashboardProps { + totalIssues: number; + totalPrs: number; + repositories: RepositorySummary[]; + weeklyCommitActivity: WeeklyCommitPoint[]; + analyticsLoading: boolean; + analyticsError: string; + theme: Theme; +} + +const COLORS = ['#2563eb', '#06b6d4', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6']; + +const formatMonthLabel = (date: Date) => + date.toLocaleDateString(undefined, { month: 'short', year: 'numeric' }); + +const formatWeekLabel = (week: number) => + new Date(week * 1000).toLocaleDateString(undefined, { + month: 'short', + day: 'numeric', + }); + +const RepositoryAnalyticsDashboard = ({ + totalIssues, + totalPrs, + repositories, + weeklyCommitActivity, + analyticsLoading, + analyticsError, + theme, +}: DashboardProps) => { + const totalContributions = totalIssues + totalPrs; + + const analytics = useMemo(() => { + const repoCount = repositories.length; + + const totalStars = repositories.reduce((sum, repository) => sum + repository.stargazers_count, 0); + const totalForks = repositories.reduce((sum, repository) => sum + repository.forks_count, 0); + + const languageCounts = new Map(); + const monthlyBuckets = new Map(); + + const sortedRepositories = [...repositories].sort( + (left, right) => new Date(left.created_at).getTime() - new Date(right.created_at).getTime() + ); + + sortedRepositories.forEach((repository) => { + const language = repository.language ?? 'Unknown'; + languageCounts.set(language, (languageCounts.get(language) ?? 0) + 1); + + const createdAt = new Date(repository.created_at); + const monthKey = `${createdAt.getFullYear()}-${String(createdAt.getMonth() + 1).padStart(2, '0')}`; + + if (!monthlyBuckets.has(monthKey)) { + monthlyBuckets.set(monthKey, { + label: formatMonthLabel(createdAt), + order: createdAt.getFullYear() * 12 + createdAt.getMonth(), + created: 0, + stars: 0, + forks: 0, + }); + } + + const monthBucket = monthlyBuckets.get(monthKey); + + if (monthBucket) { + monthBucket.created += 1; + monthBucket.stars += repository.stargazers_count; + monthBucket.forks += repository.forks_count; + } + }); + + let cumulativeRepositories = 0; + let cumulativeStars = 0; + let cumulativeForks = 0; + + const repositoryGrowth = Array.from(monthlyBuckets.values()) + .sort((left, right) => left.order - right.order) + .map((bucket) => { + cumulativeRepositories += bucket.created; + cumulativeStars += bucket.stars; + cumulativeForks += bucket.forks; + + return { + label: bucket.label, + repositories: cumulativeRepositories, + stars: cumulativeStars, + forks: cumulativeForks, + }; + }); + + const languageDistribution = Array.from(languageCounts.entries()) + .map(([name, value]) => ({ name, value })) + .sort((left, right) => right.value - left.value) + .slice(0, 6); + + const topRepositories = [...repositories] + .sort((left, right) => { + if (right.stargazers_count !== left.stargazers_count) { + return right.stargazers_count - left.stargazers_count; + } + + return right.forks_count - left.forks_count; + }) + .slice(0, 6) + .map((repository) => ({ + name: repository.name, + stars: repository.stargazers_count, + forks: repository.forks_count, + language: repository.language ?? 'Unknown', + })); + + const mostUsedLanguage = languageDistribution[0]?.name ?? 'Unknown'; + + return { + repoCount, + totalStars, + totalForks, + mostUsedLanguage, + repositoryGrowth, + languageDistribution, + topRepositories, + }; + }, [repositories]); + + const summaryCards = [ + { + label: 'Total repositories', + value: analytics.repoCount, + icon: Database, + accentStart: '#2563eb', + accentEnd: '#06b6d4', + }, + { + label: 'Total stars', + value: analytics.totalStars, + icon: Star, + accentStart: '#f59e0b', + accentEnd: '#f97316', + }, + { + label: 'Total forks', + value: analytics.totalForks, + icon: GitFork, + accentStart: '#10b981', + accentEnd: '#14b8a6', + }, + { + label: 'Most used language', + value: analytics.mostUsedLanguage, + icon: Languages, + accentStart: '#8b5cf6', + accentEnd: '#d946ef', + }, + { + label: 'Total contributions', + value: totalContributions, + icon: Activity, + accentStart: '#0ea5e9', + accentEnd: '#6366f1', + }, + ]; + + const hasRepositoryData = analytics.repoCount > 0; + const hasCommitData = weeklyCommitActivity.length > 0; + + if (analyticsLoading && !hasRepositoryData) { + return ( + + + Loading repository analytics... + + + ); + } + + if (!hasRepositoryData && totalContributions === 0) { + return ( + + + Enter a GitHub username to view repository growth analytics. + + + ); + } + + return ( + + + + + + + + Repo Tracker + + + Growth analytics + + + + + + + Track stars, forks, languages, and contribution momentum in one place. + + + This dashboard combines repository metadata with recent commit participation so you can spot growth, usage, and activity patterns without leaving the tracker. + + + + + + + Repos + + + {analytics.repoCount} + + + + + Stars + + + {analytics.totalStars} + + + + + Forks + + + {analytics.totalForks} + + + + + + + + {analyticsError ? ( + + + {analyticsError} + + + ) : null} + + + {summaryCards.map((card) => { + const Icon = card.icon; + + return ( + + + + + {card.label} + + + {card.value} + + + + + + + + ); + })} + + + + + + + + + Repository growth timeline + + + Cumulative repositories, stars, and forks over time. + + + + + + + + {hasRepositoryData ? ( + + + + + + + + + + + + + ) : ( + + No repository timeline data available. + + )} + + + + + + + + Language usage + + + Programming language distribution across owned repositories. + + + + {analytics.languageDistribution.length > 0 ? ( + + + `${name} ${percent && percent > 0.1 ? `${Math.round(percent * 100)}%` : ''}`} + > + {analytics.languageDistribution.map((entry, index) => ( + + ))} + + + + + + ) : ( + + No language data available. + + )} + + + + + + + + Commit activity trends + + + Recent weekly contribution intensity across the most active repositories. + + + + {hasCommitData ? ( + + ({ label: formatWeekLabel(entry.week), commits: entry.commits }))}> + + + + + + + + + + + + + + ) : ( + + Commit participation data is not available yet. + + )} + + + + + + + + Star and fork growth + + + Compare the most popular repositories in the current profile. + + + + {analytics.topRepositories.length > 0 ? ( + + + + + + + + + + + + ) : ( + + No starred repository data found. + + )} + + + + + + + + + Repository intelligence + + + Quick signals extracted from the current GitHub profile. + + + + + + Weekly commit trend + + + + Growth timeline + + + + + + ); +}; + +export default RepositoryAnalyticsDashboard; \ No newline at end of file diff --git a/src/hooks/useGitHubData.ts b/src/hooks/useGitHubData.ts index f4c78cf6..8e27eda4 100644 --- a/src/hooks/useGitHubData.ts +++ b/src/hooks/useGitHubData.ts @@ -13,6 +13,26 @@ interface GitHubItem { html_url: string; } +interface RepositorySummary { + id: number; + name: string; + full_name: string; + html_url: string; + created_at: string; + updated_at: string; + pushed_at: string; + stargazers_count: number; + forks_count: number; + language: string | null; + fork: boolean; + archived: boolean; +} + +interface WeeklyCommitPoint { + week: number; + commits: number; +} + interface FetchFilters { search?: string; repo?: string; @@ -26,8 +46,12 @@ export const useGitHubData = ( ) => { const [issues, setIssues] = useState([]); const [prs, setPrs] = useState([]); + const [repositories, setRepositories] = useState([]); + const [weeklyCommitActivity, setWeeklyCommitActivity] = useState([]); const [loading, setLoading] = useState(false); + const [analyticsLoading, setAnalyticsLoading] = useState(false); const [error, setError] = useState(''); + const [analyticsError, setAnalyticsError] = useState(''); const [totalIssues, setTotalIssues] = useState(0); const [totalPrs, setTotalPrs] = useState(0); const [rateLimited, setRateLimited] = useState(false); @@ -35,6 +59,55 @@ export const useGitHubData = ( // Prevent stale responses overwriting latest data const lastRequestId = useRef(0); + const sleep = (delay: number) => new Promise((resolve) => setTimeout(resolve, delay)); + + const fetchAllRepositories = async (octokit: Octokit, username: string) => { + const allRepositories: RepositorySummary[] = []; + let page = 1; + + while (true) { + const response = await octokit.request('GET /users/{username}/repos', { + username, + per_page: 100, + page, + sort: 'updated', + direction: 'desc', + }); + + const pageRepositories = response.data as RepositorySummary[]; + allRepositories.push(...pageRepositories); + + if (pageRepositories.length < 100) { + break; + } + + page += 1; + } + + return allRepositories; + }; + + const fetchCommitParticipation = async ( + octokit: Octokit, + owner: string, + repo: string + ) => { + for (let attempt = 0; attempt < 3; attempt += 1) { + const response = await octokit.request('GET /repos/{owner}/{repo}/stats/participation', { + owner, + repo, + }); + + if (response.status !== 202 && Array.isArray(response.data?.weeks)) { + return response.data.weeks as Array<{ w: number; c: number }>; + } + + await sleep(1000 * (attempt + 1)); + } + + return [] as Array<{ w: number; c: number }>; + }; + const fetchPaginated = async ( octokit: Octokit, username: string, @@ -239,14 +312,90 @@ export const useGitHubData = ( [getOctokit, rateLimited] ); + const fetchRepositoryAnalytics = useCallback( + async (username: string) => { + const octokit = getOctokit(); + + if (!octokit || !username.trim()) { + return; + } + + setAnalyticsLoading(true); + setAnalyticsError(''); + + try { + const allRepositories = await fetchAllRepositories(octokit, username); + const nonForkRepositories = allRepositories.filter( + (repository) => !repository.archived && !repository.fork + ); + const analyticsRepositories = nonForkRepositories.length > 0 + ? nonForkRepositories + : allRepositories.filter((repository) => !repository.archived); + + setRepositories(analyticsRepositories); + + const topRepositories = [...analyticsRepositories] + .sort((left, right) => { + if (right.stargazers_count !== left.stargazers_count) { + return right.stargazers_count - left.stargazers_count; + } + + return new Date(right.pushed_at).getTime() - new Date(left.pushed_at).getTime(); + }) + .slice(0, 5); + + const weeklyTotals = new Map(); + + await Promise.all( + topRepositories.map(async (repository) => { + try { + const participation = await fetchCommitParticipation( + octokit, + repository.full_name.split('/')[0], + repository.name + ); + + participation.forEach((entry) => { + weeklyTotals.set( + entry.w, + (weeklyTotals.get(entry.w) ?? 0) + entry.c + ); + }); + } catch { + return; + } + }) + ); + + const sortedWeeklyActivity = Array.from(weeklyTotals.entries()) + .sort((left, right) => left[0] - right[0]) + .map(([week, commits]) => ({ week, commits })); + + setWeeklyCommitActivity(sortedWeeklyActivity); + } catch { + setRepositories([]); + setWeeklyCommitActivity([]); + setAnalyticsError('Unable to load repository analytics.'); + } finally { + setAnalyticsLoading(false); + } + }, + [getOctokit] + ); + return { issues, prs, + repositories, + weeklyCommitActivity, totalIssues, totalPrs, loading, + analyticsLoading, error, + analyticsError, rateLimited, fetchData, + fetchRepositoryAnalytics, }; }; diff --git a/src/pages/Tracker/Tracker.tsx b/src/pages/Tracker/Tracker.tsx index 576f39bf..362ba929 100644 --- a/src/pages/Tracker/Tracker.tsx +++ b/src/pages/Tracker/Tracker.tsx @@ -33,6 +33,7 @@ import { useTheme } from "@mui/material/styles"; import { useGitHubAuth } from "../../hooks/useGitHubAuth"; import { useGitHubData } from "../../hooks/useGitHubData"; import { KeyIcon } from "lucide-react"; +import RepositoryAnalyticsDashboard from "../../components/RepositoryAnalyticsDashboard"; const ROWS_PER_PAGE = 10; @@ -65,8 +66,13 @@ const Home: React.FC = () => { totalIssues, totalPrs, loading, + repositories, + weeklyCommitActivity, + analyticsLoading, + analyticsError, error: dataError, fetchData, + fetchRepositoryAnalytics, } = useGitHubData(getOctokit); const [tab, setTab] = useState(0); @@ -78,6 +84,7 @@ const Home: React.FC = () => { const [selectedRepo, setSelectedRepo] = useState(""); const [startDate, setStartDate] = useState(""); const [endDate, setEndDate] = useState(""); + const isRepoTrackerTab = tab === 2; // Fetch data when username, tab, or page changes useEffect(() => { @@ -89,7 +96,17 @@ const Home: React.FC = () => { const handleSubmit = (e: React.FormEvent): void => { e.preventDefault(); setPage(0); - fetchData(username, 1, ROWS_PER_PAGE); + + const trimmedUsername = username.trim(); + + if (!trimmedUsername) { + return; + } + + void Promise.all([ + fetchData(trimmedUsername, 1, ROWS_PER_PAGE), + fetchRepositoryAnalytics(trimmedUsername), + ]); }; const handlePageChange = (_: unknown, newPage: number) => { @@ -295,6 +312,7 @@ const Home: React.FC = () => { > + State @@ -330,7 +348,17 @@ const Home: React.FC = () => { )} - {loading ? ( + {isRepoTrackerTab ? ( + + ) : loading ? ( From a96d5a12287ee9fc5a6eb88ccdd6f6df6705b018 Mon Sep 17 00:00:00 2001 From: arpit2006 Date: Sun, 31 May 2026 00:06:22 +0530 Subject: [PATCH 2/2] feat(repo-tracker): apply UI & theme changes for Repo Tracker section --- .../RepositoryAnalyticsDashboard.tsx | 181 +++++++++++++----- src/index.css | 104 ++++++++++ src/pages/Tracker/Tracker.tsx | 6 +- 3 files changed, 236 insertions(+), 55 deletions(-) diff --git a/src/components/RepositoryAnalyticsDashboard.tsx b/src/components/RepositoryAnalyticsDashboard.tsx index 906a4613..df8c6ae1 100644 --- a/src/components/RepositoryAnalyticsDashboard.tsx +++ b/src/components/RepositoryAnalyticsDashboard.tsx @@ -57,7 +57,15 @@ interface DashboardProps { theme: Theme; } -const COLORS = ['#2563eb', '#06b6d4', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6']; +// Use CSS variables so the tracker section follows the website theme +const COLORS = [ + 'var(--color-primary)', + 'var(--color-accent)', + 'var(--color-success)', + 'var(--color-danger)', + 'var(--color-accent)', + 'var(--color-primary)' +]; const formatMonthLabel = (date: Date) => date.toLocaleDateString(undefined, { month: 'short', year: 'numeric' }); @@ -182,36 +190,30 @@ const RepositoryAnalyticsDashboard = ({ label: 'Total repositories', value: analytics.repoCount, icon: Database, - accentStart: '#2563eb', - accentEnd: '#06b6d4', + accentStart: 'var(--color-primary)', + accentEnd: 'var(--color-accent)', }, { label: 'Total stars', value: analytics.totalStars, icon: Star, - accentStart: '#f59e0b', - accentEnd: '#f97316', - }, - { - label: 'Total forks', - value: analytics.totalForks, - icon: GitFork, - accentStart: '#10b981', - accentEnd: '#14b8a6', + accentStart: 'var(--color-danger)', + accentEnd: 'var(--color-danger)', }, + // forks card intentionally removed to keep the summary concise and horizontal { label: 'Most used language', value: analytics.mostUsedLanguage, icon: Languages, - accentStart: '#8b5cf6', - accentEnd: '#d946ef', + accentStart: 'var(--color-accent)', + accentEnd: 'var(--color-accent)', }, { label: 'Total contributions', value: totalContributions, icon: Activity, - accentStart: '#0ea5e9', - accentEnd: '#6366f1', + accentStart: 'var(--color-primary)', + accentEnd: 'var(--color-accent)', }, ]; @@ -264,7 +266,7 @@ const RepositoryAnalyticsDashboard = ({ p: { xs: 3, md: 4 }, borderRadius: 6, color: 'white', - background: 'linear-gradient(135deg, rgba(15,23,42,0.98), rgba(29,78,216,0.92) 45%, rgba(8,145,178,0.9))', + background: 'linear-gradient(135deg, var(--color-primary), var(--color-accent))', boxShadow: '0 24px 80px rgba(15,23,42,0.24)', border: '1px solid rgba(255,255,255,0.12)', position: 'relative', @@ -293,7 +295,15 @@ const RepositoryAnalyticsDashboard = ({ - + Track stars, forks, languages, and contribution momentum in one place. @@ -350,13 +360,11 @@ const RepositoryAnalyticsDashboard = ({ @@ -370,7 +378,8 @@ const RepositoryAnalyticsDashboard = ({ sx={{ p: 2.5, borderRadius: 4, - height: '100%', + minWidth: { md: '18%' }, + flex: { xs: '1 1 auto', md: '1 1 0' }, position: 'relative', overflow: 'hidden', background: theme.palette.background.paper, @@ -387,14 +396,36 @@ const RepositoryAnalyticsDashboard = ({ }, }} > - + - + {card.label} - - {card.value} - + { + (() => { + const isLanguage = card.label && card.label.toLowerCase().includes('language'); + const valueFont = isLanguage + ? { xs: '1rem', md: 'clamp(1.1rem, 2.2vw, 1.6rem)' } + : { xs: '1.6rem', md: '2.25rem' }; + return ( + + {card.value} + + ); + })() + } @@ -465,9 +496,9 @@ const RepositoryAnalyticsDashboard = ({ - - - + + + ) : ( @@ -500,28 +531,67 @@ const RepositoryAnalyticsDashboard = ({ {analytics.languageDistribution.length > 0 ? ( - + <> + + {/* compute language total for legend percentages */} + {/* Pie: remove in-chart labels; use bottom legend instead */} `${name} ${percent && percent > 0.1 ? `${Math.round(percent * 100)}%` : ''}`} + label={false} > {analytics.languageDistribution.map((entry, index) => ( ))} - + {/* Legend rendered below the chart (custom) */} - + + + {/* Custom legend placed inside the card so it always stays within bounds */} + + {(() => { + const languageTotal = analytics.languageDistribution.reduce((s, e) => s + (e.value ?? 0), 0); + const topThree = analytics.languageDistribution.slice(0, 3); + const othersCount = analytics.languageDistribution.length - topThree.length; + + return ( + <> + {topThree.map((entry, index) => { + const pct = languageTotal > 0 ? Math.round(((entry.value ?? 0) / languageTotal) * 100) : 0; + const color = COLORS[index % COLORS.length]; + return ( + + + + {entry.name} {pct}% + + + ); + })} + + {othersCount > 0 && ( + + + + +{othersCount} others + + + )} + + ); + })()} + + ) : ( No language data available. @@ -540,7 +610,7 @@ const RepositoryAnalyticsDashboard = ({ background: theme.palette.mode === 'dark' ? 'linear-gradient(180deg, rgba(15,23,42,0.72), rgba(15,23,42,0.94))' - : 'linear-gradient(180deg, #ffffff, #f9fbff)', + : 'linear-gradient(180deg, var(--color-surface), rgba(249,251,255,1))', border: `1px solid ${theme.palette.divider}`, boxShadow: '0 18px 40px rgba(15,23,42,0.06)', }} @@ -559,15 +629,15 @@ const RepositoryAnalyticsDashboard = ({ ({ label: formatWeekLabel(entry.week), commits: entry.commits }))}> - - + + - + ) : ( @@ -601,14 +671,19 @@ const RepositoryAnalyticsDashboard = ({ {analytics.topRepositories.length > 0 ? ( - + - + {/* hide x-axis ticks to avoid overlap; show name on hover via Tooltip */} + - + `Repository: ${label}`} + formatter={(value, name) => [value, name]} + /> - - + + ) : ( diff --git a/src/index.css b/src/index.css index 3f5943c5..e1b03471 100644 --- a/src/index.css +++ b/src/index.css @@ -89,3 +89,107 @@ .icon-issue-closed { color: #cf222e; } + +/* Scoped theme for the Repo Tracker section only */ +.repo-tracker-theme { + --color-primary: #0f3f91; /* deep site blue */ + --color-primary-rgb: 15,63,145; + --color-accent: #17a2d8; + --color-accent-rgb: 23,162,216; + --color-success: #10b981; + --color-success-rgb: 16,185,129; + --color-danger: #f97316; + --color-danger-rgb: 249,115,22; + --color-background: linear-gradient(135deg,#0f3f91 0%, #0ea5e9 50%, #06b6d4 100%); + --color-surface: #ffffff; + --color-text: #071127; + --color-muted: #64748b; +} + +@keyframes how-it-works-dash-flow { + from { + background-position: 0 0; + } + + to { + background-position: 72px 0; + } +} + +@keyframes how-it-works-dash-flow-vertical { + from { + background-position: 0 0; + } + + to { + background-position: 0 72px; + } +} + +.how-it-works-flow-line { + display: block; + height: 2px; + border-radius: 9999px; + background-image: repeating-linear-gradient( + 90deg, + rgba(var(--color-accent-rgb), 0.78) 0, + rgba(var(--color-accent-rgb), 0.78) 14px, + rgba(var(--color-accent-rgb), 0.08) 14px, + rgba(var(--color-accent-rgb), 0.08) 26px + ); + background-size: 28px 2px; + animation: how-it-works-dash-flow 10s linear infinite; + box-shadow: 0 0 18px rgba(var(--color-primary-rgb), 0.24); +} + +.how-it-works-flow-line.light { + background-image: repeating-linear-gradient( + 90deg, + rgba(var(--color-primary-rgb), 0.6) 0, + rgba(var(--color-primary-rgb), 0.6) 12px, + rgba(var(--color-primary-rgb), 0.12) 12px, + rgba(var(--color-primary-rgb), 0.12) 24px + ); + box-shadow: 0 0 14px rgba(var(--color-primary-rgb), 0.14); +} + +.how-it-works-flow-line.vertical { + width: 2px; + height: 100%; + background-image: repeating-linear-gradient( + 180deg, + rgba(var(--color-accent-rgb), 0.78) 0, + rgba(var(--color-accent-rgb), 0.78) 14px, + rgba(var(--color-accent-rgb), 0.08) 14px, + rgba(var(--color-accent-rgb), 0.08) 26px + ); + background-size: 2px 28px; + animation: how-it-works-dash-flow-vertical 10s linear infinite; +} + +.how-it-works-flow-line.vertical.light { + background-image: repeating-linear-gradient( + 180deg, + rgba(var(--color-primary-rgb), 0.6) 0, + rgba(var(--color-primary-rgb), 0.6) 12px, + rgba(var(--color-primary-rgb), 0.12) 12px, + rgba(var(--color-primary-rgb), 0.12) 24px + ); +} + + +.icon-merged { + color: var(--color-success); +} +.icon-pr-open { + color: var(--color-primary); +} +.icon-pr-closed { + color: var(--color-danger); +} +.icon-issue-open { + color: var(--color-success); +} +.icon-issue-closed { + color: var(--color-danger); +} diff --git a/src/pages/Tracker/Tracker.tsx b/src/pages/Tracker/Tracker.tsx index 362ba929..943ea512 100644 --- a/src/pages/Tracker/Tracker.tsx +++ b/src/pages/Tracker/Tracker.tsx @@ -349,7 +349,8 @@ const Home: React.FC = () => { )} {isRepoTrackerTab ? ( - + { analyticsLoading={analyticsLoading} analyticsError={analyticsError} theme={theme} - /> + /> + ) : loading ? (