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

+137
View File
@@ -0,0 +1,137 @@
# Prevod testovacích SVG cenoviek z Illustratora na pozadia šablón:
# - ceny, zľava % a „zľava“ sa odstránia (budú z nich vrstvy editora),
# - statické nápisy (SUPER / CENA / VÝHODNÉ, písmo Gilroy-Heavy) sa prevedú na krivky,
# - triedy a id dostanú jedinečnú predponu (inak by sa viaceré cenovky na stránke prebíjali),
# - obsah sa posunie tak, aby telo cenovky bolo vo všetkých šablónach na rovnakom mieste.
#
# Použitie: pip install fonttools; python convert-illustrator-svg.py <priečinok so SVG> <výstup.json>
# (Gilroy-Heavy musí byť nainštalovaný; priradenie súborov k typu/farbe/pôvodu je v ASSETS nižšie.)
# Výstup obsahuje vyčistené SVG a namerané polohy textov – z nich sa vyrobili šablóny v tabuľke badges.
import json
import re
import sys
from fontTools.pens.svgPathPen import SVGPathPen
from fontTools.pens.transformPen import TransformPen
from fontTools.ttLib import TTFont
SRC = sys.argv[1]
OUT = sys.argv[2]
GILROY = r'C:\Users\jakub\AppData\Local\Microsoft\Windows\Fonts\Gilroy-Heavy.ttf'
font = TTFont(GILROY)
glyphs = font.getGlyphSet()
cmap = font.getBestCmap()
upem = font['head'].unitsPerEm
# referenčná poloha tela cenovky (zhora ľavý roh rámika s cenou)
REF_X = 27.98
ASSETS = {
'Asset 2.svg': ('SUPER CENA', 'cervena', 'SK'),
'Asset 3.svg': ('SUPER VÝHODNÉ', 'cervena', 'SK'),
'Asset 4.svg': ('SUPER CENA', 'oranzova', 'SK'),
'Asset 5.svg': ('SUPER CENA', 'zelena', 'SK'),
'Asset 6.svg': ('SUPER CENA', 'cervena', ''),
'Asset 7.svg': ('SUPER VÝHODNÉ', 'cervena', ''),
'Asset 8.svg': ('SUPER CENA', 'oranzova', ''),
'Asset 9.svg': ('SUPER VÝHODNÉ', 'zelena', ''),
}
def parse_css(svg):
style = re.search(r'<style>(.*?)</style>', svg, re.S).group(1)
props = {}
for sel, body in re.findall(r'([^{}]+)\{([^}]*)\}', style):
decl = dict(
(k.strip(), v.strip()) for k, v in (d.split(':', 1) for d in body.split(';') if ':' in d)
)
for cls in sel.split(','):
props.setdefault(cls.strip().lstrip('.'), {}).update(decl)
return props
def text_to_path(transform, runs, size, fill):
"""runs: [(x, text, letter_spacing_em)] → <path> s tou istou transformáciou ako pôvodný <text>."""
s = size / upem
pen = SVGPathPen(glyphs)
for x, txt, ls in runs:
cursor = x
for ch in txt:
name = cmap.get(ord(ch))
if not name:
continue
glyphs[name].draw(TransformPen(pen, (s, 0, 0, -s, cursor, 0)))
cursor += glyphs[name].width * s + ls * size
d = pen.getCommands()
return f'<path transform="{transform}" fill="{fill}" d="{d}"/>' if d else ''
result = []
for fname, (btype, color, origin) in ASSETS.items():
svg = open(f'{SRC}/{fname}', encoding='utf-8').read()
key = 'b' + re.sub(r'\D', '', fname)
css = parse_css(svg)
texts = {} # rola → údaje
def replace_text(m):
classes = m.group(1).split()
transform = m.group(2)
body = m.group(3)
p = {}
for c in classes:
p.update(css.get(c, {}))
size = float(p.get('font-size', '0').replace('px', ''))
family = p.get('font-family', '')
fill = p.get('fill', '#000')
runs = []
for tcls, x, txt in re.findall(r'<tspan(?: class="([^"]*)")? x="([\d.\-]+)" y="[\d.\-]+">([^<]*)</tspan>', body):
ls = css.get(tcls, {}).get('letter-spacing', '0em').replace('em', '') if tcls else '0'
runs.append((float(x), txt, float(ls or 0)))
content = ''.join(r[1] for r in runs)
tr = re.match(r'translate\(([\d.\-]+) ([\d.\-]+)\)', transform)
tx, ty = float(tr.group(1)), float(tr.group(2))
if not content.strip():
return ''
if 'Gilroy' in family:
return text_to_path(transform, runs, size, fill)
# Aptly: ceny, zľava % a „zľava“ → vrstvy editora
if '%' in content:
role = 'discount'
elif content.isdigit() and size >= 25:
role = 'main'
elif content.isdigit():
role = 'cents'
else:
role = 'label'
texts[role] = {'text': content, 'x': tx, 'y': ty, 'size': size, 'fill': fill, 'runs': runs}
return ''
svg = re.sub(r'<text class="([^"]+)" transform="([^"]+)">(.*?)</text>', replace_text, svg, flags=re.S)
# posun obsahu: rámik s cenou vždy na REF_X a jeho horná hrana na rovnakej výške v rámci druhu cenovky
rects = re.findall(r'<rect class="(cls-\d+)" x="([\d.]+)" y="([\d.]+)" width="48.53" height="41.94"/>', svg)
box_x, box_y = float(rects[0][1]), float(rects[0][2])
dx = REF_X - box_x
dy = (92.67 if btype == 'SUPER CENA' else 44.98) - box_y
# jedinečné triedy a id
svg = re.sub(r'\bcls-(\d+)\b', rf'{key}-c\1', svg)
for ident in set(re.findall(r'id="([^"]+)"', svg)):
svg = re.sub(rf'(id="|url\(#|xlink:href="#){re.escape(ident)}(["\)])', rf'\1{key}-{ident}\2', svg)
inner = re.sub(r'^.*?<svg[^>]*>', '', svg, flags=re.S)
inner = re.sub(r'</svg>\s*$', '', inner)
defs = re.search(r'<defs>.*?</defs>', inner, re.S).group(0)
body = inner.replace(defs, '')
vb = [float(v) for v in re.search(r'viewBox="([^"]+)"', svg).group(1).split()]
result.append({
'file': fname, 'key': key, 'type': btype, 'color': color, 'origin': origin,
'dx': dx, 'dy': dy, 'boxY': box_y, 'vb': vb, 'texts': texts,
'svg': f'{defs}<g transform="translate({dx:.2f} {dy:.2f})">{body.strip()}</g>',
})
json.dump(result, open(OUT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
for r in result:
print(r['file'], r['type'], r['color'], r['origin'], 'dx', round(r['dx'], 2), 'dy', round(r['dy'], 2), 'boxY', r['boxY'], 'texts', {k: v['text'] for k, v in r['texts'].items()}, len(r['svg']))