Skip to content
Merged
Changes from 1 commit
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
31 changes: 28 additions & 3 deletions src/components/repo-analytics/RepoAnalyticsExplorer.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
"use client";

import { useCallback, useEffect, useState } from "react";
import RepoCarousel from "./RepoCarousel";
import { ExplorerRepoCardData } from "@/lib/repoAnalytics";
import { toast } from "sonner";

function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}

export default function RepoAnalyticsExplorer() {
const [repos, setRepos] = useState<ExplorerRepoCardData[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);

const fetchRepos = useCallback(() => {
setLoading(true);
setError(null);

fetch("/api/metrics/repo-explorer")
.then((res) => {
if (!res.ok) throw new Error("Failed");
Expand All @@ -32,6 +43,10 @@ export default function RepoAnalyticsExplorer() {
fetchRepos();
}, [fetchRepos]);

const filteredRepos = repos.filter((repo) =>
repo.name?.toLowerCase().includes(debouncedQuery.toLowerCase())
);

return (
<section className="mt-6 min-w-0 overflow-hidden rounded-2xl border border-[var(--border)] bg-[var(--card)] p-4 shadow-sm md:p-6 fade-up transition-all duration-300 hover:shadow-md hover:-translate-y-1">
<div className="mb-6 flex items-center justify-between gap-3">
Expand All @@ -41,6 +56,16 @@ export default function RepoAnalyticsExplorer() {
</div>
</div>

<div className="mb-4">
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search repositories..."
className="w-full rounded-xl border border-[var(--border)] bg-[var(--card)] px-4 py-2 text-sm text-[var(--card-foreground)] placeholder:text-[var(--muted-foreground)] focus:outline-none focus:ring-2 focus:ring-[var(--primary)]"
/>
</div>

{loading ? (
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
{[1, 2, 3].map((i) => <div key={i} className="h-64 animate-pulse rounded-3xl bg-[var(--card-muted)]/50 border border-[var(--border)]" />)}
Expand All @@ -51,7 +76,7 @@ export default function RepoAnalyticsExplorer() {
<button onClick={fetchRepos} className="rounded-xl border border-[var(--destructive-muted-border)] bg-transparent px-4 py-2 text-sm font-medium text-[var(--destructive)] transition-colors hover:bg-[var(--destructive)] hover:text-white">Try again</button>
</div>
) : (
<RepoCarousel repos={repos} />
<RepoCarousel repos={filteredRepos} />
)}
</section>
);
Expand Down
Loading