UNPKG

kiutils

Version:

🎑 (Library) an Javascript library that provide various utilities, including Image manipulation tools, Discord-related utilities, and a logger.

292 lines • 14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Discord = void 0; const canvas_1 = require("@napi-rs/canvas"); const enums_1 = require("../typings/enums"); class Discord { /** * Creates a rank card for Discord users with improved styling * @param {RankData} options - Rank card options * @returns {Promise<Buffer>} The generated rank card as a buffer * @example * const { Discord } = require("kiutils"); * const rankCard = await new Discord().createRankCard({ * username: { name: "User" }, * level: { data: 5, display: true }, * currentXP: { data: 300 }, * requiredXP: { data: 500 } * }); */ async createRankCard(options = {}) { // Default values const rankData = { width: options.width ?? 934, height: options.height ?? 282, background: { type: options.background?.type ?? "color", image: options.background?.image ?? "#23272A" }, progressBar: { rounded: options.progressBar?.rounded ?? true, x: options.progressBar?.x ?? 275.5, y: options.progressBar?.y ?? 170, height: options.progressBar?.height ?? 25, width: options.progressBar?.width ?? 596.5, track: { color: options.progressBar?.track?.color ?? "#484b4e" }, bar: { type: options.progressBar?.bar?.type ?? "color", color: options.progressBar?.bar?.color ?? "#5865F2" // Discord blue } }, overlay: { display: options.overlay?.display ?? true, level: options.overlay?.level ?? 0.3, color: options.overlay?.color ?? "#1E2124" // Darker overlay }, avatar: { source: options.avatar?.source ?? "", x: options.avatar?.x ?? 42, y: options.avatar?.y ?? 45, height: options.avatar?.height ?? 200, width: options.avatar?.width ?? 200 }, status: { width: options.status?.width ?? 5, type: options.status?.type ?? enums_1.StatusType.ONLINE, color: options.status?.color ?? this.getStatusColor(options.status?.type), circle: options.status?.circle ?? true // Set to true by default for a modern look }, rank: { display: options.rank?.display ?? true, data: options.rank?.data ?? 1, textColor: options.rank?.textColor ?? "#ffffff", color: options.rank?.color ?? "#A3A6AA", displayText: options.rank?.displayText ?? "RANK" }, level: { display: options.level?.display ?? true, data: options.level?.data ?? 1, textColor: options.level?.textColor ?? "#ffffff", color: options.level?.color ?? "#A3A6AA", displayText: options.level?.displayText ?? "LEVEL" }, currentXP: { data: options.currentXP?.data ?? 0, color: options.currentXP?.color ?? "#A3A6AA" // More subtle color }, requiredXP: { data: options.requiredXP?.data ?? 100, color: options.requiredXP?.color ?? "#A3A6AA" // More subtle color }, discriminator: { discrim: options.discriminator?.discrim ?? "0000", color: options.discriminator?.color ?? "#A3A6AA" // More subtle color }, username: { name: options.username?.name ?? "User", color: options.username?.color ?? "#ffffff" }, renderEmojis: options.renderEmojis ?? false }; // Create a canvas with the specified dimensions const canvas = (0, canvas_1.createCanvas)(rankData.width, rankData.height); const ctx = canvas.getContext("2d"); // Apply rounded corners to the entire card this.roundRect(ctx, 0, 0, canvas.width, canvas.height, 16); ctx.clip(); // Draw background if (rankData.background.type === "color") { ctx.fillStyle = rankData.background.image || "#23272A"; ctx.fillRect(0, 0, canvas.width, canvas.height); } else if (rankData.background.type === "image" && rankData.background.image) { const backgroundImage = await (0, canvas_1.loadImage)(rankData.background.image); ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height); } // Apply overlay if enabled if (rankData.overlay.display) { ctx.fillStyle = rankData.overlay.color || "#1E2124"; ctx.globalAlpha = rankData.overlay.level || 0.3; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.globalAlpha = 1; } // Draw avatar if provided if (rankData.avatar.source) { try { const avatar = await (0, canvas_1.loadImage)(rankData.avatar.source); // Calculate vertical center position const avatarWidth = rankData.avatar.width || 200; const avatarHeight = rankData.avatar.height || 200; const avatarX = 55; // Fixed left position const avatarY = (rankData.height / 2) - (avatarHeight / 2); // Vertically centered // Create circular avatar ctx.save(); ctx.beginPath(); ctx.arc(avatarX + avatarWidth / 2, avatarY + avatarHeight / 2, avatarWidth / 2, 0, Math.PI * 2); ctx.closePath(); ctx.clip(); // Draw the avatar ctx.drawImage(avatar, avatarX, avatarY, avatarWidth, avatarHeight); // Draw a subtle border around avatar ctx.strokeStyle = "#ffffff26"; ctx.lineWidth = 4; ctx.stroke(); ctx.restore(); // Draw status indicator if (rankData.status.type) { // Position the status at the bottom right of avatar const statusX = avatarX + avatarWidth - 20; const statusY = avatarY + avatarHeight - 20; const statusSize = (rankData.status.width || 5) * 4; // Add status border ctx.beginPath(); ctx.arc(statusX, statusY, statusSize, 0, Math.PI * 2); ctx.fillStyle = "#2A2C31"; ctx.fill(); // Create smaller circle for status ctx.beginPath(); ctx.arc(statusX, statusY, (rankData.status.width || 5) * 3, 0, Math.PI * 2); ctx.fillStyle = rankData.status.color || "#43b581"; ctx.fill(); } } catch (error) { console.error("Failed to load avatar:", error); } } // Draw username with a modern font ctx.font = "bold 32px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.fillStyle = rankData.username.color || "#ffffff"; ctx.textAlign = "left"; // Username placement // const usernameX = (rankData.avatar.x || 0) + (rankData.avatar.width || 0) + 55; // const usernameY = (rankData.avatar.y || 0) + 50; const usernameX = 275; const usernameY = 100; ctx.fillText(rankData.username.name || "User", usernameX, usernameY); // Draw discriminator if available - with smaller modern font if (rankData.discriminator.discrim) { ctx.font = "18px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.fillStyle = rankData.discriminator.color || "#A3A6AA"; const usernameWidth = ctx.measureText(rankData.username.name || "User").width; ctx.fillText(`#${rankData.discriminator.discrim}`, usernameX + usernameWidth + 50, usernameY); } // Draw level info in a more compact format if (rankData.level.display) { // Level label with smaller font ctx.font = "18px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.fillStyle = rankData.level.color || "#A3A6AA"; ctx.textAlign = "left"; ctx.fillText(rankData.level.displayText || "LEVEL", usernameX, usernameY + 35); // Level value with bolder font ctx.font = "bold 24px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.fillStyle = rankData.level.textColor || "#ffffff"; ctx.fillText(`${rankData.level.data}`, usernameX + 70, usernameY + 35); } // Draw rank with improved layout if (rankData.rank.display) { ctx.font = "18px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.fillStyle = rankData.rank.color || "#A3A6AA"; ctx.textAlign = "left"; ctx.fillText(rankData.rank.displayText || "RANK", usernameX + 140, usernameY + 35); ctx.font = "bold 22px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.fillStyle = rankData.rank.textColor || "#ffffff"; ctx.fillText(`#${rankData.rank.data}`, usernameX + 205, usernameY + 35); } // Draw progress bar with improved style ctx.beginPath(); ctx.fillStyle = rankData.progressBar?.track?.color || "#2A2C31"; if (rankData.progressBar.rounded) { // Rounded progress track with slightly elevated look this.roundRect(ctx, rankData.progressBar.x || 0, rankData.progressBar.y || 0, rankData.progressBar.width || 0, rankData.progressBar.height || 0, (rankData.progressBar.height || 0) / 2); } else { // Regular progress track ctx.rect(rankData.progressBar.x || 0, rankData.progressBar.y || 0, rankData.progressBar.width || 0, rankData.progressBar.height || 0); } ctx.fill(); // Calculate progress const progress = Math.min((rankData.currentXP.data || 0) / (rankData.requiredXP.data || 1), 1); const progressWidth = (rankData.progressBar.width || 0) * progress; // Draw progress bar fill - modern style ctx.beginPath(); if (rankData.progressBar.bar?.type === "gradient" && Array.isArray(rankData.progressBar.bar?.color)) { const gradient = ctx.createLinearGradient(rankData.progressBar.x || 0, rankData.progressBar.y || 0, (rankData.progressBar.x || 0) + (rankData.progressBar.width || 0), rankData.progressBar.y || 0); const colors = rankData.progressBar.bar.color; colors.forEach((color, index) => { gradient.addColorStop(index / (colors.length - 1), color); }); ctx.fillStyle = gradient; } else { const barColor = Array.isArray(rankData.progressBar.bar?.color) ? rankData.progressBar.bar?.color[0] : rankData.progressBar.bar?.color; ctx.fillStyle = barColor || "#5865F2"; // Discord blue } if (rankData.progressBar.rounded) { // Rounded progress fill - modern look this.roundRect(ctx, rankData.progressBar.x || 0, rankData.progressBar.y || 0, progressWidth, rankData.progressBar.height || 0, (rankData.progressBar.height || 0) / 2); } else { // Regular progress fill ctx.rect(rankData.progressBar.x || 0, rankData.progressBar.y || 0, progressWidth, rankData.progressBar.height || 0); } ctx.fill(); // Draw XP text with smaller, cleaner font ctx.font = "bold 16px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; ctx.textAlign = "left"; ctx.fillStyle = rankData.currentXP.color || "#A3A6AA"; ctx.fillText(`XP: ${rankData.currentXP.data || 0} / ${rankData.requiredXP.data || 0}`, rankData.progressBar.x || 0, (rankData.progressBar.y || 0) + (rankData.progressBar.height || 0) + 20); // Add percentage display on the right side ctx.textAlign = "right"; ctx.fillText(`${Math.round(progress * 100)}%`, (rankData.progressBar.x || 0) + (rankData.progressBar.width || 0), (rankData.progressBar.y || 0) + (rankData.progressBar.height || 0) + 20); return canvas.toBuffer("image/png"); } /** * Utility function to draw rounded rectangles * @private */ roundRect(ctx, x, y, width, height, radius) { if (width < 2 * radius) radius = width / 2; if (height < 2 * radius) radius = height / 2; ctx.beginPath(); ctx.moveTo(x + radius, y); ctx.arcTo(x + width, y, x + width, y + height, radius); ctx.arcTo(x + width, y + height, x, y + height, radius); ctx.arcTo(x, y + height, x, y, radius); ctx.arcTo(x, y, x + width, y, radius); ctx.closePath(); } /** * Get default color based on status type * @private */ getStatusColor(statusType) { switch (statusType) { case enums_1.StatusType.ONLINE: case "online": return "#43b581"; case enums_1.StatusType.DND: case "dnd": return "#f04747"; case enums_1.StatusType.IDLE: case "idle": return "#faa61a"; case enums_1.StatusType.STREAMING: case "streaming": return "#6441a5"; case enums_1.StatusType.OFFLINE: case "offline": return "#747f8d"; default: return "#43b581"; // Default to online } } } exports.Discord = Discord; //# sourceMappingURL=discord.js.map