Skip to content

Commit ddbed83

Browse files
CopilotBoshen
andcommitted
Add NPM Downloads page with shields.io badges
Co-authored-by: Boshen <[email protected]>
1 parent 136486b commit ddbed83

File tree

5 files changed

+151
-1
lines changed

5 files changed

+151
-1
lines changed

apps/dashboard/src/App.css

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,52 @@
323323
border-bottom: 2px solid #e2e8f0;
324324
}
325325

326+
/* NPM Downloads Grid */
327+
.npm-downloads-grid {
328+
display: grid;
329+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
330+
gap: 1.5rem;
331+
margin-bottom: 2rem;
332+
}
333+
334+
.npm-download-card {
335+
background: white;
336+
border: 1px solid #e2e8f0;
337+
padding: 1.5rem;
338+
border-radius: 0.75rem;
339+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
340+
transition: all 0.2s ease;
341+
text-align: center;
342+
}
343+
344+
.npm-download-card:hover {
345+
transform: translateY(-2px);
346+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
347+
}
348+
349+
.package-name {
350+
margin: 0 0 1rem 0;
351+
color: #1e293b;
352+
font-size: 1.125rem;
353+
font-weight: 600;
354+
font-family: 'Courier New', Courier, monospace;
355+
background: #f8fafc;
356+
padding: 0.5rem 1rem;
357+
border-radius: 0.375rem;
358+
border: 1px solid #e2e8f0;
359+
}
360+
361+
.download-badge {
362+
display: flex;
363+
justify-content: center;
364+
align-items: center;
365+
}
366+
367+
.download-badge img {
368+
max-width: 100%;
369+
height: auto;
370+
}
371+
326372
/* Responsive Design */
327373
@media (max-width: 768px) {
328374
.page-nav {
@@ -347,6 +393,11 @@
347393
grid-template-columns: 1fr;
348394
}
349395

396+
.npm-downloads-grid {
397+
grid-template-columns: 1fr;
398+
gap: 1rem;
399+
}
400+
350401
.library-charts-grid {
351402
padding: 0 1rem;
352403
gap: 1rem;

apps/dashboard/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom';
22
import './App.css';
33
import Layout from './components/Layout';
44
import MinificationBenchmarksPage from './pages/MinificationBenchmarksPage';
5+
import NpmDownloadsPage from './pages/NpmDownloadsPage';
56
import RolldownStatsPage from './pages/RolldownStatsPage';
67

78
function App() {
@@ -11,6 +12,7 @@ function App() {
1112
<Route path='/' element={<Layout />}>
1213
<Route index element={<RolldownStatsPage />} />
1314
<Route path='minification' element={<MinificationBenchmarksPage />} />
15+
<Route path='npm-downloads' element={<NpmDownloadsPage />} />
1416
</Route>
1517
</Routes>
1618
</BrowserRouter>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
interface NpmDownloadsProps {}
2+
3+
// List of npm packages to display download counts for
4+
const packages = [
5+
'vite',
6+
'rolldown-vite',
7+
'rolldown',
8+
'tsdown',
9+
'oxlint',
10+
'oxc-parser',
11+
'oxc-transform',
12+
'oxc-minify',
13+
'oxc-resolver'
14+
];
15+
16+
function NpmDownloads({}: NpmDownloadsProps) {
17+
return (
18+
<>
19+
<main className='dashboard-main'>
20+
<div className='chart-container'>
21+
<h2>NPM Weekly Downloads</h2>
22+
23+
<div className='npm-downloads-grid'>
24+
{packages.map((packageName) => (
25+
<div key={packageName} className='npm-download-card'>
26+
<h3 className='package-name'>{packageName}</h3>
27+
<div className='download-badge'>
28+
<img
29+
src={`https://img.shields.io/npm/dw/${packageName}?label=npm`}
30+
alt={`Weekly downloads for ${packageName}`}
31+
loading="lazy"
32+
/>
33+
</div>
34+
</div>
35+
))}
36+
</div>
37+
</div>
38+
39+
<div className='stats-grid'>
40+
<div className='stat-card'>
41+
<h3>Total Packages</h3>
42+
<p className='stat-value'>{packages.length}</p>
43+
<span className='stat-change positive'>NPM Packages</span>
44+
</div>
45+
<div className='stat-card'>
46+
<h3>Registry</h3>
47+
<p className='stat-value'>NPM</p>
48+
<span className='stat-change positive'>Public Registry</span>
49+
</div>
50+
<div className='stat-card'>
51+
<h3>Update Frequency</h3>
52+
<p className='stat-value'>Weekly</p>
53+
<span className='stat-change positive'>Auto Updated</span>
54+
</div>
55+
<div className='stat-card'>
56+
<h3>Data Source</h3>
57+
<p className='stat-value'>Shields.io</p>
58+
<span className='stat-change positive'>Live Data</span>
59+
</div>
60+
</div>
61+
</main>
62+
</>
63+
);
64+
}
65+
66+
export default NpmDownloads;

apps/dashboard/src/components/Layout.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BarChart3, Package, Zap } from 'lucide-react';
1+
import { BarChart3, Download, Package, Zap } from 'lucide-react';
22
import { Link, Outlet, useLocation } from 'react-router-dom';
33

44
function Layout() {
@@ -30,6 +30,13 @@ function Layout() {
3030
<Zap size={20} />
3131
Minification Benchmarks
3232
</Link>
33+
<Link
34+
to='/npm-downloads'
35+
className={`page-button ${location.pathname === '/npm-downloads' ? 'active' : ''}`}
36+
>
37+
<Download size={20} />
38+
NPM Downloads
39+
</Link>
3340
</nav>
3441

3542
{/* Render the current route's component */}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { BarChart3 } from 'lucide-react';
2+
import NpmDownloads from '../NpmDownloads';
3+
4+
function NpmDownloadsPage() {
5+
return (
6+
<div className='dashboard'>
7+
<header className='dashboard-header'>
8+
<div className='header-content'>
9+
<div className='logo'>
10+
<BarChart3 size={28} />
11+
<h1>NPM Downloads</h1>
12+
</div>
13+
<p className='header-subtitle'>
14+
Weekly download statistics for key packages
15+
</p>
16+
</div>
17+
</header>
18+
19+
<NpmDownloads />
20+
</div>
21+
);
22+
}
23+
24+
export default NpmDownloadsPage;

0 commit comments

Comments
 (0)