JSPM

@nannoy/git-folio

0.1.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 13
  • Score
    100M100P100Q60954F
  • License MIT

Embeddable GitHub stats card for developer portfolios

Package Exports

  • @nannoy/git-folio
  • @nannoy/git-folio/react

Readme

@nannoy/git-folio

Embeddable GitHub stats card for developer portfolios. No API token required — works entirely with public GitHub data.

Install

npm install @nannoy/git-folio

Quick Start — Vanilla JS

import { fetchGitHubStats } from "@nannoy/git-folio";

const stats = await fetchGitHubStats({ username: "torvalds" });

console.log(stats.totalStars);            // number
console.log(stats.totalCommits);          // number (from GitHub Search API)
console.log(stats.topLanguages);          // LanguageStat[]
console.log(stats.contributionStreak);    // number — consecutive days
console.log(stats.contributionCalendar);  // ContributionWeek[]

React Component

import { GitFolioCard } from "@nannoy/git-folio/react";

export default function Portfolio() {
  return (
    <GitFolioCard
      username="torvalds"
      theme="auto"
      variant="full"
      accentColor="#2dd4bf"
    />
  );
}

How it works (no token)

All data is fetched from public GitHub endpoints in parallel:

Data Source
Profile, repos, stars, forks, followers GitHub REST API (/users/{u}, /users/{u}/repos)
Top languages + colors REST repos list + bundled color map
Commit count GitHub Search API (/search/commits?q=author:{u})
PR count GitHub Search API (/search/issues?q=author:{u}+type:pr)
Issue count GitHub Search API (/search/issues?q=author:{u}+type:issue)
Contribution heatmap, streak github-contributions-api.jogruber.de

Rate limits (unauthenticated):

  • REST API: 60 requests/hour per IP
  • Search API: 10 requests/minute per IP (separate bucket)
  • Contributions proxy: cached 1 hour

For server-side rendering, cache the result and revalidate on a schedule — the built-in cache option handles this: fetchGitHubStats({ username, cache: 3600 }).

React Props

Prop Type Default Description
username string required GitHub username
theme 'light' | 'dark' | 'auto' 'auto' Color theme — auto follows system preference
variant 'compact' | 'full' 'full' compact shows avatar, name, and 4 key stats only
accentColor string #2dd4bf Hex color for accents and heatmap tint
showContributions boolean true Show contribution heatmap
showLanguages boolean true Show top languages bar
className string Extra CSS class on the card element

GitFolioStats type

interface GitFolioStats {
  name: string;
  login: string;
  avatarUrl: string;
  bio: string | null;
  location: string | null;
  websiteUrl: string | null;
  followers: number;
  following: number;
  totalRepositories: number;
  totalStars: number;
  totalForks: number;
  totalCommits: number | null;      // null only if Search API rate-limited
  totalPullRequests: number | null; // null only if Search API rate-limited
  totalIssues: number | null;       // null only if Search API rate-limited
  totalContributions: number;
  topLanguages: LanguageStat[];
  contributionStreak: number;
  contributionCalendar: ContributionWeek[];
}

Error Handling

import { fetchGitHubStats, GitFolioError } from "@nannoy/git-folio";

try {
  const stats = await fetchGitHubStats({ username });
} catch (err) {
  if (err instanceof GitFolioError) {
    console.error(err.code);        // 'RATE_LIMITED' | 'USER_NOT_FOUND' | 'NETWORK_ERROR' | ...
    console.error(err.retryAfter);  // Date | undefined
  }
}
Error code Cause
RATE_LIMITED GitHub REST API rate limit hit
USER_NOT_FOUND Username doesn't exist on GitHub
NETWORK_ERROR DNS / fetch failure
HTTP_ERROR Non-200 GitHub API response
PARSE_ERROR Unexpected response body

Theming

CSS custom properties can be overridden on any ancestor:

.my-portfolio {
  --gf-accent: #a78bfa;
  --gf-accent-rgb: 167, 139, 250;
  --gf-radius: 12px;
  --gf-font: "Inter", sans-serif;
}

License

MIT — github.com/Nannoy/git-folio