feat: okraj stitkov predajni tensi (polovica linky cenovky) so zaoblenymi vonkajsimi rohmi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5cbe981430
commit
2a0b1f37ba
1 file changed
+23
-18
+23
-18
@@ -185,23 +185,28 @@ function renderDualSticker(p: CardProduct): string {
|
||||
</table>`;
|
||||
}
|
||||
|
||||
// Biely okraj okolo štítkov predajní ako skupiny (obrys celej skupiny, nie každého štítka zvlášť) – rovnako hrubý
|
||||
// ako biela linka okolo pozadia cenovky: 4,5 px pri predvolenej šírke cenovky 130 px, mení sa spolu s cenovkou.
|
||||
// Štyri biele tiene bez rozmazania (vľavo, vpravo, hore, dole) za sebou rozšíria tvar skupiny o hrúbku linky.
|
||||
function storesOutline(badgeWidth: number): string {
|
||||
const t = Math.round(((4.5 * badgeWidth) / 130) * 10) / 10;
|
||||
return `filter: drop-shadow(${t}px 0 0 #fff) drop-shadow(-${t}px 0 0 #fff) drop-shadow(0 ${t}px 0 #fff) drop-shadow(0 -${t}px 0 #fff);`;
|
||||
}
|
||||
|
||||
// Štítky predajní (Potraviny / Supermarket / Tempo) pod sebou; výška podľa veľkosti cenovky
|
||||
function renderStores(p: CardProduct, mode: RenderMode, tagHeight: number): string {
|
||||
const tag = (color: string, file: string, alt: string) =>
|
||||
`<div style="text-align: right; line-height: 0;"><img src="${escapeHtml(assetUrl(SUPABASE_ASSETS_BASE + file, mode))}" height="${tagHeight}" alt="${alt}" style="display: inline-block; height: ${tagHeight}px; width: auto; border: 0; background-color: ${color};"></div>`;
|
||||
return [
|
||||
p.stores?.potraviny ? tag('#e2001a', 'stit_potraviny.png', 'Potraviny') : '',
|
||||
p.stores?.supermarket ? tag('#f9890e', 'stit_supermarket.png', 'Supermarket') : '',
|
||||
p.stores?.tempo ? tag('#005239', 'stit_tempo.png', 'Tempo') : ''
|
||||
].join('');
|
||||
// Biely okraj okolo nich ako skupiny: pod štítkami je biela vrstva z rovnakých štítkov, každý o hrúbku okraja
|
||||
// väčší a so zaoblenými rohmi – kde sa štítky dotýkajú, biela splynie, takže linka ide okolo celej skupiny
|
||||
// a vonkajšie rohy sú zaoblené (polovica hrúbky linky okolo pozadia cenovky: 2,25 px pri cenovke širokej 130 px).
|
||||
function renderStores(p: CardProduct, mode: RenderMode, tagHeight: number, badgeWidth: number): string {
|
||||
const t = Math.round(((2.25 * badgeWidth) / 130) * 10) / 10;
|
||||
const tags = [
|
||||
p.stores?.potraviny ? ['#e2001a', 'stit_potraviny.png', 'Potraviny'] : null,
|
||||
p.stores?.supermarket ? ['#f9890e', 'stit_supermarket.png', 'Supermarket'] : null,
|
||||
p.stores?.tempo ? ['#005239', 'stit_tempo.png', 'Tempo'] : null
|
||||
].filter((x): x is string[] => !!x);
|
||||
if (!tags.length) return '';
|
||||
const row = ([color, file, alt]: string[], halo: boolean) =>
|
||||
`<div style="text-align: right; line-height: 0;"><img src="${escapeHtml(assetUrl(SUPABASE_ASSETS_BASE + file, mode))}" height="${tagHeight}" alt="${halo ? '' : alt}" style="display: inline-block; height: ${tagHeight}px; width: auto; border: 0; ${
|
||||
halo
|
||||
? `background-color: #ffffff; filter: brightness(0) invert(1); padding: ${t}px; margin: -${t}px; border-radius: ${t}px; box-sizing: content-box;`
|
||||
: `background-color: ${color};`
|
||||
}"></div>`;
|
||||
return `<div style="position: relative;">
|
||||
<div style="position: absolute; inset: 0;" aria-hidden="true">${tags.map((x) => row(x, true)).join('')}</div>
|
||||
<div style="position: relative;">${tags.map((x) => row(x, false)).join('')}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// Jednoznačný kľúč vizuálu – pri zmene čohokoľvek, čo ovplyvní obrázok, sa pri exporte vytvorí nový
|
||||
@@ -323,7 +328,7 @@ function renderVisualPreview(p: CardProduct, ctx: CardContext, key: string): str
|
||||
const oy = p.imageOffsetY || 0;
|
||||
const sx = Math.round(p.storesOffsetX ?? DEFAULT_STORES_OFFSET_X);
|
||||
const sy = Math.round(p.storesOffsetY ?? DEFAULT_STORES_OFFSET_Y);
|
||||
const stores = renderStores(p, ctx.mode, p.storesSize ?? DEFAULT_STORES_SIZE);
|
||||
const stores = renderStores(p, ctx.mode, p.storesSize ?? DEFAULT_STORES_SIZE, bw);
|
||||
// Pravý horný roh viditeľného pozadia cenovky (pri PNG a predvolenej cenovke = roh cenovky)
|
||||
const bgBox = p.badgeCustomTemplate && !p.customBadgePngUrl ? badgeBackgroundBox(p.badgeCustomTemplate) : null;
|
||||
const insetTop = bgBox ? Math.round(bgBox.top * bw * bgBox.aspect) : 0;
|
||||
@@ -341,7 +346,7 @@ function renderVisualPreview(p: CardProduct, ctx: CardContext, key: string): str
|
||||
.join('')}
|
||||
${(p.labels || []).map(renderLabel).join('')}
|
||||
<div style="position: absolute; right: 8px; bottom: 8px; width: ${bw}px;">
|
||||
${stores ? `<div style="position: absolute; right: ${insetRight - sx}px; bottom: calc(100% - ${insetTop}px + ${sy}px); ${storesOutline(bw)}">${stores}</div>` : ''}
|
||||
${stores ? `<div style="position: absolute; right: ${insetRight - sx}px; bottom: calc(100% - ${insetTop}px + ${sy}px);">${stores}</div>` : ''}
|
||||
${renderBadge(p, ctx, bw)}
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
Reference in new issue
Block a user