Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions apps/dashboard/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions apps/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -11,6 +12,7 @@ function App() {
<Route path='/' element={<Layout />}>
<Route index element={<RolldownStatsPage />} />
<Route path='minification' element={<MinificationBenchmarksPage />} />
<Route path='npm-downloads' element={<NpmDownloadsPage />} />
</Route>
</Routes>
</BrowserRouter>
Expand Down
84 changes: 84 additions & 0 deletions apps/dashboard/src/NpmDownloads.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<main className='dashboard-main'>
<div className='chart-container'>
<h2>NPM Weekly Downloads</h2>

<div className='npm-downloads-list-container'>
<ul className='npm-downloads-list'>
{packages.map((packageName) => (
<li
key={packageName}
className='npm-download-item'
onClick={() => handleCardClick(packageName)}
role="button"
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleCardClick(packageName);
}
}}
>
<span className='package-name'>{packageName}</span>
<img
className='download-badge'
src={`https://img.shields.io/npm/dw/${packageName}?label=npm`}
alt={`Weekly downloads for ${packageName}`}
loading="lazy"
/>
</li>
))}
</ul>
</div>
</div>

<div className='stats-grid'>
<div className='stat-card'>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot when clicked on the card, open a new tab to the npm package url

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added click functionality to NPM package cards. When clicked, cards now open the corresponding npm package URL (https://www.npmjs.com/package/{package-name}) in a new tab. Also added keyboard navigation support - you can Tab to focus on cards and press Enter or Space to activate them. Added visual feedback with hover effects and focus indicators for better accessibility.

Commit: af0518e

NPM Downloads with Clickable Cards

<h3>Total Packages</h3>
<p className='stat-value'>{packages.length}</p>
<span className='stat-change positive'>NPM Packages</span>
</div>
<div className='stat-card'>
<h3>Registry</h3>
<p className='stat-value'>NPM</p>
<span className='stat-change positive'>Public Registry</span>
</div>
<div className='stat-card'>
<h3>Update Frequency</h3>
<p className='stat-value'>Weekly</p>
<span className='stat-change positive'>Auto Updated</span>
</div>
<div className='stat-card'>
<h3>Data Source</h3>
<p className='stat-value'>Shields.io</p>
<span className='stat-change positive'>Live Data</span>
</div>
</div>
</main>
</>
);
}

export default NpmDownloads;
9 changes: 8 additions & 1 deletion apps/dashboard/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -30,6 +30,13 @@ function Layout() {
<Zap size={20} />
Minification Benchmarks
</Link>
<Link
to='/npm-downloads'
className={`page-button ${location.pathname === '/npm-downloads' ? 'active' : ''}`}
>
<Download size={20} />
NPM Downloads
</Link>
</nav>

{/* Render the current route's component */}
Expand Down
24 changes: 24 additions & 0 deletions apps/dashboard/src/pages/NpmDownloadsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { BarChart3 } from 'lucide-react';
import NpmDownloads from '../NpmDownloads';

function NpmDownloadsPage() {
return (
<div className='dashboard'>
<header className='dashboard-header'>
<div className='header-content'>
<div className='logo'>
<BarChart3 size={28} />
<h1>NPM Downloads</h1>
</div>
<p className='header-subtitle'>
Weekly download statistics for key packages
</p>
</div>
</header>

<NpmDownloads />
</div>
);
}

export default NpmDownloadsPage;