From 67b37924263220ef8193fd8bbfa5f306f0517cb3 Mon Sep 17 00:00:00 2001
From: Rohit Ghumare <48523873+rohitg00@users.noreply.github.com>
Date: Sat, 7 Feb 2026 13:42:08 +0000
Subject: [PATCH] feat: show live Product Hunt upvotes, remove Apache license
from stats bar
---
docs/skillkit/App.tsx | 18 +++++++++---------
docs/skillkit/hooks/useStats.ts | 24 ++++++++++++++++++++++--
2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/docs/skillkit/App.tsx b/docs/skillkit/App.tsx
index 3da0705f..b003567b 100644
--- a/docs/skillkit/App.tsx
+++ b/docs/skillkit/App.tsx
@@ -180,15 +180,15 @@ export default function App(): React.ReactElement {
Featured
-
- ·
-
- Apache 2.0
+ {stats.phUpvotes > 0 && (
+ <>
+ ·
+
+ {stats.phUpvotes}
+ >
+ )}
diff --git a/docs/skillkit/hooks/useStats.ts b/docs/skillkit/hooks/useStats.ts
index b9d4d61c..9775699e 100644
--- a/docs/skillkit/hooks/useStats.ts
+++ b/docs/skillkit/hooks/useStats.ts
@@ -4,6 +4,7 @@ interface Stats {
version: string;
downloads: string;
stars: number;
+ phUpvotes: number;
loading: boolean;
}
@@ -57,6 +58,7 @@ export function useStats(): Stats {
version: '1.9.0',
downloads: '2.4k',
stars: 66,
+ phUpvotes: 0,
loading: true,
});
@@ -69,13 +71,19 @@ export function useStats(): Stats {
async function fetchStats(): Promise {
try {
- const [npmResponse, githubResponse] = await Promise.allSettled([
+ const [npmResponse, githubResponse, phResponse] = await Promise.allSettled([
fetch('https://api.npmjs.org/downloads/point/last-month/skillkit'),
fetch('https://api.github.com/repos/rohitg00/skillkit'),
+ fetch('https://api.producthunt.com/v2/api/graphql', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ query: '{ post(slug: "skillkit-2") { votesCount } }' }),
+ }),
]);
let downloads = '2.4k';
let stars = 66;
+ let phUpvotes = 0;
let version = '1.9.0';
if (npmResponse.status === 'fulfilled' && npmResponse.value.ok) {
@@ -92,6 +100,18 @@ export function useStats(): Stats {
}
}
+ if (phResponse.status === 'fulfilled' && phResponse.value.ok) {
+ try {
+ const phData = await phResponse.value.json();
+ const votes = phData?.data?.post?.votesCount;
+ if (typeof votes === 'number' && Number.isFinite(votes)) {
+ phUpvotes = votes;
+ }
+ } catch {
+ // PH API may require auth, fall back silently
+ }
+ }
+
try {
const registryResponse = await fetch('https://registry.npmjs.org/skillkit/latest');
if (registryResponse.ok) {
@@ -104,7 +124,7 @@ export function useStats(): Stats {
// Use default version
}
- const newStats = { version, downloads, stars };
+ const newStats = { version, downloads, stars, phUpvotes };
setCachedStats(newStats);
setStats({ ...newStats, loading: false });
} catch {