|
| 1 | +import { getTheme, getBadgeTheme } from '../utils/themes.js'; |
| 2 | + |
| 3 | +export class BadgeRenderer { |
| 4 | + static generateBadge(username: string, count: number, themeName: string = 'default', customColors?: { |
| 5 | + labelColor?: string; |
| 6 | + labelBackground?: string; |
| 7 | + valueColor?: string; |
| 8 | + valueBackground?: string; |
| 9 | + }): string { |
| 10 | + const theme = getTheme(themeName); |
| 11 | + const badgeTheme = getBadgeTheme(themeName); |
| 12 | + |
| 13 | + const finalLabelColor = customColors?.labelColor || badgeTheme.labelColor; |
| 14 | + const finalLabelBg = customColors?.labelBackground || badgeTheme.labelBackground; |
| 15 | + const finalValueColor = customColors?.valueColor || badgeTheme.valueColor; |
| 16 | + const finalValueBg = customColors?.valueBackground || badgeTheme.valueBackground; |
| 17 | + |
| 18 | + const fontName = theme.fontName || 'Orbitron'; |
| 19 | + const fontFamily = theme.fontFamily || `'${fontName}', 'Ubuntu', 'sans-serif'`; |
| 20 | + |
| 21 | + // Formatted count |
| 22 | + const formattedCount = count.toLocaleString(); |
| 23 | + |
| 24 | + // Calculate widths based on text length (estimations) |
| 25 | + const labelText = "VISITORS"; |
| 26 | + const labelWidth = labelText.length * 8 + 20; |
| 27 | + const countWidth = formattedCount.length * 10 + 20; |
| 28 | + const totalWidth = labelWidth + countWidth; |
| 29 | + const height = 28; |
| 30 | + |
| 31 | + return ` |
| 32 | + <svg width="${totalWidth}" height="${height}" viewBox="0 0 ${totalWidth} ${height}" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 33 | + <defs> |
| 34 | + <filter id="glow" x="-20%" y="-20%" width="140%" height="140%"> |
| 35 | + <feGaussianBlur in="SourceGraphic" stdDeviation="2" result="blur"/> |
| 36 | + <feMerge> |
| 37 | + <feMergeNode in="blur"/> |
| 38 | + <feMergeNode in="SourceGraphic"/> |
| 39 | + </feMerge> |
| 40 | + </filter> |
| 41 | + </defs> |
| 42 | +
|
| 43 | + <style> |
| 44 | + @font-face { |
| 45 | + font-family: '${fontName}'; |
| 46 | + font-style: normal; |
| 47 | + font-weight: 400 900; |
| 48 | + font-display: swap; |
| 49 | + src: url(/fonts/orbitron.woff2) format('woff2'); |
| 50 | + } |
| 51 | + text { |
| 52 | + font-family: ${fontFamily}; |
| 53 | + font-weight: 700; |
| 54 | + text-transform: uppercase; |
| 55 | + letter-spacing: 1px; |
| 56 | + } |
| 57 | + .label-text { |
| 58 | + fill: ${finalLabelColor}; |
| 59 | + font-size: 11px; |
| 60 | + } |
| 61 | + .count-text { |
| 62 | + fill: ${finalValueColor}; |
| 63 | + font-size: 14px; |
| 64 | + } |
| 65 | + </style> |
| 66 | +
|
| 67 | + <!-- Background --> |
| 68 | + <rect width="${totalWidth}" height="${height}" rx="4" fill="${finalValueBg}" stroke="${theme.borderColor}" stroke-width="1" /> |
| 69 | + |
| 70 | + <!-- Label Section --> |
| 71 | + <path d="M 4 1 H ${labelWidth} V ${height - 1} H 4 Q 1 ${height - 1} 1 ${height - 4} V 4 Q 1 1 4 1 Z" fill="${finalLabelBg}" /> |
| 72 | + <text x="${labelWidth / 2}" y="${height / 2 + 4}" text-anchor="middle" class="label-text">${labelText}</text> |
| 73 | + |
| 74 | + <!-- Count Section --> |
| 75 | + <text x="${labelWidth + (countWidth / 2)}" y="${height / 2 + 5}" text-anchor="middle" class="count-text" filter="url(#glow)">${formattedCount}</text> |
| 76 | + |
| 77 | + <!-- Accent Line --> |
| 78 | + <line x1="${labelWidth}" y1="6" x2="${labelWidth}" y2="${height - 6}" stroke="${theme.borderColor}" stroke-width="1" opacity="0.3" /> |
| 79 | + </svg> |
| 80 | + `.trim(); |
| 81 | + } |
| 82 | +} |
0 commit comments