diff --git a/app/api/widget/[username]/share/combined/route.ts b/app/api/widget/[username]/share/combined/route.ts deleted file mode 100644 index 895269f0..00000000 --- a/app/api/widget/[username]/share/combined/route.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { NextResponse } from 'next/server' -import puppeteer from 'puppeteer' - -export async function GET( - request: Request, - { params }: { params: { username: string } } -) { - const { username } = params - const { searchParams } = new URL(request.url) - const format = searchParams.get('format') - const baseUrl = process.env.NEXT_PUBLIC_GITHUB_WIDGET_URL - - try { - // Fetch all SVGs - const responses = await Promise.all([ - fetch(`${baseUrl}/${username}/share/stats`), - fetch(`${baseUrl}/${username}/share/contributions`) - ]) - - if (!responses.every(r => r.ok)) { - throw new Error(`Failed to fetch widgets: ${responses.map(r => r.status).join(', ')}`) - } - - const svgs = await Promise.all(responses.map(r => r.text())) - - // Extract the inner content of each SVG - const innerContents = svgs.map(svg => { - const match = svg.match(/]*>([\s\S]*)<\/svg>/) - return match ? match[1] : '' - }) - - // Create combined SVG with both stats and contributions stacked - const combinedSvg = ` - - - - - - - ${innerContents[0]} - - - - - ${innerContents[1]} - - ` - - if (format === 'png') { - const browser = await puppeteer.launch({ headless: true }); - let screenshot; - try { - const page = await browser.newPage(); - await page.setViewport({ width: 600, height: 400 }); - await page.setContent(` - - ${combinedSvg} - `); - screenshot = await page.screenshot({ - type: 'png', - clip: { x: 0, y: 0, width: 600, height: 400 } - }); - } finally { - await browser.close(); - } - - return new NextResponse(screenshot, { - headers: { - 'Content-Type': 'image/png', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - }, - }); - } - - return new NextResponse(combinedSvg, { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - }, - }) - } catch (error) { - console.error('Error generating combined widget:', error) - return new NextResponse('Error generating combined image', { status: 500 }) - } -} diff --git a/app/api/widget/[username]/share/contributions/route.ts b/app/api/widget/[username]/share/contributions/route.ts deleted file mode 100644 index 4322ddb8..00000000 --- a/app/api/widget/[username]/share/contributions/route.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { NextResponse } from 'next/server' -import { fetchGitHubStats } from "@/lib/actions/github-actions" -import { batchCheckCache } from '@/lib/redis' -import { generateTopContributions } from '@/lib/actions/ai-actions' - -// Simple loading SVG -const loadingSvg = ` - - - - Loading GitHub Contributions... - -`.trim() - -export async function GET( - request: Request, - { params }: { params: { username: string } } -) { - const { username } = params - - try { - const cachedData = await batchCheckCache(username, false) - const stats = cachedData['github:stats'] || - await fetchGitHubStats(username, false) - - if (!stats) { - return new NextResponse(loadingSvg.replace('Loading GitHub Contributions...', 'GitHub Profile Not Found'), { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }) - } - - // Get top contributions from AI - const contributions = await generateTopContributions( - stats.topRepositories, - username, - false, - false - ) - - // Take top 3 contributions for the widget - const topThree = contributions.slice(0, 3) - - const svg = ` - - - - - - - Top Contributions - - - ${topThree.map((contribution, index) => { - // Split impact text into words and create lines - const words = contribution.impact.split(' '); - let lines = []; - let currentLine = [] as any; - const maxLineLength = 24; // Reduced from 28 - const maxLines = 4; // Reduced from 6 - - words.forEach(word => { - if ((currentLine.concat([word])).join(' ').length > maxLineLength) { - lines.push(currentLine.join(' ')); - currentLine = [word]; - } else { - currentLine.push(word); - } - }); - if (currentLine.length > 0) { - lines.push(currentLine.join(' ')); - } - - // Limit to max lines and add ellipsis if needed - if (lines.length > maxLines) { - lines = lines.slice(0, maxLines - 1); - const lastLine = lines[maxLines - 2]; - if (lastLine.length > maxLineLength - 3) { - lines[maxLines - 2] = lastLine.slice(0, maxLineLength - 3) + '...'; - } else { - lines[maxLines - 2] = lastLine + '...'; - } - } - - // Truncate repo name if too long - const maxRepoLength = 20; // Reduced from 25 - const truncatedRepo = contribution.repo.length > maxRepoLength - ? contribution.repo.slice(0, maxRepoLength - 3) + '...' - : contribution.repo; - - return ` - - - ${lines.map((line, i) => - `${line}` - ).join('')} - - - - - ${truncatedRepo} - - - `}).join('')} - - - - - - - - - - - statsforgit.com - `.trim() - - return new NextResponse(svg, { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }) - } catch (error) { - console.error('Error generating GitHub contributions widget:', error) - return new NextResponse(loadingSvg.replace('Loading GitHub Contributions...', 'Error Loading Contributions'), { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }) - } -} diff --git a/app/api/widget/[username]/share/stats/route.ts b/app/api/widget/[username]/share/stats/route.ts deleted file mode 100644 index 0ad09ab3..00000000 --- a/app/api/widget/[username]/share/stats/route.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { NextResponse } from 'next/server' -import { calculateScores } from '@/lib/calculate-scores' -import { fetchGitHubStats } from "@/lib/actions/github-actions" -import { batchCheckCache } from '@/lib/redis' - -// Simple loading SVG -const loadingSvg = ` - - - - Loading GitHub Stats... - -`.trim() - -export async function GET( - request: Request, - { params }: { params: { username: string } } -) { - const { username } = params - - try { - const cachedData = await batchCheckCache(username, false) - const stats = cachedData['github:stats'] || - await fetchGitHubStats(username, false) - - if (!stats) { - return new NextResponse(loadingSvg.replace('Loading GitHub Stats...', 'GitHub Profile Not Found'), { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }) - } - - // Calculate scores (from cache or compute) - const scores = cachedData['scores'] || - await calculateScores({ - totalCommits: stats.totalCommits, - additions: stats.totalAdditions, - deletions: stats.totalDeletions - }, { - username, - isAuthenticated: false - }) -const svg = ` - - - - - - ${stats.name}'s Github Stats - - - - - - - - Total Commits - - ${stats.totalCommits.toLocaleString()} - - - - - - - - Number Of Lines Added - - ${stats.totalAdditions >= 1000000 ? (stats.totalAdditions/1000000).toFixed(1) + 'M' : (stats.totalAdditions/1000).toFixed(1) + 'k'} - - - - - - Number Of Lines Deleted - - ${stats.totalDeletions >= 1000000 ? (stats.totalDeletions/1000000).toFixed(1) + 'M' : (stats.totalDeletions/1000).toFixed(1) + 'k'} - - - - - - ${scores.score} - rating - - - - - - - - - - - statsforgit.com - `.trim() - - return new NextResponse(svg, { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }) - } catch (error) { - console.error('Error generating GitHub widget:', error) - return new NextResponse(loadingSvg.replace('Loading GitHub Stats...', 'Error Loading Stats'), { - headers: { - 'Content-Type': 'image/svg+xml', - 'Cache-Control': 'max-age=0, s-maxage=3600', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }) - } -} \ No newline at end of file diff --git a/app/globals.css b/app/globals.css index 1dcb0fc6..e47624c9 100644 --- a/app/globals.css +++ b/app/globals.css @@ -75,4 +75,4 @@ body { body { @apply bg-background text-foreground; } -} +} \ No newline at end of file diff --git a/components/stats-page.tsx b/components/stats-page.tsx index 871e3274..533c82f4 100644 --- a/components/stats-page.tsx +++ b/components/stats-page.tsx @@ -110,7 +110,12 @@ export default function StatsPage({ - +