feat: zalamovanie riadkov v nadpisoch, cely nahlad cenovky v zozname sablon

- Enter alebo <br> v nadpise = novy riadok (clanky, recepty, letaky, banner,
  nazov produktu); polia nadpisov su viacriadkove
- nahlad sablony v editore cenoviek uz nie je orezany zhora a zdola

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub_HostacnyandClaude Opus 5.5 committed 2026-10-19 16:50:27 +02:00
1 parent 090fd8d1ce
commit a2d009bcb8
3 files changed
+35 -23

No files matched your search

+1 -1
View File
@@ -722,7 +722,7 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
</div>
</div>
<div
className="w-full h-12 flex items-center justify-center transform scale-75 origin-center overflow-hidden pointer-events-none"
className="w-full h-20 flex items-center justify-center overflow-hidden pointer-events-none [&>svg]:h-full! [&>svg]:w-auto! [&>svg]:max-w-full!"
dangerouslySetInnerHTML={{
__html: renderCleanBadgeSvg(
b,
+20 -15
View File
@@ -526,11 +526,12 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
</div>
<div>
<label className="block text-xs font-semibold text-gray-700 mb-1">Nadpis pod bannerom</label>
<input
type="text"
<textarea
rows={2}
value={module.data.title || ''}
onChange={(e) => updateData({ title: e.target.value })}
className="w-full text-sm border border-gray-300 rounded-lg p-2"
title="Enter = nový riadok (alebo <br>)"
className="w-full text-sm border border-gray-300 rounded-lg p-2 resize-y"
/>
</div>
<div>
@@ -2020,13 +2021,14 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
<div className="space-y-3">
<div>
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Nadpis letáku</label>
<input
type="text"
<textarea
rows={2}
value={module.data.item1?.title || ''}
onChange={(e) => updateData({
item1: { ...module.data.item1, title: e.target.value }
})}
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
title="Enter = nový riadok (alebo <br>)"
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold resize-y"
placeholder="Aktuálne letáky"
/>
</div>
@@ -2065,13 +2067,14 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
<div className="space-y-3">
<div>
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Nadpis letáku</label>
<input
type="text"
<textarea
rows={2}
value={module.data.item2?.title || ''}
onChange={(e) => updateData({
item2: { ...module.data.item2, title: e.target.value }
})}
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
title="Enter = nový riadok (alebo <br>)"
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold resize-y"
placeholder="Rozšírený leták"
/>
</div>
@@ -2113,13 +2116,14 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
<div className="space-y-3">
<div>
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Názov / Text článku</label>
<input
type="text"
<textarea
rows={2}
value={module.data.item1?.title || ''}
onChange={(e) => updateData({
item1: { ...module.data.item1, title: e.target.value }
})}
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
title="Enter = nový riadok (alebo <br>)"
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold resize-y"
/>
</div>
<div>
@@ -2156,13 +2160,14 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
<div className="space-y-3">
<div>
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Názov / Text článku</label>
<input
type="text"
<textarea
rows={2}
value={module.data.item2?.title || ''}
onChange={(e) => updateData({
item2: { ...module.data.item2, title: e.target.value }
})}
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
title="Enter = nový riadok (alebo <br>)"
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold resize-y"
/>
</div>
<div>
+14 -7
View File
@@ -328,8 +328,8 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
${m.data.title || m.data.description || m.data.buttonText ? `
<tr>
<td style="padding: 30px 20px; text-align: center;" class="mobile-padding">
${m.data.title ? `<h1 class="force-text-dark" style="margin: 0 0 15px 0; font-size: 24px; color: #1a1a1a; font-weight: 700;">${escapeHtml(m.data.title)}</h1>` : ''}
${m.data.description ? `<p class="force-text-dark" style="margin: 0 0 25px 0; font-size: 15px; line-height: 1.5; color: #555555;">${escapeHtml(m.data.description)}</p>` : ''}
${m.data.title ? `<h1 class="force-text-dark" style="margin: 0 0 15px 0; font-size: 24px; color: #1a1a1a; font-weight: 700;">${escapeWithBreaks(m.data.title)}</h1>` : ''}
${m.data.description ? `<p class="force-text-dark" style="margin: 0 0 25px 0; font-size: 15px; line-height: 1.5; color: #555555;">${escapeWithBreaks(m.data.description)}</p>` : ''}
${m.data.buttonText ? `
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: auto;" class="btn-table">
<tr>
@@ -473,7 +473,7 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" style="height: 100%;">
<tr>
<td valign="top" style="text-align: center; min-height: 44px; padding-bottom: 15px;">
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: ${it1.textColor || '#fefefe'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.25;">${escapeHtml(it1.title)}</h3>
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: ${it1.textColor || '#fefefe'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.25;">${escapeWithBreaks(it1.title)}</h3>
</td>
</tr>
<tr height="1">
@@ -507,7 +507,7 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" style="height: 100%;">
<tr>
<td valign="top" style="text-align: center; min-height: 44px; padding-bottom: 15px;">
<h3 style="margin: 0; font-size: 17px; color: ${it2.textColor || '#29446f'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.25;">${escapeHtml(it2.title)}</h3>
<h3 style="margin: 0; font-size: 17px; color: ${it2.textColor || '#29446f'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.25;">${escapeWithBreaks(it2.title)}</h3>
</td>
</tr>
<tr height="1">
@@ -560,7 +560,7 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
</tr>
<tr>
<td style="padding: 15px 15px 25px 15px; text-align: center; height: 100%;" valign="middle">
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: #fefefe; font-weight: 800; text-transform: uppercase; letter-spacing: 0.8px; line-height: 1.25;">${escapeHtml(it1.title)}</h3>
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: #fefefe; font-weight: 800; text-transform: uppercase; letter-spacing: 0.8px; line-height: 1.25;">${escapeWithBreaks(it1.title)}</h3>
</td>
</tr>
</table>
@@ -589,7 +589,7 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
</tr>
<tr>
<td style="padding: 15px 15px 25px 15px; text-align: center; height: 100%;" valign="middle">
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: #fefefe; font-weight: 800; text-transform: uppercase; letter-spacing: 0.8px; line-height: 1.25;">${escapeHtml(it2.title)}</h3>
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: #fefefe; font-weight: 800; text-transform: uppercase; letter-spacing: 0.8px; line-height: 1.25;">${escapeWithBreaks(it2.title)}</h3>
</td>
</tr>
</table>
@@ -717,7 +717,7 @@ function renderStackedImageRow(p: ProductItem, imgHtml: string, cellStyle: strin
// názov 15px/700 · gramáž 15px/400 (v tom istom riadku) · jednotková cena 11px #555 · poznámka 10px #888
const PRODUCT_TEXT_FONT = "font-family: 'Poppins', Helvetica, Arial, sans-serif;";
function renderProductTextBlock(p: { title?: string; quantity?: string; note?: string }, unitPrice?: string): string {
return `<h3 class="prod-name force-text-dark" style="margin: 0; ${PRODUCT_TEXT_FONT} font-size: 15px; line-height: 1.25; font-weight: 700; color: #1a1a1a;">${escapeHtml(p.title || '')}${p.quantity ? ` <span style="font-weight: 400;">${escapeHtml(p.quantity)}</span>` : ''}</h3>${
return `<h3 class="prod-name force-text-dark" style="margin: 0; ${PRODUCT_TEXT_FONT} font-size: 15px; line-height: 1.25; font-weight: 700; color: #1a1a1a;">${escapeWithBreaks(p.title || '')}${p.quantity ? ` <span style="font-weight: 400;">${escapeHtml(p.quantity)}</span>` : ''}</h3>${
unitPrice ? `
<div class="prod-unit force-text-dark" style="margin-top: 3px; ${PRODUCT_TEXT_FONT} font-size: 11px; line-height: 1.3; color: #555555;">${escapeHtml(unitPrice)}</div>` : ''}${
p.note ? `
@@ -1095,6 +1095,13 @@ function renderExactLoyaltyCard(p: any, validity: string, storesOffset: StoresOf
</table>`;
}
// Text nadpisu so zalomením riadkov: Enter (nový riadok) alebo <br> v texte = <br>, inak escapované
function escapeWithBreaks(str: string): string {
return escapeHtml(str)
.replace(/&lt;br\s*\/?&gt;/gi, '<br>')
.replace(/\r?\n/g, '<br>');
}
function escapeHtml(str: string): string {
if (!str) return '';
return String(str)