feat: nahradenie produktov pri importe ZIP, mensia cena od 10 EUR v cenovke, prevod SVG cenoviek

- import ZIP: volba Vymazat doterajsie produkty v sekcii
- vrstva ceny: longPriceScale (Cena od 10 EUR) zmensi dvojciferne eura, uciaria ostava
- skript na prevod SVG z Illustratora na pozadia sablon (texty na krivky,
  jedinecne triedy a id, zarovnanie tela cenovky)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub_HostacnyandClaude Opus 5.5 committed 2026-10-21 16:00:35 +02:00
1 parent bd67fc7020
commit fa824c541e
6 files changed
+173 -11

No files matched your search

+18 -7
View File
@@ -97,6 +97,8 @@ export function badgePriceParts(token: string, product: BadgeProductData): [stri
return [product.priceMain || '0', product.priceSub || '00'];
}
const round2 = (n: number) => Math.round(n * 100) / 100;
/**
* Vygeneruje 100% čistý vektorový SVG reťazec cenovky bez akýchkoľvek
* editovacích rámčekov, tooltippov či ovládacích prvkov.
@@ -155,11 +157,21 @@ export function renderCleanBadgeSvg(
// Zostavenie textových vrstiev
const textLayersSvg = (template.layersConfig || []).map((layer, layerIndex) => {
const rawText = layer.text || '';
const fontSize = layer.fontSize || 16;
const subFontSize = layer.indexFontSize || Math.max(10, Math.round(fontSize * 0.55));
const subDy = layer.indexOffsetY !== undefined ? `${layer.indexOffsetY}px` : '-0.45em';
const subDx = layer.indexOffsetX !== undefined ? `${layer.indexOffsetX}px` : '1px';
const revertDy = layer.indexOffsetY !== undefined ? `${-layer.indexOffsetY}px` : '0.45em';
const priceMatch = rawText.match(BADGE_PRICE_TOKEN_RE);
// Cena od 10 € (dvojciferné eurá): menšie písmo, účiaria eur aj centov ostáva na mieste
// (0.43 ≈ vzdialenosť stredu písma od účiarie v em – vrstvy sa kreslia so strednou účiariou)
const baseSize = layer.fontSize || 16;
const baseSub = layer.indexFontSize || Math.max(10, Math.round(baseSize * 0.55));
const long = !!priceMatch && !!layer.longPriceScale && layer.longPriceScale < 1 && badgePriceParts(priceMatch[1], product)[0].length >= 2;
const k = long ? layer.longPriceScale! : 1;
const fontSize = round2(baseSize * k);
const subFontSize = round2(baseSub * k);
const layerY = long ? round2(layer.y + 0.43 * baseSize * (1 - k)) : layer.y;
const offY = layer.indexOffsetY !== undefined ? round2(layer.indexOffsetY - (long ? 0.43 * (1 - k) * (baseSize - baseSub) : 0)) : undefined;
const offX = layer.indexOffsetX !== undefined ? round2(layer.indexOffsetX * k) : undefined;
const subDy = offY !== undefined ? `${offY}px` : '-0.45em';
const subDx = offX !== undefined ? `${offX}px` : '1px';
const revertDy = offY !== undefined ? `${-offY}px` : '0.45em';
const fontWeight = layer.fontWeight || '700';
const fill = layer.fill || '#ffffff';
const fontFamily = layer.fontFamily
@@ -172,7 +184,6 @@ export function renderCleanBadgeSvg(
// Formátovanie textu: ak obsahuje {cena} alebo {centy}, centy vložíme do <tspan> ako horný index
let contentSvg = '';
const priceMatch = rawText.match(BADGE_PRICE_TOKEN_RE);
if (priceMatch) {
const [tokMain, tokSub] = badgePriceParts(priceMatch[1], product);
const idx = priceMatch.index || 0;
@@ -189,7 +200,7 @@ export function renderCleanBadgeSvg(
}
// data-layer-index: editor cenoviek podľa neho nájde a odmeria vrstvu na plátne
return `<text data-layer-index="${layerIndex}" x="${layer.x}" y="${layer.y}" text-anchor="${anchor}" dominant-baseline="central" font-family="${fontFamily}" font-size="${fontSize}px" font-weight="${fontWeight}" fill="${fill}">${contentSvg}</text>`;
return `<text data-layer-index="${layerIndex}" x="${layer.x}" y="${layerY}" text-anchor="${anchor}" dominant-baseline="central" font-family="${fontFamily}" font-size="${fontSize}px" font-weight="${fontWeight}" fill="${fill}">${contentSvg}</text>`;
}).join('\n ');
return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="${vb}" width="${displayWidth}" height="${displayHeight}" style="display:block;max-width:100%;height:auto;">