helmet added, box real width/height

This commit is contained in:
2025-07-09 13:49:23 +02:00
parent ec9359fb0a
commit b72e4861eb
4 changed files with 41 additions and 31 deletions
+7 -3
View File
@@ -10,7 +10,8 @@ Az alábbi paraméterekkel szabályozhatod a `/badge` végpont működését:
|-------------|----------|-----------------------|----------------------------------------------------------------------------------------|------------------------------| |-------------|----------|-----------------------|----------------------------------------------------------------------------------------|------------------------------|
| `icon` | Igen |`simpleicons` | A SimpleIcons ikon neve (kisbetű, kötőjellel). | `github`, `docker`, `nginx` | | `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` | | `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` | | `bgicon` | Nem |`#cccccc` | Icon Háttérszín (hex vagy CSS színnév). | `#fff`, `#222`, `red` |
| `bglabel` | Nem |`#cccccc` | Label 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` | | `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` | | `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` | | `labelpos` | Nem | `right` | Szöveg pozíciója az ikonhoz képest: `right`, `left`, `above`, `below`. | `left`, `above` |
@@ -21,8 +22,11 @@ Az alábbi paraméterekkel szabályozhatod a `/badge` végpont működését:
- **Alap badge:** - **Alap badge:**
`/badge` `/badge`
- **GitHub ikon, piros háttér, fehér szöveg:** - **React ikon, label, size: 64, font: bold, fehér label szöveg, sárga label háttérszín, piros ikon háttérszín, label jobbra**
`/badge?icon=github&bg=red&color=white` `/badge?icon=react&label=React%20expert%20level&size=64&fontweight=bold&color=white&bgicon=red&bglabel=yellow&labelpos=right`
- **GitHub ikon, piros label háttér, fehér szöveg:**
`/badge?icon=github&bglabel=red&color=white`
- **Szöveg balra, ikon jobbra:** - **Szöveg balra, ikon jobbra:**
`/badge?labelpos=left` `/badge?labelpos=left`
+23 -28
View File
@@ -1,9 +1,13 @@
const express = require('express'); const express = require('express');
const axios = require('axios'); const axios = require('axios');
const helmet = require('helmet');
const app = express(); const app = express();
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
app.use(helmet({
crossOriginResourcePolicy: false,
}));
app.get('/badge', async (req, res) => { app.get('/badge', async (req, res) => {
const { const {
icon = 'simpleicons', icon = 'simpleicons',
@@ -17,7 +21,7 @@ app.get('/badge', async (req, res) => {
} = req.query; } = req.query;
try { try {
// Ikon letöltése // download icon SVG from SimpleIcons CDN
const iconUrl = `https://cdn.simpleicons.org/${icon}?viewbox=auto&size=${size}`; const iconUrl = `https://cdn.simpleicons.org/${icon}?viewbox=auto&size=${size}`;
const iconResponse = await axios.get(iconUrl, { responseType: 'text' }); const iconResponse = await axios.get(iconUrl, { responseType: 'text' });
if (iconResponse.status !== 200) { if (iconResponse.status !== 200) {
@@ -25,7 +29,7 @@ app.get('/badge', async (req, res) => {
} }
const iconSVG = iconResponse.data; const iconSVG = iconResponse.data;
// Ha nincs label paraméter, akkor az ikon SVG <title> mezőjét használjuk // if there is no label query, use the title from the SVG
let effectiveLabel = label; let effectiveLabel = label;
if (!req.query.label || req.query.label === 'Simple Icons') { if (!req.query.label || req.query.label === 'Simple Icons') {
const titleMatch = iconSVG.match(/<title>([^<]+)<\/title>/i); const titleMatch = iconSVG.match(/<title>([^<]+)<\/title>/i);
@@ -34,11 +38,11 @@ app.get('/badge', async (req, res) => {
} }
} }
// Badge méretek // Badge size
const padding = 10; const padding = 10;
const iconSize = parseInt(size); const iconSize = parseInt(size);
const fontSize = Math.round(iconSize * 0.6); // Font size az ikon méret 60%-a const fontSize = Math.round(iconSize * 0.6);
const textPadding = Math.round(iconSize * 0.4); // Dinamikus: size 40%-a const textPadding = Math.round(iconSize * 0.4);
const radius = 8; const radius = 8;
const approxCharWidth = fontSize * 0.6; const approxCharWidth = fontSize * 0.6;
const textWidth = effectiveLabel.length * approxCharWidth; const textWidth = effectiveLabel.length * approxCharWidth;
@@ -58,26 +62,17 @@ app.get('/badge', async (req, res) => {
// Ha a color paraméter nincs megadva, próbáljuk kinyerni az ikon színét // Ha a color paraméter nincs megadva, próbáljuk kinyerni az ikon színét
let effectiveColor = color; let effectiveColor = color;
if (!req.query.color || req.query.color === '#000000') { if (!req.query.color || req.query.color === '#000000') {
// Próbáljuk kinyerni az ikon fő színét a SimpleIcons API-ból const match = iconSVG.match(/fill="([^"]+)"/);
try { if (match && match[1]) {
const iconMetaUrl = `https://cdn.simpleicons.org/${icon}`; effectiveColor = match[1];
const iconMetaResp = await axios.get(iconMetaUrl, { responseType: 'text' }); } else {
// Kikeressük az első "fill=" attribútumot effectiveColor = "#222"; // fallback
const match = iconMetaResp.data.match(/fill="([^"]+)"/);
if (match && match[1]) {
effectiveColor = match[1];
} else {
effectiveColor = "#222"; // fallback
}
} catch {
effectiveColor = "#222";
} }
} }
// ÚJ: doboz magasság 5 pixellel nagyobb legyen az ikon méreténél // doboz magasság 5 pixellel nagyobb legyen az ikon méreténél
const boxHeight = iconSize + 5; const iconSizeAndPadding = iconSize + 5;
const labelBoxHeight = boxHeight; const labelRectHeight = fontSize + padding;
const totalHeight = Math.max(boxHeight, fontSize + padding * 2);
let width, height, iconGroup, textElem; let width, height, iconGroup, textElem;
@@ -94,15 +89,15 @@ app.get('/badge', async (req, res) => {
`; `;
} else if (labelpos === 'above' || labelpos === 'below') { } 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 // 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); width = Math.max(iiconSizeAndPadding, textWidth);
const labelRectHeight = fontSize + padding;
const iconRectY = labelpos === 'above' const iconRectY = labelpos === 'above'
? labelRectHeight ? labelRectHeight
: 0; : 0;
const labelRectY = labelpos === 'above' const labelRectY = labelpos === 'above'
? 0 ? 0
: iconSize + 5; : iiconSizeAndPadding;
height = iconSize + 5 + textPadding + labelRectHeight; height = iconSizeAndPadding + textPadding + labelRectHeight;
// Label háttér // Label háttér
const labelRect = `<rect x="0" y="${labelRectY}" width="${width}" height="${labelRectHeight}" rx="${radius}" fill="${bglabel}"/>`; const labelRect = `<rect x="0" y="${labelRectY}" width="${width}" height="${labelRectHeight}" rx="${radius}" fill="${bglabel}"/>`;
@@ -135,7 +130,7 @@ app.get('/badge', async (req, res) => {
// SVG badge string összefűzéssel, szöveg árnyékkal // SVG badge string összefűzéssel, szöveg árnyékkal
const svg = ` const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" style="background:none"> <svg xmlns="http://www.w3.org/2000/svg" width="${(labelpos === 'left' || labelpos === 'right') ? iconBoxWidth + textWidth : width}" height="${(labelpos === 'left' || labelpos === 'right') ? iconBoxHeight : labelRectHeight+iconSize + 5}" style="background:none">
<defs> <defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%"> <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="1" stdDeviation="1" flood-color="#000" flood-opacity="0.25"/> <feDropShadow dx="0" dy="1" stdDeviation="1" flood-color="#000" flood-opacity="0.25"/>
+10
View File
@@ -12,6 +12,7 @@
"@svgdotjs/svg.js": "^3.2.4", "@svgdotjs/svg.js": "^3.2.4",
"axios": "^1.10.0", "axios": "^1.10.0",
"express": "^5.1.0", "express": "^5.1.0",
"helmet": "^8.1.0",
"svgdom": "^0.1.21" "svgdom": "^0.1.21"
} }
}, },
@@ -595,6 +596,15 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/helmet": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz",
"integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+1
View File
@@ -21,6 +21,7 @@
"@svgdotjs/svg.js": "^3.2.4", "@svgdotjs/svg.js": "^3.2.4",
"axios": "^1.10.0", "axios": "^1.10.0",
"express": "^5.1.0", "express": "^5.1.0",
"helmet": "^8.1.0",
"svgdom": "^0.1.21" "svgdom": "^0.1.21"
} }
} }