From 3df651cbd6e5ad4ea1638abaf82b6344e685b797 Mon Sep 17 00:00:00 2001 From: akramj13 <125495000+akramj13@users.noreply.github.com> Date: Sat, 15 Mar 2025 15:21:37 -0400 Subject: [PATCH] updated reddit poster styles --- app/api/generate-poster/route.ts | 283 ++++++++++++++++++++++++------- 1 file changed, 226 insertions(+), 57 deletions(-) diff --git a/app/api/generate-poster/route.ts b/app/api/generate-poster/route.ts index 00a6dbe..730e9ac 100644 --- a/app/api/generate-poster/route.ts +++ b/app/api/generate-poster/route.ts @@ -3,7 +3,7 @@ import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"; import { createCanvas, loadImage } from "canvas"; import path from "path"; import { createClerkClient } from "@clerk/backend"; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from "uuid"; // Initialize S3 Client const s3Client = new S3Client({ @@ -70,52 +70,157 @@ export async function POST(req: Request) { const canvas = createCanvas(width, height); const ctx = canvas.getContext("2d"); - // Set background to white + // Set background to white with a slight border effect ctx.fillStyle = "#ffffff"; ctx.fillRect(0, 0, width, height); - - // Header section (top 250px) - const redditLogo = await loadImage(path.join(process.cwd(), "public", "reddit-logo.png")); - const logoSize = 150; // Slightly smaller logo - const headerPadding = 50; - ctx.drawImage(redditLogo, headerPadding, headerPadding, logoSize, logoSize); - - // Add username with verification badge style - ctx.font = "bold 70px Arial"; + + // Add a subtle rounded rectangle container for the post + const padding = 40; + const cornerRadius = 20; + const containerWidth = width - padding * 2; + const containerHeight = height - padding * 2; + + // Draw rounded rectangle for post container + ctx.beginPath(); + ctx.moveTo(padding + cornerRadius, padding); + ctx.lineTo(padding + containerWidth - cornerRadius, padding); + ctx.arcTo( + padding + containerWidth, + padding, + padding + containerWidth, + padding + cornerRadius, + cornerRadius + ); + ctx.lineTo( + padding + containerWidth, + padding + containerHeight - cornerRadius + ); + ctx.arcTo( + padding + containerWidth, + padding + containerHeight, + padding + containerWidth - cornerRadius, + padding + containerHeight, + cornerRadius + ); + ctx.lineTo(padding + cornerRadius, padding + containerHeight); + ctx.arcTo( + padding, + padding + containerHeight, + padding, + padding + containerHeight - cornerRadius, + cornerRadius + ); + ctx.lineTo(padding, padding + cornerRadius); + ctx.arcTo(padding, padding, padding + cornerRadius, padding, cornerRadius); + ctx.closePath(); + + // Add subtle shadow effect + ctx.shadowColor = "rgba(0, 0, 0, 0.1)"; + ctx.shadowBlur = 15; + ctx.shadowOffsetX = 0; + ctx.shadowOffsetY = 5; + ctx.fillStyle = "#ffffff"; + ctx.fill(); + + // Reset shadow + ctx.shadowColor = "transparent"; + ctx.shadowBlur = 0; + ctx.shadowOffsetX = 0; + ctx.shadowOffsetY = 0; + + // Header section with Reddit styling + const headerPadding = 60; + const headerY = padding + headerPadding; + + // Load and draw Reddit logo (smaller, like a profile picture) + const redditLogo = await loadImage( + path.join(process.cwd(), "public", "reddit-logo.png") + ); + const logoSize = 80; + ctx.drawImage( + redditLogo, + padding + headerPadding, + headerY, + logoSize, + logoSize + ); + + // Add username in Reddit style + ctx.font = "bold 40px Arial"; ctx.fillStyle = "#000000"; ctx.textAlign = "left"; - const usernameX = logoSize + headerPadding + 50; - const usernameY = headerPadding + (logoSize / 2) + 20; - ctx.fillText(`@${subreddit}Book`, usernameX, usernameY); - - // Add verification badge (blue circle) - const usernameWidth = ctx.measureText(`@${subreddit}Book`).width; - const badgeX = usernameX + usernameWidth + 30; - const badgeY = usernameY - 25; + const usernameX = padding + headerPadding + logoSize + 20; + const usernameY = headerY + logoSize / 2; + ctx.fillText(`${subreddit}`, usernameX, usernameY); + + // Add verified badge + const usernameWidth = ctx.measureText(`${subreddit}`).width; + const badgeX = usernameX + usernameWidth + 15; + const badgeY = usernameY - 15; ctx.beginPath(); - ctx.arc(badgeX, badgeY, 30, 0, 2 * Math.PI); + ctx.arc(badgeX, badgeY, 15, 0, 2 * Math.PI); ctx.fillStyle = "#1DA1F2"; ctx.fill(); - + // Add checkmark in verification badge - ctx.font = "bold 40px Arial"; + ctx.font = "bold 20px Arial"; ctx.fillStyle = "#ffffff"; ctx.textAlign = "center"; - ctx.fillText("✓", badgeX, badgeY + 15); - - // Title section (centered in remaining space) - ctx.font = "bold 100px Arial"; // Slightly smaller font + ctx.fillText("✓", badgeX, badgeY + 7); + + // Add view count + ctx.font = "28px Arial"; + ctx.fillStyle = "#6e767d"; + ctx.textAlign = "left"; + ctx.fillText("999,999", usernameX, usernameY + 30); + + // Add audio control visual element (red pause button with waveform) + const audioControlX = width - padding - headerPadding - 200; + const audioControlY = headerY + logoSize / 2 - 20; + + // Pause button (red circle) + ctx.beginPath(); + ctx.arc(audioControlX, audioControlY, 20, 0, 2 * Math.PI); + ctx.fillStyle = "#FF4500"; // Reddit orange-red + ctx.fill(); + + // Pause icon (white) + ctx.fillStyle = "#ffffff"; + ctx.fillRect(audioControlX - 7, audioControlY - 10, 5, 20); + ctx.fillRect(audioControlX + 2, audioControlY - 10, 5, 20); + + // Audio waveform visualization + const waveformWidth = 150; + const waveformHeight = 40; + const waveformX = audioControlX + 40; + const waveformY = audioControlY - waveformHeight / 2; + + // Draw waveform bars + ctx.fillStyle = "#FF4500"; // Reddit orange-red + for (let i = 0; i < 15; i++) { + const barHeight = Math.random() * waveformHeight; + const barWidth = 6; + const barX = waveformX + i * 10; + const barY = waveformY + (waveformHeight - barHeight) / 2; + ctx.fillRect(barX, barY, barWidth, barHeight); + } + + // Title section + const titlePadding = 60; + const titleX = padding + titlePadding; + const titleY = headerY + logoSize + 80; + + // Draw title in Reddit style + ctx.font = "bold 60px Arial"; ctx.fillStyle = "#000000"; - ctx.textAlign = "center"; - + ctx.textAlign = "left"; + // Word wrap the title const words = title.split(" "); let line = ""; let lines = []; - const maxWidth = width - 200; - const titleX = width / 2; // Center horizontally - const titleStartY = 300; // Start below header - + const maxWidth = containerWidth - titlePadding * 2; + for (let word of words) { const testLine = line + word + " "; const metrics = ctx.measureText(testLine); @@ -128,48 +233,113 @@ export async function POST(req: Request) { } lines.push(line); - // Calculate total height of title to center vertically in remaining space - const lineHeight = 120; - const totalTitleHeight = lines.length * lineHeight; - const availableSpace = height - titleStartY - 200; // Space between header and metrics - const titleY = titleStartY + (availableSpace - totalTitleHeight) / 2; - // Draw wrapped title + const lineHeight = 85; lines.forEach((line, i) => { - ctx.fillText(line.trim(), titleX, titleY + (i * lineHeight)); + ctx.fillText(line.trim(), titleX, titleY + i * lineHeight); }); - + // Metrics section (bottom) - const metricY = height - 100; - - // Heart icon + const metricY = height - padding - headerPadding; + + // Heart icon and count ctx.beginPath(); - ctx.arc(120, metricY, 35, 0, 2 * Math.PI); + ctx.arc(padding + headerPadding + 30, metricY, 20, 0, 2 * Math.PI); + ctx.fillStyle = "#ffffff"; + ctx.fill(); ctx.strokeStyle = "#6e767d"; - ctx.lineWidth = 3; + ctx.lineWidth = 2; ctx.stroke(); - + + // Heart shape + const heartX = padding + headerPadding + 30; + const heartY = metricY; + const heartSize = 12; + + ctx.beginPath(); + ctx.moveTo(heartX, heartY + heartSize * 0.3); + ctx.bezierCurveTo( + heartX, + heartY, + heartX - heartSize, + heartY, + heartX - heartSize, + heartY - heartSize * 0.5 + ); + ctx.bezierCurveTo( + heartX - heartSize, + heartY - heartSize * 1.1, + heartX, + heartY - heartSize * 1.1, + heartX, + heartY - heartSize * 0.6 + ); + ctx.bezierCurveTo( + heartX, + heartY - heartSize * 1.1, + heartX + heartSize, + heartY - heartSize * 1.1, + heartX + heartSize, + heartY - heartSize * 0.5 + ); + ctx.bezierCurveTo( + heartX + heartSize, + heartY, + heartX, + heartY, + heartX, + heartY + heartSize * 0.3 + ); + ctx.closePath(); + + ctx.fillStyle = "#6e767d"; + ctx.fill(); + // Like count - ctx.font = "bold 50px Arial"; + ctx.font = "bold 32px Arial"; ctx.fillStyle = "#6e767d"; ctx.textAlign = "left"; - ctx.fillText("99+", 180, metricY + 15); - + ctx.fillText("999+", padding + headerPadding + 70, metricY + 10); + // Comment icon + const commentX = padding + headerPadding + 170; + const commentY = metricY; + ctx.beginPath(); - ctx.arc(320, metricY, 35, 0, 2 * Math.PI); + ctx.arc(commentX, commentY, 20, 0, 2 * Math.PI); + ctx.fillStyle = "#ffffff"; + ctx.fill(); ctx.strokeStyle = "#6e767d"; - ctx.lineWidth = 3; + ctx.lineWidth = 2; ctx.stroke(); - + + // Comment bubble shape + const bubbleSize = 12; + ctx.beginPath(); + ctx.moveTo(commentX - bubbleSize, commentY - bubbleSize); + ctx.lineTo(commentX + bubbleSize, commentY - bubbleSize); + ctx.lineTo(commentX + bubbleSize, commentY + bubbleSize * 0.5); + ctx.lineTo(commentX + bubbleSize * 0.5, commentY + bubbleSize * 0.5); + ctx.lineTo(commentX, commentY + bubbleSize); + ctx.lineTo(commentX, commentY + bubbleSize * 0.5); + ctx.lineTo(commentX - bubbleSize, commentY + bubbleSize * 0.5); + ctx.closePath(); + + ctx.fillStyle = "#6e767d"; + ctx.fill(); + // Comment count - ctx.fillText("99+", 380, metricY + 15); - + ctx.fillText("999+", commentX + 40, metricY + 10); + // Author attribution ctx.font = "28px Arial"; ctx.fillStyle = "#6e767d"; ctx.textAlign = "right"; - ctx.fillText(`Posted by u/${author}`, width - headerPadding, height - headerPadding); + ctx.fillText( + `Posted by u/${author}`, + width - padding - headerPadding, + metricY + 10 + ); // Convert canvas to buffer const buffer = canvas.toBuffer("image/png"); @@ -198,7 +368,6 @@ export async function POST(req: Request) { success: true, poster_file_name, }); - } catch (error) { console.error("Error generating poster:", error); return NextResponse.json( @@ -206,4 +375,4 @@ export async function POST(req: Request) { { status: 500 } ); } -} \ No newline at end of file +}