From ec9359fb0aefa44c056306d0e128a6e8b6856ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mih=C3=A1ly=20Andr=C3=A1s=20T=C3=B3th?= Date: Wed, 9 Jul 2025 12:38:10 +0200 Subject: [PATCH] static badge positions working, updae optionals field of the README --- README.md | 18 ++++---- index.js | 124 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 95 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 62411fa..1011c16 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ BadgeDex Az alábbi paraméterekkel szabályozhatod a `/badge` végpont működését: -| Paraméter | Alapértelmezett érték | Leírás | Példa értékek | -|-------------|-----------------------|----------------------------------------------------------------------------------------|------------------------------| -| `icon` | `portainer` | A SimpleIcons ikon neve (kisbetű, kötőjellel). | `github`, `docker`, `nginx` | -| `label` | `Portainer` | A badge-en megjelenő szöveg. | `MyApp`, `Status` | -| `bg` | `#f0f0f0` | Háttérszín (hex vagy CSS színnév). | `#fff`, `#222`, `red` | -| `color` | `#000000` | Szöveg színe (hex vagy CSS színnév). Harmonizál az icon szinével ha nem kérünk külön. | `#333`, `white` | -| `size` | `24` | Ikon (és badge) magassága pixelben. | `16`, `32`, `64` | -| `labelpos` | `right` | Szöveg pozíciója az ikonhoz képest: `right`, `left`, `above`, `below`. | `left`, `above` | -| `fontweight`| `normal` | Szöveg vastagsága (`normal`, `bold`, `lighter`, szám is lehet pl. `600`). | `bold`, `600` | +| Paraméter | Kötelező | Alapértelmezett érték | Leírás | Példa értékek | +|-------------|----------|-----------------------|----------------------------------------------------------------------------------------|------------------------------| +| `icon` | Igen |`simpleicons` | A SimpleIcons ikon neve (kisbetű, kötőjellel). | `github`, `docker`, `nginx` | +| `label` | Nem |`Simple Icons` | A badge-en megjelenő szöveg. | `MyApp`, `Status` | +| `bg` | Nem |`#f0f0f0` | Háttérszín (hex vagy CSS színnév). | `#fff`, `#222`, `red` | +| `color` | Nem |`#000000` | Szöveg színe (hex vagy CSS színnév). Harmonizál az icon szinével ha nem kérünk külön. | `#333`, `white` | +| `size` | Nem |`24` | Ikon (és badge) magassága pixelben. | `16`, `32`, `64` | +| `labelpos` | Nem | `right` | Szöveg pozíciója az ikonhoz képest: `right`, `left`, `above`, `below`. | `left`, `above` | +| `fontweight`| Nem | `normal` | Szöveg vastagsága (`normal`, `bold`, `lighter`, szám is lehet pl. `600`). | `bold`, `600` | ## Példák diff --git a/index.js b/index.js index 8e74e13..6073eb5 100644 --- a/index.js +++ b/index.js @@ -6,13 +6,14 @@ const PORT = process.env.PORT || 3000; app.get('/badge', async (req, res) => { const { - icon = 'portainer', - label = 'Portainer', - bg = '#f0f0f0', + icon = 'simpleicons', + label = 'Simple Icons', + bgicon = '#cccccc', // ikon háttérszín, alap: világosszürke + bglabel = '#444444', // label háttérszín, alap: sötétszürke color = '#000000', size = 24, - labelpos = 'right', // lehet: 'right', 'left', 'above', 'below' - fontweight = 'normal', // új paraméter, alapértelmezett: normal + labelpos = 'right', + fontweight = 'normal', } = req.query; try { @@ -24,6 +25,36 @@ app.get('/badge', async (req, res) => { } const iconSVG = iconResponse.data; + // Ha nincs label paraméter, akkor az ikon SVG mezőjét használjuk + let effectiveLabel = label; + if (!req.query.label || req.query.label === 'Simple Icons') { + const titleMatch = iconSVG.match(/<title>([^<]+)<\/title>/i); + if (titleMatch && titleMatch[1]) { + effectiveLabel = titleMatch[1]; + } + } + + // Badge méretek + const padding = 10; + const iconSize = parseInt(size); + const fontSize = Math.round(iconSize * 0.6); // Font size az ikon méret 60%-a + const textPadding = Math.round(iconSize * 0.4); // Dinamikus: size 40%-a + const radius = 8; + const approxCharWidth = fontSize * 0.6; + const textWidth = effectiveLabel.length * approxCharWidth; + + // Kinyerjük az ikon SVG-ből a width és height attribútumokat (ha vannak) + let iconViewBoxWidth = iconSize; + let iconViewBoxHeight = iconSize; + const widthMatch = iconSVG.match(/width="(\d+\.?\d*)"/); + const heightMatch = iconSVG.match(/height="(\d+\.?\d*)"/); + if (widthMatch) iconViewBoxWidth = parseFloat(widthMatch[1]); + if (heightMatch) iconViewBoxHeight = parseFloat(heightMatch[1]); + + // Ikon doboz mérete + const iconBoxWidth = iconViewBoxWidth + 5; + const iconBoxHeight = iconViewBoxHeight + 5; + // Ha a color paraméter nincs megadva, próbáljuk kinyerni az ikon színét let effectiveColor = color; if (!req.query.color || req.query.color === '#000000') { @@ -43,46 +74,64 @@ app.get('/badge', async (req, res) => { } } - // Badge méretek - const padding = 10; - const iconSize = parseInt(size); - const fontSize = Math.round(iconSize * 0.6); // Font size az ikon méret 60%-a - const textPadding = Math.round(iconSize * 0.4); // Dinamikus: size 40%-a - const radius = 8; - const approxCharWidth = fontSize * 0.6; - const textWidth = label.length * approxCharWidth; + // ÚJ: doboz magasság 5 pixellel nagyobb legyen az ikon méreténél + const boxHeight = iconSize + 5; + const labelBoxHeight = boxHeight; + const totalHeight = Math.max(boxHeight, fontSize + padding * 2); let width, height, iconGroup, textElem; - // Szebb, élsimított font shields.io stílusban const fontFamily = "Verdana,Geneva,DejaVu Sans,sans-serif"; const fontWeight = fontweight; // paraméterből - if (labelpos === 'above' || labelpos === 'below') { - width = Math.max(iconSize, textWidth) + padding * 2; - height = padding * 2 + iconSize + textPadding + fontSize; - if (labelpos === 'above') { - // Szöveg felül, ikon alul - textElem = `<text x="${width / 2}" y="${padding + fontSize}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" text-anchor="middle" dominant-baseline="middle">${label}</text>`; - iconGroup = `<g transform="translate(${(width - iconSize) / 2}, ${padding + fontSize + textPadding})">${iconSVG}</g>`; - } else { - // Szöveg alul, ikon felül - iconGroup = `<g transform="translate(${(width - iconSize) / 2}, ${padding})">${iconSVG}</g>`; - textElem = `<text x="${width / 2}" y="${padding + iconSize + textPadding}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" text-anchor="middle" dominant-baseline="hanging">${label}</text>`; - } - } else if (labelpos === 'left') { - width = padding * 2 + iconSize + textPadding + textWidth; - height = Math.max(iconSize + padding * 2, fontSize + padding * 2); - // Szöveg balra, ikon jobbra (függőleges közép) - textElem = `<text x="${padding}" y="${height / 2}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" alignment-baseline="middle" dominant-baseline="middle">${label}</text>`; - iconGroup = `<g transform="translate(${padding + textWidth + textPadding}, ${(height - iconSize) / 2})">${iconSVG}</g>`; + if (labelpos === 'left') { + // Külön dobozok: padding csak a széleken kell, a dobozokon belül nem! + textElem = `<rect x="0" y="0" width="${textWidth}" height="${iconBoxHeight}" rx="${radius}" fill="${bglabel}"/> + <text x="${textWidth / 2}" y="${iconBoxHeight / 2}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" text-anchor="middle" dominant-baseline="middle">${effectiveLabel}</text>`; + iconGroup = ` + <rect x="${textWidth}" y="0" width="${iconBoxWidth + 5}" height="${iconBoxHeight}" rx="${radius}" fill="${bgicon}"/> + <g transform="translate(${textWidth + (5 / 2)}, ${(iconBoxHeight - iconSize) / 2})">${iconSVG}</g> + `; + } else if (labelpos === 'above' || labelpos === 'below') { + // Felső vagy alsó label: ikon doboz magassága = iconSize + 5, szélessége = szöveg doboz szélessége + width = Math.max(iconSize + 5, textWidth); + const labelRectHeight = fontSize + padding; + const iconRectY = labelpos === 'above' + ? labelRectHeight + : 0; + const labelRectY = labelpos === 'above' + ? 0 + : iconSize + 5; + height = iconSize + 5 + textPadding + labelRectHeight; + + // Label háttér + const labelRect = `<rect x="0" y="${labelRectY}" width="${width}" height="${labelRectHeight}" rx="${radius}" fill="${bglabel}"/>`; + // Ikon háttér + const iconRect = `<rect x="0" y="${iconRectY}" width="${width}" height="${iconSize + 5}" rx="${radius}" fill="${bgicon}"/>`; + + // Szöveg + const textY = labelpos === 'above' + ? labelRectY + 5 + labelRectHeight / 2 + : labelRectY + 5 + labelRectHeight / 2; + textElem = ` + ${labelRect} + <text x="${width / 2}" y="${textY}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" text-anchor="middle" dominant-baseline="middle">${effectiveLabel}</text> + `; + + // Ikon + iconGroup = ` + ${iconRect} + <g transform="translate(${(width - iconSize) / 2 + 2.5}, ${iconRectY + (iconSize + 5 - iconSize) / 2})">${iconSVG}</g> + `; } else { - width = padding * 2 + iconSize + textPadding + textWidth; - height = Math.max(iconSize + padding * 2, fontSize + padding * 2); // Alapértelmezett: ikon balra, szöveg jobbra (függőleges közép) - iconGroup = `<g transform="translate(${padding}, ${(height - iconSize) / 2})">${iconSVG}</g>`; - textElem = `<text x="${padding + iconSize + textPadding + textWidth / 2}" y="${height / 2}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" text-anchor="middle" dominant-baseline="middle">${label}</text>`; - } + iconGroup = ` + <rect x="0" y="0" width="${iconBoxWidth}" height="${iconBoxHeight}" rx="${radius}" fill="${bgicon}"/> + <g transform="translate(${(iconBoxWidth - iconViewBoxWidth) / 2}, ${(iconBoxHeight - iconViewBoxHeight) / 2})">${iconSVG}</g> + `; + textElem = `<rect x="${iconBoxWidth}" y="0" width="${textWidth}" height="${iconBoxHeight}" rx="${radius}" fill="${bglabel}"/> + <text x="${iconBoxWidth + textWidth / 2}" y="${iconBoxHeight / 2}" font-size="${fontSize}" font-family="${fontFamily}" font-weight="${fontWeight}" fill="${effectiveColor}" text-anchor="middle" dominant-baseline="middle">${effectiveLabel}</text>`; + } // SVG badge string összefűzéssel, szöveg árnyékkal const svg = ` @@ -92,7 +141,6 @@ app.get('/badge', async (req, res) => { <feDropShadow dx="0" dy="1" stdDeviation="1" flood-color="#000" flood-opacity="0.25"/> </filter> </defs> - <rect x="0" y="0" width="${width}" height="${height}" rx="${radius}" fill="${bg}"/> ${iconGroup} ${textElem.replace('<text ', '<text filter="url(#shadow)" ')} </svg>