Stats
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
|
|
||||||
|
var lastGitRequest = new Date("2023-01-10T12:00:00Z");
|
||||||
|
var stats = { stars: 0, forks: 0, contributors: 0 };
|
||||||
|
|
||||||
|
async function getStats() {
|
||||||
|
let page = 0;
|
||||||
|
let stars = 0;
|
||||||
|
let forks = 0;
|
||||||
|
let contributors = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const res = await fetch(
|
||||||
|
`https://api.github.com/users/orus-dev/repos?per_page=100&page=${page}`
|
||||||
|
);
|
||||||
|
const repos = await res.json();
|
||||||
|
|
||||||
|
if (repos.length === 0) break;
|
||||||
|
|
||||||
|
for (const repo of repos) {
|
||||||
|
stars += repo.stargazers_count;
|
||||||
|
forks += repo.forks_count;
|
||||||
|
const conRes = await fetch(repo.contributors_url);
|
||||||
|
contributors += (await conRes.json()).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { stars, forks, contributors };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GET(req: NextRequest) {
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
if (now.getTime() - lastGitRequest.getTime() > 60 * 60 * 1000) {
|
||||||
|
stats = await getStats();
|
||||||
|
lastGitRequest = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json(stats);
|
||||||
|
}
|
||||||
@@ -12,15 +12,31 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import WebStuff from "@/components/Web";
|
import WebStuff from "@/components/Web";
|
||||||
import projects from "@/lib/projects";
|
import projects from "@/lib/projects";
|
||||||
|
import formatNumber from "@/lib/formatNumber";
|
||||||
|
|
||||||
export default function ProjectsPage() {
|
export default function ProjectsPage() {
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
const [activeFilter, setActiveFilter] = useState("all");
|
const [activeFilter, setActiveFilter] = useState("all");
|
||||||
|
const [orgStats, setOrgStats] = useState({
|
||||||
|
contributors: 0,
|
||||||
|
stars: 0,
|
||||||
|
forks: 0,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMounted(true);
|
setMounted(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchStats() {
|
||||||
|
const res = await fetch(`/api/stats`);
|
||||||
|
|
||||||
|
setOrgStats(await res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchStats();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filters = [
|
const filters = [
|
||||||
{ id: "all", label: "All Projects" },
|
{ id: "all", label: "All Projects" },
|
||||||
{ id: "security", label: "Security" },
|
{ id: "security", label: "Security" },
|
||||||
@@ -221,9 +237,12 @@ export default function ProjectsPage() {
|
|||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||||||
{[
|
{[
|
||||||
{ label: "Projects", value: `${projects.length}+` },
|
{ label: "Projects", value: `${projects.length}+` },
|
||||||
{ label: "Contributors", value: "180+" },
|
{
|
||||||
{ label: "Stars", value: "12.5K+" },
|
label: "Contributors",
|
||||||
{ label: "Forks", value: "2.1K+" },
|
value: `${formatNumber(orgStats.contributors)}+`,
|
||||||
|
},
|
||||||
|
{ label: "Stars", value: `${formatNumber(orgStats.stars)}+` },
|
||||||
|
{ label: "Forks", value: `${formatNumber(orgStats.forks)}+` },
|
||||||
].map((stat, i) => (
|
].map((stat, i) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={i}
|
key={i}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export default function formatNumber(num: number): string {
|
||||||
|
if (num < 1000) return num.toString();
|
||||||
|
if (num < 1_000_000)
|
||||||
|
return (num / 1000).toFixed(num % 1000 === 0 ? 0 : 1) + "k";
|
||||||
|
return (num / 1_000_000).toFixed(num % 1_000_000 === 0 ? 0 : 1) + "M";
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user