mirror of
https://github.com/ahmadk953/poixpixel-discord-bot.git
synced 2025-06-22 22:24:20 +00:00
115 lines
2.8 KiB
TypeScript
115 lines
2.8 KiB
TypeScript
import Canvas, { GlobalFonts } from '@napi-rs/canvas';
|
|
import { AttachmentBuilder } from 'discord.js';
|
|
import path from 'path';
|
|
|
|
import * as schema from '@/db/schema.js';
|
|
import { drawMultilineText, roundRect } from './helpers.js';
|
|
|
|
const __dirname = path.resolve();
|
|
|
|
/**
|
|
* Generates an achievement card for a user
|
|
* TODO: Make this look better
|
|
* @param achievement - The achievement to generate a card for
|
|
* @returns - The generated card as an AttachmentBuilder
|
|
*/
|
|
export async function generateAchievementCard(
|
|
achievement: schema.achievementDefinitionsTableTypes,
|
|
): Promise<AttachmentBuilder> {
|
|
GlobalFonts.registerFromPath(
|
|
path.join(__dirname, 'assets', 'fonts', 'Manrope-Bold.ttf'),
|
|
'Manrope Bold',
|
|
);
|
|
GlobalFonts.registerFromPath(
|
|
path.join(__dirname, 'assets', 'fonts', 'Manrope-Regular.ttf'),
|
|
'Manrope',
|
|
);
|
|
|
|
const width = 600;
|
|
const height = 180;
|
|
const canvas = Canvas.createCanvas(width, height);
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
const gradient = ctx.createLinearGradient(0, 0, width, 0);
|
|
gradient.addColorStop(0, '#5865F2');
|
|
gradient.addColorStop(1, '#EB459E');
|
|
ctx.fillStyle = gradient;
|
|
roundRect({ ctx, x: 0, y: 0, width, height, radius: 16, fill: true });
|
|
|
|
ctx.lineWidth = 4;
|
|
ctx.strokeStyle = '#FFFFFF';
|
|
roundRect({
|
|
ctx,
|
|
x: 2,
|
|
y: 2,
|
|
width: width - 4,
|
|
height: height - 4,
|
|
radius: 16,
|
|
fill: false,
|
|
});
|
|
|
|
const padding = 40;
|
|
const iconSize = 72;
|
|
const iconX = padding;
|
|
const iconY = height / 2 - iconSize / 2;
|
|
|
|
try {
|
|
const iconImage = await Canvas.loadImage(
|
|
achievement.imageUrl ||
|
|
path.join(__dirname, 'assets', 'images', 'trophy.png'),
|
|
);
|
|
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
ctx.arc(
|
|
iconX + iconSize / 2,
|
|
iconY + iconSize / 2,
|
|
iconSize / 2,
|
|
0,
|
|
Math.PI * 2,
|
|
);
|
|
ctx.clip();
|
|
ctx.drawImage(iconImage, iconX, iconY, iconSize, iconSize);
|
|
ctx.restore();
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(
|
|
iconX + iconSize / 2,
|
|
iconY + iconSize / 2,
|
|
iconSize / 2 + 4,
|
|
0,
|
|
Math.PI * 2,
|
|
);
|
|
ctx.lineWidth = 3;
|
|
ctx.strokeStyle = '#FFFFFF';
|
|
ctx.stroke();
|
|
} catch (e) {
|
|
console.error('Error loading icon:', e);
|
|
}
|
|
|
|
const textX = iconX + iconSize + 24;
|
|
const titleY = 60;
|
|
const nameY = titleY + 35;
|
|
const descY = nameY + 34;
|
|
|
|
ctx.fillStyle = '#FFFFFF';
|
|
|
|
ctx.font = '22px "Manrope Bold"';
|
|
ctx.fillText('Achievement Unlocked!', textX, titleY);
|
|
|
|
ctx.font = '32px "Manrope Bold"';
|
|
ctx.fillText(achievement.name, textX, nameY);
|
|
|
|
ctx.font = '20px "Manrope"';
|
|
drawMultilineText(
|
|
ctx,
|
|
achievement.description,
|
|
textX,
|
|
descY,
|
|
width - textX - 32,
|
|
24,
|
|
);
|
|
|
|
const buffer = canvas.toBuffer('image/png');
|
|
return new AttachmentBuilder(buffer, { name: 'achievement.png' });
|
|
}
|