import { useEffect, useState } from "react"; import { GitFork, Loader2, Star, Clock, Lock, Globe, } from "lucide-react"; import { api } from "@/client"; import RepoDrawer from "./repo-drawer"; import type { RepoLinkMatch } from "./repo-link-parser"; type RepoEmbedData = { name: string; description: string | null; default_branch: string; visibility: string; updated_at: string; language: string | null; star_count: number; fork_count: number; topics: string[]; }; function languageColor(lang: string): string { const map: Record = { Rust: "#DEA584", TypeScript: "#3178C6", JavaScript: "#F7DF1E", Python: "#3572A5", Go: "#00ADD8", Java: "#B07219", Kotlin: "#A97BFF", Swift: "#F05138", C: "#555555", "C++": "#F34B7D", "C#": "#178600", Ruby: "#701516", Zig: "#EC915C", Elixir: "#6E4A7E", Haskell: "#5E5086", CSS: "#563D7C", HTML: "#E34C26", Shell: "#89E051", PHP: "#4F5D95", Dart: "#00B4AB", Scala: "#C22D40", R: "#198CE7", Lua: "#000080", Vue: "#41B883", Svelte: "#FF3E00", MDX: "#FCB32C", Dockerfile: "#384D54", Makefile: "#427819", Markdown: "#083FA1", Nix: "#7E7EFF", OCaml: "#3BE133", "Objective-C": "#438EFF", Perl: "#0298C3", Erlang: "#B83998", CMake: "#DA3434", PowerShell: "#012456", SQL: "#E38C00", Solidity: "#AA6746", Terraform: "#7B42BC", }; return map[lang] ?? "#6B7280"; } function formatCount(n: number): string { if (n === 0) return ""; if (n >= 1000) return `${(n / 1000).toFixed(1)}k`; return n.toString(); } function timeAgo(iso: string): string { const diff = Date.now() - new Date(iso).getTime(); const days = Math.floor(diff / 86400000); if (days < 1) return "today"; if (days === 1) return "yesterday"; if (days < 30) return `${days}d ago`; const months = Math.floor(days / 30); if (months < 12) return `${months}mo ago`; return `${Math.floor(months / 12)}y ago`; } export default function RepoEmbedCard({ link }: { link: RepoLinkMatch }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(false); useEffect(() => { let cancelled = false; setLoading(true); setError(false); api .get( `/api/v1/workspace/${link.workspace}/repos/${link.repo}/embed-card`, ) .then((res) => { if (!cancelled) setData(res.data); }) .catch(() => { if (!cancelled) setError(true); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [link.workspace, link.repo]); return (
{loading ? (
Loading repo info…
) : error || !data ? (
{link.repo.charAt(0).toUpperCase()}

{link.workspace}/ {link.repo}

) : ( <>
{data.name.charAt(0).toUpperCase()}

{link.workspace}/ {link.repo}

{data.description && (

{data.description}

)}
{data.language && ( {data.language} )} {data.star_count > 0 && ( {formatCount(data.star_count)} )} {data.fork_count > 0 && ( {formatCount(data.fork_count)} )} {data.visibility === "private" ? ( ) : ( )} {data.visibility === "private" ? "private" : "public"} {data.updated_at ? timeAgo(data.updated_at) : ""}
{data.topics.length > 0 && (
{data.topics.slice(0, 5).map((t) => ( {t} ))}
)} )}
); }