@cognima/banners 0.0.1-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/assets/fonts/Manrope/Manrope-Bold.ttf +0 -0
  2. package/assets/fonts/Manrope/Manrope-Regular.ttf +0 -0
  3. package/assets/fonts/Others/AbyssinicaSIL-Regular.ttf +0 -0
  4. package/assets/fonts/Others/ChirpRegular.ttf +0 -0
  5. package/assets/fonts/Poppins/Poppins-Bold.ttf +0 -0
  6. package/assets/fonts/Poppins/Poppins-Medium.ttf +0 -0
  7. package/assets/fonts/Poppins/Poppins-Regular.ttf +0 -0
  8. package/assets/placeholders/album_art.png +0 -0
  9. package/assets/placeholders/avatar.png +0 -0
  10. package/assets/placeholders/badge.jpg +0 -0
  11. package/assets/placeholders/badge.png +0 -0
  12. package/assets/placeholders/badge_2.jpg +0 -0
  13. package/assets/placeholders/badge_3.jpg +0 -0
  14. package/assets/placeholders/badge_4.jpg +0 -0
  15. package/assets/placeholders/badge_5.jpg +0 -0
  16. package/assets/placeholders/banner.jpeg +0 -0
  17. package/assets/placeholders/images.jpeg +0 -0
  18. package/index.js +153 -0
  19. package/package.json +34 -0
  20. package/src/animation-effects.js +631 -0
  21. package/src/cache-manager.js +258 -0
  22. package/src/community-banner.js +1536 -0
  23. package/src/constants.js +208 -0
  24. package/src/discord-profile.js +584 -0
  25. package/src/e-commerce-banner.js +1214 -0
  26. package/src/effects.js +355 -0
  27. package/src/error-handler.js +305 -0
  28. package/src/event-banner.js +1319 -0
  29. package/src/facebook-post.js +679 -0
  30. package/src/gradient-welcome.js +430 -0
  31. package/src/image-filters.js +1034 -0
  32. package/src/image-processor.js +1014 -0
  33. package/src/instagram-post.js +504 -0
  34. package/src/interactive-elements.js +1208 -0
  35. package/src/linkedin-post.js +658 -0
  36. package/src/marketing-banner.js +1089 -0
  37. package/src/minimalist-banner.js +892 -0
  38. package/src/modern-profile.js +755 -0
  39. package/src/performance-optimizer.js +216 -0
  40. package/src/telegram-header.js +544 -0
  41. package/src/test-runner.js +645 -0
  42. package/src/tiktok-post.js +713 -0
  43. package/src/twitter-header.js +604 -0
  44. package/src/validator.js +442 -0
  45. package/src/welcome-leave.js +445 -0
  46. package/src/whatsapp-status.js +386 -0
  47. package/src/youtube-thumbnail.js +681 -0
  48. package/utils.js +710 -0
@@ -0,0 +1,430 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Módulo de Banner de Boas-vindas com Gradiente
5
+ *
6
+ * Este módulo gera banners de boas-vindas modernos com gradientes personalizáveis,
7
+ * efeitos de sombra e design minimalista.
8
+ *
9
+ * @author Cognima Team (melhorado)
10
+ * @version 2.0.0
11
+ */
12
+
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+
15
+ const pureimage = require("pureimage");
16
+ const path = require("path");
17
+ const {
18
+ loadImageWithAxios,
19
+ encodeToBuffer,
20
+ roundRect,
21
+ wrapText,
22
+ registerFontIfNeeded,
23
+ isValidHexColor,
24
+ DEFAULT_FONT_FAMILY,
25
+ applyTextShadow,
26
+ clearShadow,
27
+ createLinearGradient,
28
+ hexToRgba
29
+ } = require("../utils");
30
+
31
+ /**
32
+ * @class GradientWelcome
33
+ * @classdesc Gera um banner de boas-vindas moderno com gradientes e design minimalista.
34
+ * @example const welcomeCard = new GradientWelcome()
35
+ * .setAvatar("avatar.png")
36
+ * .setUsername("NovoUsuário")
37
+ * .setMessage("Bem-vindo à nossa comunidade!")
38
+ * .setGradient("#3498db", "#8e44ad", "diagonal")
39
+ * .build();
40
+ */
41
+ module.exports = class GradientWelcome {
42
+ constructor(options) {
43
+ // Dados Principais
44
+ this.avatar = null;
45
+ this.username = "Usuário";
46
+ this.message = "Bem-vindo à comunidade!";
47
+ this.memberCount = null;
48
+
49
+ // Personalização Visual
50
+ this.font = { name: options?.font?.name ?? DEFAULT_FONT_FAMILY, path: options?.font?.path };
51
+ this.gradientStart = "#3498db";
52
+ this.gradientEnd = "#8e44ad";
53
+ this.gradientDirection = "diagonal";
54
+ this.textColor = "#FFFFFF";
55
+ this.secondaryTextColor = "#E0E0E0";
56
+ this.avatarBorderColor = "#FFFFFF";
57
+ this.avatarBorderWidth = 4;
58
+ this.cornerRadius = 30;
59
+ this.useTextShadow = true;
60
+ this.useBlur = true;
61
+ this.blurAmount = 10;
62
+
63
+ // Configurações de Layout
64
+ this.cardWidth = 800;
65
+ this.cardHeight = 300;
66
+ this.avatarSize = 150;
67
+ }
68
+
69
+ // --- Setters para Dados Principais ---
70
+ /**
71
+ * Define a imagem do avatar
72
+ * @param {string|Buffer|Object} image - URL, Buffer ou caminho da imagem do avatar
73
+ * @returns {GradientWelcome} - Instância atual para encadeamento
74
+ */
75
+ setAvatar(image) {
76
+ if (!image) throw new Error("A fonte da imagem do avatar não pode estar vazia.");
77
+ this.avatar = image;
78
+ return this;
79
+ }
80
+
81
+ /**
82
+ * Define o nome de usuário
83
+ * @param {string} name - Nome do usuário
84
+ * @returns {GradientWelcome} - Instância atual para encadeamento
85
+ */
86
+ setUsername(name) {
87
+ if (!name || typeof name !== "string") throw new Error("O nome de usuário deve ser uma string não vazia.");
88
+ this.username = name;
89
+ return this;
90
+ }
91
+
92
+ /**
93
+ * Define o texto da mensagem
94
+ * @param {string} text - Texto da mensagem
95
+ * @returns {GradientWelcome} - Instância atual para encadeamento
96
+ */
97
+ setMessage(text) {
98
+ if (!text || typeof text !== "string") throw new Error("O texto da mensagem deve ser uma string não vazia.");
99
+ this.message = text;
100
+ return this;
101
+ }
102
+
103
+ /**
104
+ * Define o contador de membros
105
+ * @param {number|string} count - Número de membros
106
+ * @returns {GradientWelcome} - Instância atual para encadeamento
107
+ */
108
+ setMemberCount(count) {
109
+ if (count === null || count === undefined) {
110
+ this.memberCount = null;
111
+ return this;
112
+ }
113
+
114
+ if (typeof count !== "number" && typeof count !== "string") {
115
+ throw new Error("O contador de membros deve ser um número ou uma string.");
116
+ }
117
+
118
+ this.memberCount = count.toString();
119
+ return this;
120
+ }
121
+
122
+ // --- Setters para Personalização Visual ---
123
+ /**
124
+ * Define o gradiente de fundo
125
+ * @param {string} startColor - Cor inicial do gradiente (hexadecimal)
126
+ * @param {string} endColor - Cor final do gradiente (hexadecimal)
127
+ * @param {string} direction - Direção do gradiente ('vertical', 'horizontal', 'diagonal')
128
+ * @returns {GradientWelcome} - Instância atual para encadeamento
129
+ */
130
+ setGradient(startColor, endColor, direction = "diagonal") {
131
+ if (!startColor || !isValidHexColor(startColor)) throw new Error("Cor inicial do gradiente inválida. Use o formato hexadecimal.");
132
+ if (!endColor || !isValidHexColor(endColor)) throw new Error("Cor final do gradiente inválida. Use o formato hexadecimal.");
133
+
134
+ const validDirections = ["vertical", "horizontal", "diagonal"];
135
+ if (!validDirections.includes(direction.toLowerCase())) {
136
+ throw new Error(`Direção do gradiente inválida. Use uma das seguintes: ${validDirections.join(", ")}`);
137
+ }
138
+
139
+ this.gradientStart = startColor;
140
+ this.gradientEnd = endColor;
141
+ this.gradientDirection = direction.toLowerCase();
142
+
143
+ return this;
144
+ }
145
+
146
+ /**
147
+ * Define a cor do texto principal
148
+ * @param {string} color - Cor hexadecimal
149
+ * @returns {GradientWelcome} - Instância atual para encadeamento
150
+ */
151
+ setTextColor(color) {
152
+ if (!color || !isValidHexColor(color)) throw new Error("Cor de texto inválida. Use o formato hexadecimal.");
153
+ this.textColor = color;
154
+ return this;
155
+ }
156
+
157
+ /**
158
+ * Define a cor do texto secundário
159
+ * @param {string} color - Cor hexadecimal
160
+ * @returns {GradientWelcome} - Instância atual para encadeamento
161
+ */
162
+ setSecondaryTextColor(color) {
163
+ if (!color || !isValidHexColor(color)) throw new Error("Cor de texto secundário inválida. Use o formato hexadecimal.");
164
+ this.secondaryTextColor = color;
165
+ return this;
166
+ }
167
+
168
+ /**
169
+ * Define a cor da borda do avatar
170
+ * @param {string} color - Cor hexadecimal
171
+ * @returns {GradientWelcome} - Instância atual para encadeamento
172
+ */
173
+ setAvatarBorderColor(color) {
174
+ if (!color || !isValidHexColor(color)) throw new Error("Cor de borda do avatar inválida. Use o formato hexadecimal.");
175
+ this.avatarBorderColor = color;
176
+ return this;
177
+ }
178
+
179
+ /**
180
+ * Define a largura da borda do avatar
181
+ * @param {number} width - Largura da borda em pixels
182
+ * @returns {GradientWelcome} - Instância atual para encadeamento
183
+ */
184
+ setAvatarBorderWidth(width) {
185
+ if (typeof width !== "number" || width < 0) throw new Error("A largura da borda do avatar deve ser um número não negativo.");
186
+ this.avatarBorderWidth = width;
187
+ return this;
188
+ }
189
+
190
+ /**
191
+ * Define o raio dos cantos arredondados
192
+ * @param {number} radius - Raio dos cantos em pixels
193
+ * @returns {GradientWelcome} - Instância atual para encadeamento
194
+ */
195
+ setCornerRadius(radius) {
196
+ if (typeof radius !== "number" || radius < 0) throw new Error("O raio dos cantos deve ser um número não negativo.");
197
+ this.cornerRadius = radius;
198
+ return this;
199
+ }
200
+
201
+ /**
202
+ * Ativa ou desativa a sombra de texto
203
+ * @param {boolean} enabled - Se a sombra de texto deve ser ativada
204
+ * @returns {GradientWelcome} - Instância atual para encadeamento
205
+ */
206
+ enableTextShadow(enabled = true) {
207
+ this.useTextShadow = enabled;
208
+ return this;
209
+ }
210
+
211
+ /**
212
+ * Ativa ou desativa o efeito de desfoque
213
+ * @param {boolean} enabled - Se o desfoque deve ser ativado
214
+ * @param {number} amount - Quantidade de desfoque (1-20)
215
+ * @returns {GradientWelcome} - Instância atual para encadeamento
216
+ */
217
+ enableBlur(enabled = true, amount = 10) {
218
+ this.useBlur = enabled;
219
+
220
+ if (typeof amount === "number" && amount >= 1 && amount <= 20) {
221
+ this.blurAmount = amount;
222
+ }
223
+
224
+ return this;
225
+ }
226
+
227
+ /**
228
+ * Define as dimensões do card
229
+ * @param {number} width - Largura do card em pixels
230
+ * @param {number} height - Altura do card em pixels
231
+ * @returns {GradientWelcome} - Instância atual para encadeamento
232
+ */
233
+ setCardDimensions(width, height) {
234
+ if (typeof width !== "number" || width < 400 || width > 1200) {
235
+ throw new Error("A largura do card deve estar entre 400 e 1200 pixels.");
236
+ }
237
+
238
+ if (typeof height !== "number" || height < 200 || height > 600) {
239
+ throw new Error("A altura do card deve estar entre 200 e 600 pixels.");
240
+ }
241
+
242
+ this.cardWidth = width;
243
+ this.cardHeight = height;
244
+
245
+ return this;
246
+ }
247
+
248
+ /**
249
+ * Define o tamanho do avatar
250
+ * @param {number} size - Tamanho do avatar em pixels
251
+ * @returns {GradientWelcome} - Instância atual para encadeamento
252
+ */
253
+ setAvatarSize(size) {
254
+ if (typeof size !== "number" || size < 80 || size > 250) {
255
+ throw new Error("O tamanho do avatar deve estar entre 80 e 250 pixels.");
256
+ }
257
+
258
+ this.avatarSize = size;
259
+ return this;
260
+ }
261
+
262
+ // --- Método de Construção ---
263
+ /**
264
+ * Constrói o banner e retorna um buffer de imagem
265
+ * @returns {Promise<Buffer>} - Buffer contendo a imagem do banner
266
+ */
267
+ async build() {
268
+ if (!this.avatar) throw new Error("A imagem do avatar deve ser definida usando setAvatar().");
269
+
270
+ // --- Registro de Fonte ---
271
+ const registeredFontName = await registerFontIfNeeded(this.font);
272
+
273
+ // --- Configuração do Canvas ---
274
+ const cardWidth = this.cardWidth;
275
+ const cardHeight = this.cardHeight;
276
+ const avatarSize = this.avatarSize;
277
+ const borderRadius = this.cornerRadius;
278
+ const padding = 40;
279
+
280
+ const canvas = pureimage.make(cardWidth, cardHeight);
281
+ const ctx = canvas.getContext("2d");
282
+
283
+ // --- Desenha Plano de Fundo com Gradiente ---
284
+ ctx.save();
285
+ roundRect(ctx, 0, 0, cardWidth, cardHeight, borderRadius, false, false);
286
+ ctx.clip();
287
+
288
+ // Cria e aplica o gradiente
289
+ const gradient = createLinearGradient(
290
+ ctx,
291
+ 0,
292
+ 0,
293
+ cardWidth,
294
+ cardHeight,
295
+ this.gradientStart,
296
+ this.gradientEnd,
297
+ this.gradientDirection
298
+ );
299
+
300
+ ctx.fillStyle = gradient;
301
+ ctx.fillRect(0, 0, cardWidth, cardHeight);
302
+
303
+ // Adiciona um efeito de "brilho" no canto superior
304
+ ctx.globalAlpha = 0.15;
305
+ ctx.fillStyle = "#FFFFFF";
306
+ ctx.beginPath();
307
+ ctx.arc(cardWidth * 0.2, cardHeight * 0.2, Math.min(cardWidth, cardHeight) * 0.5, 0, Math.PI * 2);
308
+ ctx.fill();
309
+
310
+ ctx.restore();
311
+ ctx.globalAlpha = 1;
312
+
313
+ // --- Desenha Avatar ---
314
+ const avatarX = padding;
315
+ const avatarY = (cardHeight - avatarSize) / 2;
316
+
317
+ // Desenha sombra do avatar
318
+ ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
319
+ ctx.shadowBlur = 15;
320
+ ctx.shadowOffsetX = 0;
321
+ ctx.shadowOffsetY = 5;
322
+
323
+ ctx.save();
324
+ ctx.beginPath();
325
+ ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2, 0, Math.PI * 2);
326
+ ctx.closePath();
327
+ ctx.clip();
328
+
329
+ try {
330
+ const avatarImg = await loadImageWithAxios(this.avatar);
331
+ ctx.drawImage(avatarImg, avatarX, avatarY, avatarSize, avatarSize);
332
+ } catch (e) {
333
+ console.error("Falha ao desenhar imagem do avatar:", e.message);
334
+ ctx.fillStyle = "#555";
335
+ ctx.fillRect(avatarX, avatarY, avatarSize, avatarSize);
336
+ ctx.fillStyle = "#FFF";
337
+ ctx.font = `bold 30px ${registeredFontName}-Bold`;
338
+ ctx.textAlign = "center";
339
+ ctx.textBaseline = "middle";
340
+ ctx.fillText("?", avatarX + avatarSize / 2, avatarY + avatarSize / 2);
341
+ }
342
+
343
+ ctx.restore();
344
+
345
+ // Remove a sombra para os próximos elementos
346
+ clearShadow(ctx);
347
+
348
+ // --- Desenha Borda do Avatar ---
349
+ if (this.avatarBorderColor) {
350
+ ctx.strokeStyle = this.avatarBorderColor;
351
+ ctx.lineWidth = this.avatarBorderWidth;
352
+ ctx.beginPath();
353
+ ctx.arc(avatarX + avatarSize / 2, avatarY + avatarSize / 2, avatarSize / 2 + ctx.lineWidth / 2, 0, Math.PI * 2);
354
+ ctx.stroke();
355
+ ctx.closePath();
356
+ }
357
+
358
+ // --- Desenha Texto --- (À direita do avatar)
359
+ const textX = avatarX + avatarSize + padding;
360
+ const textY = cardHeight / 2 - 40;
361
+ const textMaxWidth = cardWidth - textX - padding;
362
+
363
+ // Mensagem de Boas-vindas
364
+ ctx.fillStyle = this.textColor;
365
+ ctx.font = `bold 36px ${registeredFontName}-Bold`;
366
+ ctx.textAlign = "start";
367
+ ctx.textBaseline = "middle";
368
+
369
+ // Aplica sombra de texto se ativada
370
+ if (this.useTextShadow) {
371
+ applyTextShadow(ctx, "rgba(0, 0, 0, 0.5)", 3, 2, 2);
372
+ }
373
+
374
+ ctx.fillText(this.message, textX, textY);
375
+ wrapText(ctx, this.message, textX, textY, textMaxWidth, 28, registeredFontName);
376
+
377
+ // Remove sombra para o próximo texto
378
+ if (this.useTextShadow) {
379
+ clearShadow(ctx);
380
+ }
381
+
382
+ // Nome de Usuário
383
+ ctx.fillStyle = this.secondaryTextColor;
384
+ ctx.font = `medium 28px ${registeredFontName}-Medium`;
385
+
386
+ // Aplica sombra de texto se ativada
387
+ if (this.useTextShadow) {
388
+ applyTextShadow(ctx, "rgba(0, 0, 0, 0.4)", 2, 1, 1);
389
+ }
390
+
391
+ const usernameText = this.username.length > 25 ? this.username.slice(0, 22) + "..." : this.username;
392
+ ctx.fillText(usernameText, textX, textY + 50);
393
+ wrapText(ctx, usernameText, textX, textY + 50, textMaxWidth, 28, registeredFontName);
394
+
395
+ // Remove sombra para o próximo texto
396
+ if (this.useTextShadow) {
397
+ clearShadow(ctx);
398
+ }
399
+
400
+ // Contador de Membros (se fornecido)
401
+ if (this.memberCount !== null) {
402
+ ctx.fillStyle = this.secondaryTextColor;
403
+ ctx.font = `regular 20px ${registeredFontName}-Regular`;
404
+ ctx.textAlign = "start";
405
+
406
+ // Aplica sombra de texto se ativada
407
+ if (this.useTextShadow) {
408
+ applyTextShadow(ctx, "rgba(0, 0, 0, 0.3)", 2, 1, 1);
409
+ }
410
+
411
+ const memberText = `Membro #${this.memberCount}`;
412
+ ctx.fillText(memberText, textX, textY + 90);
413
+ wrapText(ctx, memberText, textX, textY + 90, textMaxWidth, 28, registeredFontName);
414
+
415
+ // Remove sombra
416
+ if (this.useTextShadow) {
417
+ clearShadow(ctx);
418
+ }
419
+ }
420
+
421
+ // --- Codifica e Retorna Buffer ---
422
+ try {
423
+ return await encodeToBuffer(canvas);
424
+ } catch (err) {
425
+ console.error("Falha ao codificar o card de Boas-vindas com Gradiente:", err);
426
+ throw new Error("Não foi possível gerar o buffer de imagem do card de Boas-vindas com Gradiente.");
427
+ }
428
+ }
429
+ };
430
+