fix: replace gourmet-hero's fake category tabs with real ones
Same issue as the cards just removed from cream-elegance: a hardcoded ['РЫБНЫЕ','МЯСНЫЕ','ВЕГЕТАРИАНСКИЕ','САЛАТЫ','ДЕСЕРТЫ'] tab row that had nothing to do with what was actually in the order (an order with zero vegetarian items still showed a "ВЕГЕТАРИАНСКИЕ" tab as if active/relevant). Now derives the chip row from the distinct categoryName values actually present on the order's items, and renders nothing if that data isn't available. Verified this pass end-to-end rather than just by inspection: - Real "Скачать PDF" pipeline (sunClientOfferDebugPdf) produces a valid application/pdf blob with a correct %PDF-1.4 header, not just canvases. - Confirmed Canvas text genuinely falls back through the font stack (measured identical metrics for an unregistered font vs. Georgia directly, and document.fonts.load() resolves instantly for a never-registered family) -- so a blocked/unreachable Google Fonts degrades silently to Georgia/Arial instead of hanging or erroring, which matters given this app already had to work around Russia connectivity issues elsewhere. - Re-rendered all 6 templates against deliberately adversarial data (150+ word event name, 44-char client name, 350 guests, a million-ruble price, an item with no photo/price/category, a long promo code) -- no crashes, no overlap, graceful ellipsis truncation throughout. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
b702b4b69e
commit
28fd97bcf3
@ -146,7 +146,8 @@
|
|||||||
checklistCard(ctx,p,M,1170,470,150,'ВСЁ ПОД КОНТРОЛЕМ КОМАНДЫ СОЛНЦА',CHECK_LINES,{dark:true,fonts:f});addonRow(ctx,p,540,1170,406,150,ADDON_LINES,{dark:true,fonts:f});
|
checklistCard(ctx,p,M,1170,470,150,'ВСЁ ПОД КОНТРОЛЕМ КОМАНДЫ СОЛНЦА',CHECK_LINES,{dark:true,fonts:f});addonRow(ctx,p,540,1170,406,150,ADDON_LINES,{dark:true,fonts:f});
|
||||||
}else if(id==='gourmet-hero'){
|
}else if(id==='gourmet-hero'){
|
||||||
logoOrBrand(ctx,logo,p,{x:W-M-190,y:44,dark:true,fonts:f},s.brandName);text(ctx,'КЕЙТЕРИНГ ДЛЯ',M,96,460,44,{font:`700 32px ${f.display}`,color:'#fff',maxLines:1});text(ctx,'ВАШЕГО СОБЫТИЯ',M,140,460,44,{font:`700 32px ${f.display}`,color:'#fff',maxLines:1});text(ctx,'Индивидуальное меню, безупречная подача и сервис, о котором будут говорить ваши гости.',M,235,400,24,{font:`500 14px ${f.label}`,color:p.muted,maxLines:3});if(hero)coverImage(ctx,hero,520,60,426,340,18);roundRect(ctx,520,420,240,42,12,p.paper,p.line);text(ctx,String((s.items||[]).length)+' блюд в меню',540,432,220,18,{font:`700 12px ${f.label}`,color:p.accent,maxLines:1});
|
logoOrBrand(ctx,logo,p,{x:W-M-190,y:44,dark:true,fonts:f},s.brandName);text(ctx,'КЕЙТЕРИНГ ДЛЯ',M,96,460,44,{font:`700 32px ${f.display}`,color:'#fff',maxLines:1});text(ctx,'ВАШЕГО СОБЫТИЯ',M,140,460,44,{font:`700 32px ${f.display}`,color:'#fff',maxLines:1});text(ctx,'Индивидуальное меню, безупречная подача и сервис, о котором будут говорить ваши гости.',M,235,400,24,{font:`500 14px ${f.label}`,color:p.muted,maxLines:3});if(hero)coverImage(ctx,hero,520,60,426,340,18);roundRect(ctx,520,420,240,42,12,p.paper,p.line);text(ctx,String((s.items||[]).length)+' блюд в меню',540,432,220,18,{font:`700 12px ${f.label}`,color:p.accent,maxLines:1});
|
||||||
const tabs=['РЫБНЫЕ','МЯСНЫЕ','ВЕГЕТАРИАНСКИЕ','САЛАТЫ','ДЕСЕРТЫ'];let tx=M;tabs.forEach((t,i)=>{text(ctx,t,tx,505,200,16,{font:`700 11px ${f.label}`,color:i===0?'#fff':p.muted,maxLines:1});if(i===0)line(ctx,tx,528,tx+70,528,p.accent,2);tx+=90});
|
const realCats=[...new Set((s.items||[]).map(it=>it.categoryName).filter(Boolean))].slice(0,5);
|
||||||
|
if(realCats.length){const gap=10,cw=(W-2*M-gap*(realCats.length-1))/realCats.length;realCats.forEach((t,i)=>{const xx=M+i*(cw+gap);roundRect(ctx,xx,494,cw,32,10,'rgba(255,255,255,.06)',p.line);text(ctx,t,xx+cw/2,503,cw-10,14,{font:`600 10px ${f.label}`,color:p.accent,align:'center',maxLines:1})})}
|
||||||
const featured=(s.items||[]).slice(0,3);const cardW=(W-2*M-2*14)/3;
|
const featured=(s.items||[]).slice(0,3);const cardW=(W-2*M-2*14)/3;
|
||||||
{const imgs=await Promise.all(featured.map(it=>loadImage(it.photoData||'')));featured.forEach((it,i)=>{const xx=M+i*(cardW+14);roundRect(ctx,xx,555,cardW,230,16,p.paper,p.line);if(imgs[i])coverImage(ctx,imgs[i],xx,555,cardW,150,16);text(ctx,String(i+1).padStart(2,'0'),xx+14,715,40,16,{font:`700 12px ${f.label}`,color:p.accent,maxLines:1});text(ctx,it.name||'Позиция меню',xx+14,735,cardW-28,20,{font:`600 13px ${f.display}`,color:'#fff',maxLines:2});if(it.weight)text(ctx,String(it.weight),xx+14,765,cardW-28,14,{font:`500 10px ${f.label}`,color:p.muted,maxLines:1})})}
|
{const imgs=await Promise.all(featured.map(it=>loadImage(it.photoData||'')));featured.forEach((it,i)=>{const xx=M+i*(cardW+14);roundRect(ctx,xx,555,cardW,230,16,p.paper,p.line);if(imgs[i])coverImage(ctx,imgs[i],xx,555,cardW,150,16);text(ctx,String(i+1).padStart(2,'0'),xx+14,715,40,16,{font:`700 12px ${f.label}`,color:p.accent,maxLines:1});text(ctx,it.name||'Позиция меню',xx+14,735,cardW-28,20,{font:`600 13px ${f.display}`,color:'#fff',maxLines:2});if(it.weight)text(ctx,String(it.weight),xx+14,765,cardW-28,14,{font:`500 10px ${f.label}`,color:p.muted,maxLines:1})})}
|
||||||
roundRect(ctx,M,822,W-2*M,52,14,null,p.accent,1.4);text(ctx,'СМОТРЕТЬ ПОЛНОЕ МЕНЮ →',W/2,838,W,18,{font:`700 12px ${f.label}`,color:p.accent,align:'center',maxLines:1});
|
roundRect(ctx,M,822,W-2*M,52,14,null,p.accent,1.4);text(ctx,'СМОТРЕТЬ ПОЛНОЕ МЕНЮ →',W/2,838,W,18,{font:`700 12px ${f.label}`,color:p.accent,align:'center',maxLines:1});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user