UNPKG

@moontra/moonui-pro

Version:

Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components

426 lines (363 loc) 11.6 kB
import { GitHubRepository, GitHubStats, GitHubActivity, LanguageStats, RateLimitInfo, StarHistory } from "./types" // Cache management const cache = new Map<string, { data: any; timestamp: number; expiresAt: number }>() // Docs mode detection const isDocsMode = () => { return typeof window !== "undefined" && (window.location.pathname.includes("/docs/") || window.location.pathname.includes("/components/")) } // Get cache duration based on mode const getCacheDuration = (defaultDuration: number) => { // Increase cache duration to 30 minutes in docs mode return isDocsMode() ? 1800000 : defaultDuration // 30 minutes : default } // Language colors export const LANGUAGE_COLORS: Record<string, string> = { JavaScript: "#f7df1e", TypeScript: "#3178c6", Python: "#3776ab", Java: "#ed8b00", "C++": "#00599c", "C#": "#239120", Go: "#00add8", Rust: "#000000", Swift: "#fa7343", Kotlin: "#7f52ff", PHP: "#777bb4", Ruby: "#cc342d", HTML: "#e34f26", CSS: "#1572b6", Vue: "#4fc08d", React: "#61dafb", Shell: "#89e051", Dart: "#0175c2", Elixir: "#6e4a7e", Scala: "#c22d40", R: "#198ce7", Julia: "#9558b2", Lua: "#000080", Perl: "#39457e", Haskell: "#5e5086", Clojure: "#db5855", Erlang: "#b83998", Objective_C: "#438eff", // Add more as needed } // API base URL const API_BASE = "https://api.github.com" // Helper to make authenticated requests async function githubFetch(url: string, token?: string): Promise<Response> { const headers: HeadersInit = { Accept: "application/vnd.github.v3+json", } if (token) { headers.Authorization = `token ${token}` } const response = await fetch(url, { headers }) if (response.status === 403 && response.headers.get("X-RateLimit-Remaining") === "0") { const resetTime = parseInt(response.headers.get("X-RateLimit-Reset") || "0") * 1000 const resetDate = new Date(resetTime) throw new Error(`GitHub API rate limit exceeded. Resets at ${resetDate.toLocaleTimeString()}`) } if (!response.ok) { throw new Error(`GitHub API error: ${response.status} ${response.statusText}`) } return response } // Get rate limit info export async function getRateLimitInfo(token?: string): Promise<RateLimitInfo> { const cacheKey = `rate-limit-${token || "public"}` const cached = cache.get(cacheKey) if (cached && cached.expiresAt > Date.now()) { return cached.data } const response = await githubFetch(`${API_BASE}/rate_limit`, token) const data = await response.json() const rateLimitInfo: RateLimitInfo = { limit: data.rate.limit, remaining: data.rate.remaining, reset: data.rate.reset * 1000, used: data.rate.used, } cache.set(cacheKey, { data: rateLimitInfo, timestamp: Date.now(), expiresAt: Date.now() + getCacheDuration(60000), // Docs modunda daha uzun cache }) return rateLimitInfo } // Fetch user repositories export async function fetchUserRepositories( username: string, token?: string, options?: { sort?: string per_page?: number page?: number } ): Promise<GitHubRepository[]> { const params = new URLSearchParams({ sort: options?.sort || "updated", per_page: String(options?.per_page || 100), page: String(options?.page || 1), }) const cacheKey = `repos-${username}-${params.toString()}` const cached = cache.get(cacheKey) if (cached && cached.expiresAt > Date.now()) { return cached.data } const response = await githubFetch(`${API_BASE}/users/${username}/repos?${params}`, token) const repos = await response.json() cache.set(cacheKey, { data: repos, timestamp: Date.now(), expiresAt: Date.now() + getCacheDuration(300000), // 30 minutes in docs mode }) return repos } // Fetch single repository export async function fetchRepository( owner: string, repo: string, token?: string ): Promise<GitHubRepository> { const cacheKey = `repo-${owner}-${repo}` const cached = cache.get(cacheKey) if (cached && cached.expiresAt > Date.now()) { return cached.data } const response = await githubFetch(`${API_BASE}/repos/${owner}/${repo}`, token) const repository = await response.json() cache.set(cacheKey, { data: repository, timestamp: Date.now(), expiresAt: Date.now() + getCacheDuration(300000), // 30 minutes in docs mode }) return repository } // Fetch repository contributors count export async function fetchContributorsCount( owner: string, repo: string, token?: string ): Promise<number> { const cacheKey = `contributors-${owner}-${repo}` const cached = cache.get(cacheKey) if (cached && cached.expiresAt > Date.now()) { return cached.data } try { const response = await githubFetch( `${API_BASE}/repos/${owner}/${repo}/contributors?per_page=1&anon=true`, token ) // Get total count from Link header const linkHeader = response.headers.get("Link") if (linkHeader) { const match = linkHeader.match(/page=(\d+)>; rel="last"/) if (match) { const count = parseInt(match[1]) cache.set(cacheKey, { data: count, timestamp: Date.now(), expiresAt: Date.now() + getCacheDuration(3600000), // 30 minutes in docs mode }) return count } } // If no pagination, count the results const contributors = await response.json() const count = contributors.length cache.set(cacheKey, { data: count, timestamp: Date.now(), expiresAt: Date.now() + getCacheDuration(3600000), // 30 minutes in docs mode }) return count } catch (error) { console.error("Failed to fetch contributors:", error) return 0 } } // Fetch repository star history (limited without token) export async function fetchStarHistory( owner: string, repo: string, token?: string ): Promise<StarHistory[]> { const cacheKey = `star-history-${owner}-${repo}` const cached = cache.get(cacheKey) if (cached && cached.expiresAt > Date.now()) { return cached.data } try { // This is a simplified version - for full star history you'd need // to use the stargazers API with Accept: application/vnd.github.v3.star+json // header and paginate through all results const response = await githubFetch(`${API_BASE}/repos/${owner}/${repo}`, token) const repoData = await response.json() // For now, return current count as single data point const history: StarHistory[] = [{ date: new Date().toISOString(), count: repoData.stargazers_count, repository: repoData.full_name, }] cache.set(cacheKey, { data: history, timestamp: Date.now(), expiresAt: Date.now() + getCacheDuration(3600000), // 30 minutes in docs mode }) return history } catch (error) { console.error("Failed to fetch star history:", error) return [] } } // Calculate repository statistics export function calculateStats(repositories: GitHubRepository[]): GitHubStats { const totalStars = repositories.reduce((sum, repo) => sum + repo.stargazers_count, 0) const totalForks = repositories.reduce((sum, repo) => sum + repo.forks_count, 0) const totalWatchers = repositories.reduce((sum, repo) => sum + repo.watchers_count, 0) const totalIssues = repositories.reduce((sum, repo) => sum + repo.open_issues_count, 0) const avgStarsPerRepo = repositories.length > 0 ? totalStars / repositories.length : 0 const mostStarredRepo = repositories.reduce((max, repo) => repo.stargazers_count > (max?.stargazers_count || 0) ? repo : max , null as GitHubRepository | null) // Calculate language statistics const languageMap = new Map<string, number>() repositories.forEach(repo => { if (repo.language) { languageMap.set(repo.language, (languageMap.get(repo.language) || 0) + 1) } }) const totalRepos = repositories.length const languages: LanguageStats[] = Array.from(languageMap.entries()) .map(([language, count]) => ({ language, count, percentage: (count / totalRepos) * 100, color: LANGUAGE_COLORS[language] || "#6b7280", })) .sort((a, b) => b.count - a.count) // Generate recent activity (mock for now) const recentActivity: GitHubActivity[] = repositories .slice(0, 5) .map(repo => ({ type: "star" as const, repository: repo.full_name, timestamp: repo.updated_at, description: `Repository updated`, })) return { totalStars, totalForks, totalWatchers, totalIssues, avgStarsPerRepo, mostStarredRepo, recentActivity, languages, } } // Format numbers for display export function formatNumber(num: number): string { if (num >= 1000000) { return (num / 1000000).toFixed(1) + "M" } if (num >= 1000) { return (num / 1000).toFixed(1) + "k" } return num.toString() } // Format date for display export function formatDate(dateString: string): string { const date = new Date(dateString) const now = new Date() const diffMs = now.getTime() - date.getTime() const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)) if (diffDays === 0) { const diffHours = Math.floor(diffMs / (1000 * 60 * 60)) if (diffHours === 0) { const diffMinutes = Math.floor(diffMs / (1000 * 60)) return `${diffMinutes} minutes ago` } return `${diffHours} hours ago` } if (diffDays === 1) return "yesterday" if (diffDays < 7) return `${diffDays} days ago` if (diffDays < 30) return `${Math.floor(diffDays / 7)} weeks ago` if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago` return date.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", }) } // Clear cache export function clearCache(pattern?: string): void { if (pattern) { for (const key of cache.keys()) { if (key.includes(pattern)) { cache.delete(key) } } } else { cache.clear() } } // Export data as JSON export function exportData(data: any, filename: string): void { const jsonString = JSON.stringify(data, null, 2) const blob = new Blob([jsonString], { type: "application/json" }) const url = URL.createObjectURL(blob) const link = document.createElement("a") link.href = url link.download = filename document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) } // Export data as CSV export function exportAsCSV(repositories: GitHubRepository[], filename: string): void { const headers = [ "Name", "Owner", "Stars", "Forks", "Watchers", "Issues", "Language", "Description", "URL", "Created", "Updated", ] const rows = repositories.map(repo => [ repo.name, repo.owner.login, repo.stargazers_count, repo.forks_count, repo.watchers_count, repo.open_issues_count, repo.language || "", repo.description || "", repo.html_url, new Date(repo.created_at).toLocaleDateString(), new Date(repo.updated_at).toLocaleDateString(), ]) const csvContent = [ headers.join(","), ...rows.map(row => row.map(cell => `"${cell}"`).join(",")), ].join("\n") const blob = new Blob([csvContent], { type: "text/csv" }) const url = URL.createObjectURL(blob) const link = document.createElement("a") link.href = url link.download = filename document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) }