diff --git a/apps/dashboard/src/App.css b/apps/dashboard/src/App.css
index d29bf54..c855304 100644
--- a/apps/dashboard/src/App.css
+++ b/apps/dashboard/src/App.css
@@ -323,6 +323,68 @@
border-bottom: 2px solid #e2e8f0;
}
+/* NPM Downloads List */
+.npm-downloads-list-container {
+ margin: 0 auto 2rem auto;
+ border-radius: 0.5rem;
+ border: 1px solid #e2e8f0;
+ background: white;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ max-width: 500px;
+ width: fit-content;
+}
+
+.npm-downloads-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.npm-download-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.5rem 1rem;
+ border-bottom: 1px solid #e2e8f0;
+ transition: all 0.2s ease;
+ cursor: pointer;
+ gap: 0.75rem;
+ min-width: fit-content;
+}
+
+.npm-download-item:hover {
+ background: #f8fafc;
+}
+
+.npm-download-item:focus {
+ outline: 2px solid #3b82f6;
+ outline-offset: -2px;
+ background: #f8fafc;
+}
+
+.npm-download-item:last-child {
+ border-bottom: none;
+}
+
+.npm-download-item .package-name {
+ font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: #374151;
+ background: #f1f5f9;
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.25rem;
+ border: 1px solid #cbd5e1;
+ min-width: fit-content;
+ white-space: nowrap;
+}
+
+.npm-download-item .download-badge {
+ height: auto;
+ max-height: 20px;
+ flex-shrink: 0;
+}
+
/* Responsive Design */
@media (max-width: 768px) {
.page-nav {
@@ -347,6 +409,27 @@
grid-template-columns: 1fr;
}
+ .npm-downloads-list-container {
+ margin-bottom: 1rem;
+ }
+
+ .npm-download-item {
+ padding: 0.75rem;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0.5rem;
+ }
+
+ .npm-download-item .package-name {
+ font-size: 0.875rem;
+ padding: 0.375rem 0.5rem;
+ }
+
+ .npm-download-item .download-badge {
+ max-width: 100%;
+ height: auto;
+ }
+
.library-charts-grid {
padding: 0 1rem;
gap: 1rem;
diff --git a/apps/dashboard/src/App.tsx b/apps/dashboard/src/App.tsx
index 4d6c1dd..bfb704b 100644
--- a/apps/dashboard/src/App.tsx
+++ b/apps/dashboard/src/App.tsx
@@ -2,6 +2,7 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom';
import './App.css';
import Layout from './components/Layout';
import MinificationBenchmarksPage from './pages/MinificationBenchmarksPage';
+import NpmDownloadsPage from './pages/NpmDownloadsPage';
import RolldownStatsPage from './pages/RolldownStatsPage';
function App() {
@@ -11,6 +12,7 @@ function App() {
}>
} />
} />
+ } />
diff --git a/apps/dashboard/src/NpmDownloads.tsx b/apps/dashboard/src/NpmDownloads.tsx
new file mode 100644
index 0000000..60a487e
--- /dev/null
+++ b/apps/dashboard/src/NpmDownloads.tsx
@@ -0,0 +1,84 @@
+interface NpmDownloadsProps {}
+
+// List of npm packages to display download counts for
+const packages = [
+ 'vite',
+ 'rolldown-vite',
+ 'rolldown',
+ 'tsdown',
+ 'oxlint',
+ 'oxc-parser',
+ 'oxc-transform',
+ 'oxc-minify',
+ 'oxc-resolver'
+];
+
+function NpmDownloads({}: NpmDownloadsProps) {
+ const handleCardClick = (packageName: string) => {
+ const npmUrl = `https://www.npmjs.com/package/${packageName}`;
+ window.open(npmUrl, '_blank', 'noopener,noreferrer');
+ };
+
+ return (
+ <>
+
+
+
NPM Weekly Downloads
+
+
+
+ {packages.map((packageName) => (
+ - handleCardClick(packageName)}
+ role="button"
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ handleCardClick(packageName);
+ }
+ }}
+ >
+ {packageName}
+
+
+ ))}
+
+
+
+
+
+
+
Total Packages
+
{packages.length}
+
NPM Packages
+
+
+
Registry
+
NPM
+
Public Registry
+
+
+
Update Frequency
+
Weekly
+
Auto Updated
+
+
+
Data Source
+
Shields.io
+
Live Data
+
+
+
+ >
+ );
+}
+
+export default NpmDownloads;
\ No newline at end of file
diff --git a/apps/dashboard/src/components/Layout.tsx b/apps/dashboard/src/components/Layout.tsx
index 0f2edd9..b4a8581 100644
--- a/apps/dashboard/src/components/Layout.tsx
+++ b/apps/dashboard/src/components/Layout.tsx
@@ -1,4 +1,4 @@
-import { BarChart3, Package, Zap } from 'lucide-react';
+import { BarChart3, Download, Package, Zap } from 'lucide-react';
import { Link, Outlet, useLocation } from 'react-router-dom';
function Layout() {
@@ -30,6 +30,13 @@ function Layout() {
Minification Benchmarks
+
+
+ NPM Downloads
+
{/* Render the current route's component */}
diff --git a/apps/dashboard/src/pages/NpmDownloadsPage.tsx b/apps/dashboard/src/pages/NpmDownloadsPage.tsx
new file mode 100644
index 0000000..816752a
--- /dev/null
+++ b/apps/dashboard/src/pages/NpmDownloadsPage.tsx
@@ -0,0 +1,24 @@
+import { BarChart3 } from 'lucide-react';
+import NpmDownloads from '../NpmDownloads';
+
+function NpmDownloadsPage() {
+ return (
+
+ );
+}
+
+export default NpmDownloadsPage;
\ No newline at end of file