feat: vsetky sablony cenoviek z novych SVG (zakladne, appkaci, vernostna karta)

- 22 sablon: Super cena / Super vyhodne / Zakladna v 3 farbach so SK aj bez,
  Appkaci (SK / bez), Vernostna karta (so zlavou / bez); orezane na viditelny
  obsah, rovnaka mierka (sirka = viewBox x 130 / 80,1)
- nove premenne {zlava_app}, {jednotkova_cena_app}, {cena_bez_karty},
  {zlava_bez_karty}, {jednotkova_cena_s_kartou}, {jednotkova_cena_bez_karty};
  zvisle natiahnutie textu (scaleY), viac nazvov pisma, napis zlava len pri zlave
- Vernostna karta je predvolena cenovka sekcie Vernostne zlavy
- produkty pri nacitani dostanu aktualnu verziu svojej sablony
- import: zlava pre appkacov a s vernostnou kartou z poznamky, jednotkova cena
  pre appkacov prepocitana, sirka cenovky podla sablony
- okraj stitkov predajni podla mierky cenovky
- postup prevodu v scripts/badges

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub_HostacnyandClaude Opus 5.5 committed 2026-10-22 10:36:37 +02:00
1 parent 50af94f954
commit af35334688
13 files changed
+300 -107

No files matched your search

+27 -4
View File
@@ -73,16 +73,28 @@ export interface BadgeProductData {
cardDiscount?: string; // zľava s kartou → {zlava_s_kartou}
appPriceMain?: string; // cena pre appkáčov → {cena_app}
appPriceSub?: string;
appDiscount?: string; // → {zlava_app}
appUnitPrice?: string; // → {jednotkova_cena_app}
cardUnitPrice?: string; // → {jednotkova_cena_s_kartou}
noCardPriceMain?: string; // cena bez vernostnej karty → {cena_bez_karty}
noCardPriceSub?: string;
noCardDiscount?: string; // → {zlava_bez_karty}
noCardUnitPrice?: string; // → {jednotkova_cena_bez_karty}
}
// Premenné ceny s centami v hornom indexe: {cena}, {cena_s_kartou} a {cena_app}
export const BADGE_PRICE_TOKEN_RE = /\{(cena|cena_s_kartou|cena_app)\}/;
// Premenné ceny s centami v hornom indexe: {cena}, {cena_s_kartou}, {cena_bez_karty} a {cena_app}
export const BADGE_PRICE_TOKEN_RE = /\{(cena|cena_s_kartou|cena_bez_karty|cena_app)\}/;
// Nahradenie jednoduchých textových premenných (bez horného indexu)
export function replaceBadgeTextVars(text: string, product: BadgeProductData): string {
return text
.replace(/{cela_suma}/g, product.priceMain || '0')
.replace(/{zlava_s_kartou}/g, (product.cardDiscount || '').replace('-', ''))
.replace(/{zlava_bez_karty}/g, (product.noCardDiscount || '').replace('-', ''))
.replace(/{zlava_app}/g, (product.appDiscount || '').replace('-', ''))
.replace(/{jednotkova_cena_s_kartou}/g, product.cardUnitPrice || product.unitPrice || '')
.replace(/{jednotkova_cena_bez_karty}/g, product.noCardUnitPrice || '')
.replace(/{jednotkova_cena_app}/g, product.appUnitPrice || '')
.replace(/{zlava}/g, (product.discountText || '').replace('-', ''))
.replace(/{jednotkova_cena}/g, product.unitPrice || '')
.replace(/{mena}/g, '€');
@@ -96,6 +108,9 @@ export function badgePriceParts(token: string, product: BadgeProductData): [stri
if (token === 'cena_app') {
return [product.appPriceMain || '', product.appPriceSub || ''];
}
if (token === 'cena_bez_karty') {
return [product.noCardPriceMain || '', product.noCardPriceSub || ''];
}
return [product.priceMain || '0', product.priceSub || '00'];
}
@@ -158,6 +173,8 @@ export function renderCleanBadgeSvg(
// Zostavenie textových vrstiev
const textLayersSvg = (template.layersConfig || []).map((layer, layerIndex) => {
// napr. nápis „zľava“ len vtedy, keď má produkt zľavu
if (layer.showIfFilled && !replaceBadgeTextVars(layer.showIfFilled, product).trim()) return '';
const rawText = layer.text || '';
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
@@ -176,8 +193,12 @@ export function renderCleanBadgeSvg(
const revertDy = offY !== undefined ? `${-offY}px` : '0.45em';
const fontWeight = layer.fontWeight || '700';
const fill = layer.fill || '#ffffff';
// písmo môže mať viac názvov oddelených čiarkou (napr. názov v Adobe Fonts a názov nainštalovaného písma)
const fontFamily = layer.fontFamily
? `'${layer.fontFamily}', -apple-system, BlinkMacSystemFont, Arial, sans-serif`
? `${layer.fontFamily
.split(',')
.map((f) => `'${f.trim().replace(/'/g, '')}'`)
.join(', ')}, -apple-system, BlinkMacSystemFont, Arial, sans-serif`
: `'Arial Narrow', Arial, sans-serif`;
let anchor = 'middle';
@@ -205,7 +226,9 @@ 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="${layerY}" text-anchor="${anchor}" dominant-baseline="central"${caronDx ? ` dx="${caronDx}"` : ''}${layer.letterSpacing ? ` letter-spacing="${layer.letterSpacing}em"` : ''} 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"${
layer.scaleY && layer.scaleY !== 1 ? ` transform="translate(${layer.x} ${layerY}) scale(1 ${layer.scaleY}) translate(${-layer.x} ${-layerY})"` : ''
}${caronDx ? ` dx="${caronDx}"` : ''}${layer.letterSpacing ? ` letter-spacing="${layer.letterSpacing}em"` : ''} 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;">