From 69525abb78754f5a8cb57472af0b15de462f1cc6 Mon Sep 17 00:00:00 2001 From: Rohit Ghumare <48523873+rohitg00@users.noreply.github.com> Date: Mon, 2 Feb 2026 17:13:14 +0000 Subject: [PATCH 1/2] feat(website): add dynamic stats from npm and GitHub APIs - Create useStats hook to fetch real-time version, downloads, and stars - Replace hardcoded values in App.tsx stats bar with dynamic data - Replace hardcoded version in Hero.tsx badge with dynamic data - Add 5-minute cache to reduce API calls - Fallback to default values if APIs fail --- docs/skillkit/App.tsx | 9 ++- docs/skillkit/components/Hero.tsx | 4 +- docs/skillkit/hooks/useStats.ts | 119 ++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 docs/skillkit/hooks/useStats.ts diff --git a/docs/skillkit/App.tsx b/docs/skillkit/App.tsx index b110ea16..3219d890 100644 --- a/docs/skillkit/App.tsx +++ b/docs/skillkit/App.tsx @@ -12,6 +12,7 @@ import { Attribution } from './components/Attribution'; import { AdvancedFeatures } from './components/AdvancedFeatures'; import { UseCases } from './components/UseCases'; import { TeamEnterprise } from './components/TeamEnterprise'; +import { useStats } from './hooks/useStats'; const GITHUB_ICON = ( @@ -34,6 +35,8 @@ function scrollToSection(e: React.MouseEvent, sectionId: string): void { } export default function App(): React.ReactElement { + const stats = useStats(); + return (
- +
diff --git a/docs/skillkit/components/Hero.tsx b/docs/skillkit/components/Hero.tsx index fe96e57e..5cf488a6 100644 --- a/docs/skillkit/components/Hero.tsx +++ b/docs/skillkit/components/Hero.tsx @@ -1,6 +1,9 @@ import React, { useState, useEffect } from 'react'; import { Button } from './Button'; -import { useStats } from '../hooks/useStats'; + +interface HeroProps { + version: string; +} const ASCII_LOGO = ` ███████╗██╗ ██╗██╗██╗ ██╗ ██╗ ██╗██╗████████╗ @@ -56,12 +59,11 @@ const COPY_ICON = ( ); -export function Hero(): React.ReactElement { +export function Hero({ version }: HeroProps): React.ReactElement { const [copied, setCopied] = useState(false); const [visibleLines, setVisibleLines] = useState(0); const [typingIndex, setTypingIndex] = useState(0); const [currentText, setCurrentText] = useState(''); - const stats = useStats(); useEffect(() => { if (visibleLines >= TERMINAL_LINES.length) { @@ -128,7 +130,7 @@ export function Hero(): React.ReactElement {
- v{stats.version} + v{version}

diff --git a/docs/skillkit/hooks/useStats.ts b/docs/skillkit/hooks/useStats.ts index ea677a11..b9d4d61c 100644 --- a/docs/skillkit/hooks/useStats.ts +++ b/docs/skillkit/hooks/useStats.ts @@ -80,14 +80,14 @@ export function useStats(): Stats { if (npmResponse.status === 'fulfilled' && npmResponse.value.ok) { const npmData = await npmResponse.value.json(); - if (npmData.downloads) { + if (typeof npmData.downloads === 'number' && Number.isFinite(npmData.downloads)) { downloads = formatDownloads(npmData.downloads); } } if (githubResponse.status === 'fulfilled' && githubResponse.value.ok) { const githubData = await githubResponse.value.json(); - if (githubData.stargazers_count) { + if (typeof githubData.stargazers_count === 'number' && Number.isFinite(githubData.stargazers_count)) { stars = githubData.stargazers_count; } }