Skip to content

Commit 1378fc8

Browse files
committed
add dependents page
1 parent 65e0312 commit 1378fc8

File tree

3 files changed

+205
-1
lines changed

3 files changed

+205
-1
lines changed

apps/dashboard/src/App.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const DashboardPage = lazy(() => import('./pages/DashboardPage'));
77
const MinificationBenchmarksPage = lazy(() => import('./pages/MinificationBenchmarksPage'));
88
const NpmDownloadsPage = lazy(() => import('./pages/NpmDownloadsPage'));
99
const RolldownStatsPage = lazy(() => import('./pages/RolldownStatsPage'));
10+
const DependentsPage = lazy(() => import('./pages/DependentsPage'));
1011

1112
// Loading component for Suspense fallback
1213
const PageLoader = () => (
@@ -51,6 +52,14 @@ function App() {
5152
</Suspense>
5253
}
5354
/>
55+
<Route
56+
path='dependents'
57+
element={
58+
<Suspense fallback={<PageLoader />}>
59+
<DependentsPage />
60+
</Suspense>
61+
}
62+
/>
5463
</Route>
5564
</Routes>
5665
);

apps/dashboard/src/components/layout/Sidebar.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BarChart3, ChevronLeft, Download, Home, Menu, Package, X, Zap } from 'lucide-react';
1+
import { BarChart3, ChevronLeft, Download, GitBranch, Home, Menu, Package, X, Zap } from 'lucide-react';
22
import { useEffect, useState } from 'react';
33
import { Link, useLocation } from 'react-router-dom';
44

@@ -31,6 +31,11 @@ const navItems: NavItem[] = [
3131
label: 'NPM Downloads',
3232
icon: <Download size={20} />,
3333
},
34+
{
35+
path: '/dependents',
36+
label: 'GitHub Dependents',
37+
icon: <GitBranch size={20} />,
38+
},
3439
];
3540

3641
export function Sidebar() {
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import { PageHeader } from '@vibe/shared';
2+
import { Badge, Card, CardGrid } from '@vibe/ui';
3+
import { GitBranch, Star, Package, Users, ExternalLink } from 'lucide-react';
4+
import dependentsData from '../../../../data/dependents.json';
5+
import { PageContainer } from '../components/layout/PageContainer';
6+
7+
interface Dependent {
8+
url: string;
9+
stars: number;
10+
}
11+
12+
interface DependentsData {
13+
[repo: string]: {
14+
[pkg: string]: Dependent[];
15+
};
16+
}
17+
18+
interface PackageData {
19+
repo: string;
20+
package: string;
21+
dependents: Dependent[];
22+
}
23+
24+
function DependentsPage() {
25+
const data = dependentsData as DependentsData;
26+
27+
// Flatten the data structure to get all packages
28+
const allPackages: PackageData[] = [];
29+
Object.entries(data).forEach(([repo, packages]) => {
30+
Object.entries(packages).forEach(([pkg, dependents]) => {
31+
allPackages.push({
32+
repo,
33+
package: pkg,
34+
dependents
35+
});
36+
});
37+
});
38+
39+
// Calculate stats
40+
const totalRepos = Object.keys(data).length;
41+
const totalPackages = allPackages.length;
42+
const totalDependents = allPackages.reduce((sum, pkg) => sum + pkg.dependents.length, 0);
43+
44+
// Get top dependent across all packages
45+
const allDependents: Array<Dependent & { package: string; repo: string }> = [];
46+
allPackages.forEach(({ repo, package: pkg, dependents }) => {
47+
dependents.forEach(dep => {
48+
allDependents.push({ ...dep, package: pkg, repo });
49+
});
50+
});
51+
const topDependent = allDependents.sort((a, b) => b.stars - a.stars)[0];
52+
53+
return (
54+
<PageContainer>
55+
<PageHeader
56+
icon={<GitBranch className='text-purple-600 dark:text-purple-400' />}
57+
title='GitHub Dependents'
58+
subtitle='Top repositories and packages that depend on our projects'
59+
action={
60+
<Badge variant='info' size='md'>
61+
{totalDependents} Total Dependents
62+
</Badge>
63+
}
64+
/>
65+
66+
{/* Stats Cards */}
67+
<CardGrid className='grid-cols-1 md:grid-cols-4 mb-8'>
68+
<Card className='bg-gradient-to-br from-purple-50 to-purple-100 dark:from-purple-900/20 dark:to-purple-800/20 border-purple-200 dark:border-purple-800'>
69+
<div className='flex items-center justify-between'>
70+
<div>
71+
<p className='text-sm font-medium text-purple-600 dark:text-purple-300'>Repositories</p>
72+
<p className='text-2xl font-bold text-purple-900 dark:text-white'>{totalRepos}</p>
73+
</div>
74+
<GitBranch className='w-8 h-8 text-purple-500' />
75+
</div>
76+
</Card>
77+
78+
<Card className='bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-900/20 dark:to-blue-800/20 border-blue-200 dark:border-blue-800'>
79+
<div className='flex items-center justify-between'>
80+
<div>
81+
<p className='text-sm font-medium text-blue-600 dark:text-blue-300'>Packages</p>
82+
<p className='text-2xl font-bold text-blue-900 dark:text-white'>{totalPackages}</p>
83+
</div>
84+
<Package className='w-8 h-8 text-blue-500' />
85+
</div>
86+
</Card>
87+
88+
<Card className='bg-gradient-to-br from-amber-50 to-amber-100 dark:from-amber-900/20 dark:to-amber-800/20 border-amber-200 dark:border-amber-800'>
89+
<div className='flex items-center justify-between'>
90+
<div>
91+
<p className='text-sm font-medium text-amber-600 dark:text-amber-300'>Top Stars</p>
92+
<p className='text-2xl font-bold text-amber-900 dark:text-white'>
93+
{topDependent ? topDependent.stars.toLocaleString() : '0'}
94+
</p>
95+
</div>
96+
<Star className='w-8 h-8 text-amber-500' />
97+
</div>
98+
</Card>
99+
100+
<Card className='bg-gradient-to-br from-green-50 to-green-100 dark:from-green-900/20 dark:to-green-800/20 border-green-200 dark:border-green-800'>
101+
<div className='flex items-center justify-between'>
102+
<div>
103+
<p className='text-sm font-medium text-green-600 dark:text-green-300'>Total Dependents</p>
104+
<p className='text-2xl font-bold text-green-900 dark:text-white'>{totalDependents}</p>
105+
</div>
106+
<Users className='w-8 h-8 text-green-500' />
107+
</div>
108+
</Card>
109+
</CardGrid>
110+
111+
{/* All Packages in 2 Column Grid */}
112+
<div className='grid grid-cols-1 lg:grid-cols-2 gap-6'>
113+
{allPackages.map(({ repo, package: pkg, dependents }) => (
114+
<Card key={`${repo}/${pkg}`} className='p-6'>
115+
<div className='mb-4 flex items-center justify-between'>
116+
<div className='flex items-center gap-2'>
117+
<Package className='w-4 h-4' />
118+
<span className='text-sm text-slate-600 dark:text-slate-400'>{repo}</span>
119+
</div>
120+
<h3 className='text-lg font-semibold'>
121+
{pkg}
122+
</h3>
123+
<div className='w-20'></div>
124+
</div>
125+
126+
<div className='overflow-x-auto max-h-96 overflow-y-auto'>
127+
<table className='w-full text-sm'>
128+
<thead className='sticky top-0 bg-white dark:bg-slate-900 z-10'>
129+
<tr className='border-b border-slate-200 dark:border-slate-700'>
130+
<th className='text-left py-2 px-2 font-medium text-slate-600 dark:text-slate-400 w-12'>
131+
#
132+
</th>
133+
<th className='text-left py-2 px-2 font-medium text-slate-600 dark:text-slate-400'>
134+
Repository
135+
</th>
136+
<th className='text-right py-2 px-2 font-medium text-slate-600 dark:text-slate-400 w-24'>
137+
Stars
138+
</th>
139+
</tr>
140+
</thead>
141+
<tbody>
142+
{dependents.map((dep, index) => {
143+
const repoName = dep.url.replace('https://github.com/', '');
144+
return (
145+
<tr
146+
key={index}
147+
className={`
148+
border-b border-slate-100 dark:border-slate-800
149+
transition-colors duration-150
150+
${index % 2 === 0
151+
? 'bg-white dark:bg-slate-950'
152+
: 'bg-gray-50/20 dark:bg-slate-900/10'
153+
}
154+
hover:bg-blue-50 dark:hover:bg-blue-950/40
155+
`}
156+
>
157+
<td className='py-2 px-2 text-slate-500 dark:text-slate-400'>
158+
{index + 1}
159+
</td>
160+
<td className='py-2 px-2'>
161+
<a
162+
href={dep.url}
163+
target='_blank'
164+
rel='noopener noreferrer'
165+
className='text-slate-700 dark:text-slate-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors flex items-center gap-1 group'
166+
>
167+
<span className='truncate'>{repoName}</span>
168+
<ExternalLink className='w-3 h-3 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0' />
169+
</a>
170+
</td>
171+
<td className='py-2 px-2 text-right'>
172+
<span className='inline-flex items-center gap-1 text-slate-600 dark:text-slate-400'>
173+
<Star className='w-3 h-3' />
174+
<span className='font-medium'>{dep.stars.toLocaleString()}</span>
175+
</span>
176+
</td>
177+
</tr>
178+
);
179+
})}
180+
</tbody>
181+
</table>
182+
</div>
183+
</Card>
184+
))}
185+
</div>
186+
</PageContainer>
187+
);
188+
}
189+
190+
export default DependentsPage;

0 commit comments

Comments
 (0)